2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2015, 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
.Media
->IoAlign
= ScsiIo
->IoAlign
;
238 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
239 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
240 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
241 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
242 ScsiDiskDevice
->Handle
= Controller
;
244 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
245 switch (ScsiDiskDevice
->DeviceType
) {
246 case EFI_SCSI_TYPE_DISK
:
247 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
248 MustReadCapacity
= TRUE
;
251 case EFI_SCSI_TYPE_CDROM
:
252 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
253 MustReadCapacity
= FALSE
;
257 // The Sense Data Array's initial size is 6
259 ScsiDiskDevice
->SenseDataNumber
= 6;
260 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
261 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
263 if (ScsiDiskDevice
->SenseData
== NULL
) {
266 &gEfiScsiIoProtocolGuid
,
267 This
->DriverBindingHandle
,
270 FreePool (ScsiDiskDevice
);
271 return EFI_OUT_OF_RESOURCES
;
275 // Retrieve device information
278 for (Index
= 0; Index
< MaxRetry
; Index
++) {
279 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
280 if (!EFI_ERROR (Status
)) {
285 FreePool (ScsiDiskDevice
->SenseData
);
288 &gEfiScsiIoProtocolGuid
,
289 This
->DriverBindingHandle
,
292 FreePool (ScsiDiskDevice
);
293 return EFI_DEVICE_ERROR
;
297 // The second parameter "TRUE" means must
298 // retrieve media capacity
300 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
301 if (!EFI_ERROR (Status
)) {
303 // Determine if Block IO should be produced on this controller handle
305 if (DetermineInstallBlockIo(Controller
)) {
306 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
307 Status
= gBS
->InstallMultipleProtocolInterfaces (
309 &gEfiBlockIoProtocolGuid
,
310 &ScsiDiskDevice
->BlkIo
,
311 &gEfiDiskInfoProtocolGuid
,
312 &ScsiDiskDevice
->DiskInfo
,
315 if (!EFI_ERROR(Status
)) {
316 ScsiDiskDevice
->ControllerNameTable
= NULL
;
319 gScsiDiskComponentName
.SupportedLanguages
,
320 &ScsiDiskDevice
->ControllerNameTable
,
326 gScsiDiskComponentName2
.SupportedLanguages
,
327 &ScsiDiskDevice
->ControllerNameTable
,
336 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
337 gBS
->FreePool (ScsiDiskDevice
);
340 &gEfiScsiIoProtocolGuid
,
341 This
->DriverBindingHandle
,
350 Stop this driver on ControllerHandle.
352 This service is called by the EFI boot service DisconnectController().
353 In order to make drivers as small as possible, there are a few calling
354 restrictions for this service. DisconnectController() must follow these
355 calling restrictions. If any other agent wishes to call Stop() it must
356 also follow these calling restrictions.
358 @param This Protocol instance pointer.
359 @param ControllerHandle Handle of device to stop driver on
360 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
361 children is zero stop the entire bus driver.
362 @param ChildHandleBuffer List of Child Handles to Stop.
364 @retval EFI_SUCCESS This driver is removed ControllerHandle
365 @retval other This driver was not removed from this device
370 ScsiDiskDriverBindingStop (
371 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
372 IN EFI_HANDLE Controller
,
373 IN UINTN NumberOfChildren
,
374 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
377 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
378 SCSI_DISK_DEV
*ScsiDiskDevice
;
381 Status
= gBS
->OpenProtocol (
383 &gEfiBlockIoProtocolGuid
,
385 This
->DriverBindingHandle
,
387 EFI_OPEN_PROTOCOL_GET_PROTOCOL
389 if (EFI_ERROR (Status
)) {
393 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
394 Status
= gBS
->UninstallMultipleProtocolInterfaces (
396 &gEfiBlockIoProtocolGuid
,
397 &ScsiDiskDevice
->BlkIo
,
398 &gEfiDiskInfoProtocolGuid
,
399 &ScsiDiskDevice
->DiskInfo
,
402 if (!EFI_ERROR (Status
)) {
405 &gEfiScsiIoProtocolGuid
,
406 This
->DriverBindingHandle
,
410 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
424 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
425 @param ExtendedVerification The flag about if extend verificate
427 @retval EFI_SUCCESS The device was reset.
428 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
430 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
436 IN EFI_BLOCK_IO_PROTOCOL
*This
,
437 IN BOOLEAN ExtendedVerification
441 SCSI_DISK_DEV
*ScsiDiskDevice
;
444 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
446 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
448 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
450 if (EFI_ERROR (Status
)) {
451 Status
= EFI_DEVICE_ERROR
;
455 if (!ExtendedVerification
) {
459 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
461 if (EFI_ERROR (Status
)) {
462 Status
= EFI_DEVICE_ERROR
;
467 gBS
->RestoreTPL (OldTpl
);
472 The function is to Read Block from SCSI Disk.
474 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
475 @param MediaId The Id of Media detected
476 @param Lba The logic block address
477 @param BufferSize The size of Buffer
478 @param Buffer The buffer to fill the read out data
480 @retval EFI_SUCCESS Successfully to read out block.
481 @retval EFI_DEVICE_ERROR Fail to detect media.
482 @retval EFI_NO_MEDIA Media is not present.
483 @retval EFI_MEDIA_CHANGED Media has changed.
484 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
485 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
491 IN EFI_BLOCK_IO_PROTOCOL
*This
,
498 SCSI_DISK_DEV
*ScsiDiskDevice
;
499 EFI_BLOCK_IO_MEDIA
*Media
;
502 UINTN NumberOfBlocks
;
507 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
508 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
510 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
512 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
513 if (EFI_ERROR (Status
)) {
514 Status
= EFI_DEVICE_ERROR
;
519 gBS
->ReinstallProtocolInterface (
520 ScsiDiskDevice
->Handle
,
521 &gEfiBlockIoProtocolGuid
,
522 &ScsiDiskDevice
->BlkIo
,
523 &ScsiDiskDevice
->BlkIo
525 Status
= EFI_MEDIA_CHANGED
;
530 // Get the intrinsic block size
532 Media
= ScsiDiskDevice
->BlkIo
.Media
;
533 BlockSize
= Media
->BlockSize
;
535 NumberOfBlocks
= BufferSize
/ BlockSize
;
537 if (!(Media
->MediaPresent
)) {
538 Status
= EFI_NO_MEDIA
;
542 if (MediaId
!= Media
->MediaId
) {
543 Status
= EFI_MEDIA_CHANGED
;
547 if (Buffer
== NULL
) {
548 Status
= EFI_INVALID_PARAMETER
;
552 if (BufferSize
== 0) {
553 Status
= EFI_SUCCESS
;
557 if (BufferSize
% BlockSize
!= 0) {
558 Status
= EFI_BAD_BUFFER_SIZE
;
562 if (Lba
> Media
->LastBlock
) {
563 Status
= EFI_INVALID_PARAMETER
;
567 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
568 Status
= EFI_INVALID_PARAMETER
;
572 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
573 Status
= EFI_INVALID_PARAMETER
;
578 // If all the parameters are valid, then perform read sectors command
579 // to transfer data from device to host.
581 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
584 gBS
->RestoreTPL (OldTpl
);
589 The function is to Write Block to SCSI Disk.
591 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
592 @param MediaId The Id of Media detected
593 @param Lba The logic block address
594 @param BufferSize The size of Buffer
595 @param Buffer The buffer to fill the read out data
597 @retval EFI_SUCCESS Successfully to read out block.
598 @retval EFI_WRITE_PROTECTED The device can not be written to.
599 @retval EFI_DEVICE_ERROR Fail to detect media.
600 @retval EFI_NO_MEDIA Media is not present.
601 @retval EFI_MEDIA_CHNAGED Media has changed.
602 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
603 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
608 ScsiDiskWriteBlocks (
609 IN EFI_BLOCK_IO_PROTOCOL
*This
,
616 SCSI_DISK_DEV
*ScsiDiskDevice
;
617 EFI_BLOCK_IO_MEDIA
*Media
;
620 UINTN NumberOfBlocks
;
625 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
626 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
628 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
630 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
631 if (EFI_ERROR (Status
)) {
632 Status
= EFI_DEVICE_ERROR
;
637 gBS
->ReinstallProtocolInterface (
638 ScsiDiskDevice
->Handle
,
639 &gEfiBlockIoProtocolGuid
,
640 &ScsiDiskDevice
->BlkIo
,
641 &ScsiDiskDevice
->BlkIo
643 Status
= EFI_MEDIA_CHANGED
;
648 // Get the intrinsic block size
650 Media
= ScsiDiskDevice
->BlkIo
.Media
;
651 BlockSize
= Media
->BlockSize
;
653 NumberOfBlocks
= BufferSize
/ BlockSize
;
655 if (!(Media
->MediaPresent
)) {
656 Status
= EFI_NO_MEDIA
;
660 if (MediaId
!= Media
->MediaId
) {
661 Status
= EFI_MEDIA_CHANGED
;
665 if (BufferSize
== 0) {
666 Status
= EFI_SUCCESS
;
670 if (Buffer
== NULL
) {
671 Status
= EFI_INVALID_PARAMETER
;
675 if (BufferSize
% BlockSize
!= 0) {
676 Status
= EFI_BAD_BUFFER_SIZE
;
680 if (Lba
> Media
->LastBlock
) {
681 Status
= EFI_INVALID_PARAMETER
;
685 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
686 Status
= EFI_INVALID_PARAMETER
;
690 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
691 Status
= EFI_INVALID_PARAMETER
;
695 // if all the parameters are valid, then perform read sectors command
696 // to transfer data from device to host.
698 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
701 gBS
->RestoreTPL (OldTpl
);
708 EFI_SUCCESS is returned directly.
710 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
712 @retval EFI_SUCCESS All outstanding data was written to the device
717 ScsiDiskFlushBlocks (
718 IN EFI_BLOCK_IO_PROTOCOL
*This
729 Detect Device and read out capacity ,if error occurs, parse the sense key.
731 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
732 @param MustReadCapacity The flag about reading device capacity
733 @param MediaChange The pointer of flag indicates if media has changed
735 @retval EFI_DEVICE_ERROR Indicates that error occurs
736 @retval EFI_SUCCESS Successfully to detect media
740 ScsiDiskDetectMedia (
741 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
742 IN BOOLEAN MustReadCapacity
,
743 OUT BOOLEAN
*MediaChange
747 EFI_SCSI_SENSE_DATA
*SenseData
;
748 UINTN NumberOfSenseKeys
;
750 BOOLEAN NeedReadCapacity
;
753 EFI_BLOCK_IO_MEDIA OldMedia
;
755 EFI_EVENT TimeoutEvt
;
757 Status
= EFI_SUCCESS
;
759 NumberOfSenseKeys
= 0;
762 Action
= ACTION_NO_ACTION
;
763 NeedReadCapacity
= FALSE
;
764 *MediaChange
= FALSE
;
767 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
769 Status
= gBS
->CreateEvent (
776 if (EFI_ERROR (Status
)) {
780 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
781 if (EFI_ERROR (Status
)) {
786 // Sending Test_Unit cmd to poll device status.
787 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
788 // We limit the upper boundary to 120 seconds.
790 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
791 Status
= ScsiDiskTestUnitReady (
797 if (!EFI_ERROR (Status
)) {
798 Status
= DetectMediaParsingSenseKeys (
804 if (EFI_ERROR (Status
)) {
806 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
813 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
819 if (EFI_ERROR (Status
)) {
824 // ACTION_NO_ACTION: need not read capacity
825 // other action code: need read capacity
827 if (Action
== ACTION_READ_CAPACITY
) {
828 NeedReadCapacity
= TRUE
;
832 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
833 // retrieve capacity via Read Capacity command
835 if (NeedReadCapacity
|| MustReadCapacity
) {
837 // retrieve media information
839 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
840 Status
= ScsiDiskReadCapacity (
846 if (!EFI_ERROR (Status
)) {
848 // analyze sense key to action
850 Status
= DetectMediaParsingSenseKeys (
856 if (EFI_ERROR (Status
)) {
858 // if Status is error, it may indicate crisis error,
859 // so return without retry.
862 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
870 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
876 if (EFI_ERROR (Status
)) {
881 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
883 // Media change information got from the device
888 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
890 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
893 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
895 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
898 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
900 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
903 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
904 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
906 // when change from no media to media present, reset the MediaId to 1.
908 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
911 // when no media, reset the MediaId to zero.
913 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
920 if (TimeoutEvt
!= NULL
) {
921 gBS
->CloseEvent (TimeoutEvt
);
928 Send out Inquiry command to Device.
930 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
931 @param NeedRetry Indicates if needs try again when error happens
933 @retval EFI_DEVICE_ERROR Indicates that error occurs
934 @retval EFI_SUCCESS Successfully to detect media
938 ScsiDiskInquiryDevice (
939 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
940 OUT BOOLEAN
*NeedRetry
943 UINT32 InquiryDataLength
;
944 UINT8 SenseDataLength
;
945 UINT8 HostAdapterStatus
;
947 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
948 UINTN NumberOfSenseKeys
;
952 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
953 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
956 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
959 Status
= ScsiInquiryCommand (
960 ScsiDiskDevice
->ScsiIo
,
966 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
971 // no need to check HostAdapterStatus and TargetStatus
973 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
974 ParseInquiryData (ScsiDiskDevice
);
976 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
978 // Check whether the device supports Block Limits VPD page (0xB0)
980 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
981 if (SupportedVpdPages
== NULL
) {
983 return EFI_DEVICE_ERROR
;
985 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
986 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
988 Status
= ScsiInquiryCommandEx (
989 ScsiDiskDevice
->ScsiIo
,
995 (VOID
*) SupportedVpdPages
,
998 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1000 if (!EFI_ERROR (Status
)) {
1001 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1002 | SupportedVpdPages
->PageLength1
;
1003 for (Index
= 0; Index
< PageLength
; Index
++) {
1004 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
1010 // Query the Block Limits VPD page
1012 if (Index
< PageLength
) {
1013 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1014 if (BlockLimits
== NULL
) {
1015 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1017 return EFI_DEVICE_ERROR
;
1019 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1020 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
1021 SenseDataLength
= 0;
1022 Status
= ScsiInquiryCommandEx (
1023 ScsiDiskDevice
->ScsiIo
,
1029 (VOID
*) BlockLimits
,
1032 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1034 if (!EFI_ERROR (Status
)) {
1035 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
1036 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
1037 BlockLimits
->OptimalTransferLengthGranularity1
;
1040 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1044 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1048 if (!EFI_ERROR (Status
)) {
1051 } else if (Status
== EFI_NOT_READY
) {
1053 return EFI_DEVICE_ERROR
;
1055 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1057 return EFI_DEVICE_ERROR
;
1060 // go ahead to check HostAdapterStatus and TargetStatus
1061 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1064 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1065 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1067 return EFI_DEVICE_ERROR
;
1068 } else if (Status
== EFI_DEVICE_ERROR
) {
1070 // reset the scsi channel
1072 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1074 return EFI_DEVICE_ERROR
;
1077 Status
= CheckTargetStatus (TargetStatus
);
1078 if (Status
== EFI_NOT_READY
) {
1080 // reset the scsi device
1082 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1084 return EFI_DEVICE_ERROR
;
1086 } else if (Status
== EFI_DEVICE_ERROR
) {
1088 return EFI_DEVICE_ERROR
;
1092 // if goes here, meant ScsiInquiryCommand() failed.
1093 // if ScsiDiskRequestSenseKeys() succeeds at last,
1094 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1097 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1098 Status
= ScsiDiskRequestSenseKeys (
1105 if (!EFI_ERROR (Status
)) {
1107 return EFI_DEVICE_ERROR
;
1111 return EFI_DEVICE_ERROR
;
1115 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1116 // set *NeedRetry = FALSE to avoid the outside caller try again.
1119 return EFI_DEVICE_ERROR
;
1125 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1126 When Test Unit Ready command encounters any error caused by host adapter or
1127 target, return error without retrieving Sense Keys.
1129 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1130 @param NeedRetry The pointer of flag indicates try again
1131 @param SenseDataArray The pointer of an array of sense data
1132 @param NumberOfSenseKeys The pointer of the number of sense data array
1134 @retval EFI_DEVICE_ERROR Indicates that error occurs
1135 @retval EFI_SUCCESS Successfully to test unit
1139 ScsiDiskTestUnitReady (
1140 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1141 OUT BOOLEAN
*NeedRetry
,
1142 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1143 OUT UINTN
*NumberOfSenseKeys
1147 UINT8 SenseDataLength
;
1148 UINT8 HostAdapterStatus
;
1153 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
1154 *NumberOfSenseKeys
= 0;
1157 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1159 Status
= ScsiTestUnitReadyCommand (
1160 ScsiDiskDevice
->ScsiIo
,
1162 ScsiDiskDevice
->SenseData
,
1168 // no need to check HostAdapterStatus and TargetStatus
1170 if (Status
== EFI_NOT_READY
) {
1172 return EFI_DEVICE_ERROR
;
1174 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1176 return EFI_DEVICE_ERROR
;
1179 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1182 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1183 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1185 return EFI_DEVICE_ERROR
;
1187 } else if (Status
== EFI_DEVICE_ERROR
) {
1189 // reset the scsi channel
1191 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1193 return EFI_DEVICE_ERROR
;
1196 Status
= CheckTargetStatus (TargetStatus
);
1197 if (Status
== EFI_NOT_READY
) {
1199 // reset the scsi device
1201 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1203 return EFI_DEVICE_ERROR
;
1205 } else if (Status
== EFI_DEVICE_ERROR
) {
1207 return EFI_DEVICE_ERROR
;
1210 if (SenseDataLength
!= 0) {
1211 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
1212 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1217 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1218 Status
= ScsiDiskRequestSenseKeys (
1225 if (!EFI_ERROR (Status
)) {
1230 return EFI_DEVICE_ERROR
;
1234 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1235 // set *NeedRetry = FALSE to avoid the outside caller try again.
1238 return EFI_DEVICE_ERROR
;
1242 Parsing Sense Keys which got from request sense command.
1244 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1245 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1246 @param NumberOfSenseKeys The number of sense key
1247 @param Action The pointer of action which indicates what is need to do next
1249 @retval EFI_DEVICE_ERROR Indicates that error occurs
1250 @retval EFI_SUCCESS Successfully to complete the parsing
1254 DetectMediaParsingSenseKeys (
1255 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1256 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1257 IN UINTN NumberOfSenseKeys
,
1264 // Default is to read capacity, unless..
1266 *Action
= ACTION_READ_CAPACITY
;
1268 if (NumberOfSenseKeys
== 0) {
1269 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1270 *Action
= ACTION_NO_ACTION
;
1275 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1277 // No Sense Key returned from last submitted command
1279 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1280 *Action
= ACTION_NO_ACTION
;
1285 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1286 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1287 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1288 *Action
= ACTION_NO_ACTION
;
1289 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1293 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1294 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1295 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1299 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1300 *Action
= ACTION_RETRY_COMMAND_LATER
;
1301 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1305 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1306 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
1307 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1308 return EFI_DEVICE_ERROR
;
1311 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1312 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1313 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1314 return EFI_DEVICE_ERROR
;
1317 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1319 *Action
= ACTION_RETRY_COMMAND_LATER
;
1320 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1323 *Action
= ACTION_NO_ACTION
;
1324 return EFI_DEVICE_ERROR
;
1327 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1328 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
1334 Send read capacity command to device and get the device parameter.
1336 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1337 @param NeedRetry The pointer of flag indicates if need a retry
1338 @param SenseDataArray The pointer of an array of sense data
1339 @param NumberOfSenseKeys The number of sense key
1341 @retval EFI_DEVICE_ERROR Indicates that error occurs
1342 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1346 ScsiDiskReadCapacity (
1347 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1348 OUT BOOLEAN
*NeedRetry
,
1349 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1350 OUT UINTN
*NumberOfSenseKeys
1353 UINT8 HostAdapterStatus
;
1355 EFI_STATUS CommandStatus
;
1359 UINT8 SenseDataLength
;
1360 UINT32 DataLength10
;
1361 UINT32 DataLength16
;
1362 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
1363 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
1365 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1366 if (CapacityData10
== NULL
) {
1368 return EFI_DEVICE_ERROR
;
1370 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1371 if (CapacityData16
== NULL
) {
1372 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1374 return EFI_DEVICE_ERROR
;
1377 SenseDataLength
= 0;
1378 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1379 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1380 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1381 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1383 *NumberOfSenseKeys
= 0;
1387 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1388 // 16 byte command should be used to access large hard disk >2TB
1390 CommandStatus
= ScsiReadCapacityCommand (
1391 ScsiDiskDevice
->ScsiIo
,
1397 (VOID
*) CapacityData10
,
1402 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1403 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
1404 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
1406 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1408 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1410 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1411 // and LowestAlignedLba
1413 CommandStatus
= ScsiReadCapacity16Command (
1414 ScsiDiskDevice
->ScsiIo
,
1420 (VOID
*) CapacityData16
,
1427 // no need to check HostAdapterStatus and TargetStatus
1429 if (CommandStatus
== EFI_SUCCESS
) {
1430 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
1431 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1432 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1436 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1437 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1439 if (CommandStatus
== EFI_NOT_READY
) {
1441 return EFI_DEVICE_ERROR
;
1442 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1444 return EFI_DEVICE_ERROR
;
1448 // go ahead to check HostAdapterStatus and TargetStatus
1449 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1452 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1453 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1455 return EFI_DEVICE_ERROR
;
1457 } else if (Status
== EFI_DEVICE_ERROR
) {
1459 // reset the scsi channel
1461 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1463 return EFI_DEVICE_ERROR
;
1466 Status
= CheckTargetStatus (TargetStatus
);
1467 if (Status
== EFI_NOT_READY
) {
1469 // reset the scsi device
1471 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1473 return EFI_DEVICE_ERROR
;
1475 } else if (Status
== EFI_DEVICE_ERROR
) {
1477 return EFI_DEVICE_ERROR
;
1481 // if goes here, meant ScsiReadCapacityCommand() failed.
1482 // if ScsiDiskRequestSenseKeys() succeeds at last,
1483 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1486 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1488 Status
= ScsiDiskRequestSenseKeys (
1495 if (!EFI_ERROR (Status
)) {
1500 return EFI_DEVICE_ERROR
;
1504 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1505 // set *NeedRetry = FALSE to avoid the outside caller try again.
1508 return EFI_DEVICE_ERROR
;
1512 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1514 @param HostAdapterStatus Host Adapter status
1516 @retval EFI_SUCCESS Host adapter is OK.
1517 @retval EFI_TIMEOUT Timeout.
1518 @retval EFI_NOT_READY Adapter NOT ready.
1519 @retval EFI_DEVICE_ERROR Adapter device error.
1523 CheckHostAdapterStatus (
1524 IN UINT8 HostAdapterStatus
1527 switch (HostAdapterStatus
) {
1528 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1531 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1532 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1533 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1536 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1537 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1538 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1539 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1540 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1541 return EFI_NOT_READY
;
1543 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1544 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1545 return EFI_DEVICE_ERROR
;
1554 Check the target status and re-interpret it in EFI_STATUS.
1556 @param TargetStatus Target status
1558 @retval EFI_NOT_READY Device is NOT ready.
1559 @retval EFI_DEVICE_ERROR
1565 IN UINT8 TargetStatus
1568 switch (TargetStatus
) {
1569 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1570 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1571 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1574 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1575 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1576 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1577 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1578 return EFI_NOT_READY
;
1580 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1581 return EFI_DEVICE_ERROR
;
1590 Retrieve all sense keys from the device.
1592 When encountering error during the process, if retrieve sense keys before
1593 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1594 and NeedRetry set to FALSE; otherwize, return the proper return status.
1596 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1597 @param NeedRetry The pointer of flag indicates if need a retry
1598 @param SenseDataArray The pointer of an array of sense data
1599 @param NumberOfSenseKeys The number of sense key
1600 @param AskResetIfError The flag indicates if need reset when error occurs
1602 @retval EFI_DEVICE_ERROR Indicates that error occurs
1603 @retval EFI_SUCCESS Successfully to request sense key
1607 ScsiDiskRequestSenseKeys (
1608 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1609 OUT BOOLEAN
*NeedRetry
,
1610 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1611 OUT UINTN
*NumberOfSenseKeys
,
1612 IN BOOLEAN AskResetIfError
1615 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1616 UINT8 SenseDataLength
;
1619 EFI_STATUS FallStatus
;
1620 UINT8 HostAdapterStatus
;
1623 FallStatus
= EFI_SUCCESS
;
1624 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1627 ScsiDiskDevice
->SenseData
,
1628 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1631 *NumberOfSenseKeys
= 0;
1632 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1633 Status
= EFI_SUCCESS
;
1634 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
1635 if (PtrSenseData
== NULL
) {
1636 return EFI_DEVICE_ERROR
;
1639 for (SenseReq
= TRUE
; SenseReq
;) {
1640 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
1641 Status
= ScsiRequestSenseCommand (
1642 ScsiDiskDevice
->ScsiIo
,
1649 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1650 FallStatus
= EFI_SUCCESS
;
1652 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1654 FallStatus
= EFI_DEVICE_ERROR
;
1656 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1658 FallStatus
= EFI_DEVICE_ERROR
;
1660 } else if (Status
== EFI_DEVICE_ERROR
) {
1661 if (AskResetIfError
) {
1662 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1665 FallStatus
= EFI_DEVICE_ERROR
;
1668 if (EFI_ERROR (FallStatus
)) {
1669 if (*NumberOfSenseKeys
!= 0) {
1671 Status
= EFI_SUCCESS
;
1674 Status
= EFI_DEVICE_ERROR
;
1679 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
1680 (*NumberOfSenseKeys
) += 1;
1683 // no more sense key or number of sense keys exceeds predefined,
1686 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1687 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1693 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
1699 Get information from media read capacity command.
1701 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1702 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1703 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1708 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1709 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1710 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1715 if (!ScsiDiskDevice
->Cdb16Byte
) {
1716 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1717 (Capacity10
->LastLba2
<< 16) |
1718 (Capacity10
->LastLba1
<< 8) |
1719 Capacity10
->LastLba0
;
1721 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1722 (Capacity10
->BlockSize2
<< 16) |
1723 (Capacity10
->BlockSize1
<< 8) |
1724 Capacity10
->BlockSize0
;
1725 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1726 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
1728 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1729 *Ptr
++ = Capacity16
->LastLba0
;
1730 *Ptr
++ = Capacity16
->LastLba1
;
1731 *Ptr
++ = Capacity16
->LastLba2
;
1732 *Ptr
++ = Capacity16
->LastLba3
;
1733 *Ptr
++ = Capacity16
->LastLba4
;
1734 *Ptr
++ = Capacity16
->LastLba5
;
1735 *Ptr
++ = Capacity16
->LastLba6
;
1736 *Ptr
= Capacity16
->LastLba7
;
1738 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1739 (Capacity16
->BlockSize2
<< 16) |
1740 (Capacity16
->BlockSize1
<< 8) |
1741 Capacity16
->BlockSize0
;
1743 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
1744 Capacity16
->LowestAlignLogic1
;
1745 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
1748 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1754 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1759 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1762 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1763 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1767 Read sector from SCSI Disk.
1769 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1770 @param Buffer The buffer to fill in the read out data
1771 @param Lba Logic block address
1772 @param NumberOfBlocks The number of blocks to read
1774 @retval EFI_DEVICE_ERROR Indicates a device error.
1775 @retval EFI_SUCCESS Operation is successful.
1779 ScsiDiskReadSectors (
1780 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1783 IN UINTN NumberOfBlocks
1786 UINTN BlocksRemaining
;
1798 Status
= EFI_SUCCESS
;
1800 BlocksRemaining
= NumberOfBlocks
;
1801 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1804 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1806 if (!ScsiDiskDevice
->Cdb16Byte
) {
1809 MaxBlock
= 0xFFFFFFFF;
1814 while (BlocksRemaining
> 0) {
1816 if (BlocksRemaining
<= MaxBlock
) {
1817 if (!ScsiDiskDevice
->Cdb16Byte
) {
1818 SectorCount
= (UINT16
) BlocksRemaining
;
1820 SectorCount
= (UINT32
) BlocksRemaining
;
1823 SectorCount
= MaxBlock
;
1826 ByteCount
= SectorCount
* BlockSize
;
1828 // |------------------------|-----------------|------------------|-----------------|
1829 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
1830 // |------------------------|-----------------|------------------|-----------------|
1831 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
1832 // |------------------------|-----------------|------------------|-----------------|
1833 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
1834 // |------------------------|-----------------|------------------|-----------------|
1835 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
1836 // |------------------------|-----------------|------------------|-----------------|
1837 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
1838 // |------------------------|-----------------|------------------|-----------------|
1839 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
1840 // |------------------------|-----------------|------------------|-----------------|
1841 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
1842 // |------------------------|-----------------|------------------|-----------------|
1843 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
1844 // |------------------------|-----------------|------------------|-----------------|
1845 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
1846 // |------------------------|-----------------|------------------|-----------------|
1847 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
1848 // |------------------------|-----------------|------------------|-----------------|
1849 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
1850 // |------------------------|-----------------|------------------|-----------------|
1852 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
1853 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
1854 // From the above table, we could know 2.1Mbytes per second is lowest one.
1855 // The timout value is rounded up to nearest integar and here an additional 30s is added
1856 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
1857 // commands in the Standby/Idle mode.
1859 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
1862 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1863 if (!ScsiDiskDevice
->Cdb16Byte
) {
1864 Status
= ScsiDiskRead10 (
1874 Status
= ScsiDiskRead16 (
1884 if (!EFI_ERROR (Status
)) {
1889 return EFI_DEVICE_ERROR
;
1894 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1895 return EFI_DEVICE_ERROR
;
1899 // actual transferred sectors
1901 SectorCount
= ByteCount
/ BlockSize
;
1904 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1905 BlocksRemaining
-= SectorCount
;
1912 Write sector to SCSI Disk.
1914 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1915 @param Buffer The buffer of data to be written into SCSI Disk
1916 @param Lba Logic block address
1917 @param NumberOfBlocks The number of blocks to read
1919 @retval EFI_DEVICE_ERROR Indicates a device error.
1920 @retval EFI_SUCCESS Operation is successful.
1924 ScsiDiskWriteSectors (
1925 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1928 IN UINTN NumberOfBlocks
1931 UINTN BlocksRemaining
;
1943 Status
= EFI_SUCCESS
;
1945 BlocksRemaining
= NumberOfBlocks
;
1946 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1949 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1951 if (!ScsiDiskDevice
->Cdb16Byte
) {
1954 MaxBlock
= 0xFFFFFFFF;
1959 while (BlocksRemaining
> 0) {
1961 if (BlocksRemaining
<= MaxBlock
) {
1962 if (!ScsiDiskDevice
->Cdb16Byte
) {
1963 SectorCount
= (UINT16
) BlocksRemaining
;
1965 SectorCount
= (UINT32
) BlocksRemaining
;
1968 SectorCount
= MaxBlock
;
1971 ByteCount
= SectorCount
* BlockSize
;
1973 // |------------------------|-----------------|------------------|-----------------|
1974 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
1975 // |------------------------|-----------------|------------------|-----------------|
1976 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
1977 // |------------------------|-----------------|------------------|-----------------|
1978 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
1979 // |------------------------|-----------------|------------------|-----------------|
1980 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
1981 // |------------------------|-----------------|------------------|-----------------|
1982 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
1983 // |------------------------|-----------------|------------------|-----------------|
1984 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
1985 // |------------------------|-----------------|------------------|-----------------|
1986 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
1987 // |------------------------|-----------------|------------------|-----------------|
1988 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
1989 // |------------------------|-----------------|------------------|-----------------|
1990 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
1991 // |------------------------|-----------------|------------------|-----------------|
1992 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
1993 // |------------------------|-----------------|------------------|-----------------|
1994 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
1995 // |------------------------|-----------------|------------------|-----------------|
1997 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
1998 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
1999 // From the above table, we could know 2.1Mbytes per second is lowest one.
2000 // The timout value is rounded up to nearest integar and here an additional 30s is added
2001 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2002 // commands in the Standby/Idle mode.
2004 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2006 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2007 if (!ScsiDiskDevice
->Cdb16Byte
) {
2008 Status
= ScsiDiskWrite10 (
2018 Status
= ScsiDiskWrite16 (
2028 if (!EFI_ERROR (Status
)) {
2033 return EFI_DEVICE_ERROR
;
2037 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2038 return EFI_DEVICE_ERROR
;
2041 // actual transferred sectors
2043 SectorCount
= ByteCount
/ BlockSize
;
2046 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2047 BlocksRemaining
-= SectorCount
;
2055 Submit Read(10) command.
2057 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2058 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2059 @param Timeout The time to complete the command
2060 @param DataBuffer The buffer to fill with the read out data
2061 @param DataLength The length of buffer
2062 @param StartLba The start logic block address
2063 @param SectorCount The number of blocks to read
2065 @return EFI_STATUS is returned by calling ScsiRead10Command().
2069 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2070 OUT BOOLEAN
*NeedRetry
,
2072 OUT UINT8
*DataBuffer
,
2073 IN OUT UINT32
*DataLength
,
2075 IN UINT32 SectorCount
2078 UINT8 SenseDataLength
;
2080 EFI_STATUS ReturnStatus
;
2081 UINT8 HostAdapterStatus
;
2086 // Implement a backoff algorithem to resolve some compatibility issues that
2087 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2088 // big data in a single operation.
2089 // This algorithem will at first try to execute original request. If the request fails
2090 // with media error sense data or else, it will reduce the transfer length to half and
2091 // try again till the operation succeeds or fails with one sector transfer length.
2095 Action
= ACTION_NO_ACTION
;
2096 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2097 ReturnStatus
= ScsiRead10Command (
2098 ScsiDiskDevice
->ScsiIo
,
2100 ScsiDiskDevice
->SenseData
,
2110 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
2112 return EFI_DEVICE_ERROR
;
2113 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2115 return ReturnStatus
;
2119 // go ahead to check HostAdapterStatus and TargetStatus
2120 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2122 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2123 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2125 return EFI_DEVICE_ERROR
;
2126 } else if (Status
== EFI_DEVICE_ERROR
) {
2128 // reset the scsi channel
2130 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2132 return EFI_DEVICE_ERROR
;
2135 Status
= CheckTargetStatus (TargetStatus
);
2136 if (Status
== EFI_NOT_READY
) {
2138 // reset the scsi device
2140 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2142 return EFI_DEVICE_ERROR
;
2143 } else if (Status
== EFI_DEVICE_ERROR
) {
2145 return EFI_DEVICE_ERROR
;
2148 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2149 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
2150 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2151 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2153 return EFI_DEVICE_ERROR
;
2154 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2155 if (SectorCount
<= 1) {
2157 // Jump out if the operation still fails with one sector transfer length.
2160 return EFI_DEVICE_ERROR
;
2163 // Try again with half length if the sense data shows we need to retry.
2166 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2170 return EFI_DEVICE_ERROR
;
2174 return ReturnStatus
;
2179 Submit Write(10) Command.
2181 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2182 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2183 @param Timeout The time to complete the command
2184 @param DataBuffer The buffer to fill with the read out data
2185 @param DataLength The length of buffer
2186 @param StartLba The start logic block address
2187 @param SectorCount The number of blocks to write
2189 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2194 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2195 OUT BOOLEAN
*NeedRetry
,
2197 IN UINT8
*DataBuffer
,
2198 IN OUT UINT32
*DataLength
,
2200 IN UINT32 SectorCount
2204 EFI_STATUS ReturnStatus
;
2205 UINT8 SenseDataLength
;
2206 UINT8 HostAdapterStatus
;
2211 // Implement a backoff algorithem to resolve some compatibility issues that
2212 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2213 // big data in a single operation.
2214 // This algorithem will at first try to execute original request. If the request fails
2215 // with media error sense data or else, it will reduce the transfer length to half and
2216 // try again till the operation succeeds or fails with one sector transfer length.
2220 Action
= ACTION_NO_ACTION
;
2221 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2222 ReturnStatus
= ScsiWrite10Command (
2223 ScsiDiskDevice
->ScsiIo
,
2225 ScsiDiskDevice
->SenseData
,
2234 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
2236 return EFI_DEVICE_ERROR
;
2237 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2239 return ReturnStatus
;
2243 // go ahead to check HostAdapterStatus and TargetStatus
2244 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2246 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2247 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2249 return EFI_DEVICE_ERROR
;
2250 } else if (Status
== EFI_DEVICE_ERROR
) {
2252 // reset the scsi channel
2254 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2256 return EFI_DEVICE_ERROR
;
2259 Status
= CheckTargetStatus (TargetStatus
);
2260 if (Status
== EFI_NOT_READY
) {
2262 // reset the scsi device
2264 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2266 return EFI_DEVICE_ERROR
;
2267 } else if (Status
== EFI_DEVICE_ERROR
) {
2269 return EFI_DEVICE_ERROR
;
2272 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2273 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
2274 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2275 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2277 return EFI_DEVICE_ERROR
;
2278 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2279 if (SectorCount
<= 1) {
2281 // Jump out if the operation still fails with one sector transfer length.
2284 return EFI_DEVICE_ERROR
;
2287 // Try again with half length if the sense data shows we need to retry.
2290 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2294 return EFI_DEVICE_ERROR
;
2298 return ReturnStatus
;
2303 Submit Read(16) command.
2305 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2306 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2307 @param Timeout The time to complete the command
2308 @param DataBuffer The buffer to fill with the read out data
2309 @param DataLength The length of buffer
2310 @param StartLba The start logic block address
2311 @param SectorCount The number of blocks to read
2313 @return EFI_STATUS is returned by calling ScsiRead16Command().
2317 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2318 OUT BOOLEAN
*NeedRetry
,
2320 OUT UINT8
*DataBuffer
,
2321 IN OUT UINT32
*DataLength
,
2323 IN UINT32 SectorCount
2326 UINT8 SenseDataLength
;
2328 EFI_STATUS ReturnStatus
;
2329 UINT8 HostAdapterStatus
;
2334 // Implement a backoff algorithem to resolve some compatibility issues that
2335 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2336 // big data in a single operation.
2337 // This algorithem will at first try to execute original request. If the request fails
2338 // with media error sense data or else, it will reduce the transfer length to half and
2339 // try again till the operation succeeds or fails with one sector transfer length.
2343 Action
= ACTION_NO_ACTION
;
2344 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2345 ReturnStatus
= ScsiRead16Command (
2346 ScsiDiskDevice
->ScsiIo
,
2348 ScsiDiskDevice
->SenseData
,
2357 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
2359 return EFI_DEVICE_ERROR
;
2360 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2362 return ReturnStatus
;
2366 // go ahead to check HostAdapterStatus and TargetStatus
2367 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2369 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2370 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2372 return EFI_DEVICE_ERROR
;
2373 } else if (Status
== EFI_DEVICE_ERROR
) {
2375 // reset the scsi channel
2377 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2379 return EFI_DEVICE_ERROR
;
2382 Status
= CheckTargetStatus (TargetStatus
);
2383 if (Status
== EFI_NOT_READY
) {
2385 // reset the scsi device
2387 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2389 return EFI_DEVICE_ERROR
;
2390 } else if (Status
== EFI_DEVICE_ERROR
) {
2392 return EFI_DEVICE_ERROR
;
2395 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2396 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
2397 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2398 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2400 return EFI_DEVICE_ERROR
;
2401 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2402 if (SectorCount
<= 1) {
2404 // Jump out if the operation still fails with one sector transfer length.
2407 return EFI_DEVICE_ERROR
;
2410 // Try again with half length if the sense data shows we need to retry.
2413 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2417 return EFI_DEVICE_ERROR
;
2421 return ReturnStatus
;
2426 Submit Write(16) Command.
2428 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2429 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2430 @param Timeout The time to complete the command
2431 @param DataBuffer The buffer to fill with the read out data
2432 @param DataLength The length of buffer
2433 @param StartLba The start logic block address
2434 @param SectorCount The number of blocks to write
2436 @return EFI_STATUS is returned by calling ScsiWrite16Command().
2441 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2442 OUT BOOLEAN
*NeedRetry
,
2444 IN UINT8
*DataBuffer
,
2445 IN OUT UINT32
*DataLength
,
2447 IN UINT32 SectorCount
2451 EFI_STATUS ReturnStatus
;
2452 UINT8 SenseDataLength
;
2453 UINT8 HostAdapterStatus
;
2458 // Implement a backoff algorithem to resolve some compatibility issues that
2459 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2460 // big data in a single operation.
2461 // This algorithem will at first try to execute original request. If the request fails
2462 // with media error sense data or else, it will reduce the transfer length to half and
2463 // try again till the operation succeeds or fails with one sector transfer length.
2467 Action
= ACTION_NO_ACTION
;
2468 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2469 ReturnStatus
= ScsiWrite16Command (
2470 ScsiDiskDevice
->ScsiIo
,
2472 ScsiDiskDevice
->SenseData
,
2481 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
2483 return EFI_DEVICE_ERROR
;
2484 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2486 return ReturnStatus
;
2490 // go ahead to check HostAdapterStatus and TargetStatus
2491 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2493 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2494 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2496 return EFI_DEVICE_ERROR
;
2497 } else if (Status
== EFI_DEVICE_ERROR
) {
2499 // reset the scsi channel
2501 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2503 return EFI_DEVICE_ERROR
;
2506 Status
= CheckTargetStatus (TargetStatus
);
2507 if (Status
== EFI_NOT_READY
) {
2509 // reset the scsi device
2511 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2513 return EFI_DEVICE_ERROR
;
2514 } else if (Status
== EFI_DEVICE_ERROR
) {
2516 return EFI_DEVICE_ERROR
;
2519 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2520 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
2521 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2522 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2524 return EFI_DEVICE_ERROR
;
2525 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2526 if (SectorCount
<= 1) {
2528 // Jump out if the operation still fails with one sector transfer length.
2531 return EFI_DEVICE_ERROR
;
2534 // Try again with half length if the sense data shows we need to retry.
2537 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2541 return EFI_DEVICE_ERROR
;
2545 return ReturnStatus
;
2550 Check sense key to find if media presents.
2552 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2553 @param SenseCounts The number of sense key
2555 @retval TRUE NOT any media
2556 @retval FALSE Media presents
2560 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2561 IN UINTN SenseCounts
2564 EFI_SCSI_SENSE_DATA
*SensePtr
;
2569 SensePtr
= SenseData
;
2571 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2573 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2574 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2576 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
2577 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
2590 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2591 @param SenseCounts The number of sense key
2594 @retval FALSE NOT error
2598 ScsiDiskIsMediaError (
2599 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2600 IN UINTN SenseCounts
2603 EFI_SCSI_SENSE_DATA
*SensePtr
;
2608 SensePtr
= SenseData
;
2610 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2612 switch (SensePtr
->Sense_Key
) {
2614 case EFI_SCSI_SK_MEDIUM_ERROR
:
2616 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2618 switch (SensePtr
->Addnl_Sense_Code
) {
2623 case EFI_SCSI_ASC_MEDIA_ERR1
:
2628 case EFI_SCSI_ASC_MEDIA_ERR2
:
2633 case EFI_SCSI_ASC_MEDIA_ERR3
:
2634 case EFI_SCSI_ASC_MEDIA_ERR4
:
2644 case EFI_SCSI_SK_NOT_READY
:
2646 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2648 switch (SensePtr
->Addnl_Sense_Code
) {
2650 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2652 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2673 Check sense key to find if hardware error happens.
2675 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2676 @param SenseCounts The number of sense key
2678 @retval TRUE Hardware error exits.
2679 @retval FALSE NO error.
2683 ScsiDiskIsHardwareError (
2684 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2685 IN UINTN SenseCounts
2688 EFI_SCSI_SENSE_DATA
*SensePtr
;
2693 SensePtr
= SenseData
;
2695 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2698 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2700 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2712 Check sense key to find if media has changed.
2714 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2715 @param SenseCounts The number of sense key
2717 @retval TRUE Media is changed.
2718 @retval FALSE Media is NOT changed.
2721 ScsiDiskIsMediaChange (
2722 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2723 IN UINTN SenseCounts
2726 EFI_SCSI_SENSE_DATA
*SensePtr
;
2728 BOOLEAN IsMediaChanged
;
2730 IsMediaChanged
= FALSE
;
2731 SensePtr
= SenseData
;
2733 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2735 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2736 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2738 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2739 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2740 IsMediaChanged
= TRUE
;
2746 return IsMediaChanged
;
2750 Check sense key to find if reset happens.
2752 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2753 @param SenseCounts The number of sense key
2755 @retval TRUE It is reset before.
2756 @retval FALSE It is NOT reset before.
2760 ScsiDiskIsResetBefore (
2761 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2762 IN UINTN SenseCounts
2765 EFI_SCSI_SENSE_DATA
*SensePtr
;
2767 BOOLEAN IsResetBefore
;
2769 IsResetBefore
= FALSE
;
2770 SensePtr
= SenseData
;
2772 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2775 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2776 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2778 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2779 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2780 IsResetBefore
= TRUE
;
2786 return IsResetBefore
;
2790 Check sense key to find if the drive is ready.
2792 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2793 @param SenseCounts The number of sense key
2794 @param RetryLater The flag means if need a retry
2796 @retval TRUE Drive is ready.
2797 @retval FALSE Drive is NOT ready.
2801 ScsiDiskIsDriveReady (
2802 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2803 IN UINTN SenseCounts
,
2804 OUT BOOLEAN
*RetryLater
2807 EFI_SCSI_SENSE_DATA
*SensePtr
;
2812 *RetryLater
= FALSE
;
2813 SensePtr
= SenseData
;
2815 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2817 switch (SensePtr
->Sense_Key
) {
2819 case EFI_SCSI_SK_NOT_READY
:
2821 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2823 switch (SensePtr
->Addnl_Sense_Code
) {
2824 case EFI_SCSI_ASC_NOT_READY
:
2826 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2828 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2829 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2831 // Additional Sense Code Qualifier is
2832 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2840 *RetryLater
= FALSE
;
2861 Check sense key to find if it has sense key.
2863 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2864 @param SenseCounts - The number of sense key
2866 @retval TRUE It has sense key.
2867 @retval FALSE It has NOT any sense key.
2871 ScsiDiskHaveSenseKey (
2872 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2873 IN UINTN SenseCounts
2876 EFI_SCSI_SENSE_DATA
*SensePtr
;
2878 BOOLEAN HaveSenseKey
;
2880 if (SenseCounts
== 0) {
2881 HaveSenseKey
= FALSE
;
2883 HaveSenseKey
= TRUE
;
2886 SensePtr
= SenseData
;
2888 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2891 // Sense Key is SK_NO_SENSE (0x0)
2893 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2895 HaveSenseKey
= FALSE
;
2901 return HaveSenseKey
;
2905 Release resource about disk device.
2907 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2911 ReleaseScsiDiskDeviceResources (
2912 IN SCSI_DISK_DEV
*ScsiDiskDevice
2915 if (ScsiDiskDevice
== NULL
) {
2919 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2920 FreePool (ScsiDiskDevice
->SenseData
);
2921 ScsiDiskDevice
->SenseData
= NULL
;
2924 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2925 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2926 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2929 FreePool (ScsiDiskDevice
);
2931 ScsiDiskDevice
= NULL
;
2935 Determine if Block Io should be produced.
2938 @param ChildHandle Child Handle to retrieve Parent information.
2940 @retval TRUE Should produce Block Io.
2941 @retval FALSE Should not produce Block Io.
2945 DetermineInstallBlockIo (
2946 IN EFI_HANDLE ChildHandle
2949 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2950 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2953 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2954 // check its attribute, logic or physical.
2956 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2957 if (ExtScsiPassThru
!= NULL
) {
2958 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2964 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2965 // check its attribute, logic or physical.
2967 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2968 if (ScsiPassThru
!= NULL
) {
2969 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2978 Search protocol database and check to see if the protocol
2979 specified by ProtocolGuid is present on a ControllerHandle and opened by
2980 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2981 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2982 will be opened on it.
2985 @param ProtocolGuid ProtocolGuid pointer.
2986 @param ChildHandle Child Handle to retrieve Parent information.
2992 IN EFI_GUID
*ProtocolGuid
,
2993 IN EFI_HANDLE ChildHandle
3000 EFI_HANDLE
*HandleBuffer
;
3003 // Retrieve the list of all handles from the handle database
3005 Status
= gBS
->LocateHandleBuffer (
3013 if (EFI_ERROR (Status
)) {
3018 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
3020 for (Index
= 0; Index
< HandleCount
; Index
++) {
3021 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
3022 if (!EFI_ERROR (Status
)) {
3023 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
3024 if (!EFI_ERROR (Status
)) {
3025 gBS
->FreePool (HandleBuffer
);
3031 gBS
->FreePool (HandleBuffer
);
3036 Provides inquiry information for the controller type.
3038 This function is used by the IDE bus driver to get inquiry data. Data format
3039 of Identify data is defined by the Interface GUID.
3041 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
3042 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
3043 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
3045 @retval EFI_SUCCESS The command was accepted without any errors.
3046 @retval EFI_NOT_FOUND Device does not support this data class
3047 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
3048 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
3053 ScsiDiskInfoInquiry (
3054 IN EFI_DISK_INFO_PROTOCOL
*This
,
3055 IN OUT VOID
*InquiryData
,
3056 IN OUT UINT32
*InquiryDataSize
3060 SCSI_DISK_DEV
*ScsiDiskDevice
;
3062 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
3064 Status
= EFI_BUFFER_TOO_SMALL
;
3065 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
3066 Status
= EFI_SUCCESS
;
3067 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
3069 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
3075 Provides identify information for the controller type.
3077 This function is used by the IDE bus driver to get identify data. Data format
3078 of Identify data is defined by the Interface GUID.
3080 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
3082 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
3083 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
3086 @retval EFI_SUCCESS The command was accepted without any errors.
3087 @retval EFI_NOT_FOUND Device does not support this data class
3088 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
3089 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
3094 ScsiDiskInfoIdentify (
3095 IN EFI_DISK_INFO_PROTOCOL
*This
,
3096 IN OUT VOID
*IdentifyData
,
3097 IN OUT UINT32
*IdentifyDataSize
3101 SCSI_DISK_DEV
*ScsiDiskDevice
;
3103 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
3105 // Physical SCSI bus does not support this data class.
3107 return EFI_NOT_FOUND
;
3110 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
3112 Status
= EFI_BUFFER_TOO_SMALL
;
3113 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
3114 Status
= EFI_SUCCESS
;
3115 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
3117 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
3122 Provides sense data information for the controller type.
3124 This function is used by the IDE bus driver to get sense data.
3125 Data format of Sense data is defined by the Interface GUID.
3127 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
3128 @param[in, out] SenseData Pointer to the SenseData.
3129 @param[in, out] SenseDataSize Size of SenseData in bytes.
3130 @param[out] SenseDataNumber Pointer to the value for the sense data size.
3132 @retval EFI_SUCCESS The command was accepted without any errors.
3133 @retval EFI_NOT_FOUND Device does not support this data class.
3134 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
3135 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
3140 ScsiDiskInfoSenseData (
3141 IN EFI_DISK_INFO_PROTOCOL
*This
,
3142 IN OUT VOID
*SenseData
,
3143 IN OUT UINT32
*SenseDataSize
,
3144 OUT UINT8
*SenseDataNumber
3147 return EFI_NOT_FOUND
;
3152 This function is used by the IDE bus driver to get controller information.
3154 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
3155 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
3156 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
3158 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
3159 @retval EFI_UNSUPPORTED This is not an IDE device.
3164 ScsiDiskInfoWhichIde (
3165 IN EFI_DISK_INFO_PROTOCOL
*This
,
3166 OUT UINT32
*IdeChannel
,
3167 OUT UINT32
*IdeDevice
3170 SCSI_DISK_DEV
*ScsiDiskDevice
;
3172 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
3174 // This is not an IDE physical device.
3176 return EFI_UNSUPPORTED
;
3179 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
3180 *IdeChannel
= ScsiDiskDevice
->Channel
;
3181 *IdeDevice
= ScsiDiskDevice
->Device
;
3188 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
3190 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
3191 implement Identify() interface for DiskInfo protocol. The ATA command is sent
3192 via SCSI Request Packet.
3194 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3196 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
3197 @retval others Some error occurred during the identification that ATAPI device.
3201 AtapiIdentifyDevice (
3202 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
3205 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
3209 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
3211 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
3212 ZeroMem (Cdb
, sizeof (Cdb
));
3214 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
3215 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
3216 CommandPacket
.Cdb
= Cdb
;
3217 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
3218 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
3219 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
3221 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
3226 Initialize the installation of DiskInfo protocol.
3228 This function prepares for the installation of DiskInfo protocol on the child handle.
3229 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
3230 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
3231 to be IDE/AHCI interface GUID.
3233 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3234 @param ChildHandle Child handle to install DiskInfo protocol.
3238 InitializeInstallDiskInfo (
3239 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3240 IN EFI_HANDLE ChildHandle
3244 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
3245 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
3246 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
3247 SATA_DEVICE_PATH
*SataDevicePath
;
3248 UINTN IdentifyRetry
;
3250 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
3252 // Device Path protocol must be installed on the device handle.
3254 ASSERT_EFI_ERROR (Status
);
3256 // Copy the DiskInfo protocol template.
3258 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
3260 while (!IsDevicePathEnd (DevicePathNode
)) {
3261 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
3262 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
3263 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
3264 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
3265 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
3266 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
3271 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
3272 // with IDE/AHCI interface GUID.
3274 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
3275 if (!EFI_ERROR (Status
)) {
3276 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
3278 // We find the valid ATAPI device path
3280 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
3281 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
3282 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
3284 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
3286 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
3289 // We find the valid SATA device path
3291 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
3292 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
3293 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
3295 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
3297 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
3301 } while (--IdentifyRetry
> 0);
3302 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
3303 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
3304 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
3307 DevicePathNode
= ChildDevicePathNode
;