2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2011, 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 The user Entry Point for module ScsiDisk.
38 The user code starts with this function.
40 @param ImageHandle The firmware allocated handle for the EFI image.
41 @param SystemTable A pointer to the EFI System Table.
43 @retval EFI_SUCCESS The entry point is executed successfully.
44 @retval other Some error occurs when executing this entry point.
50 IN EFI_HANDLE ImageHandle
,
51 IN EFI_SYSTEM_TABLE
*SystemTable
57 // Install driver model protocol(s).
59 Status
= EfiLibInstallDriverBindingComponentName2 (
62 &gScsiDiskDriverBinding
,
64 &gScsiDiskComponentName
,
65 &gScsiDiskComponentName2
67 ASSERT_EFI_ERROR (Status
);
74 Test to see if this driver supports ControllerHandle.
76 This service is called by the EFI boot service ConnectController(). In order
77 to make drivers as small as possible, there are a few calling restrictions for
78 this service. ConnectController() must follow these calling restrictions.
79 If any other agent wishes to call Supported() it must also follow these
82 @param This Protocol instance pointer.
83 @param ControllerHandle Handle of device to test
84 @param RemainingDevicePath Optional parameter use to pick a specific child
87 @retval EFI_SUCCESS This driver supports this device
88 @retval EFI_ALREADY_STARTED This driver is already running on this device
89 @retval other This driver does not support this device
94 ScsiDiskDriverBindingSupported (
95 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
96 IN EFI_HANDLE Controller
,
97 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
101 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
104 Status
= gBS
->OpenProtocol (
106 &gEfiScsiIoProtocolGuid
,
108 This
->DriverBindingHandle
,
110 EFI_OPEN_PROTOCOL_BY_DRIVER
112 if (EFI_ERROR (Status
)) {
116 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
117 if (!EFI_ERROR (Status
)) {
118 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
119 Status
= EFI_SUCCESS
;
121 Status
= EFI_UNSUPPORTED
;
127 &gEfiScsiIoProtocolGuid
,
128 This
->DriverBindingHandle
,
136 Start this driver on ControllerHandle.
138 This service is called by the EFI boot service ConnectController(). In order
139 to make drivers as small as possible, there are a few calling restrictions for
140 this service. ConnectController() must follow these calling restrictions. If
141 any other agent wishes to call Start() it must also follow these calling
144 @param This Protocol instance pointer.
145 @param ControllerHandle Handle of device to bind driver to
146 @param RemainingDevicePath Optional parameter use to pick a specific child
149 @retval EFI_SUCCESS This driver is added to ControllerHandle
150 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
151 @retval other This driver does not support this device
156 ScsiDiskDriverBindingStart (
157 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
158 IN EFI_HANDLE Controller
,
159 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
163 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
164 SCSI_DISK_DEV
*ScsiDiskDevice
;
169 BOOLEAN MustReadCapacity
;
171 MustReadCapacity
= TRUE
;
173 ScsiDiskDevice
= (SCSI_DISK_DEV
*) AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
174 if (ScsiDiskDevice
== NULL
) {
175 return EFI_OUT_OF_RESOURCES
;
178 Status
= gBS
->OpenProtocol (
180 &gEfiScsiIoProtocolGuid
,
182 This
->DriverBindingHandle
,
184 EFI_OPEN_PROTOCOL_BY_DRIVER
186 if (EFI_ERROR (Status
)) {
187 FreePool (ScsiDiskDevice
);
191 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
192 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
193 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
194 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
195 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
196 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
197 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
198 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
199 ScsiDiskDevice
->Handle
= Controller
;
201 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
202 switch (ScsiDiskDevice
->DeviceType
) {
203 case EFI_SCSI_TYPE_DISK
:
204 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
205 MustReadCapacity
= TRUE
;
208 case EFI_SCSI_TYPE_CDROM
:
209 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
210 MustReadCapacity
= FALSE
;
214 // The Sense Data Array's initial size is 6
216 ScsiDiskDevice
->SenseDataNumber
= 6;
217 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
218 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
220 if (ScsiDiskDevice
->SenseData
== NULL
) {
223 &gEfiScsiIoProtocolGuid
,
224 This
->DriverBindingHandle
,
227 FreePool (ScsiDiskDevice
);
228 return EFI_OUT_OF_RESOURCES
;
232 // Retrieve device information
235 for (Index
= 0; Index
< MaxRetry
; Index
++) {
236 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
237 if (!EFI_ERROR (Status
)) {
242 FreePool (ScsiDiskDevice
->SenseData
);
245 &gEfiScsiIoProtocolGuid
,
246 This
->DriverBindingHandle
,
249 FreePool (ScsiDiskDevice
);
250 return EFI_DEVICE_ERROR
;
254 // The second parameter "TRUE" means must
255 // retrieve media capacity
257 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
258 if (!EFI_ERROR (Status
)) {
260 // Determine if Block IO should be produced on this controller handle
262 if (DetermineInstallBlockIo(Controller
)) {
263 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
264 Status
= gBS
->InstallMultipleProtocolInterfaces (
266 &gEfiBlockIoProtocolGuid
,
267 &ScsiDiskDevice
->BlkIo
,
268 &gEfiDiskInfoProtocolGuid
,
269 &ScsiDiskDevice
->DiskInfo
,
272 if (!EFI_ERROR(Status
)) {
273 ScsiDiskDevice
->ControllerNameTable
= NULL
;
276 gScsiDiskComponentName
.SupportedLanguages
,
277 &ScsiDiskDevice
->ControllerNameTable
,
283 gScsiDiskComponentName2
.SupportedLanguages
,
284 &ScsiDiskDevice
->ControllerNameTable
,
293 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
294 gBS
->FreePool (ScsiDiskDevice
);
297 &gEfiScsiIoProtocolGuid
,
298 This
->DriverBindingHandle
,
307 Stop this driver on ControllerHandle.
309 This service is called by the EFI boot service DisconnectController().
310 In order to make drivers as small as possible, there are a few calling
311 restrictions for this service. DisconnectController() must follow these
312 calling restrictions. If any other agent wishes to call Stop() it must
313 also follow these calling restrictions.
315 @param This Protocol instance pointer.
316 @param ControllerHandle Handle of device to stop driver on
317 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
318 children is zero stop the entire bus driver.
319 @param ChildHandleBuffer List of Child Handles to Stop.
321 @retval EFI_SUCCESS This driver is removed ControllerHandle
322 @retval other This driver was not removed from this device
327 ScsiDiskDriverBindingStop (
328 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
329 IN EFI_HANDLE Controller
,
330 IN UINTN NumberOfChildren
,
331 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
334 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
335 SCSI_DISK_DEV
*ScsiDiskDevice
;
338 Status
= gBS
->OpenProtocol (
340 &gEfiBlockIoProtocolGuid
,
342 This
->DriverBindingHandle
,
344 EFI_OPEN_PROTOCOL_GET_PROTOCOL
346 if (EFI_ERROR (Status
)) {
350 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
351 Status
= gBS
->UninstallMultipleProtocolInterfaces (
353 &gEfiBlockIoProtocolGuid
,
354 &ScsiDiskDevice
->BlkIo
,
355 &gEfiDiskInfoProtocolGuid
,
356 &ScsiDiskDevice
->DiskInfo
,
359 if (!EFI_ERROR (Status
)) {
362 &gEfiScsiIoProtocolGuid
,
363 This
->DriverBindingHandle
,
367 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
381 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
382 @param ExtendedVerification The flag about if extend verificate
384 @retval EFI_SUCCESS The device was reset.
385 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
387 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
393 IN EFI_BLOCK_IO_PROTOCOL
*This
,
394 IN BOOLEAN ExtendedVerification
398 SCSI_DISK_DEV
*ScsiDiskDevice
;
401 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
403 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
405 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
407 if (EFI_ERROR (Status
)) {
408 Status
= EFI_DEVICE_ERROR
;
412 if (!ExtendedVerification
) {
416 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
418 if (EFI_ERROR (Status
)) {
419 Status
= EFI_DEVICE_ERROR
;
424 gBS
->RestoreTPL (OldTpl
);
429 The function is to Read Block from SCSI Disk.
431 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
432 @param MediaId The Id of Media detected
433 @param Lba The logic block address
434 @param BufferSize The size of Buffer
435 @param Buffer The buffer to fill the read out data
437 @retval EFI_SUCCESS Successfully to read out block.
438 @retval EFI_DEVICE_ERROR Fail to detect media.
439 @retval EFI_NO_MEDIA Media is not present.
440 @retval EFI_MEDIA_CHANGED Media has changed.
441 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
442 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
448 IN EFI_BLOCK_IO_PROTOCOL
*This
,
455 SCSI_DISK_DEV
*ScsiDiskDevice
;
456 EFI_BLOCK_IO_MEDIA
*Media
;
459 UINTN NumberOfBlocks
;
464 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
465 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
467 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
469 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
470 if (EFI_ERROR (Status
)) {
471 Status
= EFI_DEVICE_ERROR
;
476 gBS
->ReinstallProtocolInterface (
477 ScsiDiskDevice
->Handle
,
478 &gEfiBlockIoProtocolGuid
,
479 &ScsiDiskDevice
->BlkIo
,
480 &ScsiDiskDevice
->BlkIo
485 // Get the intrinsic block size
487 Media
= ScsiDiskDevice
->BlkIo
.Media
;
488 BlockSize
= Media
->BlockSize
;
490 NumberOfBlocks
= BufferSize
/ BlockSize
;
492 if (!(Media
->MediaPresent
)) {
493 Status
= EFI_NO_MEDIA
;
497 if (MediaId
!= Media
->MediaId
) {
498 Status
= EFI_MEDIA_CHANGED
;
502 if (Buffer
== NULL
) {
503 Status
= EFI_INVALID_PARAMETER
;
507 if (BufferSize
== 0) {
508 Status
= EFI_SUCCESS
;
512 if (BufferSize
% BlockSize
!= 0) {
513 Status
= EFI_BAD_BUFFER_SIZE
;
517 if (Lba
> Media
->LastBlock
) {
518 Status
= EFI_INVALID_PARAMETER
;
522 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
523 Status
= EFI_INVALID_PARAMETER
;
527 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
528 Status
= EFI_INVALID_PARAMETER
;
533 // If all the parameters are valid, then perform read sectors command
534 // to transfer data from device to host.
536 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
539 gBS
->RestoreTPL (OldTpl
);
544 The function is to Write Block to SCSI Disk.
546 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
547 @param MediaId The Id of Media detected
548 @param Lba The logic block address
549 @param BufferSize The size of Buffer
550 @param Buffer The buffer to fill the read out data
552 @retval EFI_SUCCESS Successfully to read out block.
553 @retval EFI_WRITE_PROTECTED The device can not be written to.
554 @retval EFI_DEVICE_ERROR Fail to detect media.
555 @retval EFI_NO_MEDIA Media is not present.
556 @retval EFI_MEDIA_CHNAGED Media has changed.
557 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
558 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
563 ScsiDiskWriteBlocks (
564 IN EFI_BLOCK_IO_PROTOCOL
*This
,
571 SCSI_DISK_DEV
*ScsiDiskDevice
;
572 EFI_BLOCK_IO_MEDIA
*Media
;
575 UINTN NumberOfBlocks
;
580 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
581 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
583 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
585 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
586 if (EFI_ERROR (Status
)) {
587 Status
= EFI_DEVICE_ERROR
;
592 gBS
->ReinstallProtocolInterface (
593 ScsiDiskDevice
->Handle
,
594 &gEfiBlockIoProtocolGuid
,
595 &ScsiDiskDevice
->BlkIo
,
596 &ScsiDiskDevice
->BlkIo
601 // Get the intrinsic block size
603 Media
= ScsiDiskDevice
->BlkIo
.Media
;
604 BlockSize
= Media
->BlockSize
;
606 NumberOfBlocks
= BufferSize
/ BlockSize
;
608 if (!(Media
->MediaPresent
)) {
609 Status
= EFI_NO_MEDIA
;
613 if (MediaId
!= Media
->MediaId
) {
614 Status
= EFI_MEDIA_CHANGED
;
618 if (BufferSize
== 0) {
619 Status
= EFI_SUCCESS
;
623 if (Buffer
== NULL
) {
624 Status
= EFI_INVALID_PARAMETER
;
628 if (BufferSize
% BlockSize
!= 0) {
629 Status
= EFI_BAD_BUFFER_SIZE
;
633 if (Lba
> Media
->LastBlock
) {
634 Status
= EFI_INVALID_PARAMETER
;
638 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
639 Status
= EFI_INVALID_PARAMETER
;
643 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
644 Status
= EFI_INVALID_PARAMETER
;
648 // if all the parameters are valid, then perform read sectors command
649 // to transfer data from device to host.
651 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
654 gBS
->RestoreTPL (OldTpl
);
661 EFI_SUCCESS is returned directly.
663 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
665 @retval EFI_SUCCESS All outstanding data was written to the device
670 ScsiDiskFlushBlocks (
671 IN EFI_BLOCK_IO_PROTOCOL
*This
682 Detect Device and read out capacity ,if error occurs, parse the sense key.
684 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
685 @param MustReadCapacity The flag about reading device capacity
686 @param MediaChange The pointer of flag indicates if media has changed
688 @retval EFI_DEVICE_ERROR Indicates that error occurs
689 @retval EFI_SUCCESS Successfully to detect media
693 ScsiDiskDetectMedia (
694 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
695 IN BOOLEAN MustReadCapacity
,
696 OUT BOOLEAN
*MediaChange
700 EFI_STATUS ReadCapacityStatus
;
701 EFI_SCSI_SENSE_DATA
*SenseData
;
702 UINTN NumberOfSenseKeys
;
704 BOOLEAN NeedReadCapacity
;
707 EFI_BLOCK_IO_MEDIA OldMedia
;
710 Status
= EFI_SUCCESS
;
711 ReadCapacityStatus
= EFI_SUCCESS
;
713 NumberOfSenseKeys
= 0;
714 NeedReadCapacity
= FALSE
;
715 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
716 *MediaChange
= FALSE
;
718 Action
= ACTION_NO_ACTION
;
720 for (Index
= 0; Index
< MaxRetry
; Index
++) {
721 Status
= ScsiDiskTestUnitReady (
727 if (!EFI_ERROR (Status
)) {
728 Status
= DetectMediaParsingSenseKeys (
734 if (EFI_ERROR (Status
)) {
736 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
748 if ((Index
== MaxRetry
) && EFI_ERROR (Status
)) {
749 return EFI_DEVICE_ERROR
;
753 // ACTION_NO_ACTION: need not read capacity
754 // other action code: need read capacity
756 if (Action
== ACTION_READ_CAPACITY
) {
757 NeedReadCapacity
= TRUE
;
761 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
762 // retrieve capacity via Read Capacity command
764 if (NeedReadCapacity
|| MustReadCapacity
) {
766 // retrieve media information
769 for (Index
= 0; Index
< MaxRetry
; Index
++) {
771 ReadCapacityStatus
= ScsiDiskReadCapacity (
777 if (EFI_ERROR (ReadCapacityStatus
) && !NeedRetry
) {
778 return EFI_DEVICE_ERROR
;
781 // analyze sense key to action
783 Status
= DetectMediaParsingSenseKeys (
790 // if Status is error, it may indicate crisis error,
791 // so return without retry.
793 if (EFI_ERROR (Status
)) {
798 case ACTION_NO_ACTION
:
805 case ACTION_RETRY_COMMAND_LATER
:
807 // retry the ReadCapacity later and continuously, until the condition
808 // no longer emerges.
809 // stall time is 100000us, or say 0.1 second.
817 // other cases, just retry the command
823 if ((Index
== MaxRetry
) && EFI_ERROR (ReadCapacityStatus
)) {
824 return EFI_DEVICE_ERROR
;
828 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
830 // Media change information got from the device
835 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
837 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
840 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
842 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
845 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
847 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
850 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
851 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
853 // when change from no media to media present, reset the MediaId to 1.
855 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
858 // when no media, reset the MediaId to zero.
860 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
871 Send out Inquiry command to Device.
873 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
874 @param NeedRetry Indicates if needs try again when error happens
876 @retval EFI_DEVICE_ERROR Indicates that error occurs
877 @retval EFI_SUCCESS Successfully to detect media
881 ScsiDiskInquiryDevice (
882 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
883 OUT BOOLEAN
*NeedRetry
886 UINT32 InquiryDataLength
;
887 UINT8 SenseDataLength
;
888 UINT8 HostAdapterStatus
;
890 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
891 UINTN NumberOfSenseKeys
;
895 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE SupportedVpdPages
;
896 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE BlockLimits
;
899 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
902 Status
= ScsiInquiryCommand (
903 ScsiDiskDevice
->ScsiIo
,
904 EFI_TIMER_PERIOD_SECONDS (1),
909 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
914 // no need to check HostAdapterStatus and TargetStatus
916 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
917 ParseInquiryData (ScsiDiskDevice
);
919 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
921 // Check whether the device supports Block Limits VPD page (0xB0)
923 ZeroMem (&SupportedVpdPages
, sizeof (SupportedVpdPages
));
924 InquiryDataLength
= sizeof (SupportedVpdPages
);
926 Status
= ScsiInquiryCommandEx (
927 ScsiDiskDevice
->ScsiIo
,
928 EFI_TIMER_PERIOD_SECONDS (1),
933 (VOID
*) &SupportedVpdPages
,
936 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
938 if (!EFI_ERROR (Status
)) {
939 PageLength
= (SupportedVpdPages
.PageLength2
<< 8)
940 | SupportedVpdPages
.PageLength1
;
941 for (Index
= 0; Index
< PageLength
; Index
++) {
942 if (SupportedVpdPages
.SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
948 // Query the Block Limits VPD page
950 if (Index
< PageLength
) {
951 ZeroMem (&BlockLimits
, sizeof (BlockLimits
));
952 InquiryDataLength
= sizeof (BlockLimits
);
954 Status
= ScsiInquiryCommandEx (
955 ScsiDiskDevice
->ScsiIo
,
956 EFI_TIMER_PERIOD_SECONDS (1),
961 (VOID
*) &BlockLimits
,
964 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
966 if (!EFI_ERROR (Status
)) {
967 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
968 (BlockLimits
.OptimalTransferLengthGranularity2
<< 8) |
969 BlockLimits
.OptimalTransferLengthGranularity1
;
976 if (!EFI_ERROR (Status
)) {
979 } else if (Status
== EFI_NOT_READY
) {
981 return EFI_DEVICE_ERROR
;
983 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
985 return EFI_DEVICE_ERROR
;
988 // go ahead to check HostAdapterStatus and TargetStatus
989 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
992 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
993 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
995 return EFI_DEVICE_ERROR
;
996 } else if (Status
== EFI_DEVICE_ERROR
) {
998 // reset the scsi channel
1000 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1002 return EFI_DEVICE_ERROR
;
1005 Status
= CheckTargetStatus (TargetStatus
);
1006 if (Status
== EFI_NOT_READY
) {
1008 // reset the scsi device
1010 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1012 return EFI_DEVICE_ERROR
;
1014 } else if (Status
== EFI_DEVICE_ERROR
) {
1016 return EFI_DEVICE_ERROR
;
1020 // if goes here, meant ScsiInquiryCommand() failed.
1021 // if ScsiDiskRequestSenseKeys() succeeds at last,
1022 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1025 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1026 Status
= ScsiDiskRequestSenseKeys (
1033 if (!EFI_ERROR (Status
)) {
1035 return EFI_DEVICE_ERROR
;
1039 return EFI_DEVICE_ERROR
;
1043 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1044 // set *NeedRetry = FALSE to avoid the outside caller try again.
1047 return EFI_DEVICE_ERROR
;
1053 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1054 When Test Unit Ready command encounters any error caused by host adapter or
1055 target, return error without retrieving Sense Keys.
1057 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1058 @param NeedRetry The pointer of flag indicates try again
1059 @param SenseDataArray The pointer of an array of sense data
1060 @param NumberOfSenseKeys The pointer of the number of sense data array
1062 @retval EFI_DEVICE_ERROR Indicates that error occurs
1063 @retval EFI_SUCCESS Successfully to test unit
1067 ScsiDiskTestUnitReady (
1068 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1069 OUT BOOLEAN
*NeedRetry
,
1070 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1071 OUT UINTN
*NumberOfSenseKeys
1075 UINT8 SenseDataLength
;
1076 UINT8 HostAdapterStatus
;
1081 SenseDataLength
= 0;
1082 *NumberOfSenseKeys
= 0;
1085 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1087 Status
= ScsiTestUnitReadyCommand (
1088 ScsiDiskDevice
->ScsiIo
,
1089 EFI_TIMER_PERIOD_SECONDS (1),
1096 // no need to check HostAdapterStatus and TargetStatus
1098 if (Status
== EFI_NOT_READY
) {
1100 return EFI_DEVICE_ERROR
;
1102 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1104 return EFI_DEVICE_ERROR
;
1107 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1110 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1111 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1113 return EFI_DEVICE_ERROR
;
1115 } else if (Status
== EFI_DEVICE_ERROR
) {
1117 // reset the scsi channel
1119 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1121 return EFI_DEVICE_ERROR
;
1124 Status
= CheckTargetStatus (TargetStatus
);
1125 if (Status
== EFI_NOT_READY
) {
1127 // reset the scsi device
1129 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1131 return EFI_DEVICE_ERROR
;
1133 } else if (Status
== EFI_DEVICE_ERROR
) {
1135 return EFI_DEVICE_ERROR
;
1139 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1140 Status
= ScsiDiskRequestSenseKeys (
1147 if (!EFI_ERROR (Status
)) {
1152 return EFI_DEVICE_ERROR
;
1156 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1157 // set *NeedRetry = FALSE to avoid the outside caller try again.
1160 return EFI_DEVICE_ERROR
;
1164 Parsing Sense Keys which got from request sense command.
1166 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1167 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1168 @param NumberOfSenseKeys The number of sense key
1169 @param Action The pointer of action which indicates what is need to do next
1171 @retval EFI_DEVICE_ERROR Indicates that error occurs
1172 @retval EFI_SUCCESS Successfully to complete the parsing
1176 DetectMediaParsingSenseKeys (
1177 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1178 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1179 IN UINTN NumberOfSenseKeys
,
1186 // Default is to read capacity, unless..
1188 *Action
= ACTION_READ_CAPACITY
;
1190 if (NumberOfSenseKeys
== 0) {
1191 *Action
= ACTION_NO_ACTION
;
1195 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1197 // No Sense Key returned from last submitted command
1199 *Action
= ACTION_NO_ACTION
;
1203 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1204 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1205 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1206 *Action
= ACTION_NO_ACTION
;
1210 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1211 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1215 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1216 *Action
= ACTION_RETRY_COMMAND_LATER
;
1220 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1221 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1222 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1223 return EFI_DEVICE_ERROR
;
1226 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1227 return EFI_DEVICE_ERROR
;
1230 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1232 *Action
= ACTION_RETRY_COMMAND_LATER
;
1236 return EFI_DEVICE_ERROR
;
1244 Send read capacity command to device and get the device parameter.
1246 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1247 @param NeedRetry The pointer of flag indicates if need a retry
1248 @param SenseDataArray The pointer of an array of sense data
1249 @param NumberOfSenseKeys The number of sense key
1251 @retval EFI_DEVICE_ERROR Indicates that error occurs
1252 @retval EFI_SUCCESS Successfully to read capacity
1256 ScsiDiskReadCapacity (
1257 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1258 OUT BOOLEAN
*NeedRetry
,
1259 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1260 OUT UINTN
*NumberOfSenseKeys
1263 UINT8 HostAdapterStatus
;
1265 EFI_STATUS CommandStatus
;
1269 UINT8 SenseDataLength
;
1270 UINT32 DataLength10
;
1271 UINT32 DataLength16
;
1272 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10
;
1273 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16
;
1276 SenseDataLength
= 0;
1277 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1278 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1279 ZeroMem (&CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1280 ZeroMem (&CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1282 *NumberOfSenseKeys
= 0;
1286 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1287 // 16 byte command should be used to access large hard disk >2TB
1289 CommandStatus
= ScsiReadCapacityCommand (
1290 ScsiDiskDevice
->ScsiIo
,
1291 EFI_TIMER_PERIOD_SECONDS(1),
1296 (VOID
*) &CapacityData10
,
1301 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1302 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
.LastLba3
== 0xff) && (CapacityData10
.LastLba2
== 0xff) &&
1303 (CapacityData10
.LastLba1
== 0xff) && (CapacityData10
.LastLba0
== 0xff)) {
1305 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1307 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1309 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1310 // and LowestAlignedLba
1312 CommandStatus
= ScsiReadCapacity16Command (
1313 ScsiDiskDevice
->ScsiIo
,
1314 EFI_TIMER_PERIOD_SECONDS (1),
1319 (VOID
*) &CapacityData16
,
1326 // no need to check HostAdapterStatus and TargetStatus
1328 if (CommandStatus
== EFI_SUCCESS
) {
1329 GetMediaInfo (ScsiDiskDevice
, &CapacityData10
,&CapacityData16
);
1332 } else if (CommandStatus
== EFI_NOT_READY
) {
1334 return EFI_DEVICE_ERROR
;
1336 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1338 return EFI_DEVICE_ERROR
;
1341 // go ahead to check HostAdapterStatus and TargetStatus
1342 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1345 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1346 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1348 return EFI_DEVICE_ERROR
;
1350 } else if (Status
== EFI_DEVICE_ERROR
) {
1352 // reset the scsi channel
1354 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1356 return EFI_DEVICE_ERROR
;
1359 Status
= CheckTargetStatus (TargetStatus
);
1360 if (Status
== EFI_NOT_READY
) {
1362 // reset the scsi device
1364 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1366 return EFI_DEVICE_ERROR
;
1368 } else if (Status
== EFI_DEVICE_ERROR
) {
1370 return EFI_DEVICE_ERROR
;
1374 // if goes here, meant ScsiReadCapacityCommand() failed.
1375 // if ScsiDiskRequestSenseKeys() succeeds at last,
1376 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1379 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1381 Status
= ScsiDiskRequestSenseKeys (
1388 if (!EFI_ERROR (Status
)) {
1390 return EFI_DEVICE_ERROR
;
1394 return EFI_DEVICE_ERROR
;
1398 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1399 // set *NeedRetry = FALSE to avoid the outside caller try again.
1402 return EFI_DEVICE_ERROR
;
1406 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1408 @param HostAdapterStatus Host Adapter status
1410 @retval EFI_SUCCESS Host adapter is OK.
1411 @retval EFI_TIMEOUT Timeout.
1412 @retval EFI_NOT_READY Adapter NOT ready.
1413 @retval EFI_DEVICE_ERROR Adapter device error.
1417 CheckHostAdapterStatus (
1418 IN UINT8 HostAdapterStatus
1421 switch (HostAdapterStatus
) {
1422 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1425 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1426 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1427 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1430 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1431 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1432 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1433 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1434 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1435 return EFI_NOT_READY
;
1437 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1438 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1439 return EFI_DEVICE_ERROR
;
1448 Check the target status and re-interpret it in EFI_STATUS.
1450 @param TargetStatus Target status
1452 @retval EFI_NOT_READY Device is NOT ready.
1453 @retval EFI_DEVICE_ERROR
1459 IN UINT8 TargetStatus
1462 switch (TargetStatus
) {
1463 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1464 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1465 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1468 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1469 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1470 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1471 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1472 return EFI_NOT_READY
;
1474 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1475 return EFI_DEVICE_ERROR
;
1485 Retrieve all sense keys from the device.
1487 When encountering error during the process, if retrieve sense keys before
1488 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1489 and NeedRetry set to FALSE; otherwize, return the proper return status.
1491 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1492 @param NeedRetry The pointer of flag indicates if need a retry
1493 @param SenseDataArray The pointer of an array of sense data
1494 @param NumberOfSenseKeys The number of sense key
1495 @param AskResetIfError The flag indicates if need reset when error occurs
1497 @retval EFI_DEVICE_ERROR Indicates that error occurs
1498 @retval EFI_SUCCESS Successfully to request sense key
1502 ScsiDiskRequestSenseKeys (
1503 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1504 OUT BOOLEAN
*NeedRetry
,
1505 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1506 OUT UINTN
*NumberOfSenseKeys
,
1507 IN BOOLEAN AskResetIfError
1510 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1511 UINT8 SenseDataLength
;
1514 EFI_STATUS FallStatus
;
1515 UINT8 HostAdapterStatus
;
1518 FallStatus
= EFI_SUCCESS
;
1519 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1522 ScsiDiskDevice
->SenseData
,
1523 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1526 *NumberOfSenseKeys
= 0;
1527 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1528 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1530 for (SenseReq
= TRUE
; SenseReq
;) {
1531 Status
= ScsiRequestSenseCommand (
1532 ScsiDiskDevice
->ScsiIo
,
1533 EFI_TIMER_PERIOD_SECONDS (2),
1539 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1540 FallStatus
= EFI_SUCCESS
;
1542 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1544 FallStatus
= EFI_DEVICE_ERROR
;
1546 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1548 FallStatus
= EFI_DEVICE_ERROR
;
1550 } else if (Status
== EFI_DEVICE_ERROR
) {
1551 if (AskResetIfError
) {
1552 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1555 FallStatus
= EFI_DEVICE_ERROR
;
1558 if (EFI_ERROR (FallStatus
)) {
1559 if (*NumberOfSenseKeys
!= 0) {
1563 return EFI_DEVICE_ERROR
;
1567 (*NumberOfSenseKeys
) += 1;
1570 // no more sense key or number of sense keys exceeds predefined,
1573 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1574 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1584 Get information from media read capacity command.
1586 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1587 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1588 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1593 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1594 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1595 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1600 if (!ScsiDiskDevice
->Cdb16Byte
) {
1601 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1602 (Capacity10
->LastLba2
<< 16) |
1603 (Capacity10
->LastLba1
<< 8) |
1604 Capacity10
->LastLba0
;
1606 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1607 (Capacity10
->BlockSize2
<< 16) |
1608 (Capacity10
->BlockSize1
<< 8) |
1609 Capacity10
->BlockSize0
;
1610 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1611 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
1613 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1614 *Ptr
++ = Capacity16
->LastLba0
;
1615 *Ptr
++ = Capacity16
->LastLba1
;
1616 *Ptr
++ = Capacity16
->LastLba2
;
1617 *Ptr
++ = Capacity16
->LastLba3
;
1618 *Ptr
++ = Capacity16
->LastLba4
;
1619 *Ptr
++ = Capacity16
->LastLba5
;
1620 *Ptr
++ = Capacity16
->LastLba6
;
1621 *Ptr
= Capacity16
->LastLba7
;
1623 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1624 (Capacity16
->BlockSize2
<< 16) |
1625 (Capacity16
->BlockSize1
<< 8) |
1626 Capacity16
->BlockSize0
;
1628 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
1629 Capacity16
->LowestAlignLogic1
;
1630 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
1633 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1635 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1636 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1639 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1640 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1647 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1652 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1655 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1656 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1660 Read sector from SCSI Disk.
1662 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1663 @param Buffer The buffer to fill in the read out data
1664 @param Lba Logic block address
1665 @param NumberOfBlocks The number of blocks to read
1667 @retval EFI_DEVICE_ERROR Indicates a device error.
1668 @retval EFI_SUCCESS Operation is successful.
1672 ScsiDiskReadSectors (
1673 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1676 IN UINTN NumberOfBlocks
1679 UINTN BlocksRemaining
;
1690 EFI_SCSI_SENSE_DATA
*SenseData
;
1691 UINTN NumberOfSenseKeys
;
1694 NumberOfSenseKeys
= 0;
1696 Status
= EFI_SUCCESS
;
1698 BlocksRemaining
= NumberOfBlocks
;
1699 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1702 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1704 if (!ScsiDiskDevice
->Cdb16Byte
) {
1707 MaxBlock
= 0xFFFFFFFF;
1712 while (BlocksRemaining
> 0) {
1714 if (BlocksRemaining
<= MaxBlock
) {
1715 if (!ScsiDiskDevice
->Cdb16Byte
) {
1716 SectorCount
= (UINT16
) BlocksRemaining
;
1718 SectorCount
= (UINT32
) BlocksRemaining
;
1721 SectorCount
= MaxBlock
;
1724 ByteCount
= SectorCount
* BlockSize
;
1725 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1728 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1729 if (!ScsiDiskDevice
->Cdb16Byte
) {
1730 Status
= ScsiDiskRead10 (
1742 Status
= ScsiDiskRead16 (
1754 if (!EFI_ERROR (Status
)) {
1759 return EFI_DEVICE_ERROR
;
1764 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1765 return EFI_DEVICE_ERROR
;
1769 // actual transferred sectors
1771 SectorCount
= ByteCount
/ BlockSize
;
1774 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1775 BlocksRemaining
-= SectorCount
;
1782 Write sector to SCSI Disk.
1784 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1785 @param Buffer The buffer of data to be written into SCSI Disk
1786 @param Lba Logic block address
1787 @param NumberOfBlocks The number of blocks to read
1789 @retval EFI_DEVICE_ERROR Indicates a device error.
1790 @retval EFI_SUCCESS Operation is successful.
1794 ScsiDiskWriteSectors (
1795 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1798 IN UINTN NumberOfBlocks
1801 UINTN BlocksRemaining
;
1812 EFI_SCSI_SENSE_DATA
*SenseData
;
1813 UINTN NumberOfSenseKeys
;
1816 NumberOfSenseKeys
= 0;
1818 Status
= EFI_SUCCESS
;
1820 BlocksRemaining
= NumberOfBlocks
;
1821 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1824 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1826 if (!ScsiDiskDevice
->Cdb16Byte
) {
1829 MaxBlock
= 0xFFFFFFFF;
1834 while (BlocksRemaining
> 0) {
1836 if (BlocksRemaining
<= MaxBlock
) {
1837 if (!ScsiDiskDevice
->Cdb16Byte
) {
1838 SectorCount
= (UINT16
) BlocksRemaining
;
1840 SectorCount
= (UINT32
) BlocksRemaining
;
1843 SectorCount
= MaxBlock
;
1846 ByteCount
= SectorCount
* BlockSize
;
1847 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1849 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1850 if (!ScsiDiskDevice
->Cdb16Byte
) {
1851 Status
= ScsiDiskWrite10 (
1863 Status
= ScsiDiskWrite16 (
1875 if (!EFI_ERROR (Status
)) {
1880 return EFI_DEVICE_ERROR
;
1884 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1885 return EFI_DEVICE_ERROR
;
1888 // actual transferred sectors
1890 SectorCount
= ByteCount
/ BlockSize
;
1893 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1894 BlocksRemaining
-= SectorCount
;
1902 Submit Read(10) command.
1904 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1905 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1906 @param SenseDataArray NOT used yet in this function
1907 @param NumberOfSenseKeys The number of sense key
1908 @param Timeout The time to complete the command
1909 @param DataBuffer The buffer to fill with the read out data
1910 @param DataLength The length of buffer
1911 @param StartLba The start logic block address
1912 @param SectorSize The size of sector
1914 @return EFI_STATUS is returned by calling ScsiRead10Command().
1918 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1919 OUT BOOLEAN
*NeedRetry
,
1920 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1921 OUT UINTN
*NumberOfSenseKeys
,
1923 OUT UINT8
*DataBuffer
,
1924 IN OUT UINT32
*DataLength
,
1926 IN UINT32 SectorSize
1929 UINT8 SenseDataLength
;
1931 UINT8 HostAdapterStatus
;
1935 *NumberOfSenseKeys
= 0;
1936 SenseDataLength
= 0;
1937 Status
= ScsiRead10Command (
1938 ScsiDiskDevice
->ScsiIo
,
1954 Submit Write(10) Command.
1956 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1957 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1958 @param SenseDataArray NOT used yet in this function
1959 @param NumberOfSenseKeys The number of sense key
1960 @param Timeout The time to complete the command
1961 @param DataBuffer The buffer to fill with the read out data
1962 @param DataLength The length of buffer
1963 @param StartLba The start logic block address
1964 @param SectorSize The size of sector
1966 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1971 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1972 OUT BOOLEAN
*NeedRetry
,
1973 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1974 OUT UINTN
*NumberOfSenseKeys
,
1976 IN UINT8
*DataBuffer
,
1977 IN OUT UINT32
*DataLength
,
1979 IN UINT32 SectorSize
1983 UINT8 SenseDataLength
;
1984 UINT8 HostAdapterStatus
;
1988 *NumberOfSenseKeys
= 0;
1989 SenseDataLength
= 0;
1990 Status
= ScsiWrite10Command (
1991 ScsiDiskDevice
->ScsiIo
,
2007 Submit Read(16) command.
2009 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2010 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2011 @param SenseDataArray NOT used yet in this function
2012 @param NumberOfSenseKeys The number of sense key
2013 @param Timeout The time to complete the command
2014 @param DataBuffer The buffer to fill with the read out data
2015 @param DataLength The length of buffer
2016 @param StartLba The start logic block address
2017 @param SectorSize The size of sector
2019 @return EFI_STATUS is returned by calling ScsiRead10Command().
2023 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2024 OUT BOOLEAN
*NeedRetry
,
2025 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2026 OUT UINTN
*NumberOfSenseKeys
,
2028 OUT UINT8
*DataBuffer
,
2029 IN OUT UINT32
*DataLength
,
2031 IN UINT32 SectorSize
2034 UINT8 SenseDataLength
;
2036 UINT8 HostAdapterStatus
;
2040 *NumberOfSenseKeys
= 0;
2041 SenseDataLength
= 0;
2042 Status
= ScsiRead16Command (
2043 ScsiDiskDevice
->ScsiIo
,
2059 Submit Write(16) Command.
2061 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2062 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2063 @param SenseDataArray NOT used yet in this function
2064 @param NumberOfSenseKeys The number of sense key
2065 @param Timeout The time to complete the command
2066 @param DataBuffer The buffer to fill with the read out data
2067 @param DataLength The length of buffer
2068 @param StartLba The start logic block address
2069 @param SectorSize The size of sector
2071 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2076 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2077 OUT BOOLEAN
*NeedRetry
,
2078 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2079 OUT UINTN
*NumberOfSenseKeys
,
2081 IN UINT8
*DataBuffer
,
2082 IN OUT UINT32
*DataLength
,
2084 IN UINT32 SectorSize
2088 UINT8 SenseDataLength
;
2089 UINT8 HostAdapterStatus
;
2093 *NumberOfSenseKeys
= 0;
2094 SenseDataLength
= 0;
2095 Status
= ScsiWrite16Command (
2096 ScsiDiskDevice
->ScsiIo
,
2112 Check sense key to find if media presents.
2114 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2115 @param SenseCounts The number of sense key
2117 @retval TRUE NOT any media
2118 @retval FALSE Media presents
2122 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2123 IN UINTN SenseCounts
2126 EFI_SCSI_SENSE_DATA
*SensePtr
;
2131 SensePtr
= SenseData
;
2133 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2135 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2136 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2138 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
2139 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
2152 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2153 @param SenseCounts The number of sense key
2156 @retval FALSE NOT error
2160 ScsiDiskIsMediaError (
2161 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2162 IN UINTN SenseCounts
2165 EFI_SCSI_SENSE_DATA
*SensePtr
;
2170 SensePtr
= SenseData
;
2172 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2174 switch (SensePtr
->Sense_Key
) {
2176 case EFI_SCSI_SK_MEDIUM_ERROR
:
2178 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2180 switch (SensePtr
->Addnl_Sense_Code
) {
2185 case EFI_SCSI_ASC_MEDIA_ERR1
:
2190 case EFI_SCSI_ASC_MEDIA_ERR2
:
2195 case EFI_SCSI_ASC_MEDIA_ERR3
:
2196 case EFI_SCSI_ASC_MEDIA_ERR4
:
2206 case EFI_SCSI_SK_NOT_READY
:
2208 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2210 switch (SensePtr
->Addnl_Sense_Code
) {
2212 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2214 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2235 Check sense key to find if hardware error happens.
2237 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2238 @param SenseCounts The number of sense key
2240 @retval TRUE Hardware error exits.
2241 @retval FALSE NO error.
2245 ScsiDiskIsHardwareError (
2246 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2247 IN UINTN SenseCounts
2250 EFI_SCSI_SENSE_DATA
*SensePtr
;
2255 SensePtr
= SenseData
;
2257 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2260 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2262 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2274 Check sense key to find if media has changed.
2276 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2277 @param SenseCounts The number of sense key
2279 @retval TRUE Media is changed.
2280 @retval FALSE Media is NOT changed.
2283 ScsiDiskIsMediaChange (
2284 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2285 IN UINTN SenseCounts
2288 EFI_SCSI_SENSE_DATA
*SensePtr
;
2290 BOOLEAN IsMediaChanged
;
2292 IsMediaChanged
= FALSE
;
2293 SensePtr
= SenseData
;
2295 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2297 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2298 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2300 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2301 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2302 IsMediaChanged
= TRUE
;
2308 return IsMediaChanged
;
2312 Check sense key to find if reset happens.
2314 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2315 @param SenseCounts The number of sense key
2317 @retval TRUE It is reset before.
2318 @retval FALSE It is NOT reset before.
2322 ScsiDiskIsResetBefore (
2323 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2324 IN UINTN SenseCounts
2327 EFI_SCSI_SENSE_DATA
*SensePtr
;
2329 BOOLEAN IsResetBefore
;
2331 IsResetBefore
= FALSE
;
2332 SensePtr
= SenseData
;
2334 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2337 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2338 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2340 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2341 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2342 IsResetBefore
= TRUE
;
2348 return IsResetBefore
;
2352 Check sense key to find if the drive is ready.
2354 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2355 @param SenseCounts The number of sense key
2356 @param RetryLater The flag means if need a retry
2358 @retval TRUE Drive is ready.
2359 @retval FALSE Drive is NOT ready.
2363 ScsiDiskIsDriveReady (
2364 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2365 IN UINTN SenseCounts
,
2366 OUT BOOLEAN
*RetryLater
2369 EFI_SCSI_SENSE_DATA
*SensePtr
;
2374 *RetryLater
= FALSE
;
2375 SensePtr
= SenseData
;
2377 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2379 switch (SensePtr
->Sense_Key
) {
2381 case EFI_SCSI_SK_NOT_READY
:
2383 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2385 switch (SensePtr
->Addnl_Sense_Code
) {
2386 case EFI_SCSI_ASC_NOT_READY
:
2388 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2390 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2391 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2393 // Additional Sense Code Qualifier is
2394 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2402 *RetryLater
= FALSE
;
2423 Check sense key to find if it has sense key.
2425 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2426 @param SenseCounts - The number of sense key
2428 @retval TRUE It has sense key.
2429 @retval FALSE It has NOT any sense key.
2433 ScsiDiskHaveSenseKey (
2434 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2435 IN UINTN SenseCounts
2438 EFI_SCSI_SENSE_DATA
*SensePtr
;
2440 BOOLEAN HaveSenseKey
;
2442 if (SenseCounts
== 0) {
2443 HaveSenseKey
= FALSE
;
2445 HaveSenseKey
= TRUE
;
2448 SensePtr
= SenseData
;
2450 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2453 // Sense Key is SK_NO_SENSE (0x0)
2455 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2457 HaveSenseKey
= FALSE
;
2463 return HaveSenseKey
;
2467 Release resource about disk device.
2469 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2473 ReleaseScsiDiskDeviceResources (
2474 IN SCSI_DISK_DEV
*ScsiDiskDevice
2477 if (ScsiDiskDevice
== NULL
) {
2481 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2482 FreePool (ScsiDiskDevice
->SenseData
);
2483 ScsiDiskDevice
->SenseData
= NULL
;
2486 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2487 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2488 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2491 FreePool (ScsiDiskDevice
);
2493 ScsiDiskDevice
= NULL
;
2497 Determine if Block Io should be produced.
2500 @param ChildHandle Child Handle to retrieve Parent information.
2502 @retval TRUE Should produce Block Io.
2503 @retval FALSE Should not produce Block Io.
2507 DetermineInstallBlockIo (
2508 IN EFI_HANDLE ChildHandle
2511 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2512 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2515 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2516 // check its attribute, logic or physical.
2518 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2519 if (ExtScsiPassThru
!= NULL
) {
2520 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2526 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2527 // check its attribute, logic or physical.
2529 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2530 if (ScsiPassThru
!= NULL
) {
2531 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2540 Search protocol database and check to see if the protocol
2541 specified by ProtocolGuid is present on a ControllerHandle and opened by
2542 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2543 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2544 will be opened on it.
2547 @param ProtocolGuid ProtocolGuid pointer.
2548 @param ChildHandle Child Handle to retrieve Parent information.
2554 IN EFI_GUID
*ProtocolGuid
,
2555 IN EFI_HANDLE ChildHandle
2562 EFI_HANDLE
*HandleBuffer
;
2565 // Retrieve the list of all handles from the handle database
2567 Status
= gBS
->LocateHandleBuffer (
2575 if (EFI_ERROR (Status
)) {
2580 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
2582 for (Index
= 0; Index
< HandleCount
; Index
++) {
2583 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
2584 if (!EFI_ERROR (Status
)) {
2585 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
2586 if (!EFI_ERROR (Status
)) {
2587 gBS
->FreePool (HandleBuffer
);
2593 gBS
->FreePool (HandleBuffer
);
2598 Provides inquiry information for the controller type.
2600 This function is used by the IDE bus driver to get inquiry data. Data format
2601 of Identify data is defined by the Interface GUID.
2603 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2604 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
2605 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
2607 @retval EFI_SUCCESS The command was accepted without any errors.
2608 @retval EFI_NOT_FOUND Device does not support this data class
2609 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
2610 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
2615 ScsiDiskInfoInquiry (
2616 IN EFI_DISK_INFO_PROTOCOL
*This
,
2617 IN OUT VOID
*InquiryData
,
2618 IN OUT UINT32
*InquiryDataSize
2622 SCSI_DISK_DEV
*ScsiDiskDevice
;
2624 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2626 Status
= EFI_BUFFER_TOO_SMALL
;
2627 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
2628 Status
= EFI_SUCCESS
;
2629 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
2631 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
2637 Provides identify information for the controller type.
2639 This function is used by the IDE bus driver to get identify data. Data format
2640 of Identify data is defined by the Interface GUID.
2642 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
2644 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
2645 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
2648 @retval EFI_SUCCESS The command was accepted without any errors.
2649 @retval EFI_NOT_FOUND Device does not support this data class
2650 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
2651 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
2656 ScsiDiskInfoIdentify (
2657 IN EFI_DISK_INFO_PROTOCOL
*This
,
2658 IN OUT VOID
*IdentifyData
,
2659 IN OUT UINT32
*IdentifyDataSize
2663 SCSI_DISK_DEV
*ScsiDiskDevice
;
2665 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2667 // Physical SCSI bus does not support this data class.
2669 return EFI_NOT_FOUND
;
2672 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2674 Status
= EFI_BUFFER_TOO_SMALL
;
2675 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
2676 Status
= EFI_SUCCESS
;
2677 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
2679 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
2684 Provides sense data information for the controller type.
2686 This function is used by the IDE bus driver to get sense data.
2687 Data format of Sense data is defined by the Interface GUID.
2689 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2690 @param[in, out] SenseData Pointer to the SenseData.
2691 @param[in, out] SenseDataSize Size of SenseData in bytes.
2692 @param[out] SenseDataNumber Pointer to the value for the sense data size.
2694 @retval EFI_SUCCESS The command was accepted without any errors.
2695 @retval EFI_NOT_FOUND Device does not support this data class.
2696 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
2697 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
2702 ScsiDiskInfoSenseData (
2703 IN EFI_DISK_INFO_PROTOCOL
*This
,
2704 IN OUT VOID
*SenseData
,
2705 IN OUT UINT32
*SenseDataSize
,
2706 OUT UINT8
*SenseDataNumber
2709 return EFI_NOT_FOUND
;
2714 This function is used by the IDE bus driver to get controller information.
2716 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2717 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
2718 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
2720 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
2721 @retval EFI_UNSUPPORTED This is not an IDE device.
2726 ScsiDiskInfoWhichIde (
2727 IN EFI_DISK_INFO_PROTOCOL
*This
,
2728 OUT UINT32
*IdeChannel
,
2729 OUT UINT32
*IdeDevice
2732 SCSI_DISK_DEV
*ScsiDiskDevice
;
2734 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2736 // This is not an IDE physical device.
2738 return EFI_UNSUPPORTED
;
2741 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2742 *IdeChannel
= ScsiDiskDevice
->Channel
;
2743 *IdeDevice
= ScsiDiskDevice
->Device
;
2750 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
2752 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
2753 implement Identify() interface for DiskInfo protocol. The ATA command is sent
2754 via SCSI Request Packet.
2756 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2758 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
2759 @retval others Some error occurred during the identification that ATAPI device.
2763 AtapiIdentifyDevice (
2764 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2767 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
2771 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
2773 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
2774 ZeroMem (Cdb
, sizeof (Cdb
));
2776 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
2777 CommandPacket
.Timeout
= EFI_TIMER_PERIOD_SECONDS (1);
2778 CommandPacket
.Cdb
= Cdb
;
2779 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
2780 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
2781 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
2783 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
2788 Initialize the installation of DiskInfo protocol.
2790 This function prepares for the installation of DiskInfo protocol on the child handle.
2791 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
2792 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
2793 to be IDE/AHCI interface GUID.
2795 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2796 @param ChildHandle Child handle to install DiskInfo protocol.
2800 InitializeInstallDiskInfo (
2801 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2802 IN EFI_HANDLE ChildHandle
2806 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2807 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
2808 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
2809 SATA_DEVICE_PATH
*SataDevicePath
;
2810 UINTN IdentifyRetry
;
2812 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
2814 // Device Path protocol must be installed on the device handle.
2816 ASSERT_EFI_ERROR (Status
);
2818 // Copy the DiskInfo protocol template.
2820 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
2822 while (!IsDevicePathEnd (DevicePathNode
)) {
2823 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
2824 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
2825 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
2826 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
2827 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
2828 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
2833 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
2834 // with IDE/AHCI interface GUID.
2836 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
2837 if (!EFI_ERROR (Status
)) {
2838 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
2840 // We find the valid ATAPI device path
2842 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
2843 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
2844 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
2846 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
2848 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
2851 // We find the valid SATA device path
2853 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
2854 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
2855 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
2857 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
2859 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
2863 } while (--IdentifyRetry
> 0);
2865 DevicePathNode
= ChildDevicePathNode
;