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
;
170 ScsiDiskDevice
= (SCSI_DISK_DEV
*) AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
171 if (ScsiDiskDevice
== NULL
) {
172 return EFI_OUT_OF_RESOURCES
;
175 Status
= gBS
->OpenProtocol (
177 &gEfiScsiIoProtocolGuid
,
179 This
->DriverBindingHandle
,
181 EFI_OPEN_PROTOCOL_BY_DRIVER
183 if (EFI_ERROR (Status
)) {
184 FreePool (ScsiDiskDevice
);
188 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
189 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
190 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
191 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
192 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
193 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
194 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
195 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
196 ScsiDiskDevice
->Handle
= Controller
;
198 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
199 switch (ScsiDiskDevice
->DeviceType
) {
200 case EFI_SCSI_TYPE_DISK
:
201 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
204 case EFI_SCSI_TYPE_CDROM
:
205 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
209 // The Sense Data Array's initial size is 6
211 ScsiDiskDevice
->SenseDataNumber
= 6;
212 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
213 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
215 if (ScsiDiskDevice
->SenseData
== NULL
) {
218 &gEfiScsiIoProtocolGuid
,
219 This
->DriverBindingHandle
,
222 FreePool (ScsiDiskDevice
);
223 return EFI_OUT_OF_RESOURCES
;
227 // Retrieve device information
230 for (Index
= 0; Index
< MaxRetry
; Index
++) {
231 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
232 if (!EFI_ERROR (Status
)) {
237 FreePool (ScsiDiskDevice
->SenseData
);
240 &gEfiScsiIoProtocolGuid
,
241 This
->DriverBindingHandle
,
244 FreePool (ScsiDiskDevice
);
245 return EFI_DEVICE_ERROR
;
249 // The second parameter "TRUE" means must
250 // retrieve media capacity
252 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, TRUE
, &Temp
);
253 if (!EFI_ERROR (Status
)) {
255 // Determine if Block IO should be produced on this controller handle
257 if (DetermineInstallBlockIo(Controller
)) {
258 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
259 Status
= gBS
->InstallMultipleProtocolInterfaces (
261 &gEfiBlockIoProtocolGuid
,
262 &ScsiDiskDevice
->BlkIo
,
263 &gEfiDiskInfoProtocolGuid
,
264 &ScsiDiskDevice
->DiskInfo
,
267 if (!EFI_ERROR(Status
)) {
268 ScsiDiskDevice
->ControllerNameTable
= NULL
;
271 gScsiDiskComponentName
.SupportedLanguages
,
272 &ScsiDiskDevice
->ControllerNameTable
,
278 gScsiDiskComponentName2
.SupportedLanguages
,
279 &ScsiDiskDevice
->ControllerNameTable
,
288 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
289 gBS
->FreePool (ScsiDiskDevice
);
292 &gEfiScsiIoProtocolGuid
,
293 This
->DriverBindingHandle
,
302 Stop this driver on ControllerHandle.
304 This service is called by the EFI boot service DisconnectController().
305 In order to make drivers as small as possible, there are a few calling
306 restrictions for this service. DisconnectController() must follow these
307 calling restrictions. If any other agent wishes to call Stop() it must
308 also follow these calling restrictions.
310 @param This Protocol instance pointer.
311 @param ControllerHandle Handle of device to stop driver on
312 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
313 children is zero stop the entire bus driver.
314 @param ChildHandleBuffer List of Child Handles to Stop.
316 @retval EFI_SUCCESS This driver is removed ControllerHandle
317 @retval other This driver was not removed from this device
322 ScsiDiskDriverBindingStop (
323 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
324 IN EFI_HANDLE Controller
,
325 IN UINTN NumberOfChildren
,
326 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
329 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
330 SCSI_DISK_DEV
*ScsiDiskDevice
;
333 Status
= gBS
->OpenProtocol (
335 &gEfiBlockIoProtocolGuid
,
337 This
->DriverBindingHandle
,
339 EFI_OPEN_PROTOCOL_GET_PROTOCOL
341 if (EFI_ERROR (Status
)) {
345 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
346 Status
= gBS
->UninstallMultipleProtocolInterfaces (
348 &gEfiBlockIoProtocolGuid
,
349 &ScsiDiskDevice
->BlkIo
,
350 &gEfiDiskInfoProtocolGuid
,
351 &ScsiDiskDevice
->DiskInfo
,
354 if (!EFI_ERROR (Status
)) {
357 &gEfiScsiIoProtocolGuid
,
358 This
->DriverBindingHandle
,
362 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
376 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
377 @param ExtendedVerification The flag about if extend verificate
379 @retval EFI_SUCCESS The device was reset.
380 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
382 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
388 IN EFI_BLOCK_IO_PROTOCOL
*This
,
389 IN BOOLEAN ExtendedVerification
393 SCSI_DISK_DEV
*ScsiDiskDevice
;
396 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
398 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
400 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
402 if (EFI_ERROR (Status
)) {
403 Status
= EFI_DEVICE_ERROR
;
407 if (!ExtendedVerification
) {
411 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
413 if (EFI_ERROR (Status
)) {
414 Status
= EFI_DEVICE_ERROR
;
419 gBS
->RestoreTPL (OldTpl
);
424 The function is to Read Block from SCSI Disk.
426 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
427 @param MediaId The Id of Media detected
428 @param Lba The logic block address
429 @param BufferSize The size of Buffer
430 @param Buffer The buffer to fill the read out data
432 @retval EFI_SUCCESS Successfully to read out block.
433 @retval EFI_DEVICE_ERROR Fail to detect media.
434 @retval EFI_NO_MEDIA Media is not present.
435 @retval EFI_MEDIA_CHANGED Media has changed.
436 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
437 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
443 IN EFI_BLOCK_IO_PROTOCOL
*This
,
450 SCSI_DISK_DEV
*ScsiDiskDevice
;
451 EFI_BLOCK_IO_MEDIA
*Media
;
454 UINTN NumberOfBlocks
;
459 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
460 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
462 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
464 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
465 if (EFI_ERROR (Status
)) {
466 Status
= EFI_DEVICE_ERROR
;
471 gBS
->ReinstallProtocolInterface (
472 ScsiDiskDevice
->Handle
,
473 &gEfiBlockIoProtocolGuid
,
474 &ScsiDiskDevice
->BlkIo
,
475 &ScsiDiskDevice
->BlkIo
480 // Get the intrinsic block size
482 Media
= ScsiDiskDevice
->BlkIo
.Media
;
483 BlockSize
= Media
->BlockSize
;
485 NumberOfBlocks
= BufferSize
/ BlockSize
;
487 if (!(Media
->MediaPresent
)) {
488 Status
= EFI_NO_MEDIA
;
492 if (MediaId
!= Media
->MediaId
) {
493 Status
= EFI_MEDIA_CHANGED
;
497 if (Buffer
== NULL
) {
498 Status
= EFI_INVALID_PARAMETER
;
502 if (BufferSize
== 0) {
503 Status
= EFI_SUCCESS
;
507 if (BufferSize
% BlockSize
!= 0) {
508 Status
= EFI_BAD_BUFFER_SIZE
;
512 if (Lba
> Media
->LastBlock
) {
513 Status
= EFI_INVALID_PARAMETER
;
517 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
518 Status
= EFI_INVALID_PARAMETER
;
522 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
523 Status
= EFI_INVALID_PARAMETER
;
528 // If all the parameters are valid, then perform read sectors command
529 // to transfer data from device to host.
531 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
534 gBS
->RestoreTPL (OldTpl
);
539 The function is to Write Block to SCSI Disk.
541 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
542 @param MediaId The Id of Media detected
543 @param Lba The logic block address
544 @param BufferSize The size of Buffer
545 @param Buffer The buffer to fill the read out data
547 @retval EFI_SUCCESS Successfully to read out block.
548 @retval EFI_WRITE_PROTECTED The device can not be written to.
549 @retval EFI_DEVICE_ERROR Fail to detect media.
550 @retval EFI_NO_MEDIA Media is not present.
551 @retval EFI_MEDIA_CHNAGED Media has changed.
552 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
553 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
558 ScsiDiskWriteBlocks (
559 IN EFI_BLOCK_IO_PROTOCOL
*This
,
566 SCSI_DISK_DEV
*ScsiDiskDevice
;
567 EFI_BLOCK_IO_MEDIA
*Media
;
570 UINTN NumberOfBlocks
;
575 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
576 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
578 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
580 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
581 if (EFI_ERROR (Status
)) {
582 Status
= EFI_DEVICE_ERROR
;
587 gBS
->ReinstallProtocolInterface (
588 ScsiDiskDevice
->Handle
,
589 &gEfiBlockIoProtocolGuid
,
590 &ScsiDiskDevice
->BlkIo
,
591 &ScsiDiskDevice
->BlkIo
596 // Get the intrinsic block size
598 Media
= ScsiDiskDevice
->BlkIo
.Media
;
599 BlockSize
= Media
->BlockSize
;
601 NumberOfBlocks
= BufferSize
/ BlockSize
;
603 if (!(Media
->MediaPresent
)) {
604 Status
= EFI_NO_MEDIA
;
608 if (MediaId
!= Media
->MediaId
) {
609 Status
= EFI_MEDIA_CHANGED
;
613 if (BufferSize
== 0) {
614 Status
= EFI_SUCCESS
;
618 if (Buffer
== NULL
) {
619 Status
= EFI_INVALID_PARAMETER
;
623 if (BufferSize
% BlockSize
!= 0) {
624 Status
= EFI_BAD_BUFFER_SIZE
;
628 if (Lba
> Media
->LastBlock
) {
629 Status
= EFI_INVALID_PARAMETER
;
633 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
634 Status
= EFI_INVALID_PARAMETER
;
638 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
639 Status
= EFI_INVALID_PARAMETER
;
643 // if all the parameters are valid, then perform read sectors command
644 // to transfer data from device to host.
646 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
649 gBS
->RestoreTPL (OldTpl
);
656 EFI_SUCCESS is returned directly.
658 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
660 @retval EFI_SUCCESS All outstanding data was written to the device
665 ScsiDiskFlushBlocks (
666 IN EFI_BLOCK_IO_PROTOCOL
*This
677 Detect Device and read out capacity ,if error occurs, parse the sense key.
679 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
680 @param MustReadCapacity The flag about reading device capacity
681 @param MediaChange The pointer of flag indicates if media has changed
683 @retval EFI_DEVICE_ERROR Indicates that error occurs
684 @retval EFI_SUCCESS Successfully to detect media
688 ScsiDiskDetectMedia (
689 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
690 IN BOOLEAN MustReadCapacity
,
691 OUT BOOLEAN
*MediaChange
695 EFI_STATUS ReadCapacityStatus
;
696 EFI_SCSI_SENSE_DATA
*SenseData
;
697 UINTN NumberOfSenseKeys
;
699 BOOLEAN NeedReadCapacity
;
702 EFI_BLOCK_IO_MEDIA OldMedia
;
705 Status
= EFI_SUCCESS
;
706 ReadCapacityStatus
= EFI_SUCCESS
;
708 NumberOfSenseKeys
= 0;
709 NeedReadCapacity
= FALSE
;
710 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
711 *MediaChange
= FALSE
;
714 for (Index
= 0; Index
< MaxRetry
; Index
++) {
715 Status
= ScsiDiskTestUnitReady (
721 if (!EFI_ERROR (Status
)) {
730 if ((Index
== MaxRetry
) && EFI_ERROR (Status
)) {
731 return EFI_DEVICE_ERROR
;
734 Status
= DetectMediaParsingSenseKeys (
740 if (EFI_ERROR (Status
)) {
744 // ACTION_NO_ACTION: need not read capacity
745 // other action code: need read capacity
747 if (Action
== ACTION_NO_ACTION
) {
748 NeedReadCapacity
= FALSE
;
750 NeedReadCapacity
= TRUE
;
754 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
755 // retrieve capacity via Read Capacity command
757 if (NeedReadCapacity
|| MustReadCapacity
) {
759 // retrieve media information
762 for (Index
= 0; Index
< MaxRetry
; Index
++) {
764 ReadCapacityStatus
= ScsiDiskReadCapacity (
770 if (EFI_ERROR (ReadCapacityStatus
) && !NeedRetry
) {
771 return EFI_DEVICE_ERROR
;
774 // analyze sense key to action
776 Status
= DetectMediaParsingSenseKeys (
783 // if Status is error, it may indicate crisis error,
784 // so return without retry.
786 if (EFI_ERROR (Status
)) {
791 case ACTION_NO_ACTION
:
798 case ACTION_RETRY_COMMAND_LATER
:
800 // retry the ReadCapacity later and continuously, until the condition
801 // no longer emerges.
802 // stall time is 100000us, or say 0.1 second.
810 // other cases, just retry the command
816 if ((Index
== MaxRetry
) && EFI_ERROR (ReadCapacityStatus
)) {
817 return EFI_DEVICE_ERROR
;
821 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
823 // Media change information got from the device
828 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
830 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
833 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
835 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
838 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
840 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
843 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
844 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
846 // when change from no media to media present, reset the MediaId to 1.
848 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
851 // when no media, reset the MediaId to zero.
853 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
864 Send out Inquiry command to Device.
866 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
867 @param NeedRetry Indicates if needs try again when error happens
869 @retval EFI_DEVICE_ERROR Indicates that error occurs
870 @retval EFI_SUCCESS Successfully to detect media
874 ScsiDiskInquiryDevice (
875 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
876 OUT BOOLEAN
*NeedRetry
879 UINT32 InquiryDataLength
;
880 UINT8 SenseDataLength
;
881 UINT8 HostAdapterStatus
;
883 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
884 UINTN NumberOfSenseKeys
;
888 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE SupportedVpdPages
;
889 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE BlockLimits
;
892 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
895 Status
= ScsiInquiryCommand (
896 ScsiDiskDevice
->ScsiIo
,
897 EFI_TIMER_PERIOD_SECONDS (1),
902 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
907 // no need to check HostAdapterStatus and TargetStatus
909 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
910 ParseInquiryData (ScsiDiskDevice
);
912 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
914 // Check whether the device supports Block Limits VPD page (0xB0)
916 ZeroMem (&SupportedVpdPages
, sizeof (SupportedVpdPages
));
917 InquiryDataLength
= sizeof (SupportedVpdPages
);
919 Status
= ScsiInquiryCommandEx (
920 ScsiDiskDevice
->ScsiIo
,
921 EFI_TIMER_PERIOD_SECONDS (1),
926 (VOID
*) &SupportedVpdPages
,
929 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
931 if (!EFI_ERROR (Status
)) {
932 PageLength
= (SupportedVpdPages
.PageLength2
<< 8)
933 | SupportedVpdPages
.PageLength1
;
934 for (Index
= 0; Index
< PageLength
; Index
++) {
935 if (SupportedVpdPages
.SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
941 // Query the Block Limits VPD page
943 if (Index
< PageLength
) {
944 ZeroMem (&BlockLimits
, sizeof (BlockLimits
));
945 InquiryDataLength
= sizeof (BlockLimits
);
947 Status
= ScsiInquiryCommandEx (
948 ScsiDiskDevice
->ScsiIo
,
949 EFI_TIMER_PERIOD_SECONDS (1),
954 (VOID
*) &BlockLimits
,
957 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
959 if (!EFI_ERROR (Status
)) {
960 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
961 (BlockLimits
.OptimalTransferLengthGranularity2
<< 8) |
962 BlockLimits
.OptimalTransferLengthGranularity1
;
969 if (!EFI_ERROR (Status
)) {
972 } else if (Status
== EFI_NOT_READY
) {
974 return EFI_DEVICE_ERROR
;
976 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
978 return EFI_DEVICE_ERROR
;
981 // go ahead to check HostAdapterStatus and TargetStatus
982 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
985 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
986 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
988 return EFI_DEVICE_ERROR
;
989 } else if (Status
== EFI_DEVICE_ERROR
) {
991 // reset the scsi channel
993 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
995 return EFI_DEVICE_ERROR
;
998 Status
= CheckTargetStatus (TargetStatus
);
999 if (Status
== EFI_NOT_READY
) {
1001 // reset the scsi device
1003 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1005 return EFI_DEVICE_ERROR
;
1007 } else if (Status
== EFI_DEVICE_ERROR
) {
1009 return EFI_DEVICE_ERROR
;
1013 // if goes here, meant ScsiInquiryCommand() failed.
1014 // if ScsiDiskRequestSenseKeys() succeeds at last,
1015 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1018 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1019 Status
= ScsiDiskRequestSenseKeys (
1026 if (!EFI_ERROR (Status
)) {
1028 return EFI_DEVICE_ERROR
;
1032 return EFI_DEVICE_ERROR
;
1036 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1037 // set *NeedRetry = FALSE to avoid the outside caller try again.
1040 return EFI_DEVICE_ERROR
;
1046 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1047 When Test Unit Ready command encounters any error caused by host adapter or
1048 target, return error without retrieving Sense Keys.
1050 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1051 @param NeedRetry The pointer of flag indicates try again
1052 @param SenseDataArray The pointer of an array of sense data
1053 @param NumberOfSenseKeys The pointer of the number of sense data array
1055 @retval EFI_DEVICE_ERROR Indicates that error occurs
1056 @retval EFI_SUCCESS Successfully to test unit
1060 ScsiDiskTestUnitReady (
1061 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1062 OUT BOOLEAN
*NeedRetry
,
1063 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1064 OUT UINTN
*NumberOfSenseKeys
1068 UINT8 SenseDataLength
;
1069 UINT8 HostAdapterStatus
;
1074 SenseDataLength
= 0;
1075 *NumberOfSenseKeys
= 0;
1078 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1080 Status
= ScsiTestUnitReadyCommand (
1081 ScsiDiskDevice
->ScsiIo
,
1082 EFI_TIMER_PERIOD_SECONDS (1),
1089 // no need to check HostAdapterStatus and TargetStatus
1091 if (Status
== EFI_NOT_READY
) {
1093 return EFI_DEVICE_ERROR
;
1095 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1097 return EFI_DEVICE_ERROR
;
1100 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1103 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1104 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1106 return EFI_DEVICE_ERROR
;
1108 } else if (Status
== EFI_DEVICE_ERROR
) {
1110 // reset the scsi channel
1112 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1114 return EFI_DEVICE_ERROR
;
1117 Status
= CheckTargetStatus (TargetStatus
);
1118 if (Status
== EFI_NOT_READY
) {
1120 // reset the scsi device
1122 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1124 return EFI_DEVICE_ERROR
;
1126 } else if (Status
== EFI_DEVICE_ERROR
) {
1128 return EFI_DEVICE_ERROR
;
1132 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1133 Status
= ScsiDiskRequestSenseKeys (
1140 if (!EFI_ERROR (Status
)) {
1145 return EFI_DEVICE_ERROR
;
1149 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1150 // set *NeedRetry = FALSE to avoid the outside caller try again.
1153 return EFI_DEVICE_ERROR
;
1157 Parsing Sense Keys which got from request sense command.
1159 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1160 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1161 @param NumberOfSenseKeys The number of sense key
1162 @param Action The pointer of action which indicates what is need to do next
1164 @retval EFI_DEVICE_ERROR Indicates that error occurs
1165 @retval EFI_SUCCESS Successfully to complete the parsing
1169 DetectMediaParsingSenseKeys (
1170 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1171 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1172 IN UINTN NumberOfSenseKeys
,
1179 // Default is to read capacity, unless..
1181 *Action
= ACTION_READ_CAPACITY
;
1183 if (NumberOfSenseKeys
== 0) {
1184 *Action
= ACTION_NO_ACTION
;
1188 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1190 // No Sense Key returned from last submitted command
1192 *Action
= ACTION_NO_ACTION
;
1196 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1197 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1198 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1199 *Action
= ACTION_NO_ACTION
;
1203 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1204 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1208 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1209 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1210 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1211 return EFI_DEVICE_ERROR
;
1214 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1215 return EFI_DEVICE_ERROR
;
1218 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1220 *Action
= ACTION_RETRY_COMMAND_LATER
;
1224 return EFI_DEVICE_ERROR
;
1232 Send read capacity command to device and get the device parameter.
1234 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1235 @param NeedRetry The pointer of flag indicates if need a retry
1236 @param SenseDataArray The pointer of an array of sense data
1237 @param NumberOfSenseKeys The number of sense key
1239 @retval EFI_DEVICE_ERROR Indicates that error occurs
1240 @retval EFI_SUCCESS Successfully to read capacity
1244 ScsiDiskReadCapacity (
1245 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1246 OUT BOOLEAN
*NeedRetry
,
1247 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1248 OUT UINTN
*NumberOfSenseKeys
1251 UINT8 HostAdapterStatus
;
1253 EFI_STATUS CommandStatus
;
1257 UINT8 SenseDataLength
;
1258 UINT32 DataLength10
;
1259 UINT32 DataLength16
;
1260 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10
;
1261 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16
;
1264 SenseDataLength
= 0;
1265 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1266 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1267 ZeroMem (&CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1268 ZeroMem (&CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1270 *NumberOfSenseKeys
= 0;
1274 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1275 // 16 byte command should be used to access large hard disk >2TB
1277 CommandStatus
= ScsiReadCapacityCommand (
1278 ScsiDiskDevice
->ScsiIo
,
1279 EFI_TIMER_PERIOD_SECONDS(1),
1284 (VOID
*) &CapacityData10
,
1289 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1290 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
.LastLba3
== 0xff) && (CapacityData10
.LastLba2
== 0xff) &&
1291 (CapacityData10
.LastLba1
== 0xff) && (CapacityData10
.LastLba0
== 0xff)) {
1293 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1295 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1297 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1298 // and LowestAlignedLba
1300 CommandStatus
= ScsiReadCapacity16Command (
1301 ScsiDiskDevice
->ScsiIo
,
1302 EFI_TIMER_PERIOD_SECONDS (1),
1307 (VOID
*) &CapacityData16
,
1314 // no need to check HostAdapterStatus and TargetStatus
1316 if (CommandStatus
== EFI_SUCCESS
) {
1317 GetMediaInfo (ScsiDiskDevice
, &CapacityData10
,&CapacityData16
);
1320 } else if (CommandStatus
== EFI_NOT_READY
) {
1322 return EFI_DEVICE_ERROR
;
1324 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1326 return EFI_DEVICE_ERROR
;
1329 // go ahead to check HostAdapterStatus and TargetStatus
1330 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1333 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1334 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1336 return EFI_DEVICE_ERROR
;
1338 } else if (Status
== EFI_DEVICE_ERROR
) {
1340 // reset the scsi channel
1342 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1344 return EFI_DEVICE_ERROR
;
1347 Status
= CheckTargetStatus (TargetStatus
);
1348 if (Status
== EFI_NOT_READY
) {
1350 // reset the scsi device
1352 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1354 return EFI_DEVICE_ERROR
;
1356 } else if (Status
== EFI_DEVICE_ERROR
) {
1358 return EFI_DEVICE_ERROR
;
1362 // if goes here, meant ScsiReadCapacityCommand() failed.
1363 // if ScsiDiskRequestSenseKeys() succeeds at last,
1364 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1367 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1369 Status
= ScsiDiskRequestSenseKeys (
1376 if (!EFI_ERROR (Status
)) {
1378 return EFI_DEVICE_ERROR
;
1382 return EFI_DEVICE_ERROR
;
1386 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1387 // set *NeedRetry = FALSE to avoid the outside caller try again.
1390 return EFI_DEVICE_ERROR
;
1394 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1396 @param HostAdapterStatus Host Adapter status
1398 @retval EFI_SUCCESS Host adapter is OK.
1399 @retval EFI_TIMEOUT Timeout.
1400 @retval EFI_NOT_READY Adapter NOT ready.
1401 @retval EFI_DEVICE_ERROR Adapter device error.
1405 CheckHostAdapterStatus (
1406 IN UINT8 HostAdapterStatus
1409 switch (HostAdapterStatus
) {
1410 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1413 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1414 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1415 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1418 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1419 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1420 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1421 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1422 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1423 return EFI_NOT_READY
;
1425 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1426 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1427 return EFI_DEVICE_ERROR
;
1436 Check the target status and re-interpret it in EFI_STATUS.
1438 @param TargetStatus Target status
1440 @retval EFI_NOT_READY Device is NOT ready.
1441 @retval EFI_DEVICE_ERROR
1447 IN UINT8 TargetStatus
1450 switch (TargetStatus
) {
1451 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1452 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1453 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1456 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1457 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1458 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1459 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1460 return EFI_NOT_READY
;
1462 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1463 return EFI_DEVICE_ERROR
;
1473 Retrieve all sense keys from the device.
1475 When encountering error during the process, if retrieve sense keys before
1476 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1477 and NeedRetry set to FALSE; otherwize, return the proper return status.
1479 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1480 @param NeedRetry The pointer of flag indicates if need a retry
1481 @param SenseDataArray The pointer of an array of sense data
1482 @param NumberOfSenseKeys The number of sense key
1483 @param AskResetIfError The flag indicates if need reset when error occurs
1485 @retval EFI_DEVICE_ERROR Indicates that error occurs
1486 @retval EFI_SUCCESS Successfully to request sense key
1490 ScsiDiskRequestSenseKeys (
1491 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1492 OUT BOOLEAN
*NeedRetry
,
1493 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1494 OUT UINTN
*NumberOfSenseKeys
,
1495 IN BOOLEAN AskResetIfError
1498 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1499 UINT8 SenseDataLength
;
1502 EFI_STATUS FallStatus
;
1503 UINT8 HostAdapterStatus
;
1506 FallStatus
= EFI_SUCCESS
;
1507 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1510 ScsiDiskDevice
->SenseData
,
1511 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1514 *NumberOfSenseKeys
= 0;
1515 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1516 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1518 for (SenseReq
= TRUE
; SenseReq
;) {
1519 Status
= ScsiRequestSenseCommand (
1520 ScsiDiskDevice
->ScsiIo
,
1521 EFI_TIMER_PERIOD_SECONDS (2),
1527 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1528 FallStatus
= EFI_SUCCESS
;
1530 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1532 FallStatus
= EFI_DEVICE_ERROR
;
1534 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1536 FallStatus
= EFI_DEVICE_ERROR
;
1538 } else if (Status
== EFI_DEVICE_ERROR
) {
1539 if (AskResetIfError
) {
1540 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1543 FallStatus
= EFI_DEVICE_ERROR
;
1546 if (EFI_ERROR (FallStatus
)) {
1547 if (*NumberOfSenseKeys
!= 0) {
1551 return EFI_DEVICE_ERROR
;
1555 (*NumberOfSenseKeys
) += 1;
1558 // no more sense key or number of sense keys exceeds predefined,
1561 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1562 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1572 Get information from media read capacity command.
1574 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1575 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1576 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1581 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1582 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1583 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1588 if (!ScsiDiskDevice
->Cdb16Byte
) {
1589 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1590 (Capacity10
->LastLba2
<< 16) |
1591 (Capacity10
->LastLba1
<< 8) |
1592 Capacity10
->LastLba0
;
1594 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1595 (Capacity10
->BlockSize2
<< 16) |
1596 (Capacity10
->BlockSize1
<< 8) |
1597 Capacity10
->BlockSize0
;
1598 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1599 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
1601 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1602 *Ptr
++ = Capacity16
->LastLba0
;
1603 *Ptr
++ = Capacity16
->LastLba1
;
1604 *Ptr
++ = Capacity16
->LastLba2
;
1605 *Ptr
++ = Capacity16
->LastLba3
;
1606 *Ptr
++ = Capacity16
->LastLba4
;
1607 *Ptr
++ = Capacity16
->LastLba5
;
1608 *Ptr
++ = Capacity16
->LastLba6
;
1609 *Ptr
= Capacity16
->LastLba7
;
1611 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1612 (Capacity16
->BlockSize2
<< 16) |
1613 (Capacity16
->BlockSize1
<< 8) |
1614 Capacity16
->BlockSize0
;
1616 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
1617 Capacity16
->LowestAlignLogic1
;
1618 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
1621 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1623 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1624 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1627 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1628 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1635 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1640 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1643 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1644 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1648 Read sector from SCSI Disk.
1650 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1651 @param Buffer The buffer to fill in the read out data
1652 @param Lba Logic block address
1653 @param NumberOfBlocks The number of blocks to read
1655 @retval EFI_DEVICE_ERROR Indicates a device error.
1656 @retval EFI_SUCCESS Operation is successful.
1660 ScsiDiskReadSectors (
1661 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1664 IN UINTN NumberOfBlocks
1667 UINTN BlocksRemaining
;
1678 EFI_SCSI_SENSE_DATA
*SenseData
;
1679 UINTN NumberOfSenseKeys
;
1682 NumberOfSenseKeys
= 0;
1684 Status
= EFI_SUCCESS
;
1686 BlocksRemaining
= NumberOfBlocks
;
1687 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1690 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1692 if (!ScsiDiskDevice
->Cdb16Byte
) {
1695 MaxBlock
= 0xFFFFFFFF;
1700 while (BlocksRemaining
> 0) {
1702 if (BlocksRemaining
<= MaxBlock
) {
1703 if (!ScsiDiskDevice
->Cdb16Byte
) {
1704 SectorCount
= (UINT16
) BlocksRemaining
;
1706 SectorCount
= (UINT32
) BlocksRemaining
;
1709 SectorCount
= MaxBlock
;
1712 ByteCount
= SectorCount
* BlockSize
;
1713 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1716 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1717 if (!ScsiDiskDevice
->Cdb16Byte
) {
1718 Status
= ScsiDiskRead10 (
1730 Status
= ScsiDiskRead16 (
1742 if (!EFI_ERROR (Status
)) {
1747 return EFI_DEVICE_ERROR
;
1752 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1753 return EFI_DEVICE_ERROR
;
1757 // actual transferred sectors
1759 SectorCount
= ByteCount
/ BlockSize
;
1762 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1763 BlocksRemaining
-= SectorCount
;
1770 Write sector to SCSI Disk.
1772 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1773 @param Buffer The buffer of data to be written into SCSI Disk
1774 @param Lba Logic block address
1775 @param NumberOfBlocks The number of blocks to read
1777 @retval EFI_DEVICE_ERROR Indicates a device error.
1778 @retval EFI_SUCCESS Operation is successful.
1782 ScsiDiskWriteSectors (
1783 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1786 IN UINTN NumberOfBlocks
1789 UINTN BlocksRemaining
;
1800 EFI_SCSI_SENSE_DATA
*SenseData
;
1801 UINTN NumberOfSenseKeys
;
1804 NumberOfSenseKeys
= 0;
1806 Status
= EFI_SUCCESS
;
1808 BlocksRemaining
= NumberOfBlocks
;
1809 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1812 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1814 if (!ScsiDiskDevice
->Cdb16Byte
) {
1817 MaxBlock
= 0xFFFFFFFF;
1822 while (BlocksRemaining
> 0) {
1824 if (BlocksRemaining
<= MaxBlock
) {
1825 if (!ScsiDiskDevice
->Cdb16Byte
) {
1826 SectorCount
= (UINT16
) BlocksRemaining
;
1828 SectorCount
= (UINT32
) BlocksRemaining
;
1831 SectorCount
= MaxBlock
;
1834 ByteCount
= SectorCount
* BlockSize
;
1835 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1837 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1838 if (!ScsiDiskDevice
->Cdb16Byte
) {
1839 Status
= ScsiDiskWrite10 (
1851 Status
= ScsiDiskWrite16 (
1863 if (!EFI_ERROR (Status
)) {
1868 return EFI_DEVICE_ERROR
;
1872 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1873 return EFI_DEVICE_ERROR
;
1876 // actual transferred sectors
1878 SectorCount
= ByteCount
/ BlockSize
;
1881 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1882 BlocksRemaining
-= SectorCount
;
1890 Submit Read(10) command.
1892 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1893 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1894 @param SenseDataArray NOT used yet in this function
1895 @param NumberOfSenseKeys The number of sense key
1896 @param Timeout The time to complete the command
1897 @param DataBuffer The buffer to fill with the read out data
1898 @param DataLength The length of buffer
1899 @param StartLba The start logic block address
1900 @param SectorSize The size of sector
1902 @return EFI_STATUS is returned by calling ScsiRead10Command().
1906 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1907 OUT BOOLEAN
*NeedRetry
,
1908 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1909 OUT UINTN
*NumberOfSenseKeys
,
1911 OUT UINT8
*DataBuffer
,
1912 IN OUT UINT32
*DataLength
,
1914 IN UINT32 SectorSize
1917 UINT8 SenseDataLength
;
1919 UINT8 HostAdapterStatus
;
1923 *NumberOfSenseKeys
= 0;
1924 SenseDataLength
= 0;
1925 Status
= ScsiRead10Command (
1926 ScsiDiskDevice
->ScsiIo
,
1942 Submit Write(10) Command.
1944 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1945 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1946 @param SenseDataArray NOT used yet in this function
1947 @param NumberOfSenseKeys The number of sense key
1948 @param Timeout The time to complete the command
1949 @param DataBuffer The buffer to fill with the read out data
1950 @param DataLength The length of buffer
1951 @param StartLba The start logic block address
1952 @param SectorSize The size of sector
1954 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1959 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1960 OUT BOOLEAN
*NeedRetry
,
1961 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1962 OUT UINTN
*NumberOfSenseKeys
,
1964 IN UINT8
*DataBuffer
,
1965 IN OUT UINT32
*DataLength
,
1967 IN UINT32 SectorSize
1971 UINT8 SenseDataLength
;
1972 UINT8 HostAdapterStatus
;
1976 *NumberOfSenseKeys
= 0;
1977 SenseDataLength
= 0;
1978 Status
= ScsiWrite10Command (
1979 ScsiDiskDevice
->ScsiIo
,
1995 Submit Read(16) command.
1997 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1998 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1999 @param SenseDataArray NOT used yet in this function
2000 @param NumberOfSenseKeys The number of sense key
2001 @param Timeout The time to complete the command
2002 @param DataBuffer The buffer to fill with the read out data
2003 @param DataLength The length of buffer
2004 @param StartLba The start logic block address
2005 @param SectorSize The size of sector
2007 @return EFI_STATUS is returned by calling ScsiRead10Command().
2011 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2012 OUT BOOLEAN
*NeedRetry
,
2013 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2014 OUT UINTN
*NumberOfSenseKeys
,
2016 OUT UINT8
*DataBuffer
,
2017 IN OUT UINT32
*DataLength
,
2019 IN UINT32 SectorSize
2022 UINT8 SenseDataLength
;
2024 UINT8 HostAdapterStatus
;
2028 *NumberOfSenseKeys
= 0;
2029 SenseDataLength
= 0;
2030 Status
= ScsiRead16Command (
2031 ScsiDiskDevice
->ScsiIo
,
2047 Submit Write(16) Command.
2049 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2050 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2051 @param SenseDataArray NOT used yet in this function
2052 @param NumberOfSenseKeys The number of sense key
2053 @param Timeout The time to complete the command
2054 @param DataBuffer The buffer to fill with the read out data
2055 @param DataLength The length of buffer
2056 @param StartLba The start logic block address
2057 @param SectorSize The size of sector
2059 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2064 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2065 OUT BOOLEAN
*NeedRetry
,
2066 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2067 OUT UINTN
*NumberOfSenseKeys
,
2069 IN UINT8
*DataBuffer
,
2070 IN OUT UINT32
*DataLength
,
2072 IN UINT32 SectorSize
2076 UINT8 SenseDataLength
;
2077 UINT8 HostAdapterStatus
;
2081 *NumberOfSenseKeys
= 0;
2082 SenseDataLength
= 0;
2083 Status
= ScsiWrite16Command (
2084 ScsiDiskDevice
->ScsiIo
,
2100 Check sense key to find if media presents.
2102 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2103 @param SenseCounts The number of sense key
2105 @retval TRUE NOT any media
2106 @retval FALSE Media presents
2110 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2111 IN UINTN SenseCounts
2114 EFI_SCSI_SENSE_DATA
*SensePtr
;
2119 SensePtr
= SenseData
;
2121 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2123 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2124 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2126 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
2127 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
2140 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2141 @param SenseCounts The number of sense key
2144 @retval FALSE NOT error
2148 ScsiDiskIsMediaError (
2149 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2150 IN UINTN SenseCounts
2153 EFI_SCSI_SENSE_DATA
*SensePtr
;
2158 SensePtr
= SenseData
;
2160 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2162 switch (SensePtr
->Sense_Key
) {
2164 case EFI_SCSI_SK_MEDIUM_ERROR
:
2166 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2168 switch (SensePtr
->Addnl_Sense_Code
) {
2173 case EFI_SCSI_ASC_MEDIA_ERR1
:
2178 case EFI_SCSI_ASC_MEDIA_ERR2
:
2183 case EFI_SCSI_ASC_MEDIA_ERR3
:
2184 case EFI_SCSI_ASC_MEDIA_ERR4
:
2194 case EFI_SCSI_SK_NOT_READY
:
2196 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2198 switch (SensePtr
->Addnl_Sense_Code
) {
2200 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2202 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2223 Check sense key to find if hardware error happens.
2225 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2226 @param SenseCounts The number of sense key
2228 @retval TRUE Hardware error exits.
2229 @retval FALSE NO error.
2233 ScsiDiskIsHardwareError (
2234 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2235 IN UINTN SenseCounts
2238 EFI_SCSI_SENSE_DATA
*SensePtr
;
2243 SensePtr
= SenseData
;
2245 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2248 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2250 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2262 Check sense key to find if media has changed.
2264 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2265 @param SenseCounts The number of sense key
2267 @retval TRUE Media is changed.
2268 @retval FALSE Media is NOT changed.
2271 ScsiDiskIsMediaChange (
2272 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2273 IN UINTN SenseCounts
2276 EFI_SCSI_SENSE_DATA
*SensePtr
;
2278 BOOLEAN IsMediaChanged
;
2280 IsMediaChanged
= FALSE
;
2281 SensePtr
= SenseData
;
2283 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2285 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2286 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2288 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2289 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2290 IsMediaChanged
= TRUE
;
2296 return IsMediaChanged
;
2300 Check sense key to find if reset happens.
2302 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2303 @param SenseCounts The number of sense key
2305 @retval TRUE It is reset before.
2306 @retval FALSE It is NOT reset before.
2310 ScsiDiskIsResetBefore (
2311 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2312 IN UINTN SenseCounts
2315 EFI_SCSI_SENSE_DATA
*SensePtr
;
2317 BOOLEAN IsResetBefore
;
2319 IsResetBefore
= FALSE
;
2320 SensePtr
= SenseData
;
2322 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2325 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2326 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2328 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2329 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2330 IsResetBefore
= TRUE
;
2336 return IsResetBefore
;
2340 Check sense key to find if the drive is ready.
2342 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2343 @param SenseCounts The number of sense key
2344 @param RetryLater The flag means if need a retry
2346 @retval TRUE Drive is ready.
2347 @retval FALSE Drive is NOT ready.
2351 ScsiDiskIsDriveReady (
2352 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2353 IN UINTN SenseCounts
,
2354 OUT BOOLEAN
*RetryLater
2357 EFI_SCSI_SENSE_DATA
*SensePtr
;
2362 *RetryLater
= FALSE
;
2363 SensePtr
= SenseData
;
2365 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2367 switch (SensePtr
->Sense_Key
) {
2369 case EFI_SCSI_SK_NOT_READY
:
2371 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2373 switch (SensePtr
->Addnl_Sense_Code
) {
2374 case EFI_SCSI_ASC_NOT_READY
:
2376 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2378 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2379 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2381 // Additional Sense Code Qualifier is
2382 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2390 *RetryLater
= FALSE
;
2411 Check sense key to find if it has sense key.
2413 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2414 @param SenseCounts - The number of sense key
2416 @retval TRUE It has sense key.
2417 @retval FALSE It has NOT any sense key.
2421 ScsiDiskHaveSenseKey (
2422 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2423 IN UINTN SenseCounts
2426 EFI_SCSI_SENSE_DATA
*SensePtr
;
2428 BOOLEAN HaveSenseKey
;
2430 if (SenseCounts
== 0) {
2431 HaveSenseKey
= FALSE
;
2433 HaveSenseKey
= TRUE
;
2436 SensePtr
= SenseData
;
2438 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2441 // Sense Key is SK_NO_SENSE (0x0)
2443 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2445 HaveSenseKey
= FALSE
;
2451 return HaveSenseKey
;
2455 Release resource about disk device.
2457 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2461 ReleaseScsiDiskDeviceResources (
2462 IN SCSI_DISK_DEV
*ScsiDiskDevice
2465 if (ScsiDiskDevice
== NULL
) {
2469 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2470 FreePool (ScsiDiskDevice
->SenseData
);
2471 ScsiDiskDevice
->SenseData
= NULL
;
2474 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2475 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2476 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2479 FreePool (ScsiDiskDevice
);
2481 ScsiDiskDevice
= NULL
;
2485 Determine if Block Io should be produced.
2488 @param ChildHandle Child Handle to retrieve Parent information.
2490 @retval TRUE Should produce Block Io.
2491 @retval FALSE Should not produce Block Io.
2495 DetermineInstallBlockIo (
2496 IN EFI_HANDLE ChildHandle
2499 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2500 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2503 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2504 // check its attribute, logic or physical.
2506 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2507 if (ExtScsiPassThru
!= NULL
) {
2508 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2514 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2515 // check its attribute, logic or physical.
2517 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2518 if (ScsiPassThru
!= NULL
) {
2519 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2528 Search protocol database and check to see if the protocol
2529 specified by ProtocolGuid is present on a ControllerHandle and opened by
2530 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2531 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2532 will be opened on it.
2535 @param ProtocolGuid ProtocolGuid pointer.
2536 @param ChildHandle Child Handle to retrieve Parent information.
2542 IN EFI_GUID
*ProtocolGuid
,
2543 IN EFI_HANDLE ChildHandle
2550 EFI_HANDLE
*HandleBuffer
;
2553 // Retrieve the list of all handles from the handle database
2555 Status
= gBS
->LocateHandleBuffer (
2563 if (EFI_ERROR (Status
)) {
2568 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
2570 for (Index
= 0; Index
< HandleCount
; Index
++) {
2571 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
2572 if (!EFI_ERROR (Status
)) {
2573 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
2574 if (!EFI_ERROR (Status
)) {
2575 gBS
->FreePool (HandleBuffer
);
2581 gBS
->FreePool (HandleBuffer
);
2586 Provides inquiry information for the controller type.
2588 This function is used by the IDE bus driver to get inquiry data. Data format
2589 of Identify data is defined by the Interface GUID.
2591 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2592 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
2593 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
2595 @retval EFI_SUCCESS The command was accepted without any errors.
2596 @retval EFI_NOT_FOUND Device does not support this data class
2597 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
2598 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
2603 ScsiDiskInfoInquiry (
2604 IN EFI_DISK_INFO_PROTOCOL
*This
,
2605 IN OUT VOID
*InquiryData
,
2606 IN OUT UINT32
*InquiryDataSize
2610 SCSI_DISK_DEV
*ScsiDiskDevice
;
2612 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2614 Status
= EFI_BUFFER_TOO_SMALL
;
2615 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
2616 Status
= EFI_SUCCESS
;
2617 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
2619 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
2625 Provides identify information for the controller type.
2627 This function is used by the IDE bus driver to get identify data. Data format
2628 of Identify data is defined by the Interface GUID.
2630 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
2632 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
2633 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
2636 @retval EFI_SUCCESS The command was accepted without any errors.
2637 @retval EFI_NOT_FOUND Device does not support this data class
2638 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
2639 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
2644 ScsiDiskInfoIdentify (
2645 IN EFI_DISK_INFO_PROTOCOL
*This
,
2646 IN OUT VOID
*IdentifyData
,
2647 IN OUT UINT32
*IdentifyDataSize
2651 SCSI_DISK_DEV
*ScsiDiskDevice
;
2653 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2655 // Physical SCSI bus does not support this data class.
2657 return EFI_NOT_FOUND
;
2660 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2662 Status
= EFI_BUFFER_TOO_SMALL
;
2663 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
2664 Status
= EFI_SUCCESS
;
2665 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
2667 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
2672 Provides sense data information for the controller type.
2674 This function is used by the IDE bus driver to get sense data.
2675 Data format of Sense data is defined by the Interface GUID.
2677 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2678 @param[in, out] SenseData Pointer to the SenseData.
2679 @param[in, out] SenseDataSize Size of SenseData in bytes.
2680 @param[out] SenseDataNumber Pointer to the value for the sense data size.
2682 @retval EFI_SUCCESS The command was accepted without any errors.
2683 @retval EFI_NOT_FOUND Device does not support this data class.
2684 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
2685 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
2690 ScsiDiskInfoSenseData (
2691 IN EFI_DISK_INFO_PROTOCOL
*This
,
2692 IN OUT VOID
*SenseData
,
2693 IN OUT UINT32
*SenseDataSize
,
2694 OUT UINT8
*SenseDataNumber
2697 return EFI_NOT_FOUND
;
2702 This function is used by the IDE bus driver to get controller information.
2704 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2705 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
2706 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
2708 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
2709 @retval EFI_UNSUPPORTED This is not an IDE device.
2714 ScsiDiskInfoWhichIde (
2715 IN EFI_DISK_INFO_PROTOCOL
*This
,
2716 OUT UINT32
*IdeChannel
,
2717 OUT UINT32
*IdeDevice
2720 SCSI_DISK_DEV
*ScsiDiskDevice
;
2722 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2724 // This is not an IDE physical device.
2726 return EFI_UNSUPPORTED
;
2729 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2730 *IdeChannel
= ScsiDiskDevice
->Channel
;
2731 *IdeDevice
= ScsiDiskDevice
->Device
;
2738 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
2740 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
2741 implement Identify() interface for DiskInfo protocol. The ATA command is sent
2742 via SCSI Request Packet.
2744 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2746 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
2747 @retval others Some error occurred during the identification that ATAPI device.
2751 AtapiIdentifyDevice (
2752 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2755 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
2759 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
2761 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
2762 ZeroMem (Cdb
, sizeof (Cdb
));
2764 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
2765 CommandPacket
.Timeout
= EFI_TIMER_PERIOD_SECONDS (1);
2766 CommandPacket
.Cdb
= Cdb
;
2767 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
2768 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
2769 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
2771 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
2776 Initialize the installation of DiskInfo protocol.
2778 This function prepares for the installation of DiskInfo protocol on the child handle.
2779 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
2780 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
2781 to be IDE/AHCI interface GUID.
2783 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2784 @param ChildHandle Child handle to install DiskInfo protocol.
2788 InitializeInstallDiskInfo (
2789 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2790 IN EFI_HANDLE ChildHandle
2794 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2795 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
2796 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
2797 SATA_DEVICE_PATH
*SataDevicePath
;
2798 UINTN IdentifyRetry
;
2800 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
2802 // Device Path protocol must be installed on the device handle.
2804 ASSERT_EFI_ERROR (Status
);
2806 // Copy the DiskInfo protocol template.
2808 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
2810 while (!IsDevicePathEnd (DevicePathNode
)) {
2811 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
2812 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
2813 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
2814 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
2815 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
2816 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
2821 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
2822 // with IDE/AHCI interface GUID.
2824 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
2825 if (!EFI_ERROR (Status
)) {
2826 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
2828 // We find the valid ATAPI device path
2830 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
2831 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
2832 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
2834 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
2836 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
2839 // We find the valid SATA device path
2841 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
2842 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
2843 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
2845 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
2847 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
2851 } while (--IdentifyRetry
> 0);
2853 DevicePathNode
= ChildDevicePathNode
;