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 Allocates an aligned buffer for SCSI disk.
38 This function allocates an aligned buffer for the SCSI disk to perform
39 SCSI IO operations. The alignment requirement is from SCSI IO interface.
41 @param ScsiDiskDevice The SCSI disk involved for the operation.
42 @param BufferSize The request buffer size.
44 @return A pointer to the aligned buffer or NULL if the allocation fails.
48 AllocateAlignedBuffer (
49 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
53 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiDiskDevice
->ScsiIo
->IoAlign
);
57 Frees an aligned buffer for SCSI disk.
59 This function frees an aligned buffer for the SCSI disk to perform
62 @param Buffer The aligned buffer to be freed.
63 @param BufferSize The request buffer size.
73 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
78 The user Entry Point for module ScsiDisk.
80 The user code starts with this function.
82 @param ImageHandle The firmware allocated handle for the EFI image.
83 @param SystemTable A pointer to the EFI System Table.
85 @retval EFI_SUCCESS The entry point is executed successfully.
86 @retval other Some error occurs when executing this entry point.
92 IN EFI_HANDLE ImageHandle
,
93 IN EFI_SYSTEM_TABLE
*SystemTable
99 // Install driver model protocol(s).
101 Status
= EfiLibInstallDriverBindingComponentName2 (
104 &gScsiDiskDriverBinding
,
106 &gScsiDiskComponentName
,
107 &gScsiDiskComponentName2
109 ASSERT_EFI_ERROR (Status
);
116 Test to see if this driver supports ControllerHandle.
118 This service is called by the EFI boot service ConnectController(). In order
119 to make drivers as small as possible, there are a few calling restrictions for
120 this service. ConnectController() must follow these calling restrictions.
121 If any other agent wishes to call Supported() it must also follow these
122 calling restrictions.
124 @param This Protocol instance pointer.
125 @param ControllerHandle Handle of device to test
126 @param RemainingDevicePath Optional parameter use to pick a specific child
129 @retval EFI_SUCCESS This driver supports this device
130 @retval EFI_ALREADY_STARTED This driver is already running on this device
131 @retval other This driver does not support this device
136 ScsiDiskDriverBindingSupported (
137 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
138 IN EFI_HANDLE Controller
,
139 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
143 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
146 Status
= gBS
->OpenProtocol (
148 &gEfiScsiIoProtocolGuid
,
150 This
->DriverBindingHandle
,
152 EFI_OPEN_PROTOCOL_BY_DRIVER
154 if (EFI_ERROR (Status
)) {
158 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
159 if (!EFI_ERROR (Status
)) {
160 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
161 Status
= EFI_SUCCESS
;
163 Status
= EFI_UNSUPPORTED
;
169 &gEfiScsiIoProtocolGuid
,
170 This
->DriverBindingHandle
,
178 Start this driver on ControllerHandle.
180 This service is called by the EFI boot service ConnectController(). In order
181 to make drivers as small as possible, there are a few calling restrictions for
182 this service. ConnectController() must follow these calling restrictions. If
183 any other agent wishes to call Start() it must also follow these calling
186 @param This Protocol instance pointer.
187 @param ControllerHandle Handle of device to bind driver to
188 @param RemainingDevicePath Optional parameter use to pick a specific child
191 @retval EFI_SUCCESS This driver is added to ControllerHandle
192 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
193 @retval other This driver does not support this device
198 ScsiDiskDriverBindingStart (
199 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
200 IN EFI_HANDLE Controller
,
201 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
205 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
206 SCSI_DISK_DEV
*ScsiDiskDevice
;
211 BOOLEAN MustReadCapacity
;
213 MustReadCapacity
= TRUE
;
215 ScsiDiskDevice
= (SCSI_DISK_DEV
*) AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
216 if (ScsiDiskDevice
== NULL
) {
217 return EFI_OUT_OF_RESOURCES
;
220 Status
= gBS
->OpenProtocol (
222 &gEfiScsiIoProtocolGuid
,
224 This
->DriverBindingHandle
,
226 EFI_OPEN_PROTOCOL_BY_DRIVER
228 if (EFI_ERROR (Status
)) {
229 FreePool (ScsiDiskDevice
);
233 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
234 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
235 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
236 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
237 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
238 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
239 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
240 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
241 ScsiDiskDevice
->Handle
= Controller
;
243 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
244 switch (ScsiDiskDevice
->DeviceType
) {
245 case EFI_SCSI_TYPE_DISK
:
246 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
247 MustReadCapacity
= TRUE
;
250 case EFI_SCSI_TYPE_CDROM
:
251 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
252 MustReadCapacity
= FALSE
;
256 // The Sense Data Array's initial size is 6
258 ScsiDiskDevice
->SenseDataNumber
= 6;
259 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
260 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
262 if (ScsiDiskDevice
->SenseData
== NULL
) {
265 &gEfiScsiIoProtocolGuid
,
266 This
->DriverBindingHandle
,
269 FreePool (ScsiDiskDevice
);
270 return EFI_OUT_OF_RESOURCES
;
274 // Retrieve device information
277 for (Index
= 0; Index
< MaxRetry
; Index
++) {
278 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
279 if (!EFI_ERROR (Status
)) {
284 FreePool (ScsiDiskDevice
->SenseData
);
287 &gEfiScsiIoProtocolGuid
,
288 This
->DriverBindingHandle
,
291 FreePool (ScsiDiskDevice
);
292 return EFI_DEVICE_ERROR
;
296 // The second parameter "TRUE" means must
297 // retrieve media capacity
299 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
300 if (!EFI_ERROR (Status
)) {
302 // Determine if Block IO should be produced on this controller handle
304 if (DetermineInstallBlockIo(Controller
)) {
305 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
306 Status
= gBS
->InstallMultipleProtocolInterfaces (
308 &gEfiBlockIoProtocolGuid
,
309 &ScsiDiskDevice
->BlkIo
,
310 &gEfiDiskInfoProtocolGuid
,
311 &ScsiDiskDevice
->DiskInfo
,
314 if (!EFI_ERROR(Status
)) {
315 ScsiDiskDevice
->ControllerNameTable
= NULL
;
318 gScsiDiskComponentName
.SupportedLanguages
,
319 &ScsiDiskDevice
->ControllerNameTable
,
325 gScsiDiskComponentName2
.SupportedLanguages
,
326 &ScsiDiskDevice
->ControllerNameTable
,
335 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
336 gBS
->FreePool (ScsiDiskDevice
);
339 &gEfiScsiIoProtocolGuid
,
340 This
->DriverBindingHandle
,
349 Stop this driver on ControllerHandle.
351 This service is called by the EFI boot service DisconnectController().
352 In order to make drivers as small as possible, there are a few calling
353 restrictions for this service. DisconnectController() must follow these
354 calling restrictions. If any other agent wishes to call Stop() it must
355 also follow these calling restrictions.
357 @param This Protocol instance pointer.
358 @param ControllerHandle Handle of device to stop driver on
359 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
360 children is zero stop the entire bus driver.
361 @param ChildHandleBuffer List of Child Handles to Stop.
363 @retval EFI_SUCCESS This driver is removed ControllerHandle
364 @retval other This driver was not removed from this device
369 ScsiDiskDriverBindingStop (
370 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
371 IN EFI_HANDLE Controller
,
372 IN UINTN NumberOfChildren
,
373 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
376 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
377 SCSI_DISK_DEV
*ScsiDiskDevice
;
380 Status
= gBS
->OpenProtocol (
382 &gEfiBlockIoProtocolGuid
,
384 This
->DriverBindingHandle
,
386 EFI_OPEN_PROTOCOL_GET_PROTOCOL
388 if (EFI_ERROR (Status
)) {
392 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
393 Status
= gBS
->UninstallMultipleProtocolInterfaces (
395 &gEfiBlockIoProtocolGuid
,
396 &ScsiDiskDevice
->BlkIo
,
397 &gEfiDiskInfoProtocolGuid
,
398 &ScsiDiskDevice
->DiskInfo
,
401 if (!EFI_ERROR (Status
)) {
404 &gEfiScsiIoProtocolGuid
,
405 This
->DriverBindingHandle
,
409 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
423 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
424 @param ExtendedVerification The flag about if extend verificate
426 @retval EFI_SUCCESS The device was reset.
427 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
429 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
435 IN EFI_BLOCK_IO_PROTOCOL
*This
,
436 IN BOOLEAN ExtendedVerification
440 SCSI_DISK_DEV
*ScsiDiskDevice
;
443 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
445 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
447 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
449 if (EFI_ERROR (Status
)) {
450 Status
= EFI_DEVICE_ERROR
;
454 if (!ExtendedVerification
) {
458 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
460 if (EFI_ERROR (Status
)) {
461 Status
= EFI_DEVICE_ERROR
;
466 gBS
->RestoreTPL (OldTpl
);
471 The function is to Read Block from SCSI Disk.
473 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
474 @param MediaId The Id of Media detected
475 @param Lba The logic block address
476 @param BufferSize The size of Buffer
477 @param Buffer The buffer to fill the read out data
479 @retval EFI_SUCCESS Successfully to read out block.
480 @retval EFI_DEVICE_ERROR Fail to detect media.
481 @retval EFI_NO_MEDIA Media is not present.
482 @retval EFI_MEDIA_CHANGED Media has changed.
483 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
484 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
490 IN EFI_BLOCK_IO_PROTOCOL
*This
,
497 SCSI_DISK_DEV
*ScsiDiskDevice
;
498 EFI_BLOCK_IO_MEDIA
*Media
;
501 UINTN NumberOfBlocks
;
506 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
507 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
509 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
511 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
512 if (EFI_ERROR (Status
)) {
513 Status
= EFI_DEVICE_ERROR
;
518 gBS
->ReinstallProtocolInterface (
519 ScsiDiskDevice
->Handle
,
520 &gEfiBlockIoProtocolGuid
,
521 &ScsiDiskDevice
->BlkIo
,
522 &ScsiDiskDevice
->BlkIo
527 // Get the intrinsic block size
529 Media
= ScsiDiskDevice
->BlkIo
.Media
;
530 BlockSize
= Media
->BlockSize
;
532 NumberOfBlocks
= BufferSize
/ BlockSize
;
534 if (!(Media
->MediaPresent
)) {
535 Status
= EFI_NO_MEDIA
;
539 if (MediaId
!= Media
->MediaId
) {
540 Status
= EFI_MEDIA_CHANGED
;
544 if (Buffer
== NULL
) {
545 Status
= EFI_INVALID_PARAMETER
;
549 if (BufferSize
== 0) {
550 Status
= EFI_SUCCESS
;
554 if (BufferSize
% BlockSize
!= 0) {
555 Status
= EFI_BAD_BUFFER_SIZE
;
559 if (Lba
> Media
->LastBlock
) {
560 Status
= EFI_INVALID_PARAMETER
;
564 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
565 Status
= EFI_INVALID_PARAMETER
;
569 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
570 Status
= EFI_INVALID_PARAMETER
;
575 // If all the parameters are valid, then perform read sectors command
576 // to transfer data from device to host.
578 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
581 gBS
->RestoreTPL (OldTpl
);
586 The function is to Write Block to SCSI Disk.
588 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
589 @param MediaId The Id of Media detected
590 @param Lba The logic block address
591 @param BufferSize The size of Buffer
592 @param Buffer The buffer to fill the read out data
594 @retval EFI_SUCCESS Successfully to read out block.
595 @retval EFI_WRITE_PROTECTED The device can not be written to.
596 @retval EFI_DEVICE_ERROR Fail to detect media.
597 @retval EFI_NO_MEDIA Media is not present.
598 @retval EFI_MEDIA_CHNAGED Media has changed.
599 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
600 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
605 ScsiDiskWriteBlocks (
606 IN EFI_BLOCK_IO_PROTOCOL
*This
,
613 SCSI_DISK_DEV
*ScsiDiskDevice
;
614 EFI_BLOCK_IO_MEDIA
*Media
;
617 UINTN NumberOfBlocks
;
622 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
623 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
625 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
627 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
628 if (EFI_ERROR (Status
)) {
629 Status
= EFI_DEVICE_ERROR
;
634 gBS
->ReinstallProtocolInterface (
635 ScsiDiskDevice
->Handle
,
636 &gEfiBlockIoProtocolGuid
,
637 &ScsiDiskDevice
->BlkIo
,
638 &ScsiDiskDevice
->BlkIo
643 // Get the intrinsic block size
645 Media
= ScsiDiskDevice
->BlkIo
.Media
;
646 BlockSize
= Media
->BlockSize
;
648 NumberOfBlocks
= BufferSize
/ BlockSize
;
650 if (!(Media
->MediaPresent
)) {
651 Status
= EFI_NO_MEDIA
;
655 if (MediaId
!= Media
->MediaId
) {
656 Status
= EFI_MEDIA_CHANGED
;
660 if (BufferSize
== 0) {
661 Status
= EFI_SUCCESS
;
665 if (Buffer
== NULL
) {
666 Status
= EFI_INVALID_PARAMETER
;
670 if (BufferSize
% BlockSize
!= 0) {
671 Status
= EFI_BAD_BUFFER_SIZE
;
675 if (Lba
> Media
->LastBlock
) {
676 Status
= EFI_INVALID_PARAMETER
;
680 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
681 Status
= EFI_INVALID_PARAMETER
;
685 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
686 Status
= EFI_INVALID_PARAMETER
;
690 // if all the parameters are valid, then perform read sectors command
691 // to transfer data from device to host.
693 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
696 gBS
->RestoreTPL (OldTpl
);
703 EFI_SUCCESS is returned directly.
705 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
707 @retval EFI_SUCCESS All outstanding data was written to the device
712 ScsiDiskFlushBlocks (
713 IN EFI_BLOCK_IO_PROTOCOL
*This
724 Detect Device and read out capacity ,if error occurs, parse the sense key.
726 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
727 @param MustReadCapacity The flag about reading device capacity
728 @param MediaChange The pointer of flag indicates if media has changed
730 @retval EFI_DEVICE_ERROR Indicates that error occurs
731 @retval EFI_SUCCESS Successfully to detect media
735 ScsiDiskDetectMedia (
736 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
737 IN BOOLEAN MustReadCapacity
,
738 OUT BOOLEAN
*MediaChange
742 EFI_SCSI_SENSE_DATA
*SenseData
;
743 UINTN NumberOfSenseKeys
;
745 BOOLEAN NeedReadCapacity
;
748 EFI_BLOCK_IO_MEDIA OldMedia
;
750 EFI_EVENT TimeoutEvt
;
752 Status
= EFI_SUCCESS
;
754 NumberOfSenseKeys
= 0;
757 Action
= ACTION_NO_ACTION
;
758 NeedReadCapacity
= FALSE
;
759 *MediaChange
= FALSE
;
762 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
764 Status
= gBS
->CreateEvent (
771 if (EFI_ERROR (Status
)) {
775 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
776 if (EFI_ERROR (Status
)) {
781 // Sending Test_Unit cmd to poll device status.
782 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
783 // We limit the upper boundary to 120 seconds.
785 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
786 Status
= ScsiDiskTestUnitReady (
792 if (!EFI_ERROR (Status
)) {
793 Status
= DetectMediaParsingSenseKeys (
799 if (EFI_ERROR (Status
)) {
801 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
808 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
814 if (EFI_ERROR (Status
)) {
819 // ACTION_NO_ACTION: need not read capacity
820 // other action code: need read capacity
822 if (Action
== ACTION_READ_CAPACITY
) {
823 NeedReadCapacity
= TRUE
;
827 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
828 // retrieve capacity via Read Capacity command
830 if (NeedReadCapacity
|| MustReadCapacity
) {
832 // retrieve media information
834 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
835 Status
= ScsiDiskReadCapacity (
841 if (!EFI_ERROR (Status
)) {
843 // analyze sense key to action
845 Status
= DetectMediaParsingSenseKeys (
851 if (EFI_ERROR (Status
)) {
853 // if Status is error, it may indicate crisis error,
854 // so return without retry.
857 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
865 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
871 if (EFI_ERROR (Status
)) {
876 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
878 // Media change information got from the device
883 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
885 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
888 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
890 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
893 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
895 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
898 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
899 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
901 // when change from no media to media present, reset the MediaId to 1.
903 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
906 // when no media, reset the MediaId to zero.
908 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
915 if (TimeoutEvt
!= NULL
) {
916 gBS
->CloseEvent (TimeoutEvt
);
923 Send out Inquiry command to Device.
925 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
926 @param NeedRetry Indicates if needs try again when error happens
928 @retval EFI_DEVICE_ERROR Indicates that error occurs
929 @retval EFI_SUCCESS Successfully to detect media
933 ScsiDiskInquiryDevice (
934 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
935 OUT BOOLEAN
*NeedRetry
938 UINT32 InquiryDataLength
;
939 UINT8 SenseDataLength
;
940 UINT8 HostAdapterStatus
;
942 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
943 UINTN NumberOfSenseKeys
;
947 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
948 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
951 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
954 Status
= ScsiInquiryCommand (
955 ScsiDiskDevice
->ScsiIo
,
956 EFI_TIMER_PERIOD_SECONDS (1),
961 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
966 // no need to check HostAdapterStatus and TargetStatus
968 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
969 ParseInquiryData (ScsiDiskDevice
);
971 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
973 // Check whether the device supports Block Limits VPD page (0xB0)
975 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
976 if (SupportedVpdPages
== NULL
) {
978 return EFI_DEVICE_ERROR
;
980 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
981 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
983 Status
= ScsiInquiryCommandEx (
984 ScsiDiskDevice
->ScsiIo
,
985 EFI_TIMER_PERIOD_SECONDS (1),
990 (VOID
*) SupportedVpdPages
,
993 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
995 if (!EFI_ERROR (Status
)) {
996 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
997 | SupportedVpdPages
->PageLength1
;
998 for (Index
= 0; Index
< PageLength
; Index
++) {
999 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
1005 // Query the Block Limits VPD page
1007 if (Index
< PageLength
) {
1008 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1009 if (BlockLimits
== NULL
) {
1010 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1012 return EFI_DEVICE_ERROR
;
1014 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1015 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
1016 SenseDataLength
= 0;
1017 Status
= ScsiInquiryCommandEx (
1018 ScsiDiskDevice
->ScsiIo
,
1019 EFI_TIMER_PERIOD_SECONDS (1),
1024 (VOID
*) BlockLimits
,
1027 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1029 if (!EFI_ERROR (Status
)) {
1030 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
1031 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
1032 BlockLimits
->OptimalTransferLengthGranularity1
;
1035 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1039 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1043 if (!EFI_ERROR (Status
)) {
1046 } else if (Status
== EFI_NOT_READY
) {
1048 return EFI_DEVICE_ERROR
;
1050 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1052 return EFI_DEVICE_ERROR
;
1055 // go ahead to check HostAdapterStatus and TargetStatus
1056 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1059 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1060 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1062 return EFI_DEVICE_ERROR
;
1063 } else if (Status
== EFI_DEVICE_ERROR
) {
1065 // reset the scsi channel
1067 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1069 return EFI_DEVICE_ERROR
;
1072 Status
= CheckTargetStatus (TargetStatus
);
1073 if (Status
== EFI_NOT_READY
) {
1075 // reset the scsi device
1077 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1079 return EFI_DEVICE_ERROR
;
1081 } else if (Status
== EFI_DEVICE_ERROR
) {
1083 return EFI_DEVICE_ERROR
;
1087 // if goes here, meant ScsiInquiryCommand() failed.
1088 // if ScsiDiskRequestSenseKeys() succeeds at last,
1089 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1092 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1093 Status
= ScsiDiskRequestSenseKeys (
1100 if (!EFI_ERROR (Status
)) {
1102 return EFI_DEVICE_ERROR
;
1106 return EFI_DEVICE_ERROR
;
1110 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1111 // set *NeedRetry = FALSE to avoid the outside caller try again.
1114 return EFI_DEVICE_ERROR
;
1120 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1121 When Test Unit Ready command encounters any error caused by host adapter or
1122 target, return error without retrieving Sense Keys.
1124 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1125 @param NeedRetry The pointer of flag indicates try again
1126 @param SenseDataArray The pointer of an array of sense data
1127 @param NumberOfSenseKeys The pointer of the number of sense data array
1129 @retval EFI_DEVICE_ERROR Indicates that error occurs
1130 @retval EFI_SUCCESS Successfully to test unit
1134 ScsiDiskTestUnitReady (
1135 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1136 OUT BOOLEAN
*NeedRetry
,
1137 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1138 OUT UINTN
*NumberOfSenseKeys
1142 UINT8 SenseDataLength
;
1143 UINT8 HostAdapterStatus
;
1148 SenseDataLength
= 0;
1149 *NumberOfSenseKeys
= 0;
1152 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1154 Status
= ScsiTestUnitReadyCommand (
1155 ScsiDiskDevice
->ScsiIo
,
1156 EFI_TIMER_PERIOD_SECONDS (1),
1163 // no need to check HostAdapterStatus and TargetStatus
1165 if (Status
== EFI_NOT_READY
) {
1167 return EFI_DEVICE_ERROR
;
1169 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1171 return EFI_DEVICE_ERROR
;
1174 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1177 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1178 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1180 return EFI_DEVICE_ERROR
;
1182 } else if (Status
== EFI_DEVICE_ERROR
) {
1184 // reset the scsi channel
1186 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1188 return EFI_DEVICE_ERROR
;
1191 Status
= CheckTargetStatus (TargetStatus
);
1192 if (Status
== EFI_NOT_READY
) {
1194 // reset the scsi device
1196 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1198 return EFI_DEVICE_ERROR
;
1200 } else if (Status
== EFI_DEVICE_ERROR
) {
1202 return EFI_DEVICE_ERROR
;
1206 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1207 Status
= ScsiDiskRequestSenseKeys (
1214 if (!EFI_ERROR (Status
)) {
1219 return EFI_DEVICE_ERROR
;
1223 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1224 // set *NeedRetry = FALSE to avoid the outside caller try again.
1227 return EFI_DEVICE_ERROR
;
1231 Parsing Sense Keys which got from request sense command.
1233 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1234 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1235 @param NumberOfSenseKeys The number of sense key
1236 @param Action The pointer of action which indicates what is need to do next
1238 @retval EFI_DEVICE_ERROR Indicates that error occurs
1239 @retval EFI_SUCCESS Successfully to complete the parsing
1243 DetectMediaParsingSenseKeys (
1244 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1245 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1246 IN UINTN NumberOfSenseKeys
,
1253 // Default is to read capacity, unless..
1255 *Action
= ACTION_READ_CAPACITY
;
1257 if (NumberOfSenseKeys
== 0) {
1258 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1259 *Action
= ACTION_NO_ACTION
;
1264 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1266 // No Sense Key returned from last submitted command
1268 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1269 *Action
= ACTION_NO_ACTION
;
1274 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1275 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1276 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1277 *Action
= ACTION_NO_ACTION
;
1281 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1282 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1286 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1287 *Action
= ACTION_RETRY_COMMAND_LATER
;
1291 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1292 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1293 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1294 *Action
= ACTION_NO_ACTION
;
1295 return EFI_DEVICE_ERROR
;
1298 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1299 *Action
= ACTION_NO_ACTION
;
1300 return EFI_DEVICE_ERROR
;
1303 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1305 *Action
= ACTION_RETRY_COMMAND_LATER
;
1308 *Action
= ACTION_NO_ACTION
;
1309 return EFI_DEVICE_ERROR
;
1317 Send read capacity command to device and get the device parameter.
1319 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1320 @param NeedRetry The pointer of flag indicates if need a retry
1321 @param SenseDataArray The pointer of an array of sense data
1322 @param NumberOfSenseKeys The number of sense key
1324 @retval EFI_DEVICE_ERROR Indicates that error occurs
1325 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1329 ScsiDiskReadCapacity (
1330 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1331 OUT BOOLEAN
*NeedRetry
,
1332 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1333 OUT UINTN
*NumberOfSenseKeys
1336 UINT8 HostAdapterStatus
;
1338 EFI_STATUS CommandStatus
;
1342 UINT8 SenseDataLength
;
1343 UINT32 DataLength10
;
1344 UINT32 DataLength16
;
1345 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
1346 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
1348 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1349 if (CapacityData10
== NULL
) {
1351 return EFI_DEVICE_ERROR
;
1353 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1354 if (CapacityData16
== NULL
) {
1355 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1357 return EFI_DEVICE_ERROR
;
1360 SenseDataLength
= 0;
1361 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1362 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1363 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1364 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1366 *NumberOfSenseKeys
= 0;
1370 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1371 // 16 byte command should be used to access large hard disk >2TB
1373 CommandStatus
= ScsiReadCapacityCommand (
1374 ScsiDiskDevice
->ScsiIo
,
1375 EFI_TIMER_PERIOD_SECONDS(1),
1380 (VOID
*) CapacityData10
,
1385 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1386 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
1387 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
1389 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1391 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1393 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1394 // and LowestAlignedLba
1396 CommandStatus
= ScsiReadCapacity16Command (
1397 ScsiDiskDevice
->ScsiIo
,
1398 EFI_TIMER_PERIOD_SECONDS (1),
1403 (VOID
*) CapacityData16
,
1410 // no need to check HostAdapterStatus and TargetStatus
1412 if (CommandStatus
== EFI_SUCCESS
) {
1413 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
1414 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1415 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1419 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1420 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1422 if (CommandStatus
== EFI_NOT_READY
) {
1424 return EFI_DEVICE_ERROR
;
1425 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1427 return EFI_DEVICE_ERROR
;
1431 // go ahead to check HostAdapterStatus and TargetStatus
1432 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1435 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1436 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1438 return EFI_DEVICE_ERROR
;
1440 } else if (Status
== EFI_DEVICE_ERROR
) {
1442 // reset the scsi channel
1444 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1446 return EFI_DEVICE_ERROR
;
1449 Status
= CheckTargetStatus (TargetStatus
);
1450 if (Status
== EFI_NOT_READY
) {
1452 // reset the scsi device
1454 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1456 return EFI_DEVICE_ERROR
;
1458 } else if (Status
== EFI_DEVICE_ERROR
) {
1460 return EFI_DEVICE_ERROR
;
1464 // if goes here, meant ScsiReadCapacityCommand() failed.
1465 // if ScsiDiskRequestSenseKeys() succeeds at last,
1466 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1469 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1471 Status
= ScsiDiskRequestSenseKeys (
1478 if (!EFI_ERROR (Status
)) {
1483 return EFI_DEVICE_ERROR
;
1487 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1488 // set *NeedRetry = FALSE to avoid the outside caller try again.
1491 return EFI_DEVICE_ERROR
;
1495 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1497 @param HostAdapterStatus Host Adapter status
1499 @retval EFI_SUCCESS Host adapter is OK.
1500 @retval EFI_TIMEOUT Timeout.
1501 @retval EFI_NOT_READY Adapter NOT ready.
1502 @retval EFI_DEVICE_ERROR Adapter device error.
1506 CheckHostAdapterStatus (
1507 IN UINT8 HostAdapterStatus
1510 switch (HostAdapterStatus
) {
1511 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1514 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1515 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1516 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1519 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1520 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1521 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1522 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1523 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1524 return EFI_NOT_READY
;
1526 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1527 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1528 return EFI_DEVICE_ERROR
;
1537 Check the target status and re-interpret it in EFI_STATUS.
1539 @param TargetStatus Target status
1541 @retval EFI_NOT_READY Device is NOT ready.
1542 @retval EFI_DEVICE_ERROR
1548 IN UINT8 TargetStatus
1551 switch (TargetStatus
) {
1552 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1553 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1554 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1557 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1558 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1559 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1560 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1561 return EFI_NOT_READY
;
1563 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1564 return EFI_DEVICE_ERROR
;
1574 Retrieve all sense keys from the device.
1576 When encountering error during the process, if retrieve sense keys before
1577 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1578 and NeedRetry set to FALSE; otherwize, return the proper return status.
1580 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1581 @param NeedRetry The pointer of flag indicates if need a retry
1582 @param SenseDataArray The pointer of an array of sense data
1583 @param NumberOfSenseKeys The number of sense key
1584 @param AskResetIfError The flag indicates if need reset when error occurs
1586 @retval EFI_DEVICE_ERROR Indicates that error occurs
1587 @retval EFI_SUCCESS Successfully to request sense key
1591 ScsiDiskRequestSenseKeys (
1592 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1593 OUT BOOLEAN
*NeedRetry
,
1594 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1595 OUT UINTN
*NumberOfSenseKeys
,
1596 IN BOOLEAN AskResetIfError
1599 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1600 UINT8 SenseDataLength
;
1603 EFI_STATUS FallStatus
;
1604 UINT8 HostAdapterStatus
;
1607 FallStatus
= EFI_SUCCESS
;
1608 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1611 ScsiDiskDevice
->SenseData
,
1612 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1615 *NumberOfSenseKeys
= 0;
1616 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1617 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1619 for (SenseReq
= TRUE
; SenseReq
;) {
1620 Status
= ScsiRequestSenseCommand (
1621 ScsiDiskDevice
->ScsiIo
,
1622 EFI_TIMER_PERIOD_SECONDS (2),
1628 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1629 FallStatus
= EFI_SUCCESS
;
1631 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1633 FallStatus
= EFI_DEVICE_ERROR
;
1635 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1637 FallStatus
= EFI_DEVICE_ERROR
;
1639 } else if (Status
== EFI_DEVICE_ERROR
) {
1640 if (AskResetIfError
) {
1641 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1644 FallStatus
= EFI_DEVICE_ERROR
;
1647 if (EFI_ERROR (FallStatus
)) {
1648 if (*NumberOfSenseKeys
!= 0) {
1652 return EFI_DEVICE_ERROR
;
1656 (*NumberOfSenseKeys
) += 1;
1659 // no more sense key or number of sense keys exceeds predefined,
1662 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1663 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1673 Get information from media read capacity command.
1675 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1676 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1677 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1682 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1683 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1684 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1689 if (!ScsiDiskDevice
->Cdb16Byte
) {
1690 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1691 (Capacity10
->LastLba2
<< 16) |
1692 (Capacity10
->LastLba1
<< 8) |
1693 Capacity10
->LastLba0
;
1695 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1696 (Capacity10
->BlockSize2
<< 16) |
1697 (Capacity10
->BlockSize1
<< 8) |
1698 Capacity10
->BlockSize0
;
1699 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1700 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
1702 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1703 *Ptr
++ = Capacity16
->LastLba0
;
1704 *Ptr
++ = Capacity16
->LastLba1
;
1705 *Ptr
++ = Capacity16
->LastLba2
;
1706 *Ptr
++ = Capacity16
->LastLba3
;
1707 *Ptr
++ = Capacity16
->LastLba4
;
1708 *Ptr
++ = Capacity16
->LastLba5
;
1709 *Ptr
++ = Capacity16
->LastLba6
;
1710 *Ptr
= Capacity16
->LastLba7
;
1712 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1713 (Capacity16
->BlockSize2
<< 16) |
1714 (Capacity16
->BlockSize1
<< 8) |
1715 Capacity16
->BlockSize0
;
1717 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
1718 Capacity16
->LowestAlignLogic1
;
1719 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
1722 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1724 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1725 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1728 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1729 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1736 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1741 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1744 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1745 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1749 Read sector from SCSI Disk.
1751 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1752 @param Buffer The buffer to fill in the read out data
1753 @param Lba Logic block address
1754 @param NumberOfBlocks The number of blocks to read
1756 @retval EFI_DEVICE_ERROR Indicates a device error.
1757 @retval EFI_SUCCESS Operation is successful.
1761 ScsiDiskReadSectors (
1762 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1765 IN UINTN NumberOfBlocks
1768 UINTN BlocksRemaining
;
1779 EFI_SCSI_SENSE_DATA
*SenseData
;
1780 UINTN NumberOfSenseKeys
;
1783 NumberOfSenseKeys
= 0;
1785 Status
= EFI_SUCCESS
;
1787 BlocksRemaining
= NumberOfBlocks
;
1788 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1791 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1793 if (!ScsiDiskDevice
->Cdb16Byte
) {
1796 MaxBlock
= 0xFFFFFFFF;
1801 while (BlocksRemaining
> 0) {
1803 if (BlocksRemaining
<= MaxBlock
) {
1804 if (!ScsiDiskDevice
->Cdb16Byte
) {
1805 SectorCount
= (UINT16
) BlocksRemaining
;
1807 SectorCount
= (UINT32
) BlocksRemaining
;
1810 SectorCount
= MaxBlock
;
1813 ByteCount
= SectorCount
* BlockSize
;
1814 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1817 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1818 if (!ScsiDiskDevice
->Cdb16Byte
) {
1819 Status
= ScsiDiskRead10 (
1831 Status
= ScsiDiskRead16 (
1843 if (!EFI_ERROR (Status
)) {
1848 return EFI_DEVICE_ERROR
;
1853 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1854 return EFI_DEVICE_ERROR
;
1858 // actual transferred sectors
1860 SectorCount
= ByteCount
/ BlockSize
;
1863 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1864 BlocksRemaining
-= SectorCount
;
1871 Write sector to SCSI Disk.
1873 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1874 @param Buffer The buffer of data to be written into SCSI Disk
1875 @param Lba Logic block address
1876 @param NumberOfBlocks The number of blocks to read
1878 @retval EFI_DEVICE_ERROR Indicates a device error.
1879 @retval EFI_SUCCESS Operation is successful.
1883 ScsiDiskWriteSectors (
1884 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1887 IN UINTN NumberOfBlocks
1890 UINTN BlocksRemaining
;
1901 EFI_SCSI_SENSE_DATA
*SenseData
;
1902 UINTN NumberOfSenseKeys
;
1905 NumberOfSenseKeys
= 0;
1907 Status
= EFI_SUCCESS
;
1909 BlocksRemaining
= NumberOfBlocks
;
1910 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1913 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1915 if (!ScsiDiskDevice
->Cdb16Byte
) {
1918 MaxBlock
= 0xFFFFFFFF;
1923 while (BlocksRemaining
> 0) {
1925 if (BlocksRemaining
<= MaxBlock
) {
1926 if (!ScsiDiskDevice
->Cdb16Byte
) {
1927 SectorCount
= (UINT16
) BlocksRemaining
;
1929 SectorCount
= (UINT32
) BlocksRemaining
;
1932 SectorCount
= MaxBlock
;
1935 ByteCount
= SectorCount
* BlockSize
;
1936 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1938 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1939 if (!ScsiDiskDevice
->Cdb16Byte
) {
1940 Status
= ScsiDiskWrite10 (
1952 Status
= ScsiDiskWrite16 (
1964 if (!EFI_ERROR (Status
)) {
1969 return EFI_DEVICE_ERROR
;
1973 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1974 return EFI_DEVICE_ERROR
;
1977 // actual transferred sectors
1979 SectorCount
= ByteCount
/ BlockSize
;
1982 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1983 BlocksRemaining
-= SectorCount
;
1991 Submit Read(10) command.
1993 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1994 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1995 @param SenseDataArray NOT used yet in this function
1996 @param NumberOfSenseKeys The number of sense key
1997 @param Timeout The time to complete the command
1998 @param DataBuffer The buffer to fill with the read out data
1999 @param DataLength The length of buffer
2000 @param StartLba The start logic block address
2001 @param SectorSize The size of sector
2003 @return EFI_STATUS is returned by calling ScsiRead10Command().
2007 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2008 OUT BOOLEAN
*NeedRetry
,
2009 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2010 OUT UINTN
*NumberOfSenseKeys
,
2012 OUT UINT8
*DataBuffer
,
2013 IN OUT UINT32
*DataLength
,
2015 IN UINT32 SectorSize
2018 UINT8 SenseDataLength
;
2020 UINT8 HostAdapterStatus
;
2024 *NumberOfSenseKeys
= 0;
2025 SenseDataLength
= 0;
2026 Status
= ScsiRead10Command (
2027 ScsiDiskDevice
->ScsiIo
,
2043 Submit Write(10) Command.
2045 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2046 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2047 @param SenseDataArray NOT used yet in this function
2048 @param NumberOfSenseKeys The number of sense key
2049 @param Timeout The time to complete the command
2050 @param DataBuffer The buffer to fill with the read out data
2051 @param DataLength The length of buffer
2052 @param StartLba The start logic block address
2053 @param SectorSize The size of sector
2055 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2060 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2061 OUT BOOLEAN
*NeedRetry
,
2062 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2063 OUT UINTN
*NumberOfSenseKeys
,
2065 IN UINT8
*DataBuffer
,
2066 IN OUT UINT32
*DataLength
,
2068 IN UINT32 SectorSize
2072 UINT8 SenseDataLength
;
2073 UINT8 HostAdapterStatus
;
2077 *NumberOfSenseKeys
= 0;
2078 SenseDataLength
= 0;
2079 Status
= ScsiWrite10Command (
2080 ScsiDiskDevice
->ScsiIo
,
2096 Submit Read(16) command.
2098 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2099 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2100 @param SenseDataArray NOT used yet in this function
2101 @param NumberOfSenseKeys The number of sense key
2102 @param Timeout The time to complete the command
2103 @param DataBuffer The buffer to fill with the read out data
2104 @param DataLength The length of buffer
2105 @param StartLba The start logic block address
2106 @param SectorSize The size of sector
2108 @return EFI_STATUS is returned by calling ScsiRead10Command().
2112 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2113 OUT BOOLEAN
*NeedRetry
,
2114 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2115 OUT UINTN
*NumberOfSenseKeys
,
2117 OUT UINT8
*DataBuffer
,
2118 IN OUT UINT32
*DataLength
,
2120 IN UINT32 SectorSize
2123 UINT8 SenseDataLength
;
2125 UINT8 HostAdapterStatus
;
2129 *NumberOfSenseKeys
= 0;
2130 SenseDataLength
= 0;
2131 Status
= ScsiRead16Command (
2132 ScsiDiskDevice
->ScsiIo
,
2148 Submit Write(16) Command.
2150 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2151 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2152 @param SenseDataArray NOT used yet in this function
2153 @param NumberOfSenseKeys The number of sense key
2154 @param Timeout The time to complete the command
2155 @param DataBuffer The buffer to fill with the read out data
2156 @param DataLength The length of buffer
2157 @param StartLba The start logic block address
2158 @param SectorSize The size of sector
2160 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2165 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2166 OUT BOOLEAN
*NeedRetry
,
2167 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2168 OUT UINTN
*NumberOfSenseKeys
,
2170 IN UINT8
*DataBuffer
,
2171 IN OUT UINT32
*DataLength
,
2173 IN UINT32 SectorSize
2177 UINT8 SenseDataLength
;
2178 UINT8 HostAdapterStatus
;
2182 *NumberOfSenseKeys
= 0;
2183 SenseDataLength
= 0;
2184 Status
= ScsiWrite16Command (
2185 ScsiDiskDevice
->ScsiIo
,
2201 Check sense key to find if media presents.
2203 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2204 @param SenseCounts The number of sense key
2206 @retval TRUE NOT any media
2207 @retval FALSE Media presents
2211 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2212 IN UINTN SenseCounts
2215 EFI_SCSI_SENSE_DATA
*SensePtr
;
2220 SensePtr
= SenseData
;
2222 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2224 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2225 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2227 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
2228 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
2241 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2242 @param SenseCounts The number of sense key
2245 @retval FALSE NOT error
2249 ScsiDiskIsMediaError (
2250 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2251 IN UINTN SenseCounts
2254 EFI_SCSI_SENSE_DATA
*SensePtr
;
2259 SensePtr
= SenseData
;
2261 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2263 switch (SensePtr
->Sense_Key
) {
2265 case EFI_SCSI_SK_MEDIUM_ERROR
:
2267 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2269 switch (SensePtr
->Addnl_Sense_Code
) {
2274 case EFI_SCSI_ASC_MEDIA_ERR1
:
2279 case EFI_SCSI_ASC_MEDIA_ERR2
:
2284 case EFI_SCSI_ASC_MEDIA_ERR3
:
2285 case EFI_SCSI_ASC_MEDIA_ERR4
:
2295 case EFI_SCSI_SK_NOT_READY
:
2297 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2299 switch (SensePtr
->Addnl_Sense_Code
) {
2301 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2303 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2324 Check sense key to find if hardware error happens.
2326 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2327 @param SenseCounts The number of sense key
2329 @retval TRUE Hardware error exits.
2330 @retval FALSE NO error.
2334 ScsiDiskIsHardwareError (
2335 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2336 IN UINTN SenseCounts
2339 EFI_SCSI_SENSE_DATA
*SensePtr
;
2344 SensePtr
= SenseData
;
2346 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2349 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2351 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2363 Check sense key to find if media has changed.
2365 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2366 @param SenseCounts The number of sense key
2368 @retval TRUE Media is changed.
2369 @retval FALSE Media is NOT changed.
2372 ScsiDiskIsMediaChange (
2373 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2374 IN UINTN SenseCounts
2377 EFI_SCSI_SENSE_DATA
*SensePtr
;
2379 BOOLEAN IsMediaChanged
;
2381 IsMediaChanged
= FALSE
;
2382 SensePtr
= SenseData
;
2384 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2386 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2387 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2389 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2390 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2391 IsMediaChanged
= TRUE
;
2397 return IsMediaChanged
;
2401 Check sense key to find if reset happens.
2403 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2404 @param SenseCounts The number of sense key
2406 @retval TRUE It is reset before.
2407 @retval FALSE It is NOT reset before.
2411 ScsiDiskIsResetBefore (
2412 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2413 IN UINTN SenseCounts
2416 EFI_SCSI_SENSE_DATA
*SensePtr
;
2418 BOOLEAN IsResetBefore
;
2420 IsResetBefore
= FALSE
;
2421 SensePtr
= SenseData
;
2423 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2426 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2427 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2429 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2430 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2431 IsResetBefore
= TRUE
;
2437 return IsResetBefore
;
2441 Check sense key to find if the drive is ready.
2443 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2444 @param SenseCounts The number of sense key
2445 @param RetryLater The flag means if need a retry
2447 @retval TRUE Drive is ready.
2448 @retval FALSE Drive is NOT ready.
2452 ScsiDiskIsDriveReady (
2453 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2454 IN UINTN SenseCounts
,
2455 OUT BOOLEAN
*RetryLater
2458 EFI_SCSI_SENSE_DATA
*SensePtr
;
2463 *RetryLater
= FALSE
;
2464 SensePtr
= SenseData
;
2466 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2468 switch (SensePtr
->Sense_Key
) {
2470 case EFI_SCSI_SK_NOT_READY
:
2472 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2474 switch (SensePtr
->Addnl_Sense_Code
) {
2475 case EFI_SCSI_ASC_NOT_READY
:
2477 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2479 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2480 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2482 // Additional Sense Code Qualifier is
2483 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2491 *RetryLater
= FALSE
;
2512 Check sense key to find if it has sense key.
2514 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2515 @param SenseCounts - The number of sense key
2517 @retval TRUE It has sense key.
2518 @retval FALSE It has NOT any sense key.
2522 ScsiDiskHaveSenseKey (
2523 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2524 IN UINTN SenseCounts
2527 EFI_SCSI_SENSE_DATA
*SensePtr
;
2529 BOOLEAN HaveSenseKey
;
2531 if (SenseCounts
== 0) {
2532 HaveSenseKey
= FALSE
;
2534 HaveSenseKey
= TRUE
;
2537 SensePtr
= SenseData
;
2539 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2542 // Sense Key is SK_NO_SENSE (0x0)
2544 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2546 HaveSenseKey
= FALSE
;
2552 return HaveSenseKey
;
2556 Release resource about disk device.
2558 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2562 ReleaseScsiDiskDeviceResources (
2563 IN SCSI_DISK_DEV
*ScsiDiskDevice
2566 if (ScsiDiskDevice
== NULL
) {
2570 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2571 FreePool (ScsiDiskDevice
->SenseData
);
2572 ScsiDiskDevice
->SenseData
= NULL
;
2575 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2576 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2577 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2580 FreePool (ScsiDiskDevice
);
2582 ScsiDiskDevice
= NULL
;
2586 Determine if Block Io should be produced.
2589 @param ChildHandle Child Handle to retrieve Parent information.
2591 @retval TRUE Should produce Block Io.
2592 @retval FALSE Should not produce Block Io.
2596 DetermineInstallBlockIo (
2597 IN EFI_HANDLE ChildHandle
2600 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2601 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2604 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2605 // check its attribute, logic or physical.
2607 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2608 if (ExtScsiPassThru
!= NULL
) {
2609 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2615 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2616 // check its attribute, logic or physical.
2618 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2619 if (ScsiPassThru
!= NULL
) {
2620 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2629 Search protocol database and check to see if the protocol
2630 specified by ProtocolGuid is present on a ControllerHandle and opened by
2631 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2632 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2633 will be opened on it.
2636 @param ProtocolGuid ProtocolGuid pointer.
2637 @param ChildHandle Child Handle to retrieve Parent information.
2643 IN EFI_GUID
*ProtocolGuid
,
2644 IN EFI_HANDLE ChildHandle
2651 EFI_HANDLE
*HandleBuffer
;
2654 // Retrieve the list of all handles from the handle database
2656 Status
= gBS
->LocateHandleBuffer (
2664 if (EFI_ERROR (Status
)) {
2669 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
2671 for (Index
= 0; Index
< HandleCount
; Index
++) {
2672 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
2673 if (!EFI_ERROR (Status
)) {
2674 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
2675 if (!EFI_ERROR (Status
)) {
2676 gBS
->FreePool (HandleBuffer
);
2682 gBS
->FreePool (HandleBuffer
);
2687 Provides inquiry information for the controller type.
2689 This function is used by the IDE bus driver to get inquiry data. Data format
2690 of Identify data is defined by the Interface GUID.
2692 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2693 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
2694 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
2696 @retval EFI_SUCCESS The command was accepted without any errors.
2697 @retval EFI_NOT_FOUND Device does not support this data class
2698 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
2699 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
2704 ScsiDiskInfoInquiry (
2705 IN EFI_DISK_INFO_PROTOCOL
*This
,
2706 IN OUT VOID
*InquiryData
,
2707 IN OUT UINT32
*InquiryDataSize
2711 SCSI_DISK_DEV
*ScsiDiskDevice
;
2713 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2715 Status
= EFI_BUFFER_TOO_SMALL
;
2716 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
2717 Status
= EFI_SUCCESS
;
2718 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
2720 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
2726 Provides identify information for the controller type.
2728 This function is used by the IDE bus driver to get identify data. Data format
2729 of Identify data is defined by the Interface GUID.
2731 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
2733 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
2734 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
2737 @retval EFI_SUCCESS The command was accepted without any errors.
2738 @retval EFI_NOT_FOUND Device does not support this data class
2739 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
2740 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
2745 ScsiDiskInfoIdentify (
2746 IN EFI_DISK_INFO_PROTOCOL
*This
,
2747 IN OUT VOID
*IdentifyData
,
2748 IN OUT UINT32
*IdentifyDataSize
2752 SCSI_DISK_DEV
*ScsiDiskDevice
;
2754 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2756 // Physical SCSI bus does not support this data class.
2758 return EFI_NOT_FOUND
;
2761 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2763 Status
= EFI_BUFFER_TOO_SMALL
;
2764 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
2765 Status
= EFI_SUCCESS
;
2766 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
2768 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
2773 Provides sense data information for the controller type.
2775 This function is used by the IDE bus driver to get sense data.
2776 Data format of Sense data is defined by the Interface GUID.
2778 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2779 @param[in, out] SenseData Pointer to the SenseData.
2780 @param[in, out] SenseDataSize Size of SenseData in bytes.
2781 @param[out] SenseDataNumber Pointer to the value for the sense data size.
2783 @retval EFI_SUCCESS The command was accepted without any errors.
2784 @retval EFI_NOT_FOUND Device does not support this data class.
2785 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
2786 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
2791 ScsiDiskInfoSenseData (
2792 IN EFI_DISK_INFO_PROTOCOL
*This
,
2793 IN OUT VOID
*SenseData
,
2794 IN OUT UINT32
*SenseDataSize
,
2795 OUT UINT8
*SenseDataNumber
2798 return EFI_NOT_FOUND
;
2803 This function is used by the IDE bus driver to get controller information.
2805 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2806 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
2807 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
2809 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
2810 @retval EFI_UNSUPPORTED This is not an IDE device.
2815 ScsiDiskInfoWhichIde (
2816 IN EFI_DISK_INFO_PROTOCOL
*This
,
2817 OUT UINT32
*IdeChannel
,
2818 OUT UINT32
*IdeDevice
2821 SCSI_DISK_DEV
*ScsiDiskDevice
;
2823 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2825 // This is not an IDE physical device.
2827 return EFI_UNSUPPORTED
;
2830 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2831 *IdeChannel
= ScsiDiskDevice
->Channel
;
2832 *IdeDevice
= ScsiDiskDevice
->Device
;
2839 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
2841 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
2842 implement Identify() interface for DiskInfo protocol. The ATA command is sent
2843 via SCSI Request Packet.
2845 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2847 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
2848 @retval others Some error occurred during the identification that ATAPI device.
2852 AtapiIdentifyDevice (
2853 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2856 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
2860 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
2862 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
2863 ZeroMem (Cdb
, sizeof (Cdb
));
2865 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
2866 CommandPacket
.Timeout
= EFI_TIMER_PERIOD_SECONDS (1);
2867 CommandPacket
.Cdb
= Cdb
;
2868 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
2869 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
2870 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
2872 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
2877 Initialize the installation of DiskInfo protocol.
2879 This function prepares for the installation of DiskInfo protocol on the child handle.
2880 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
2881 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
2882 to be IDE/AHCI interface GUID.
2884 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2885 @param ChildHandle Child handle to install DiskInfo protocol.
2889 InitializeInstallDiskInfo (
2890 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2891 IN EFI_HANDLE ChildHandle
2895 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2896 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
2897 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
2898 SATA_DEVICE_PATH
*SataDevicePath
;
2899 UINTN IdentifyRetry
;
2901 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
2903 // Device Path protocol must be installed on the device handle.
2905 ASSERT_EFI_ERROR (Status
);
2907 // Copy the DiskInfo protocol template.
2909 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
2911 while (!IsDevicePathEnd (DevicePathNode
)) {
2912 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
2913 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
2914 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
2915 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
2916 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
2917 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
2922 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
2923 // with IDE/AHCI interface GUID.
2925 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
2926 if (!EFI_ERROR (Status
)) {
2927 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
2929 // We find the valid ATAPI device path
2931 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
2932 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
2933 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
2935 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
2937 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
2940 // We find the valid SATA device path
2942 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
2943 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
2944 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
2946 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
2948 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
2952 } while (--IdentifyRetry
> 0);
2954 DevicePathNode
= ChildDevicePathNode
;