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_SCSI_SENSE_DATA
*SenseData
;
701 UINTN NumberOfSenseKeys
;
703 BOOLEAN NeedReadCapacity
;
706 EFI_BLOCK_IO_MEDIA OldMedia
;
708 EFI_EVENT TimeoutEvt
;
710 Status
= EFI_SUCCESS
;
712 NumberOfSenseKeys
= 0;
715 Action
= ACTION_NO_ACTION
;
716 NeedReadCapacity
= FALSE
;
717 *MediaChange
= FALSE
;
720 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
722 Status
= gBS
->CreateEvent (
729 if (EFI_ERROR (Status
)) {
733 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
734 if (EFI_ERROR (Status
)) {
739 // Sending Test_Unit cmd to poll device status.
740 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
741 // We limit the upper boundary to 120 seconds.
743 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
744 Status
= ScsiDiskTestUnitReady (
750 if (!EFI_ERROR (Status
)) {
751 Status
= DetectMediaParsingSenseKeys (
757 if (EFI_ERROR (Status
)) {
759 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
766 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
772 if (EFI_ERROR (Status
)) {
777 // ACTION_NO_ACTION: need not read capacity
778 // other action code: need read capacity
780 if (Action
== ACTION_READ_CAPACITY
) {
781 NeedReadCapacity
= TRUE
;
785 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
786 // retrieve capacity via Read Capacity command
788 if (NeedReadCapacity
|| MustReadCapacity
) {
790 // retrieve media information
792 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
793 Status
= ScsiDiskReadCapacity (
799 if (!EFI_ERROR (Status
)) {
801 // analyze sense key to action
803 Status
= DetectMediaParsingSenseKeys (
809 if (EFI_ERROR (Status
)) {
811 // if Status is error, it may indicate crisis error,
812 // so return without retry.
815 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
823 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
829 if (EFI_ERROR (Status
)) {
834 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
836 // Media change information got from the device
841 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
843 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
846 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
848 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
851 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
853 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
856 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
857 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
859 // when change from no media to media present, reset the MediaId to 1.
861 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
864 // when no media, reset the MediaId to zero.
866 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
873 if (TimeoutEvt
!= NULL
) {
874 gBS
->CloseEvent (TimeoutEvt
);
881 Send out Inquiry command to Device.
883 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
884 @param NeedRetry Indicates if needs try again when error happens
886 @retval EFI_DEVICE_ERROR Indicates that error occurs
887 @retval EFI_SUCCESS Successfully to detect media
891 ScsiDiskInquiryDevice (
892 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
893 OUT BOOLEAN
*NeedRetry
896 UINT32 InquiryDataLength
;
897 UINT8 SenseDataLength
;
898 UINT8 HostAdapterStatus
;
900 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
901 UINTN NumberOfSenseKeys
;
905 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE SupportedVpdPages
;
906 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE BlockLimits
;
909 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
912 Status
= ScsiInquiryCommand (
913 ScsiDiskDevice
->ScsiIo
,
914 EFI_TIMER_PERIOD_SECONDS (1),
919 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
924 // no need to check HostAdapterStatus and TargetStatus
926 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
927 ParseInquiryData (ScsiDiskDevice
);
929 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
931 // Check whether the device supports Block Limits VPD page (0xB0)
933 ZeroMem (&SupportedVpdPages
, sizeof (SupportedVpdPages
));
934 InquiryDataLength
= sizeof (SupportedVpdPages
);
936 Status
= ScsiInquiryCommandEx (
937 ScsiDiskDevice
->ScsiIo
,
938 EFI_TIMER_PERIOD_SECONDS (1),
943 (VOID
*) &SupportedVpdPages
,
946 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
948 if (!EFI_ERROR (Status
)) {
949 PageLength
= (SupportedVpdPages
.PageLength2
<< 8)
950 | SupportedVpdPages
.PageLength1
;
951 for (Index
= 0; Index
< PageLength
; Index
++) {
952 if (SupportedVpdPages
.SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
958 // Query the Block Limits VPD page
960 if (Index
< PageLength
) {
961 ZeroMem (&BlockLimits
, sizeof (BlockLimits
));
962 InquiryDataLength
= sizeof (BlockLimits
);
964 Status
= ScsiInquiryCommandEx (
965 ScsiDiskDevice
->ScsiIo
,
966 EFI_TIMER_PERIOD_SECONDS (1),
971 (VOID
*) &BlockLimits
,
974 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
976 if (!EFI_ERROR (Status
)) {
977 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
978 (BlockLimits
.OptimalTransferLengthGranularity2
<< 8) |
979 BlockLimits
.OptimalTransferLengthGranularity1
;
986 if (!EFI_ERROR (Status
)) {
989 } else if (Status
== EFI_NOT_READY
) {
991 return EFI_DEVICE_ERROR
;
993 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
995 return EFI_DEVICE_ERROR
;
998 // go ahead to check HostAdapterStatus and TargetStatus
999 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1002 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1003 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1005 return EFI_DEVICE_ERROR
;
1006 } else if (Status
== EFI_DEVICE_ERROR
) {
1008 // reset the scsi channel
1010 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1012 return EFI_DEVICE_ERROR
;
1015 Status
= CheckTargetStatus (TargetStatus
);
1016 if (Status
== EFI_NOT_READY
) {
1018 // reset the scsi device
1020 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1022 return EFI_DEVICE_ERROR
;
1024 } else if (Status
== EFI_DEVICE_ERROR
) {
1026 return EFI_DEVICE_ERROR
;
1030 // if goes here, meant ScsiInquiryCommand() failed.
1031 // if ScsiDiskRequestSenseKeys() succeeds at last,
1032 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1035 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1036 Status
= ScsiDiskRequestSenseKeys (
1043 if (!EFI_ERROR (Status
)) {
1045 return EFI_DEVICE_ERROR
;
1049 return EFI_DEVICE_ERROR
;
1053 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1054 // set *NeedRetry = FALSE to avoid the outside caller try again.
1057 return EFI_DEVICE_ERROR
;
1063 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1064 When Test Unit Ready command encounters any error caused by host adapter or
1065 target, return error without retrieving Sense Keys.
1067 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1068 @param NeedRetry The pointer of flag indicates try again
1069 @param SenseDataArray The pointer of an array of sense data
1070 @param NumberOfSenseKeys The pointer of the number of sense data array
1072 @retval EFI_DEVICE_ERROR Indicates that error occurs
1073 @retval EFI_SUCCESS Successfully to test unit
1077 ScsiDiskTestUnitReady (
1078 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1079 OUT BOOLEAN
*NeedRetry
,
1080 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1081 OUT UINTN
*NumberOfSenseKeys
1085 UINT8 SenseDataLength
;
1086 UINT8 HostAdapterStatus
;
1091 SenseDataLength
= 0;
1092 *NumberOfSenseKeys
= 0;
1095 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1097 Status
= ScsiTestUnitReadyCommand (
1098 ScsiDiskDevice
->ScsiIo
,
1099 EFI_TIMER_PERIOD_SECONDS (1),
1106 // no need to check HostAdapterStatus and TargetStatus
1108 if (Status
== EFI_NOT_READY
) {
1110 return EFI_DEVICE_ERROR
;
1112 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1114 return EFI_DEVICE_ERROR
;
1117 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1120 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1121 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1123 return EFI_DEVICE_ERROR
;
1125 } else if (Status
== EFI_DEVICE_ERROR
) {
1127 // reset the scsi channel
1129 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1131 return EFI_DEVICE_ERROR
;
1134 Status
= CheckTargetStatus (TargetStatus
);
1135 if (Status
== EFI_NOT_READY
) {
1137 // reset the scsi device
1139 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1141 return EFI_DEVICE_ERROR
;
1143 } else if (Status
== EFI_DEVICE_ERROR
) {
1145 return EFI_DEVICE_ERROR
;
1149 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1150 Status
= ScsiDiskRequestSenseKeys (
1157 if (!EFI_ERROR (Status
)) {
1162 return EFI_DEVICE_ERROR
;
1166 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1167 // set *NeedRetry = FALSE to avoid the outside caller try again.
1170 return EFI_DEVICE_ERROR
;
1174 Parsing Sense Keys which got from request sense command.
1176 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1177 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1178 @param NumberOfSenseKeys The number of sense key
1179 @param Action The pointer of action which indicates what is need to do next
1181 @retval EFI_DEVICE_ERROR Indicates that error occurs
1182 @retval EFI_SUCCESS Successfully to complete the parsing
1186 DetectMediaParsingSenseKeys (
1187 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1188 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1189 IN UINTN NumberOfSenseKeys
,
1196 // Default is to read capacity, unless..
1198 *Action
= ACTION_READ_CAPACITY
;
1200 if (NumberOfSenseKeys
== 0) {
1201 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1202 *Action
= ACTION_NO_ACTION
;
1207 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1209 // No Sense Key returned from last submitted command
1211 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1212 *Action
= ACTION_NO_ACTION
;
1217 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1218 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1219 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1220 *Action
= ACTION_NO_ACTION
;
1224 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1225 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1229 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1230 *Action
= ACTION_RETRY_COMMAND_LATER
;
1234 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1235 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1236 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1237 *Action
= ACTION_NO_ACTION
;
1238 return EFI_DEVICE_ERROR
;
1241 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1242 *Action
= ACTION_NO_ACTION
;
1243 return EFI_DEVICE_ERROR
;
1246 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1248 *Action
= ACTION_RETRY_COMMAND_LATER
;
1251 *Action
= ACTION_NO_ACTION
;
1252 return EFI_DEVICE_ERROR
;
1260 Send read capacity command to device and get the device parameter.
1262 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1263 @param NeedRetry The pointer of flag indicates if need a retry
1264 @param SenseDataArray The pointer of an array of sense data
1265 @param NumberOfSenseKeys The number of sense key
1267 @retval EFI_DEVICE_ERROR Indicates that error occurs
1268 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1272 ScsiDiskReadCapacity (
1273 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1274 OUT BOOLEAN
*NeedRetry
,
1275 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1276 OUT UINTN
*NumberOfSenseKeys
1279 UINT8 HostAdapterStatus
;
1281 EFI_STATUS CommandStatus
;
1285 UINT8 SenseDataLength
;
1286 UINT32 DataLength10
;
1287 UINT32 DataLength16
;
1288 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10
;
1289 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16
;
1292 SenseDataLength
= 0;
1293 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1294 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1295 ZeroMem (&CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1296 ZeroMem (&CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1298 *NumberOfSenseKeys
= 0;
1302 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1303 // 16 byte command should be used to access large hard disk >2TB
1305 CommandStatus
= ScsiReadCapacityCommand (
1306 ScsiDiskDevice
->ScsiIo
,
1307 EFI_TIMER_PERIOD_SECONDS(1),
1312 (VOID
*) &CapacityData10
,
1317 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1318 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
.LastLba3
== 0xff) && (CapacityData10
.LastLba2
== 0xff) &&
1319 (CapacityData10
.LastLba1
== 0xff) && (CapacityData10
.LastLba0
== 0xff)) {
1321 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1323 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1325 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1326 // and LowestAlignedLba
1328 CommandStatus
= ScsiReadCapacity16Command (
1329 ScsiDiskDevice
->ScsiIo
,
1330 EFI_TIMER_PERIOD_SECONDS (1),
1335 (VOID
*) &CapacityData16
,
1342 // no need to check HostAdapterStatus and TargetStatus
1344 if (CommandStatus
== EFI_SUCCESS
) {
1345 GetMediaInfo (ScsiDiskDevice
, &CapacityData10
,&CapacityData16
);
1348 } else if (CommandStatus
== EFI_NOT_READY
) {
1350 return EFI_DEVICE_ERROR
;
1352 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1354 return EFI_DEVICE_ERROR
;
1357 // go ahead to check HostAdapterStatus and TargetStatus
1358 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1361 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1362 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1364 return EFI_DEVICE_ERROR
;
1366 } else if (Status
== EFI_DEVICE_ERROR
) {
1368 // reset the scsi channel
1370 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1372 return EFI_DEVICE_ERROR
;
1375 Status
= CheckTargetStatus (TargetStatus
);
1376 if (Status
== EFI_NOT_READY
) {
1378 // reset the scsi device
1380 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1382 return EFI_DEVICE_ERROR
;
1384 } else if (Status
== EFI_DEVICE_ERROR
) {
1386 return EFI_DEVICE_ERROR
;
1390 // if goes here, meant ScsiReadCapacityCommand() failed.
1391 // if ScsiDiskRequestSenseKeys() succeeds at last,
1392 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1395 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1397 Status
= ScsiDiskRequestSenseKeys (
1404 if (!EFI_ERROR (Status
)) {
1409 return EFI_DEVICE_ERROR
;
1413 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1414 // set *NeedRetry = FALSE to avoid the outside caller try again.
1417 return EFI_DEVICE_ERROR
;
1421 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1423 @param HostAdapterStatus Host Adapter status
1425 @retval EFI_SUCCESS Host adapter is OK.
1426 @retval EFI_TIMEOUT Timeout.
1427 @retval EFI_NOT_READY Adapter NOT ready.
1428 @retval EFI_DEVICE_ERROR Adapter device error.
1432 CheckHostAdapterStatus (
1433 IN UINT8 HostAdapterStatus
1436 switch (HostAdapterStatus
) {
1437 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1440 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1441 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1442 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1445 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1446 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1447 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1448 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1449 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1450 return EFI_NOT_READY
;
1452 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1453 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1454 return EFI_DEVICE_ERROR
;
1463 Check the target status and re-interpret it in EFI_STATUS.
1465 @param TargetStatus Target status
1467 @retval EFI_NOT_READY Device is NOT ready.
1468 @retval EFI_DEVICE_ERROR
1474 IN UINT8 TargetStatus
1477 switch (TargetStatus
) {
1478 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1479 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1480 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1483 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1484 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1485 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1486 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1487 return EFI_NOT_READY
;
1489 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1490 return EFI_DEVICE_ERROR
;
1500 Retrieve all sense keys from the device.
1502 When encountering error during the process, if retrieve sense keys before
1503 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1504 and NeedRetry set to FALSE; otherwize, return the proper return status.
1506 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1507 @param NeedRetry The pointer of flag indicates if need a retry
1508 @param SenseDataArray The pointer of an array of sense data
1509 @param NumberOfSenseKeys The number of sense key
1510 @param AskResetIfError The flag indicates if need reset when error occurs
1512 @retval EFI_DEVICE_ERROR Indicates that error occurs
1513 @retval EFI_SUCCESS Successfully to request sense key
1517 ScsiDiskRequestSenseKeys (
1518 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1519 OUT BOOLEAN
*NeedRetry
,
1520 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1521 OUT UINTN
*NumberOfSenseKeys
,
1522 IN BOOLEAN AskResetIfError
1525 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1526 UINT8 SenseDataLength
;
1529 EFI_STATUS FallStatus
;
1530 UINT8 HostAdapterStatus
;
1533 FallStatus
= EFI_SUCCESS
;
1534 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1537 ScsiDiskDevice
->SenseData
,
1538 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1541 *NumberOfSenseKeys
= 0;
1542 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1543 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1545 for (SenseReq
= TRUE
; SenseReq
;) {
1546 Status
= ScsiRequestSenseCommand (
1547 ScsiDiskDevice
->ScsiIo
,
1548 EFI_TIMER_PERIOD_SECONDS (2),
1554 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1555 FallStatus
= EFI_SUCCESS
;
1557 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1559 FallStatus
= EFI_DEVICE_ERROR
;
1561 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1563 FallStatus
= EFI_DEVICE_ERROR
;
1565 } else if (Status
== EFI_DEVICE_ERROR
) {
1566 if (AskResetIfError
) {
1567 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1570 FallStatus
= EFI_DEVICE_ERROR
;
1573 if (EFI_ERROR (FallStatus
)) {
1574 if (*NumberOfSenseKeys
!= 0) {
1578 return EFI_DEVICE_ERROR
;
1582 (*NumberOfSenseKeys
) += 1;
1585 // no more sense key or number of sense keys exceeds predefined,
1588 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1589 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1599 Get information from media read capacity command.
1601 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1602 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1603 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1608 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1609 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1610 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1615 if (!ScsiDiskDevice
->Cdb16Byte
) {
1616 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1617 (Capacity10
->LastLba2
<< 16) |
1618 (Capacity10
->LastLba1
<< 8) |
1619 Capacity10
->LastLba0
;
1621 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1622 (Capacity10
->BlockSize2
<< 16) |
1623 (Capacity10
->BlockSize1
<< 8) |
1624 Capacity10
->BlockSize0
;
1625 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1626 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
1628 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1629 *Ptr
++ = Capacity16
->LastLba0
;
1630 *Ptr
++ = Capacity16
->LastLba1
;
1631 *Ptr
++ = Capacity16
->LastLba2
;
1632 *Ptr
++ = Capacity16
->LastLba3
;
1633 *Ptr
++ = Capacity16
->LastLba4
;
1634 *Ptr
++ = Capacity16
->LastLba5
;
1635 *Ptr
++ = Capacity16
->LastLba6
;
1636 *Ptr
= Capacity16
->LastLba7
;
1638 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1639 (Capacity16
->BlockSize2
<< 16) |
1640 (Capacity16
->BlockSize1
<< 8) |
1641 Capacity16
->BlockSize0
;
1643 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
1644 Capacity16
->LowestAlignLogic1
;
1645 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
1648 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1650 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1651 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1654 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1655 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1662 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1667 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1670 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1671 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1675 Read sector from SCSI Disk.
1677 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1678 @param Buffer The buffer to fill in the read out data
1679 @param Lba Logic block address
1680 @param NumberOfBlocks The number of blocks to read
1682 @retval EFI_DEVICE_ERROR Indicates a device error.
1683 @retval EFI_SUCCESS Operation is successful.
1687 ScsiDiskReadSectors (
1688 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1691 IN UINTN NumberOfBlocks
1694 UINTN BlocksRemaining
;
1705 EFI_SCSI_SENSE_DATA
*SenseData
;
1706 UINTN NumberOfSenseKeys
;
1709 NumberOfSenseKeys
= 0;
1711 Status
= EFI_SUCCESS
;
1713 BlocksRemaining
= NumberOfBlocks
;
1714 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1717 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1719 if (!ScsiDiskDevice
->Cdb16Byte
) {
1722 MaxBlock
= 0xFFFFFFFF;
1727 while (BlocksRemaining
> 0) {
1729 if (BlocksRemaining
<= MaxBlock
) {
1730 if (!ScsiDiskDevice
->Cdb16Byte
) {
1731 SectorCount
= (UINT16
) BlocksRemaining
;
1733 SectorCount
= (UINT32
) BlocksRemaining
;
1736 SectorCount
= MaxBlock
;
1739 ByteCount
= SectorCount
* BlockSize
;
1740 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1743 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1744 if (!ScsiDiskDevice
->Cdb16Byte
) {
1745 Status
= ScsiDiskRead10 (
1757 Status
= ScsiDiskRead16 (
1769 if (!EFI_ERROR (Status
)) {
1774 return EFI_DEVICE_ERROR
;
1779 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1780 return EFI_DEVICE_ERROR
;
1784 // actual transferred sectors
1786 SectorCount
= ByteCount
/ BlockSize
;
1789 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1790 BlocksRemaining
-= SectorCount
;
1797 Write sector to SCSI Disk.
1799 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1800 @param Buffer The buffer of data to be written into SCSI Disk
1801 @param Lba Logic block address
1802 @param NumberOfBlocks The number of blocks to read
1804 @retval EFI_DEVICE_ERROR Indicates a device error.
1805 @retval EFI_SUCCESS Operation is successful.
1809 ScsiDiskWriteSectors (
1810 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1813 IN UINTN NumberOfBlocks
1816 UINTN BlocksRemaining
;
1827 EFI_SCSI_SENSE_DATA
*SenseData
;
1828 UINTN NumberOfSenseKeys
;
1831 NumberOfSenseKeys
= 0;
1833 Status
= EFI_SUCCESS
;
1835 BlocksRemaining
= NumberOfBlocks
;
1836 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1839 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1841 if (!ScsiDiskDevice
->Cdb16Byte
) {
1844 MaxBlock
= 0xFFFFFFFF;
1849 while (BlocksRemaining
> 0) {
1851 if (BlocksRemaining
<= MaxBlock
) {
1852 if (!ScsiDiskDevice
->Cdb16Byte
) {
1853 SectorCount
= (UINT16
) BlocksRemaining
;
1855 SectorCount
= (UINT32
) BlocksRemaining
;
1858 SectorCount
= MaxBlock
;
1861 ByteCount
= SectorCount
* BlockSize
;
1862 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1864 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1865 if (!ScsiDiskDevice
->Cdb16Byte
) {
1866 Status
= ScsiDiskWrite10 (
1878 Status
= ScsiDiskWrite16 (
1890 if (!EFI_ERROR (Status
)) {
1895 return EFI_DEVICE_ERROR
;
1899 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1900 return EFI_DEVICE_ERROR
;
1903 // actual transferred sectors
1905 SectorCount
= ByteCount
/ BlockSize
;
1908 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1909 BlocksRemaining
-= SectorCount
;
1917 Submit Read(10) command.
1919 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1920 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1921 @param SenseDataArray NOT used yet in this function
1922 @param NumberOfSenseKeys The number of sense key
1923 @param Timeout The time to complete the command
1924 @param DataBuffer The buffer to fill with the read out data
1925 @param DataLength The length of buffer
1926 @param StartLba The start logic block address
1927 @param SectorSize The size of sector
1929 @return EFI_STATUS is returned by calling ScsiRead10Command().
1933 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1934 OUT BOOLEAN
*NeedRetry
,
1935 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1936 OUT UINTN
*NumberOfSenseKeys
,
1938 OUT UINT8
*DataBuffer
,
1939 IN OUT UINT32
*DataLength
,
1941 IN UINT32 SectorSize
1944 UINT8 SenseDataLength
;
1946 UINT8 HostAdapterStatus
;
1950 *NumberOfSenseKeys
= 0;
1951 SenseDataLength
= 0;
1952 Status
= ScsiRead10Command (
1953 ScsiDiskDevice
->ScsiIo
,
1969 Submit Write(10) Command.
1971 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1972 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1973 @param SenseDataArray NOT used yet in this function
1974 @param NumberOfSenseKeys The number of sense key
1975 @param Timeout The time to complete the command
1976 @param DataBuffer The buffer to fill with the read out data
1977 @param DataLength The length of buffer
1978 @param StartLba The start logic block address
1979 @param SectorSize The size of sector
1981 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1986 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1987 OUT BOOLEAN
*NeedRetry
,
1988 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1989 OUT UINTN
*NumberOfSenseKeys
,
1991 IN UINT8
*DataBuffer
,
1992 IN OUT UINT32
*DataLength
,
1994 IN UINT32 SectorSize
1998 UINT8 SenseDataLength
;
1999 UINT8 HostAdapterStatus
;
2003 *NumberOfSenseKeys
= 0;
2004 SenseDataLength
= 0;
2005 Status
= ScsiWrite10Command (
2006 ScsiDiskDevice
->ScsiIo
,
2022 Submit Read(16) command.
2024 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2025 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2026 @param SenseDataArray NOT used yet in this function
2027 @param NumberOfSenseKeys The number of sense key
2028 @param Timeout The time to complete the command
2029 @param DataBuffer The buffer to fill with the read out data
2030 @param DataLength The length of buffer
2031 @param StartLba The start logic block address
2032 @param SectorSize The size of sector
2034 @return EFI_STATUS is returned by calling ScsiRead10Command().
2038 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2039 OUT BOOLEAN
*NeedRetry
,
2040 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2041 OUT UINTN
*NumberOfSenseKeys
,
2043 OUT UINT8
*DataBuffer
,
2044 IN OUT UINT32
*DataLength
,
2046 IN UINT32 SectorSize
2049 UINT8 SenseDataLength
;
2051 UINT8 HostAdapterStatus
;
2055 *NumberOfSenseKeys
= 0;
2056 SenseDataLength
= 0;
2057 Status
= ScsiRead16Command (
2058 ScsiDiskDevice
->ScsiIo
,
2074 Submit Write(16) Command.
2076 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2077 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2078 @param SenseDataArray NOT used yet in this function
2079 @param NumberOfSenseKeys The number of sense key
2080 @param Timeout The time to complete the command
2081 @param DataBuffer The buffer to fill with the read out data
2082 @param DataLength The length of buffer
2083 @param StartLba The start logic block address
2084 @param SectorSize The size of sector
2086 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2091 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2092 OUT BOOLEAN
*NeedRetry
,
2093 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2094 OUT UINTN
*NumberOfSenseKeys
,
2096 IN UINT8
*DataBuffer
,
2097 IN OUT UINT32
*DataLength
,
2099 IN UINT32 SectorSize
2103 UINT8 SenseDataLength
;
2104 UINT8 HostAdapterStatus
;
2108 *NumberOfSenseKeys
= 0;
2109 SenseDataLength
= 0;
2110 Status
= ScsiWrite16Command (
2111 ScsiDiskDevice
->ScsiIo
,
2127 Check sense key to find if media presents.
2129 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2130 @param SenseCounts The number of sense key
2132 @retval TRUE NOT any media
2133 @retval FALSE Media presents
2137 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2138 IN UINTN SenseCounts
2141 EFI_SCSI_SENSE_DATA
*SensePtr
;
2146 SensePtr
= SenseData
;
2148 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2150 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2151 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2153 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
2154 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
2167 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2168 @param SenseCounts The number of sense key
2171 @retval FALSE NOT error
2175 ScsiDiskIsMediaError (
2176 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2177 IN UINTN SenseCounts
2180 EFI_SCSI_SENSE_DATA
*SensePtr
;
2185 SensePtr
= SenseData
;
2187 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2189 switch (SensePtr
->Sense_Key
) {
2191 case EFI_SCSI_SK_MEDIUM_ERROR
:
2193 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2195 switch (SensePtr
->Addnl_Sense_Code
) {
2200 case EFI_SCSI_ASC_MEDIA_ERR1
:
2205 case EFI_SCSI_ASC_MEDIA_ERR2
:
2210 case EFI_SCSI_ASC_MEDIA_ERR3
:
2211 case EFI_SCSI_ASC_MEDIA_ERR4
:
2221 case EFI_SCSI_SK_NOT_READY
:
2223 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2225 switch (SensePtr
->Addnl_Sense_Code
) {
2227 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2229 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2250 Check sense key to find if hardware error happens.
2252 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2253 @param SenseCounts The number of sense key
2255 @retval TRUE Hardware error exits.
2256 @retval FALSE NO error.
2260 ScsiDiskIsHardwareError (
2261 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2262 IN UINTN SenseCounts
2265 EFI_SCSI_SENSE_DATA
*SensePtr
;
2270 SensePtr
= SenseData
;
2272 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2275 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2277 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2289 Check sense key to find if media has changed.
2291 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2292 @param SenseCounts The number of sense key
2294 @retval TRUE Media is changed.
2295 @retval FALSE Media is NOT changed.
2298 ScsiDiskIsMediaChange (
2299 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2300 IN UINTN SenseCounts
2303 EFI_SCSI_SENSE_DATA
*SensePtr
;
2305 BOOLEAN IsMediaChanged
;
2307 IsMediaChanged
= FALSE
;
2308 SensePtr
= SenseData
;
2310 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2312 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2313 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2315 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2316 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2317 IsMediaChanged
= TRUE
;
2323 return IsMediaChanged
;
2327 Check sense key to find if reset happens.
2329 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2330 @param SenseCounts The number of sense key
2332 @retval TRUE It is reset before.
2333 @retval FALSE It is NOT reset before.
2337 ScsiDiskIsResetBefore (
2338 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2339 IN UINTN SenseCounts
2342 EFI_SCSI_SENSE_DATA
*SensePtr
;
2344 BOOLEAN IsResetBefore
;
2346 IsResetBefore
= FALSE
;
2347 SensePtr
= SenseData
;
2349 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2352 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2353 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2355 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2356 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2357 IsResetBefore
= TRUE
;
2363 return IsResetBefore
;
2367 Check sense key to find if the drive is ready.
2369 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2370 @param SenseCounts The number of sense key
2371 @param RetryLater The flag means if need a retry
2373 @retval TRUE Drive is ready.
2374 @retval FALSE Drive is NOT ready.
2378 ScsiDiskIsDriveReady (
2379 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2380 IN UINTN SenseCounts
,
2381 OUT BOOLEAN
*RetryLater
2384 EFI_SCSI_SENSE_DATA
*SensePtr
;
2389 *RetryLater
= FALSE
;
2390 SensePtr
= SenseData
;
2392 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2394 switch (SensePtr
->Sense_Key
) {
2396 case EFI_SCSI_SK_NOT_READY
:
2398 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2400 switch (SensePtr
->Addnl_Sense_Code
) {
2401 case EFI_SCSI_ASC_NOT_READY
:
2403 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2405 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2406 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2408 // Additional Sense Code Qualifier is
2409 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2417 *RetryLater
= FALSE
;
2438 Check sense key to find if it has sense key.
2440 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2441 @param SenseCounts - The number of sense key
2443 @retval TRUE It has sense key.
2444 @retval FALSE It has NOT any sense key.
2448 ScsiDiskHaveSenseKey (
2449 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2450 IN UINTN SenseCounts
2453 EFI_SCSI_SENSE_DATA
*SensePtr
;
2455 BOOLEAN HaveSenseKey
;
2457 if (SenseCounts
== 0) {
2458 HaveSenseKey
= FALSE
;
2460 HaveSenseKey
= TRUE
;
2463 SensePtr
= SenseData
;
2465 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2468 // Sense Key is SK_NO_SENSE (0x0)
2470 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2472 HaveSenseKey
= FALSE
;
2478 return HaveSenseKey
;
2482 Release resource about disk device.
2484 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2488 ReleaseScsiDiskDeviceResources (
2489 IN SCSI_DISK_DEV
*ScsiDiskDevice
2492 if (ScsiDiskDevice
== NULL
) {
2496 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2497 FreePool (ScsiDiskDevice
->SenseData
);
2498 ScsiDiskDevice
->SenseData
= NULL
;
2501 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2502 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2503 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2506 FreePool (ScsiDiskDevice
);
2508 ScsiDiskDevice
= NULL
;
2512 Determine if Block Io should be produced.
2515 @param ChildHandle Child Handle to retrieve Parent information.
2517 @retval TRUE Should produce Block Io.
2518 @retval FALSE Should not produce Block Io.
2522 DetermineInstallBlockIo (
2523 IN EFI_HANDLE ChildHandle
2526 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2527 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2530 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2531 // check its attribute, logic or physical.
2533 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2534 if (ExtScsiPassThru
!= NULL
) {
2535 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2541 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2542 // check its attribute, logic or physical.
2544 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2545 if (ScsiPassThru
!= NULL
) {
2546 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2555 Search protocol database and check to see if the protocol
2556 specified by ProtocolGuid is present on a ControllerHandle and opened by
2557 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2558 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2559 will be opened on it.
2562 @param ProtocolGuid ProtocolGuid pointer.
2563 @param ChildHandle Child Handle to retrieve Parent information.
2569 IN EFI_GUID
*ProtocolGuid
,
2570 IN EFI_HANDLE ChildHandle
2577 EFI_HANDLE
*HandleBuffer
;
2580 // Retrieve the list of all handles from the handle database
2582 Status
= gBS
->LocateHandleBuffer (
2590 if (EFI_ERROR (Status
)) {
2595 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
2597 for (Index
= 0; Index
< HandleCount
; Index
++) {
2598 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
2599 if (!EFI_ERROR (Status
)) {
2600 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
2601 if (!EFI_ERROR (Status
)) {
2602 gBS
->FreePool (HandleBuffer
);
2608 gBS
->FreePool (HandleBuffer
);
2613 Provides inquiry information for the controller type.
2615 This function is used by the IDE bus driver to get inquiry data. Data format
2616 of Identify data is defined by the Interface GUID.
2618 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2619 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
2620 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
2622 @retval EFI_SUCCESS The command was accepted without any errors.
2623 @retval EFI_NOT_FOUND Device does not support this data class
2624 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
2625 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
2630 ScsiDiskInfoInquiry (
2631 IN EFI_DISK_INFO_PROTOCOL
*This
,
2632 IN OUT VOID
*InquiryData
,
2633 IN OUT UINT32
*InquiryDataSize
2637 SCSI_DISK_DEV
*ScsiDiskDevice
;
2639 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2641 Status
= EFI_BUFFER_TOO_SMALL
;
2642 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
2643 Status
= EFI_SUCCESS
;
2644 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
2646 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
2652 Provides identify information for the controller type.
2654 This function is used by the IDE bus driver to get identify data. Data format
2655 of Identify data is defined by the Interface GUID.
2657 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
2659 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
2660 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
2663 @retval EFI_SUCCESS The command was accepted without any errors.
2664 @retval EFI_NOT_FOUND Device does not support this data class
2665 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
2666 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
2671 ScsiDiskInfoIdentify (
2672 IN EFI_DISK_INFO_PROTOCOL
*This
,
2673 IN OUT VOID
*IdentifyData
,
2674 IN OUT UINT32
*IdentifyDataSize
2678 SCSI_DISK_DEV
*ScsiDiskDevice
;
2680 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2682 // Physical SCSI bus does not support this data class.
2684 return EFI_NOT_FOUND
;
2687 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2689 Status
= EFI_BUFFER_TOO_SMALL
;
2690 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
2691 Status
= EFI_SUCCESS
;
2692 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
2694 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
2699 Provides sense data information for the controller type.
2701 This function is used by the IDE bus driver to get sense data.
2702 Data format of Sense data is defined by the Interface GUID.
2704 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2705 @param[in, out] SenseData Pointer to the SenseData.
2706 @param[in, out] SenseDataSize Size of SenseData in bytes.
2707 @param[out] SenseDataNumber Pointer to the value for the sense data size.
2709 @retval EFI_SUCCESS The command was accepted without any errors.
2710 @retval EFI_NOT_FOUND Device does not support this data class.
2711 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
2712 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
2717 ScsiDiskInfoSenseData (
2718 IN EFI_DISK_INFO_PROTOCOL
*This
,
2719 IN OUT VOID
*SenseData
,
2720 IN OUT UINT32
*SenseDataSize
,
2721 OUT UINT8
*SenseDataNumber
2724 return EFI_NOT_FOUND
;
2729 This function is used by the IDE bus driver to get controller information.
2731 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2732 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
2733 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
2735 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
2736 @retval EFI_UNSUPPORTED This is not an IDE device.
2741 ScsiDiskInfoWhichIde (
2742 IN EFI_DISK_INFO_PROTOCOL
*This
,
2743 OUT UINT32
*IdeChannel
,
2744 OUT UINT32
*IdeDevice
2747 SCSI_DISK_DEV
*ScsiDiskDevice
;
2749 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2751 // This is not an IDE physical device.
2753 return EFI_UNSUPPORTED
;
2756 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2757 *IdeChannel
= ScsiDiskDevice
->Channel
;
2758 *IdeDevice
= ScsiDiskDevice
->Device
;
2765 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
2767 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
2768 implement Identify() interface for DiskInfo protocol. The ATA command is sent
2769 via SCSI Request Packet.
2771 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2773 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
2774 @retval others Some error occurred during the identification that ATAPI device.
2778 AtapiIdentifyDevice (
2779 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2782 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
2786 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
2788 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
2789 ZeroMem (Cdb
, sizeof (Cdb
));
2791 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
2792 CommandPacket
.Timeout
= EFI_TIMER_PERIOD_SECONDS (1);
2793 CommandPacket
.Cdb
= Cdb
;
2794 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
2795 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
2796 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
2798 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
2803 Initialize the installation of DiskInfo protocol.
2805 This function prepares for the installation of DiskInfo protocol on the child handle.
2806 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
2807 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
2808 to be IDE/AHCI interface GUID.
2810 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2811 @param ChildHandle Child handle to install DiskInfo protocol.
2815 InitializeInstallDiskInfo (
2816 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2817 IN EFI_HANDLE ChildHandle
2821 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2822 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
2823 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
2824 SATA_DEVICE_PATH
*SataDevicePath
;
2825 UINTN IdentifyRetry
;
2827 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
2829 // Device Path protocol must be installed on the device handle.
2831 ASSERT_EFI_ERROR (Status
);
2833 // Copy the DiskInfo protocol template.
2835 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
2837 while (!IsDevicePathEnd (DevicePathNode
)) {
2838 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
2839 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
2840 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
2841 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
2842 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
2843 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
2848 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
2849 // with IDE/AHCI interface GUID.
2851 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
2852 if (!EFI_ERROR (Status
)) {
2853 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
2855 // We find the valid ATAPI device path
2857 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
2858 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
2859 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
2861 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
2863 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
2866 // We find the valid SATA device path
2868 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
2869 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
2870 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
2872 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
2874 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
2878 } while (--IdentifyRetry
> 0);
2880 DevicePathNode
= ChildDevicePathNode
;