2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2014, 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
.Reset
= ScsiDiskReset
;
238 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
239 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
240 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
241 ScsiDiskDevice
->Handle
= Controller
;
243 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
244 switch (ScsiDiskDevice
->DeviceType
) {
245 case EFI_SCSI_TYPE_DISK
:
246 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
247 MustReadCapacity
= TRUE
;
250 case EFI_SCSI_TYPE_CDROM
:
251 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
252 MustReadCapacity
= FALSE
;
256 // The Sense Data Array's initial size is 6
258 ScsiDiskDevice
->SenseDataNumber
= 6;
259 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
260 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
262 if (ScsiDiskDevice
->SenseData
== NULL
) {
265 &gEfiScsiIoProtocolGuid
,
266 This
->DriverBindingHandle
,
269 FreePool (ScsiDiskDevice
);
270 return EFI_OUT_OF_RESOURCES
;
274 // Retrieve device information
277 for (Index
= 0; Index
< MaxRetry
; Index
++) {
278 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
279 if (!EFI_ERROR (Status
)) {
284 FreePool (ScsiDiskDevice
->SenseData
);
287 &gEfiScsiIoProtocolGuid
,
288 This
->DriverBindingHandle
,
291 FreePool (ScsiDiskDevice
);
292 return EFI_DEVICE_ERROR
;
296 // The second parameter "TRUE" means must
297 // retrieve media capacity
299 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
300 if (!EFI_ERROR (Status
)) {
302 // Determine if Block IO should be produced on this controller handle
304 if (DetermineInstallBlockIo(Controller
)) {
305 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
306 Status
= gBS
->InstallMultipleProtocolInterfaces (
308 &gEfiBlockIoProtocolGuid
,
309 &ScsiDiskDevice
->BlkIo
,
310 &gEfiDiskInfoProtocolGuid
,
311 &ScsiDiskDevice
->DiskInfo
,
314 if (!EFI_ERROR(Status
)) {
315 ScsiDiskDevice
->ControllerNameTable
= NULL
;
318 gScsiDiskComponentName
.SupportedLanguages
,
319 &ScsiDiskDevice
->ControllerNameTable
,
325 gScsiDiskComponentName2
.SupportedLanguages
,
326 &ScsiDiskDevice
->ControllerNameTable
,
335 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
336 gBS
->FreePool (ScsiDiskDevice
);
339 &gEfiScsiIoProtocolGuid
,
340 This
->DriverBindingHandle
,
349 Stop this driver on ControllerHandle.
351 This service is called by the EFI boot service DisconnectController().
352 In order to make drivers as small as possible, there are a few calling
353 restrictions for this service. DisconnectController() must follow these
354 calling restrictions. If any other agent wishes to call Stop() it must
355 also follow these calling restrictions.
357 @param This Protocol instance pointer.
358 @param ControllerHandle Handle of device to stop driver on
359 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
360 children is zero stop the entire bus driver.
361 @param ChildHandleBuffer List of Child Handles to Stop.
363 @retval EFI_SUCCESS This driver is removed ControllerHandle
364 @retval other This driver was not removed from this device
369 ScsiDiskDriverBindingStop (
370 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
371 IN EFI_HANDLE Controller
,
372 IN UINTN NumberOfChildren
,
373 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
376 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
377 SCSI_DISK_DEV
*ScsiDiskDevice
;
380 Status
= gBS
->OpenProtocol (
382 &gEfiBlockIoProtocolGuid
,
384 This
->DriverBindingHandle
,
386 EFI_OPEN_PROTOCOL_GET_PROTOCOL
388 if (EFI_ERROR (Status
)) {
392 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
393 Status
= gBS
->UninstallMultipleProtocolInterfaces (
395 &gEfiBlockIoProtocolGuid
,
396 &ScsiDiskDevice
->BlkIo
,
397 &gEfiDiskInfoProtocolGuid
,
398 &ScsiDiskDevice
->DiskInfo
,
401 if (!EFI_ERROR (Status
)) {
404 &gEfiScsiIoProtocolGuid
,
405 This
->DriverBindingHandle
,
409 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
423 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
424 @param ExtendedVerification The flag about if extend verificate
426 @retval EFI_SUCCESS The device was reset.
427 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
429 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
435 IN EFI_BLOCK_IO_PROTOCOL
*This
,
436 IN BOOLEAN ExtendedVerification
440 SCSI_DISK_DEV
*ScsiDiskDevice
;
443 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
445 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
447 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
449 if (EFI_ERROR (Status
)) {
450 Status
= EFI_DEVICE_ERROR
;
454 if (!ExtendedVerification
) {
458 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
460 if (EFI_ERROR (Status
)) {
461 Status
= EFI_DEVICE_ERROR
;
466 gBS
->RestoreTPL (OldTpl
);
471 The function is to Read Block from SCSI Disk.
473 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
474 @param MediaId The Id of Media detected
475 @param Lba The logic block address
476 @param BufferSize The size of Buffer
477 @param Buffer The buffer to fill the read out data
479 @retval EFI_SUCCESS Successfully to read out block.
480 @retval EFI_DEVICE_ERROR Fail to detect media.
481 @retval EFI_NO_MEDIA Media is not present.
482 @retval EFI_MEDIA_CHANGED Media has changed.
483 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
484 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
490 IN EFI_BLOCK_IO_PROTOCOL
*This
,
497 SCSI_DISK_DEV
*ScsiDiskDevice
;
498 EFI_BLOCK_IO_MEDIA
*Media
;
501 UINTN NumberOfBlocks
;
506 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
507 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
509 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
511 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
512 if (EFI_ERROR (Status
)) {
513 Status
= EFI_DEVICE_ERROR
;
518 gBS
->ReinstallProtocolInterface (
519 ScsiDiskDevice
->Handle
,
520 &gEfiBlockIoProtocolGuid
,
521 &ScsiDiskDevice
->BlkIo
,
522 &ScsiDiskDevice
->BlkIo
524 Status
= EFI_MEDIA_CHANGED
;
529 // Get the intrinsic block size
531 Media
= ScsiDiskDevice
->BlkIo
.Media
;
532 BlockSize
= Media
->BlockSize
;
534 NumberOfBlocks
= BufferSize
/ BlockSize
;
536 if (!(Media
->MediaPresent
)) {
537 Status
= EFI_NO_MEDIA
;
541 if (MediaId
!= Media
->MediaId
) {
542 Status
= EFI_MEDIA_CHANGED
;
546 if (Buffer
== NULL
) {
547 Status
= EFI_INVALID_PARAMETER
;
551 if (BufferSize
== 0) {
552 Status
= EFI_SUCCESS
;
556 if (BufferSize
% BlockSize
!= 0) {
557 Status
= EFI_BAD_BUFFER_SIZE
;
561 if (Lba
> Media
->LastBlock
) {
562 Status
= EFI_INVALID_PARAMETER
;
566 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
567 Status
= EFI_INVALID_PARAMETER
;
571 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
572 Status
= EFI_INVALID_PARAMETER
;
577 // If all the parameters are valid, then perform read sectors command
578 // to transfer data from device to host.
580 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
583 gBS
->RestoreTPL (OldTpl
);
588 The function is to Write Block to SCSI Disk.
590 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
591 @param MediaId The Id of Media detected
592 @param Lba The logic block address
593 @param BufferSize The size of Buffer
594 @param Buffer The buffer to fill the read out data
596 @retval EFI_SUCCESS Successfully to read out block.
597 @retval EFI_WRITE_PROTECTED The device can not be written to.
598 @retval EFI_DEVICE_ERROR Fail to detect media.
599 @retval EFI_NO_MEDIA Media is not present.
600 @retval EFI_MEDIA_CHNAGED Media has changed.
601 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
602 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
607 ScsiDiskWriteBlocks (
608 IN EFI_BLOCK_IO_PROTOCOL
*This
,
615 SCSI_DISK_DEV
*ScsiDiskDevice
;
616 EFI_BLOCK_IO_MEDIA
*Media
;
619 UINTN NumberOfBlocks
;
624 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
625 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
627 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
629 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
630 if (EFI_ERROR (Status
)) {
631 Status
= EFI_DEVICE_ERROR
;
636 gBS
->ReinstallProtocolInterface (
637 ScsiDiskDevice
->Handle
,
638 &gEfiBlockIoProtocolGuid
,
639 &ScsiDiskDevice
->BlkIo
,
640 &ScsiDiskDevice
->BlkIo
642 Status
= EFI_MEDIA_CHANGED
;
647 // Get the intrinsic block size
649 Media
= ScsiDiskDevice
->BlkIo
.Media
;
650 BlockSize
= Media
->BlockSize
;
652 NumberOfBlocks
= BufferSize
/ BlockSize
;
654 if (!(Media
->MediaPresent
)) {
655 Status
= EFI_NO_MEDIA
;
659 if (MediaId
!= Media
->MediaId
) {
660 Status
= EFI_MEDIA_CHANGED
;
664 if (BufferSize
== 0) {
665 Status
= EFI_SUCCESS
;
669 if (Buffer
== NULL
) {
670 Status
= EFI_INVALID_PARAMETER
;
674 if (BufferSize
% BlockSize
!= 0) {
675 Status
= EFI_BAD_BUFFER_SIZE
;
679 if (Lba
> Media
->LastBlock
) {
680 Status
= EFI_INVALID_PARAMETER
;
684 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
685 Status
= EFI_INVALID_PARAMETER
;
689 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
690 Status
= EFI_INVALID_PARAMETER
;
694 // if all the parameters are valid, then perform read sectors command
695 // to transfer data from device to host.
697 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
700 gBS
->RestoreTPL (OldTpl
);
707 EFI_SUCCESS is returned directly.
709 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
711 @retval EFI_SUCCESS All outstanding data was written to the device
716 ScsiDiskFlushBlocks (
717 IN EFI_BLOCK_IO_PROTOCOL
*This
728 Detect Device and read out capacity ,if error occurs, parse the sense key.
730 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
731 @param MustReadCapacity The flag about reading device capacity
732 @param MediaChange The pointer of flag indicates if media has changed
734 @retval EFI_DEVICE_ERROR Indicates that error occurs
735 @retval EFI_SUCCESS Successfully to detect media
739 ScsiDiskDetectMedia (
740 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
741 IN BOOLEAN MustReadCapacity
,
742 OUT BOOLEAN
*MediaChange
746 EFI_SCSI_SENSE_DATA
*SenseData
;
747 UINTN NumberOfSenseKeys
;
749 BOOLEAN NeedReadCapacity
;
752 EFI_BLOCK_IO_MEDIA OldMedia
;
754 EFI_EVENT TimeoutEvt
;
756 Status
= EFI_SUCCESS
;
758 NumberOfSenseKeys
= 0;
761 Action
= ACTION_NO_ACTION
;
762 NeedReadCapacity
= FALSE
;
763 *MediaChange
= FALSE
;
766 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
768 Status
= gBS
->CreateEvent (
775 if (EFI_ERROR (Status
)) {
779 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
780 if (EFI_ERROR (Status
)) {
785 // Sending Test_Unit cmd to poll device status.
786 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
787 // We limit the upper boundary to 120 seconds.
789 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
790 Status
= ScsiDiskTestUnitReady (
796 if (!EFI_ERROR (Status
)) {
797 Status
= DetectMediaParsingSenseKeys (
803 if (EFI_ERROR (Status
)) {
805 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
812 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
818 if (EFI_ERROR (Status
)) {
823 // ACTION_NO_ACTION: need not read capacity
824 // other action code: need read capacity
826 if (Action
== ACTION_READ_CAPACITY
) {
827 NeedReadCapacity
= TRUE
;
831 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
832 // retrieve capacity via Read Capacity command
834 if (NeedReadCapacity
|| MustReadCapacity
) {
836 // retrieve media information
838 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
839 Status
= ScsiDiskReadCapacity (
845 if (!EFI_ERROR (Status
)) {
847 // analyze sense key to action
849 Status
= DetectMediaParsingSenseKeys (
855 if (EFI_ERROR (Status
)) {
857 // if Status is error, it may indicate crisis error,
858 // so return without retry.
861 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
869 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
875 if (EFI_ERROR (Status
)) {
880 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
882 // Media change information got from the device
887 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
889 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
892 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
894 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
897 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
899 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
902 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
903 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
905 // when change from no media to media present, reset the MediaId to 1.
907 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
910 // when no media, reset the MediaId to zero.
912 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
919 if (TimeoutEvt
!= NULL
) {
920 gBS
->CloseEvent (TimeoutEvt
);
927 Send out Inquiry command to Device.
929 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
930 @param NeedRetry Indicates if needs try again when error happens
932 @retval EFI_DEVICE_ERROR Indicates that error occurs
933 @retval EFI_SUCCESS Successfully to detect media
937 ScsiDiskInquiryDevice (
938 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
939 OUT BOOLEAN
*NeedRetry
942 UINT32 InquiryDataLength
;
943 UINT8 SenseDataLength
;
944 UINT8 HostAdapterStatus
;
946 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
947 UINTN NumberOfSenseKeys
;
951 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
952 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
955 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
958 Status
= ScsiInquiryCommand (
959 ScsiDiskDevice
->ScsiIo
,
965 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
970 // no need to check HostAdapterStatus and TargetStatus
972 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
973 ParseInquiryData (ScsiDiskDevice
);
975 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
977 // Check whether the device supports Block Limits VPD page (0xB0)
979 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
980 if (SupportedVpdPages
== NULL
) {
982 return EFI_DEVICE_ERROR
;
984 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
985 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
987 Status
= ScsiInquiryCommandEx (
988 ScsiDiskDevice
->ScsiIo
,
994 (VOID
*) SupportedVpdPages
,
997 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
999 if (!EFI_ERROR (Status
)) {
1000 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1001 | SupportedVpdPages
->PageLength1
;
1002 for (Index
= 0; Index
< PageLength
; Index
++) {
1003 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
1009 // Query the Block Limits VPD page
1011 if (Index
< PageLength
) {
1012 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1013 if (BlockLimits
== NULL
) {
1014 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1016 return EFI_DEVICE_ERROR
;
1018 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1019 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
1020 SenseDataLength
= 0;
1021 Status
= ScsiInquiryCommandEx (
1022 ScsiDiskDevice
->ScsiIo
,
1028 (VOID
*) BlockLimits
,
1031 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1033 if (!EFI_ERROR (Status
)) {
1034 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
1035 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
1036 BlockLimits
->OptimalTransferLengthGranularity1
;
1039 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1043 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1047 if (!EFI_ERROR (Status
)) {
1050 } else if (Status
== EFI_NOT_READY
) {
1052 return EFI_DEVICE_ERROR
;
1054 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1056 return EFI_DEVICE_ERROR
;
1059 // go ahead to check HostAdapterStatus and TargetStatus
1060 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1063 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1064 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1066 return EFI_DEVICE_ERROR
;
1067 } else if (Status
== EFI_DEVICE_ERROR
) {
1069 // reset the scsi channel
1071 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1073 return EFI_DEVICE_ERROR
;
1076 Status
= CheckTargetStatus (TargetStatus
);
1077 if (Status
== EFI_NOT_READY
) {
1079 // reset the scsi device
1081 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1083 return EFI_DEVICE_ERROR
;
1085 } else if (Status
== EFI_DEVICE_ERROR
) {
1087 return EFI_DEVICE_ERROR
;
1091 // if goes here, meant ScsiInquiryCommand() failed.
1092 // if ScsiDiskRequestSenseKeys() succeeds at last,
1093 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1096 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1097 Status
= ScsiDiskRequestSenseKeys (
1104 if (!EFI_ERROR (Status
)) {
1106 return EFI_DEVICE_ERROR
;
1110 return EFI_DEVICE_ERROR
;
1114 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1115 // set *NeedRetry = FALSE to avoid the outside caller try again.
1118 return EFI_DEVICE_ERROR
;
1124 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1125 When Test Unit Ready command encounters any error caused by host adapter or
1126 target, return error without retrieving Sense Keys.
1128 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1129 @param NeedRetry The pointer of flag indicates try again
1130 @param SenseDataArray The pointer of an array of sense data
1131 @param NumberOfSenseKeys The pointer of the number of sense data array
1133 @retval EFI_DEVICE_ERROR Indicates that error occurs
1134 @retval EFI_SUCCESS Successfully to test unit
1138 ScsiDiskTestUnitReady (
1139 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1140 OUT BOOLEAN
*NeedRetry
,
1141 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1142 OUT UINTN
*NumberOfSenseKeys
1146 UINT8 SenseDataLength
;
1147 UINT8 HostAdapterStatus
;
1152 SenseDataLength
= 0;
1153 *NumberOfSenseKeys
= 0;
1156 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1158 Status
= ScsiTestUnitReadyCommand (
1159 ScsiDiskDevice
->ScsiIo
,
1167 // no need to check HostAdapterStatus and TargetStatus
1169 if (Status
== EFI_NOT_READY
) {
1171 return EFI_DEVICE_ERROR
;
1173 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1175 return EFI_DEVICE_ERROR
;
1178 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1181 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1182 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1184 return EFI_DEVICE_ERROR
;
1186 } else if (Status
== EFI_DEVICE_ERROR
) {
1188 // reset the scsi channel
1190 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1192 return EFI_DEVICE_ERROR
;
1195 Status
= CheckTargetStatus (TargetStatus
);
1196 if (Status
== EFI_NOT_READY
) {
1198 // reset the scsi device
1200 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1202 return EFI_DEVICE_ERROR
;
1204 } else if (Status
== EFI_DEVICE_ERROR
) {
1206 return EFI_DEVICE_ERROR
;
1210 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1211 Status
= ScsiDiskRequestSenseKeys (
1218 if (!EFI_ERROR (Status
)) {
1223 return EFI_DEVICE_ERROR
;
1227 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1228 // set *NeedRetry = FALSE to avoid the outside caller try again.
1231 return EFI_DEVICE_ERROR
;
1235 Parsing Sense Keys which got from request sense command.
1237 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1238 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1239 @param NumberOfSenseKeys The number of sense key
1240 @param Action The pointer of action which indicates what is need to do next
1242 @retval EFI_DEVICE_ERROR Indicates that error occurs
1243 @retval EFI_SUCCESS Successfully to complete the parsing
1247 DetectMediaParsingSenseKeys (
1248 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1249 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1250 IN UINTN NumberOfSenseKeys
,
1257 // Default is to read capacity, unless..
1259 *Action
= ACTION_READ_CAPACITY
;
1261 if (NumberOfSenseKeys
== 0) {
1262 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1263 *Action
= ACTION_NO_ACTION
;
1268 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1270 // No Sense Key returned from last submitted command
1272 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1273 *Action
= ACTION_NO_ACTION
;
1278 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1279 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1280 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1281 *Action
= ACTION_NO_ACTION
;
1282 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1286 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1287 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1288 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1292 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1293 *Action
= ACTION_RETRY_COMMAND_LATER
;
1294 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1298 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1299 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
1300 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1301 return EFI_DEVICE_ERROR
;
1304 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1305 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1306 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1307 return EFI_DEVICE_ERROR
;
1310 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1312 *Action
= ACTION_RETRY_COMMAND_LATER
;
1313 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1316 *Action
= ACTION_NO_ACTION
;
1317 return EFI_DEVICE_ERROR
;
1320 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1321 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
1327 Send read capacity command to device and get the device parameter.
1329 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1330 @param NeedRetry The pointer of flag indicates if need a retry
1331 @param SenseDataArray The pointer of an array of sense data
1332 @param NumberOfSenseKeys The number of sense key
1334 @retval EFI_DEVICE_ERROR Indicates that error occurs
1335 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1339 ScsiDiskReadCapacity (
1340 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1341 OUT BOOLEAN
*NeedRetry
,
1342 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1343 OUT UINTN
*NumberOfSenseKeys
1346 UINT8 HostAdapterStatus
;
1348 EFI_STATUS CommandStatus
;
1352 UINT8 SenseDataLength
;
1353 UINT32 DataLength10
;
1354 UINT32 DataLength16
;
1355 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
1356 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
1358 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1359 if (CapacityData10
== NULL
) {
1361 return EFI_DEVICE_ERROR
;
1363 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1364 if (CapacityData16
== NULL
) {
1365 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1367 return EFI_DEVICE_ERROR
;
1370 SenseDataLength
= 0;
1371 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1372 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1373 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1374 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1376 *NumberOfSenseKeys
= 0;
1380 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1381 // 16 byte command should be used to access large hard disk >2TB
1383 CommandStatus
= ScsiReadCapacityCommand (
1384 ScsiDiskDevice
->ScsiIo
,
1390 (VOID
*) CapacityData10
,
1395 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1396 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
1397 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
1399 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1401 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1403 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1404 // and LowestAlignedLba
1406 CommandStatus
= ScsiReadCapacity16Command (
1407 ScsiDiskDevice
->ScsiIo
,
1413 (VOID
*) CapacityData16
,
1420 // no need to check HostAdapterStatus and TargetStatus
1422 if (CommandStatus
== EFI_SUCCESS
) {
1423 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
1424 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1425 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1429 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1430 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1432 if (CommandStatus
== EFI_NOT_READY
) {
1434 return EFI_DEVICE_ERROR
;
1435 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1437 return EFI_DEVICE_ERROR
;
1441 // go ahead to check HostAdapterStatus and TargetStatus
1442 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1445 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1446 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1448 return EFI_DEVICE_ERROR
;
1450 } else if (Status
== EFI_DEVICE_ERROR
) {
1452 // reset the scsi channel
1454 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1456 return EFI_DEVICE_ERROR
;
1459 Status
= CheckTargetStatus (TargetStatus
);
1460 if (Status
== EFI_NOT_READY
) {
1462 // reset the scsi device
1464 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1466 return EFI_DEVICE_ERROR
;
1468 } else if (Status
== EFI_DEVICE_ERROR
) {
1470 return EFI_DEVICE_ERROR
;
1474 // if goes here, meant ScsiReadCapacityCommand() failed.
1475 // if ScsiDiskRequestSenseKeys() succeeds at last,
1476 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1479 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1481 Status
= ScsiDiskRequestSenseKeys (
1488 if (!EFI_ERROR (Status
)) {
1493 return EFI_DEVICE_ERROR
;
1497 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1498 // set *NeedRetry = FALSE to avoid the outside caller try again.
1501 return EFI_DEVICE_ERROR
;
1505 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1507 @param HostAdapterStatus Host Adapter status
1509 @retval EFI_SUCCESS Host adapter is OK.
1510 @retval EFI_TIMEOUT Timeout.
1511 @retval EFI_NOT_READY Adapter NOT ready.
1512 @retval EFI_DEVICE_ERROR Adapter device error.
1516 CheckHostAdapterStatus (
1517 IN UINT8 HostAdapterStatus
1520 switch (HostAdapterStatus
) {
1521 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1524 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1525 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1526 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1529 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1530 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1531 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1532 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1533 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1534 return EFI_NOT_READY
;
1536 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1537 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1538 return EFI_DEVICE_ERROR
;
1547 Check the target status and re-interpret it in EFI_STATUS.
1549 @param TargetStatus Target status
1551 @retval EFI_NOT_READY Device is NOT ready.
1552 @retval EFI_DEVICE_ERROR
1558 IN UINT8 TargetStatus
1561 switch (TargetStatus
) {
1562 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1563 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1564 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1567 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1568 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1569 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1570 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1571 return EFI_NOT_READY
;
1573 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1574 return EFI_DEVICE_ERROR
;
1584 Retrieve all sense keys from the device.
1586 When encountering error during the process, if retrieve sense keys before
1587 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1588 and NeedRetry set to FALSE; otherwize, return the proper return status.
1590 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1591 @param NeedRetry The pointer of flag indicates if need a retry
1592 @param SenseDataArray The pointer of an array of sense data
1593 @param NumberOfSenseKeys The number of sense key
1594 @param AskResetIfError The flag indicates if need reset when error occurs
1596 @retval EFI_DEVICE_ERROR Indicates that error occurs
1597 @retval EFI_SUCCESS Successfully to request sense key
1601 ScsiDiskRequestSenseKeys (
1602 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1603 OUT BOOLEAN
*NeedRetry
,
1604 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1605 OUT UINTN
*NumberOfSenseKeys
,
1606 IN BOOLEAN AskResetIfError
1609 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1610 UINT8 SenseDataLength
;
1613 EFI_STATUS FallStatus
;
1614 UINT8 HostAdapterStatus
;
1617 FallStatus
= EFI_SUCCESS
;
1618 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1621 ScsiDiskDevice
->SenseData
,
1622 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1625 *NumberOfSenseKeys
= 0;
1626 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1627 Status
= EFI_SUCCESS
;
1628 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
1629 if (PtrSenseData
== NULL
) {
1630 return EFI_DEVICE_ERROR
;
1633 for (SenseReq
= TRUE
; SenseReq
;) {
1634 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
1635 Status
= ScsiRequestSenseCommand (
1636 ScsiDiskDevice
->ScsiIo
,
1643 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1644 FallStatus
= EFI_SUCCESS
;
1646 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1648 FallStatus
= EFI_DEVICE_ERROR
;
1650 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1652 FallStatus
= EFI_DEVICE_ERROR
;
1654 } else if (Status
== EFI_DEVICE_ERROR
) {
1655 if (AskResetIfError
) {
1656 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1659 FallStatus
= EFI_DEVICE_ERROR
;
1662 if (EFI_ERROR (FallStatus
)) {
1663 if (*NumberOfSenseKeys
!= 0) {
1665 Status
= EFI_SUCCESS
;
1668 Status
= EFI_DEVICE_ERROR
;
1673 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
1674 (*NumberOfSenseKeys
) += 1;
1677 // no more sense key or number of sense keys exceeds predefined,
1680 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1681 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1687 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
1693 Get information from media read capacity command.
1695 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1696 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1697 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1702 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1703 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1704 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1709 if (!ScsiDiskDevice
->Cdb16Byte
) {
1710 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1711 (Capacity10
->LastLba2
<< 16) |
1712 (Capacity10
->LastLba1
<< 8) |
1713 Capacity10
->LastLba0
;
1715 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1716 (Capacity10
->BlockSize2
<< 16) |
1717 (Capacity10
->BlockSize1
<< 8) |
1718 Capacity10
->BlockSize0
;
1719 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1720 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
1722 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1723 *Ptr
++ = Capacity16
->LastLba0
;
1724 *Ptr
++ = Capacity16
->LastLba1
;
1725 *Ptr
++ = Capacity16
->LastLba2
;
1726 *Ptr
++ = Capacity16
->LastLba3
;
1727 *Ptr
++ = Capacity16
->LastLba4
;
1728 *Ptr
++ = Capacity16
->LastLba5
;
1729 *Ptr
++ = Capacity16
->LastLba6
;
1730 *Ptr
= Capacity16
->LastLba7
;
1732 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1733 (Capacity16
->BlockSize2
<< 16) |
1734 (Capacity16
->BlockSize1
<< 8) |
1735 Capacity16
->BlockSize0
;
1737 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
1738 Capacity16
->LowestAlignLogic1
;
1739 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
1742 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1744 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1745 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1748 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1749 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1756 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1761 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1764 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1765 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1769 Read sector from SCSI Disk.
1771 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1772 @param Buffer The buffer to fill in the read out data
1773 @param Lba Logic block address
1774 @param NumberOfBlocks The number of blocks to read
1776 @retval EFI_DEVICE_ERROR Indicates a device error.
1777 @retval EFI_SUCCESS Operation is successful.
1781 ScsiDiskReadSectors (
1782 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1785 IN UINTN NumberOfBlocks
1788 UINTN BlocksRemaining
;
1800 Status
= EFI_SUCCESS
;
1802 BlocksRemaining
= NumberOfBlocks
;
1803 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1806 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1808 if (!ScsiDiskDevice
->Cdb16Byte
) {
1811 MaxBlock
= 0xFFFFFFFF;
1816 while (BlocksRemaining
> 0) {
1818 if (BlocksRemaining
<= MaxBlock
) {
1819 if (!ScsiDiskDevice
->Cdb16Byte
) {
1820 SectorCount
= (UINT16
) BlocksRemaining
;
1822 SectorCount
= (UINT32
) BlocksRemaining
;
1825 SectorCount
= MaxBlock
;
1828 ByteCount
= SectorCount
* BlockSize
;
1830 // |------------------------|-----------------|------------------|-----------------|
1831 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
1832 // |------------------------|-----------------|------------------|-----------------|
1833 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
1834 // |------------------------|-----------------|------------------|-----------------|
1835 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
1836 // |------------------------|-----------------|------------------|-----------------|
1837 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
1838 // |------------------------|-----------------|------------------|-----------------|
1839 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
1840 // |------------------------|-----------------|------------------|-----------------|
1841 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
1842 // |------------------------|-----------------|------------------|-----------------|
1843 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
1844 // |------------------------|-----------------|------------------|-----------------|
1845 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
1846 // |------------------------|-----------------|------------------|-----------------|
1847 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
1848 // |------------------------|-----------------|------------------|-----------------|
1849 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
1850 // |------------------------|-----------------|------------------|-----------------|
1851 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
1852 // |------------------------|-----------------|------------------|-----------------|
1854 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
1855 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
1856 // From the above table, we could know 2.1Mbytes per second is lowest one.
1857 // The timout value is rounded up to nearest integar and here an additional 30s is added
1858 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
1859 // commands in the Standby/Idle mode.
1861 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
1864 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1865 if (!ScsiDiskDevice
->Cdb16Byte
) {
1866 Status
= ScsiDiskRead10 (
1876 Status
= ScsiDiskRead16 (
1886 if (!EFI_ERROR (Status
)) {
1891 return EFI_DEVICE_ERROR
;
1896 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1897 return EFI_DEVICE_ERROR
;
1901 // actual transferred sectors
1903 SectorCount
= ByteCount
/ BlockSize
;
1906 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1907 BlocksRemaining
-= SectorCount
;
1914 Write sector to SCSI Disk.
1916 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1917 @param Buffer The buffer of data to be written into SCSI Disk
1918 @param Lba Logic block address
1919 @param NumberOfBlocks The number of blocks to read
1921 @retval EFI_DEVICE_ERROR Indicates a device error.
1922 @retval EFI_SUCCESS Operation is successful.
1926 ScsiDiskWriteSectors (
1927 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1930 IN UINTN NumberOfBlocks
1933 UINTN BlocksRemaining
;
1945 Status
= EFI_SUCCESS
;
1947 BlocksRemaining
= NumberOfBlocks
;
1948 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1951 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1953 if (!ScsiDiskDevice
->Cdb16Byte
) {
1956 MaxBlock
= 0xFFFFFFFF;
1961 while (BlocksRemaining
> 0) {
1963 if (BlocksRemaining
<= MaxBlock
) {
1964 if (!ScsiDiskDevice
->Cdb16Byte
) {
1965 SectorCount
= (UINT16
) BlocksRemaining
;
1967 SectorCount
= (UINT32
) BlocksRemaining
;
1970 SectorCount
= MaxBlock
;
1973 ByteCount
= SectorCount
* BlockSize
;
1975 // |------------------------|-----------------|------------------|-----------------|
1976 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
1977 // |------------------------|-----------------|------------------|-----------------|
1978 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
1979 // |------------------------|-----------------|------------------|-----------------|
1980 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
1981 // |------------------------|-----------------|------------------|-----------------|
1982 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
1983 // |------------------------|-----------------|------------------|-----------------|
1984 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
1985 // |------------------------|-----------------|------------------|-----------------|
1986 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
1987 // |------------------------|-----------------|------------------|-----------------|
1988 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
1989 // |------------------------|-----------------|------------------|-----------------|
1990 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
1991 // |------------------------|-----------------|------------------|-----------------|
1992 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
1993 // |------------------------|-----------------|------------------|-----------------|
1994 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
1995 // |------------------------|-----------------|------------------|-----------------|
1996 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
1997 // |------------------------|-----------------|------------------|-----------------|
1999 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2000 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2001 // From the above table, we could know 2.1Mbytes per second is lowest one.
2002 // The timout value is rounded up to nearest integar and here an additional 30s is added
2003 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2004 // commands in the Standby/Idle mode.
2006 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2008 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2009 if (!ScsiDiskDevice
->Cdb16Byte
) {
2010 Status
= ScsiDiskWrite10 (
2020 Status
= ScsiDiskWrite16 (
2030 if (!EFI_ERROR (Status
)) {
2035 return EFI_DEVICE_ERROR
;
2039 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2040 return EFI_DEVICE_ERROR
;
2043 // actual transferred sectors
2045 SectorCount
= ByteCount
/ BlockSize
;
2048 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2049 BlocksRemaining
-= SectorCount
;
2057 Submit Read(10) command.
2059 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2060 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2061 @param Timeout The time to complete the command
2062 @param DataBuffer The buffer to fill with the read out data
2063 @param DataLength The length of buffer
2064 @param StartLba The start logic block address
2065 @param SectorCount The number of blocks to read
2067 @return EFI_STATUS is returned by calling ScsiRead10Command().
2071 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2072 OUT BOOLEAN
*NeedRetry
,
2074 OUT UINT8
*DataBuffer
,
2075 IN OUT UINT32
*DataLength
,
2077 IN UINT32 SectorCount
2080 UINT8 SenseDataLength
;
2082 EFI_STATUS ReturnStatus
;
2083 UINT8 HostAdapterStatus
;
2088 // Implement a backoff algorithem to resolve some compatibility issues that
2089 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2090 // big data in a single operation.
2091 // This algorithem will at first try to execute original request. If the request fails
2092 // with media error sense data or else, it will reduce the transfer length to half and
2093 // try again till the operation succeeds or fails with one sector transfer length.
2097 Action
= ACTION_NO_ACTION
;
2098 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2099 ReturnStatus
= ScsiRead10Command (
2100 ScsiDiskDevice
->ScsiIo
,
2102 ScsiDiskDevice
->SenseData
,
2112 if (ReturnStatus
== EFI_NOT_READY
) {
2114 return EFI_DEVICE_ERROR
;
2115 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2117 return ReturnStatus
;
2121 // go ahead to check HostAdapterStatus and TargetStatus
2122 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2124 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2125 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2127 return EFI_DEVICE_ERROR
;
2128 } else if (Status
== EFI_DEVICE_ERROR
) {
2130 // reset the scsi channel
2132 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2134 return EFI_DEVICE_ERROR
;
2137 Status
= CheckTargetStatus (TargetStatus
);
2138 if (Status
== EFI_NOT_READY
) {
2140 // reset the scsi device
2142 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2144 return EFI_DEVICE_ERROR
;
2145 } else if (Status
== EFI_DEVICE_ERROR
) {
2147 return EFI_DEVICE_ERROR
;
2150 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2151 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
2152 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2153 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2155 return EFI_DEVICE_ERROR
;
2156 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2157 if (SectorCount
<= 1) {
2159 // Jump out if the operation still fails with one sector transfer length.
2162 return EFI_DEVICE_ERROR
;
2165 // Try again with half length if the sense data shows we need to retry.
2168 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2172 return EFI_DEVICE_ERROR
;
2176 return ReturnStatus
;
2181 Submit Write(10) Command.
2183 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2184 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2185 @param Timeout The time to complete the command
2186 @param DataBuffer The buffer to fill with the read out data
2187 @param DataLength The length of buffer
2188 @param StartLba The start logic block address
2189 @param SectorCount The number of blocks to write
2191 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2196 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2197 OUT BOOLEAN
*NeedRetry
,
2199 IN UINT8
*DataBuffer
,
2200 IN OUT UINT32
*DataLength
,
2202 IN UINT32 SectorCount
2206 EFI_STATUS ReturnStatus
;
2207 UINT8 SenseDataLength
;
2208 UINT8 HostAdapterStatus
;
2213 // Implement a backoff algorithem to resolve some compatibility issues that
2214 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2215 // big data in a single operation.
2216 // This algorithem will at first try to execute original request. If the request fails
2217 // with media error sense data or else, it will reduce the transfer length to half and
2218 // try again till the operation succeeds or fails with one sector transfer length.
2222 Action
= ACTION_NO_ACTION
;
2223 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2224 ReturnStatus
= ScsiWrite10Command (
2225 ScsiDiskDevice
->ScsiIo
,
2227 ScsiDiskDevice
->SenseData
,
2236 if (ReturnStatus
== EFI_NOT_READY
) {
2238 return EFI_DEVICE_ERROR
;
2239 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2241 return ReturnStatus
;
2245 // go ahead to check HostAdapterStatus and TargetStatus
2246 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2248 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2249 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2251 return EFI_DEVICE_ERROR
;
2252 } else if (Status
== EFI_DEVICE_ERROR
) {
2254 // reset the scsi channel
2256 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2258 return EFI_DEVICE_ERROR
;
2261 Status
= CheckTargetStatus (TargetStatus
);
2262 if (Status
== EFI_NOT_READY
) {
2264 // reset the scsi device
2266 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2268 return EFI_DEVICE_ERROR
;
2269 } else if (Status
== EFI_DEVICE_ERROR
) {
2271 return EFI_DEVICE_ERROR
;
2274 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2275 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
2276 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2277 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2279 return EFI_DEVICE_ERROR
;
2280 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2281 if (SectorCount
<= 1) {
2283 // Jump out if the operation still fails with one sector transfer length.
2286 return EFI_DEVICE_ERROR
;
2289 // Try again with half length if the sense data shows we need to retry.
2292 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2296 return EFI_DEVICE_ERROR
;
2300 return ReturnStatus
;
2305 Submit Read(16) command.
2307 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2308 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2309 @param Timeout The time to complete the command
2310 @param DataBuffer The buffer to fill with the read out data
2311 @param DataLength The length of buffer
2312 @param StartLba The start logic block address
2313 @param SectorCount The number of blocks to read
2315 @return EFI_STATUS is returned by calling ScsiRead16Command().
2319 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2320 OUT BOOLEAN
*NeedRetry
,
2322 OUT UINT8
*DataBuffer
,
2323 IN OUT UINT32
*DataLength
,
2325 IN UINT32 SectorCount
2328 UINT8 SenseDataLength
;
2330 EFI_STATUS ReturnStatus
;
2331 UINT8 HostAdapterStatus
;
2336 // Implement a backoff algorithem to resolve some compatibility issues that
2337 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2338 // big data in a single operation.
2339 // This algorithem will at first try to execute original request. If the request fails
2340 // with media error sense data or else, it will reduce the transfer length to half and
2341 // try again till the operation succeeds or fails with one sector transfer length.
2345 Action
= ACTION_NO_ACTION
;
2346 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2347 ReturnStatus
= ScsiRead16Command (
2348 ScsiDiskDevice
->ScsiIo
,
2350 ScsiDiskDevice
->SenseData
,
2359 if (ReturnStatus
== EFI_NOT_READY
) {
2361 return EFI_DEVICE_ERROR
;
2362 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2364 return ReturnStatus
;
2368 // go ahead to check HostAdapterStatus and TargetStatus
2369 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2371 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2372 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2374 return EFI_DEVICE_ERROR
;
2375 } else if (Status
== EFI_DEVICE_ERROR
) {
2377 // reset the scsi channel
2379 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2381 return EFI_DEVICE_ERROR
;
2384 Status
= CheckTargetStatus (TargetStatus
);
2385 if (Status
== EFI_NOT_READY
) {
2387 // reset the scsi device
2389 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2391 return EFI_DEVICE_ERROR
;
2392 } else if (Status
== EFI_DEVICE_ERROR
) {
2394 return EFI_DEVICE_ERROR
;
2397 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2398 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
2399 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2400 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2402 return EFI_DEVICE_ERROR
;
2403 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2404 if (SectorCount
<= 1) {
2406 // Jump out if the operation still fails with one sector transfer length.
2409 return EFI_DEVICE_ERROR
;
2412 // Try again with half length if the sense data shows we need to retry.
2415 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2419 return EFI_DEVICE_ERROR
;
2423 return ReturnStatus
;
2428 Submit Write(16) Command.
2430 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2431 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2432 @param Timeout The time to complete the command
2433 @param DataBuffer The buffer to fill with the read out data
2434 @param DataLength The length of buffer
2435 @param StartLba The start logic block address
2436 @param SectorCount The number of blocks to write
2438 @return EFI_STATUS is returned by calling ScsiWrite16Command().
2443 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2444 OUT BOOLEAN
*NeedRetry
,
2446 IN UINT8
*DataBuffer
,
2447 IN OUT UINT32
*DataLength
,
2449 IN UINT32 SectorCount
2453 EFI_STATUS ReturnStatus
;
2454 UINT8 SenseDataLength
;
2455 UINT8 HostAdapterStatus
;
2460 // Implement a backoff algorithem to resolve some compatibility issues that
2461 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2462 // big data in a single operation.
2463 // This algorithem will at first try to execute original request. If the request fails
2464 // with media error sense data or else, it will reduce the transfer length to half and
2465 // try again till the operation succeeds or fails with one sector transfer length.
2469 Action
= ACTION_NO_ACTION
;
2470 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2471 ReturnStatus
= ScsiWrite16Command (
2472 ScsiDiskDevice
->ScsiIo
,
2474 ScsiDiskDevice
->SenseData
,
2483 if (ReturnStatus
== EFI_NOT_READY
) {
2485 return EFI_DEVICE_ERROR
;
2486 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2488 return ReturnStatus
;
2492 // go ahead to check HostAdapterStatus and TargetStatus
2493 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2495 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2496 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2498 return EFI_DEVICE_ERROR
;
2499 } else if (Status
== EFI_DEVICE_ERROR
) {
2501 // reset the scsi channel
2503 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2505 return EFI_DEVICE_ERROR
;
2508 Status
= CheckTargetStatus (TargetStatus
);
2509 if (Status
== EFI_NOT_READY
) {
2511 // reset the scsi device
2513 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2515 return EFI_DEVICE_ERROR
;
2516 } else if (Status
== EFI_DEVICE_ERROR
) {
2518 return EFI_DEVICE_ERROR
;
2521 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2522 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
2523 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2524 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2526 return EFI_DEVICE_ERROR
;
2527 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2528 if (SectorCount
<= 1) {
2530 // Jump out if the operation still fails with one sector transfer length.
2533 return EFI_DEVICE_ERROR
;
2536 // Try again with half length if the sense data shows we need to retry.
2539 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2543 return EFI_DEVICE_ERROR
;
2547 return ReturnStatus
;
2552 Check sense key to find if media presents.
2554 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2555 @param SenseCounts The number of sense key
2557 @retval TRUE NOT any media
2558 @retval FALSE Media presents
2562 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2563 IN UINTN SenseCounts
2566 EFI_SCSI_SENSE_DATA
*SensePtr
;
2571 SensePtr
= SenseData
;
2573 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2575 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2576 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2578 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
2579 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
2592 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2593 @param SenseCounts The number of sense key
2596 @retval FALSE NOT error
2600 ScsiDiskIsMediaError (
2601 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2602 IN UINTN SenseCounts
2605 EFI_SCSI_SENSE_DATA
*SensePtr
;
2610 SensePtr
= SenseData
;
2612 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2614 switch (SensePtr
->Sense_Key
) {
2616 case EFI_SCSI_SK_MEDIUM_ERROR
:
2618 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2620 switch (SensePtr
->Addnl_Sense_Code
) {
2625 case EFI_SCSI_ASC_MEDIA_ERR1
:
2630 case EFI_SCSI_ASC_MEDIA_ERR2
:
2635 case EFI_SCSI_ASC_MEDIA_ERR3
:
2636 case EFI_SCSI_ASC_MEDIA_ERR4
:
2646 case EFI_SCSI_SK_NOT_READY
:
2648 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2650 switch (SensePtr
->Addnl_Sense_Code
) {
2652 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2654 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2675 Check sense key to find if hardware error happens.
2677 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2678 @param SenseCounts The number of sense key
2680 @retval TRUE Hardware error exits.
2681 @retval FALSE NO error.
2685 ScsiDiskIsHardwareError (
2686 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2687 IN UINTN SenseCounts
2690 EFI_SCSI_SENSE_DATA
*SensePtr
;
2695 SensePtr
= SenseData
;
2697 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2700 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2702 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2714 Check sense key to find if media has changed.
2716 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2717 @param SenseCounts The number of sense key
2719 @retval TRUE Media is changed.
2720 @retval FALSE Media is NOT changed.
2723 ScsiDiskIsMediaChange (
2724 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2725 IN UINTN SenseCounts
2728 EFI_SCSI_SENSE_DATA
*SensePtr
;
2730 BOOLEAN IsMediaChanged
;
2732 IsMediaChanged
= FALSE
;
2733 SensePtr
= SenseData
;
2735 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2737 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2738 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2740 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2741 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2742 IsMediaChanged
= TRUE
;
2748 return IsMediaChanged
;
2752 Check sense key to find if reset happens.
2754 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2755 @param SenseCounts The number of sense key
2757 @retval TRUE It is reset before.
2758 @retval FALSE It is NOT reset before.
2762 ScsiDiskIsResetBefore (
2763 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2764 IN UINTN SenseCounts
2767 EFI_SCSI_SENSE_DATA
*SensePtr
;
2769 BOOLEAN IsResetBefore
;
2771 IsResetBefore
= FALSE
;
2772 SensePtr
= SenseData
;
2774 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2777 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2778 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2780 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2781 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2782 IsResetBefore
= TRUE
;
2788 return IsResetBefore
;
2792 Check sense key to find if the drive is ready.
2794 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2795 @param SenseCounts The number of sense key
2796 @param RetryLater The flag means if need a retry
2798 @retval TRUE Drive is ready.
2799 @retval FALSE Drive is NOT ready.
2803 ScsiDiskIsDriveReady (
2804 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2805 IN UINTN SenseCounts
,
2806 OUT BOOLEAN
*RetryLater
2809 EFI_SCSI_SENSE_DATA
*SensePtr
;
2814 *RetryLater
= FALSE
;
2815 SensePtr
= SenseData
;
2817 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2819 switch (SensePtr
->Sense_Key
) {
2821 case EFI_SCSI_SK_NOT_READY
:
2823 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2825 switch (SensePtr
->Addnl_Sense_Code
) {
2826 case EFI_SCSI_ASC_NOT_READY
:
2828 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2830 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2831 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2833 // Additional Sense Code Qualifier is
2834 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2842 *RetryLater
= FALSE
;
2863 Check sense key to find if it has sense key.
2865 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2866 @param SenseCounts - The number of sense key
2868 @retval TRUE It has sense key.
2869 @retval FALSE It has NOT any sense key.
2873 ScsiDiskHaveSenseKey (
2874 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2875 IN UINTN SenseCounts
2878 EFI_SCSI_SENSE_DATA
*SensePtr
;
2880 BOOLEAN HaveSenseKey
;
2882 if (SenseCounts
== 0) {
2883 HaveSenseKey
= FALSE
;
2885 HaveSenseKey
= TRUE
;
2888 SensePtr
= SenseData
;
2890 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2893 // Sense Key is SK_NO_SENSE (0x0)
2895 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2897 HaveSenseKey
= FALSE
;
2903 return HaveSenseKey
;
2907 Release resource about disk device.
2909 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2913 ReleaseScsiDiskDeviceResources (
2914 IN SCSI_DISK_DEV
*ScsiDiskDevice
2917 if (ScsiDiskDevice
== NULL
) {
2921 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2922 FreePool (ScsiDiskDevice
->SenseData
);
2923 ScsiDiskDevice
->SenseData
= NULL
;
2926 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2927 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2928 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2931 FreePool (ScsiDiskDevice
);
2933 ScsiDiskDevice
= NULL
;
2937 Determine if Block Io should be produced.
2940 @param ChildHandle Child Handle to retrieve Parent information.
2942 @retval TRUE Should produce Block Io.
2943 @retval FALSE Should not produce Block Io.
2947 DetermineInstallBlockIo (
2948 IN EFI_HANDLE ChildHandle
2951 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2952 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2955 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2956 // check its attribute, logic or physical.
2958 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2959 if (ExtScsiPassThru
!= NULL
) {
2960 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2966 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2967 // check its attribute, logic or physical.
2969 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2970 if (ScsiPassThru
!= NULL
) {
2971 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2980 Search protocol database and check to see if the protocol
2981 specified by ProtocolGuid is present on a ControllerHandle and opened by
2982 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2983 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2984 will be opened on it.
2987 @param ProtocolGuid ProtocolGuid pointer.
2988 @param ChildHandle Child Handle to retrieve Parent information.
2994 IN EFI_GUID
*ProtocolGuid
,
2995 IN EFI_HANDLE ChildHandle
3002 EFI_HANDLE
*HandleBuffer
;
3005 // Retrieve the list of all handles from the handle database
3007 Status
= gBS
->LocateHandleBuffer (
3015 if (EFI_ERROR (Status
)) {
3020 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
3022 for (Index
= 0; Index
< HandleCount
; Index
++) {
3023 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
3024 if (!EFI_ERROR (Status
)) {
3025 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
3026 if (!EFI_ERROR (Status
)) {
3027 gBS
->FreePool (HandleBuffer
);
3033 gBS
->FreePool (HandleBuffer
);
3038 Provides inquiry information for the controller type.
3040 This function is used by the IDE bus driver to get inquiry data. Data format
3041 of Identify data is defined by the Interface GUID.
3043 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
3044 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
3045 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
3047 @retval EFI_SUCCESS The command was accepted without any errors.
3048 @retval EFI_NOT_FOUND Device does not support this data class
3049 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
3050 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
3055 ScsiDiskInfoInquiry (
3056 IN EFI_DISK_INFO_PROTOCOL
*This
,
3057 IN OUT VOID
*InquiryData
,
3058 IN OUT UINT32
*InquiryDataSize
3062 SCSI_DISK_DEV
*ScsiDiskDevice
;
3064 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
3066 Status
= EFI_BUFFER_TOO_SMALL
;
3067 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
3068 Status
= EFI_SUCCESS
;
3069 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
3071 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
3077 Provides identify information for the controller type.
3079 This function is used by the IDE bus driver to get identify data. Data format
3080 of Identify data is defined by the Interface GUID.
3082 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
3084 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
3085 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
3088 @retval EFI_SUCCESS The command was accepted without any errors.
3089 @retval EFI_NOT_FOUND Device does not support this data class
3090 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
3091 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
3096 ScsiDiskInfoIdentify (
3097 IN EFI_DISK_INFO_PROTOCOL
*This
,
3098 IN OUT VOID
*IdentifyData
,
3099 IN OUT UINT32
*IdentifyDataSize
3103 SCSI_DISK_DEV
*ScsiDiskDevice
;
3105 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
3107 // Physical SCSI bus does not support this data class.
3109 return EFI_NOT_FOUND
;
3112 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
3114 Status
= EFI_BUFFER_TOO_SMALL
;
3115 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
3116 Status
= EFI_SUCCESS
;
3117 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
3119 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
3124 Provides sense data information for the controller type.
3126 This function is used by the IDE bus driver to get sense data.
3127 Data format of Sense data is defined by the Interface GUID.
3129 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
3130 @param[in, out] SenseData Pointer to the SenseData.
3131 @param[in, out] SenseDataSize Size of SenseData in bytes.
3132 @param[out] SenseDataNumber Pointer to the value for the sense data size.
3134 @retval EFI_SUCCESS The command was accepted without any errors.
3135 @retval EFI_NOT_FOUND Device does not support this data class.
3136 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
3137 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
3142 ScsiDiskInfoSenseData (
3143 IN EFI_DISK_INFO_PROTOCOL
*This
,
3144 IN OUT VOID
*SenseData
,
3145 IN OUT UINT32
*SenseDataSize
,
3146 OUT UINT8
*SenseDataNumber
3149 return EFI_NOT_FOUND
;
3154 This function is used by the IDE bus driver to get controller information.
3156 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
3157 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
3158 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
3160 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
3161 @retval EFI_UNSUPPORTED This is not an IDE device.
3166 ScsiDiskInfoWhichIde (
3167 IN EFI_DISK_INFO_PROTOCOL
*This
,
3168 OUT UINT32
*IdeChannel
,
3169 OUT UINT32
*IdeDevice
3172 SCSI_DISK_DEV
*ScsiDiskDevice
;
3174 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
3176 // This is not an IDE physical device.
3178 return EFI_UNSUPPORTED
;
3181 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
3182 *IdeChannel
= ScsiDiskDevice
->Channel
;
3183 *IdeDevice
= ScsiDiskDevice
->Device
;
3190 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
3192 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
3193 implement Identify() interface for DiskInfo protocol. The ATA command is sent
3194 via SCSI Request Packet.
3196 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3198 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
3199 @retval others Some error occurred during the identification that ATAPI device.
3203 AtapiIdentifyDevice (
3204 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
3207 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
3211 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
3213 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
3214 ZeroMem (Cdb
, sizeof (Cdb
));
3216 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
3217 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
3218 CommandPacket
.Cdb
= Cdb
;
3219 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
3220 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
3221 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
3223 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
3228 Initialize the installation of DiskInfo protocol.
3230 This function prepares for the installation of DiskInfo protocol on the child handle.
3231 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
3232 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
3233 to be IDE/AHCI interface GUID.
3235 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3236 @param ChildHandle Child handle to install DiskInfo protocol.
3240 InitializeInstallDiskInfo (
3241 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3242 IN EFI_HANDLE ChildHandle
3246 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
3247 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
3248 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
3249 SATA_DEVICE_PATH
*SataDevicePath
;
3250 UINTN IdentifyRetry
;
3252 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
3254 // Device Path protocol must be installed on the device handle.
3256 ASSERT_EFI_ERROR (Status
);
3258 // Copy the DiskInfo protocol template.
3260 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
3262 while (!IsDevicePathEnd (DevicePathNode
)) {
3263 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
3264 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
3265 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
3266 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
3267 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
3268 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
3273 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
3274 // with IDE/AHCI interface GUID.
3276 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
3277 if (!EFI_ERROR (Status
)) {
3278 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
3280 // We find the valid ATAPI device path
3282 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
3283 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
3284 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
3286 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
3288 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
3291 // We find the valid SATA device path
3293 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
3294 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
3295 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
3297 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
3299 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
3303 } while (--IdentifyRetry
> 0);
3305 DevicePathNode
= ChildDevicePathNode
;