2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
19 ScsiDiskDriverBindingSupported
,
20 ScsiDiskDriverBindingStart
,
21 ScsiDiskDriverBindingStop
,
27 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate
= {
28 EFI_DISK_INFO_SCSI_INTERFACE_GUID
,
31 ScsiDiskInfoSenseData
,
36 The user Entry Point for module ScsiDisk.
38 The user code starts with this function.
40 @param ImageHandle The firmware allocated handle for the EFI image.
41 @param SystemTable A pointer to the EFI System Table.
43 @retval EFI_SUCCESS The entry point is executed successfully.
44 @retval other Some error occurs when executing this entry point.
50 IN EFI_HANDLE ImageHandle
,
51 IN EFI_SYSTEM_TABLE
*SystemTable
57 // Install driver model protocol(s).
59 Status
= EfiLibInstallDriverBindingComponentName2 (
62 &gScsiDiskDriverBinding
,
64 &gScsiDiskComponentName
,
65 &gScsiDiskComponentName2
67 ASSERT_EFI_ERROR (Status
);
74 Test to see if this driver supports ControllerHandle.
76 This service is called by the EFI boot service ConnectController(). In order
77 to make drivers as small as possible, there are a few calling restrictions for
78 this service. ConnectController() must follow these calling restrictions.
79 If any other agent wishes to call Supported() it must also follow these
82 @param This Protocol instance pointer.
83 @param ControllerHandle Handle of device to test
84 @param RemainingDevicePath Optional parameter use to pick a specific child
87 @retval EFI_SUCCESS This driver supports this device
88 @retval EFI_ALREADY_STARTED This driver is already running on this device
89 @retval other This driver does not support this device
94 ScsiDiskDriverBindingSupported (
95 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
96 IN EFI_HANDLE Controller
,
97 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
101 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
104 Status
= gBS
->OpenProtocol (
106 &gEfiScsiIoProtocolGuid
,
108 This
->DriverBindingHandle
,
110 EFI_OPEN_PROTOCOL_BY_DRIVER
112 if (EFI_ERROR (Status
)) {
116 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
117 if (!EFI_ERROR (Status
)) {
118 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
119 Status
= EFI_SUCCESS
;
121 Status
= EFI_UNSUPPORTED
;
127 &gEfiScsiIoProtocolGuid
,
128 This
->DriverBindingHandle
,
136 Start this driver on ControllerHandle.
138 This service is called by the EFI boot service ConnectController(). In order
139 to make drivers as small as possible, there are a few calling restrictions for
140 this service. ConnectController() must follow these calling restrictions. If
141 any other agent wishes to call Start() it must also follow these calling
144 @param This Protocol instance pointer.
145 @param ControllerHandle Handle of device to bind driver to
146 @param RemainingDevicePath Optional parameter use to pick a specific child
149 @retval EFI_SUCCESS This driver is added to ControllerHandle
150 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
151 @retval other This driver does not support this device
156 ScsiDiskDriverBindingStart (
157 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
158 IN EFI_HANDLE Controller
,
159 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
163 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
164 SCSI_DISK_DEV
*ScsiDiskDevice
;
170 ScsiDiskDevice
= (SCSI_DISK_DEV
*) AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
171 if (ScsiDiskDevice
== NULL
) {
172 return EFI_OUT_OF_RESOURCES
;
175 Status
= gBS
->OpenProtocol (
177 &gEfiScsiIoProtocolGuid
,
179 This
->DriverBindingHandle
,
181 EFI_OPEN_PROTOCOL_BY_DRIVER
183 if (EFI_ERROR (Status
)) {
184 FreePool (ScsiDiskDevice
);
188 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
189 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
190 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
191 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
192 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
193 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
194 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
195 ScsiDiskDevice
->Handle
= Controller
;
197 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
198 switch (ScsiDiskDevice
->DeviceType
) {
199 case EFI_SCSI_TYPE_DISK
:
200 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
203 case EFI_SCSI_TYPE_CDROM
:
204 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
208 // The Sense Data Array's initial size is 6
210 ScsiDiskDevice
->SenseDataNumber
= 6;
211 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
212 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
214 if (ScsiDiskDevice
->SenseData
== NULL
) {
217 &gEfiScsiIoProtocolGuid
,
218 This
->DriverBindingHandle
,
221 FreePool (ScsiDiskDevice
);
222 return EFI_OUT_OF_RESOURCES
;
226 // Retrieve device information
229 for (Index
= 0; Index
< MaxRetry
; Index
++) {
230 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
231 if (!EFI_ERROR (Status
)) {
236 FreePool (ScsiDiskDevice
->SenseData
);
239 &gEfiScsiIoProtocolGuid
,
240 This
->DriverBindingHandle
,
243 FreePool (ScsiDiskDevice
);
244 return EFI_DEVICE_ERROR
;
248 // The second parameter "TRUE" means must
249 // retrieve media capacity
251 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, TRUE
, &Temp
);
252 if (!EFI_ERROR (Status
)) {
254 // Determine if Block IO should be produced on this controller handle
256 if (DetermineInstallBlockIo(Controller
)) {
257 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
258 Status
= gBS
->InstallMultipleProtocolInterfaces (
260 &gEfiBlockIoProtocolGuid
,
261 &ScsiDiskDevice
->BlkIo
,
262 &gEfiDiskInfoProtocolGuid
,
263 &ScsiDiskDevice
->DiskInfo
,
266 if (!EFI_ERROR(Status
)) {
267 ScsiDiskDevice
->ControllerNameTable
= NULL
;
270 gScsiDiskComponentName
.SupportedLanguages
,
271 &ScsiDiskDevice
->ControllerNameTable
,
277 gScsiDiskComponentName2
.SupportedLanguages
,
278 &ScsiDiskDevice
->ControllerNameTable
,
287 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
288 gBS
->FreePool (ScsiDiskDevice
);
291 &gEfiScsiIoProtocolGuid
,
292 This
->DriverBindingHandle
,
301 Stop this driver on ControllerHandle.
303 This service is called by the EFI boot service DisconnectController().
304 In order to make drivers as small as possible, there are a few calling
305 restrictions for this service. DisconnectController() must follow these
306 calling restrictions. If any other agent wishes to call Stop() it must
307 also follow these calling restrictions.
309 @param This Protocol instance pointer.
310 @param ControllerHandle Handle of device to stop driver on
311 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
312 children is zero stop the entire bus driver.
313 @param ChildHandleBuffer List of Child Handles to Stop.
315 @retval EFI_SUCCESS This driver is removed ControllerHandle
316 @retval other This driver was not removed from this device
321 ScsiDiskDriverBindingStop (
322 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
323 IN EFI_HANDLE Controller
,
324 IN UINTN NumberOfChildren
,
325 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
328 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
329 SCSI_DISK_DEV
*ScsiDiskDevice
;
332 Status
= gBS
->OpenProtocol (
334 &gEfiBlockIoProtocolGuid
,
336 This
->DriverBindingHandle
,
338 EFI_OPEN_PROTOCOL_GET_PROTOCOL
340 if (EFI_ERROR (Status
)) {
344 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
345 Status
= gBS
->UninstallMultipleProtocolInterfaces (
347 &gEfiBlockIoProtocolGuid
,
348 &ScsiDiskDevice
->BlkIo
,
349 &gEfiDiskInfoProtocolGuid
,
350 &ScsiDiskDevice
->DiskInfo
,
353 if (!EFI_ERROR (Status
)) {
356 &gEfiScsiIoProtocolGuid
,
357 This
->DriverBindingHandle
,
361 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
375 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
376 @param ExtendedVerification The flag about if extend verificate
378 @retval EFI_SUCCESS The device was reset.
379 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
381 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
387 IN EFI_BLOCK_IO_PROTOCOL
*This
,
388 IN BOOLEAN ExtendedVerification
392 SCSI_DISK_DEV
*ScsiDiskDevice
;
395 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
397 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
399 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
401 if (EFI_ERROR (Status
)) {
402 Status
= EFI_DEVICE_ERROR
;
406 if (!ExtendedVerification
) {
410 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
412 if (EFI_ERROR (Status
)) {
413 Status
= EFI_DEVICE_ERROR
;
418 gBS
->RestoreTPL (OldTpl
);
423 The function is to Read Block from SCSI Disk.
425 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
426 @param MediaId The Id of Media detected
427 @param Lba The logic block address
428 @param BufferSize The size of Buffer
429 @param Buffer The buffer to fill the read out data
431 @retval EFI_SUCCESS Successfully to read out block.
432 @retval EFI_DEVICE_ERROR Fail to detect media.
433 @retval EFI_NO_MEDIA Media is not present.
434 @retval EFI_MEDIA_CHANGED Media has changed.
435 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
436 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
442 IN EFI_BLOCK_IO_PROTOCOL
*This
,
449 SCSI_DISK_DEV
*ScsiDiskDevice
;
450 EFI_BLOCK_IO_MEDIA
*Media
;
453 UINTN NumberOfBlocks
;
458 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
459 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
461 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
463 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
464 if (EFI_ERROR (Status
)) {
465 Status
= EFI_DEVICE_ERROR
;
470 gBS
->ReinstallProtocolInterface (
471 ScsiDiskDevice
->Handle
,
472 &gEfiBlockIoProtocolGuid
,
473 &ScsiDiskDevice
->BlkIo
,
474 &ScsiDiskDevice
->BlkIo
479 // Get the intrinsic block size
481 Media
= ScsiDiskDevice
->BlkIo
.Media
;
482 BlockSize
= Media
->BlockSize
;
484 NumberOfBlocks
= BufferSize
/ BlockSize
;
486 if (!(Media
->MediaPresent
)) {
487 Status
= EFI_NO_MEDIA
;
491 if (MediaId
!= Media
->MediaId
) {
492 Status
= EFI_MEDIA_CHANGED
;
496 if (Buffer
== NULL
) {
497 Status
= EFI_INVALID_PARAMETER
;
501 if (BufferSize
== 0) {
502 Status
= EFI_SUCCESS
;
506 if (BufferSize
% BlockSize
!= 0) {
507 Status
= EFI_BAD_BUFFER_SIZE
;
511 if (Lba
> Media
->LastBlock
) {
512 Status
= EFI_INVALID_PARAMETER
;
516 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
517 Status
= EFI_INVALID_PARAMETER
;
521 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
522 Status
= EFI_INVALID_PARAMETER
;
527 // If all the parameters are valid, then perform read sectors command
528 // to transfer data from device to host.
530 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
533 gBS
->RestoreTPL (OldTpl
);
538 The function is to Write Block to SCSI Disk.
540 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
541 @param MediaId The Id of Media detected
542 @param Lba The logic block address
543 @param BufferSize The size of Buffer
544 @param Buffer The buffer to fill the read out data
546 @retval EFI_SUCCESS Successfully to read out block.
547 @retval EFI_WRITE_PROTECTED The device can not be written to.
548 @retval EFI_DEVICE_ERROR Fail to detect media.
549 @retval EFI_NO_MEDIA Media is not present.
550 @retval EFI_MEDIA_CHNAGED Media has changed.
551 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
552 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
557 ScsiDiskWriteBlocks (
558 IN EFI_BLOCK_IO_PROTOCOL
*This
,
565 SCSI_DISK_DEV
*ScsiDiskDevice
;
566 EFI_BLOCK_IO_MEDIA
*Media
;
569 UINTN NumberOfBlocks
;
574 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
575 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
577 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
579 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
580 if (EFI_ERROR (Status
)) {
581 Status
= EFI_DEVICE_ERROR
;
586 gBS
->ReinstallProtocolInterface (
587 ScsiDiskDevice
->Handle
,
588 &gEfiBlockIoProtocolGuid
,
589 &ScsiDiskDevice
->BlkIo
,
590 &ScsiDiskDevice
->BlkIo
595 // Get the intrinsic block size
597 Media
= ScsiDiskDevice
->BlkIo
.Media
;
598 BlockSize
= Media
->BlockSize
;
600 NumberOfBlocks
= BufferSize
/ BlockSize
;
602 if (!(Media
->MediaPresent
)) {
603 Status
= EFI_NO_MEDIA
;
607 if (MediaId
!= Media
->MediaId
) {
608 Status
= EFI_MEDIA_CHANGED
;
612 if (BufferSize
== 0) {
613 Status
= EFI_SUCCESS
;
617 if (Buffer
== NULL
) {
618 Status
= EFI_INVALID_PARAMETER
;
622 if (BufferSize
% BlockSize
!= 0) {
623 Status
= EFI_BAD_BUFFER_SIZE
;
627 if (Lba
> Media
->LastBlock
) {
628 Status
= EFI_INVALID_PARAMETER
;
632 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
633 Status
= EFI_INVALID_PARAMETER
;
637 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
638 Status
= EFI_INVALID_PARAMETER
;
642 // if all the parameters are valid, then perform read sectors command
643 // to transfer data from device to host.
645 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
648 gBS
->RestoreTPL (OldTpl
);
655 EFI_SUCCESS is returned directly.
657 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
659 @retval EFI_SUCCESS All outstanding data was written to the device
664 ScsiDiskFlushBlocks (
665 IN EFI_BLOCK_IO_PROTOCOL
*This
676 Detect Device and read out capacity ,if error occurs, parse the sense key.
678 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
679 @param MustReadCapacity The flag about reading device capacity
680 @param MediaChange The pointer of flag indicates if media has changed
682 @retval EFI_DEVICE_ERROR Indicates that error occurs
683 @retval EFI_SUCCESS Successfully to detect media
687 ScsiDiskDetectMedia (
688 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
689 IN BOOLEAN MustReadCapacity
,
690 OUT BOOLEAN
*MediaChange
694 EFI_STATUS ReadCapacityStatus
;
695 EFI_SCSI_SENSE_DATA
*SenseData
;
696 UINTN NumberOfSenseKeys
;
698 BOOLEAN NeedReadCapacity
;
701 EFI_BLOCK_IO_MEDIA OldMedia
;
704 Status
= EFI_SUCCESS
;
705 ReadCapacityStatus
= EFI_SUCCESS
;
707 NumberOfSenseKeys
= 0;
708 NeedReadCapacity
= FALSE
;
709 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
710 *MediaChange
= FALSE
;
713 for (Index
= 0; Index
< MaxRetry
; Index
++) {
714 Status
= ScsiDiskTestUnitReady (
720 if (!EFI_ERROR (Status
)) {
729 if ((Index
== MaxRetry
) && EFI_ERROR (Status
)) {
730 return EFI_DEVICE_ERROR
;
733 Status
= DetectMediaParsingSenseKeys (
739 if (EFI_ERROR (Status
)) {
743 // ACTION_NO_ACTION: need not read capacity
744 // other action code: need read capacity
746 if (Action
== ACTION_NO_ACTION
) {
747 NeedReadCapacity
= FALSE
;
749 NeedReadCapacity
= TRUE
;
753 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
754 // retrieve capacity via Read Capacity command
756 if (NeedReadCapacity
|| MustReadCapacity
) {
758 // retrieve media information
761 for (Index
= 0; Index
< MaxRetry
; Index
++) {
763 ReadCapacityStatus
= ScsiDiskReadCapacity (
769 if (EFI_ERROR (ReadCapacityStatus
) && !NeedRetry
) {
770 return EFI_DEVICE_ERROR
;
773 // analyze sense key to action
775 Status
= DetectMediaParsingSenseKeys (
782 // if Status is error, it may indicate crisis error,
783 // so return without retry.
785 if (EFI_ERROR (Status
)) {
790 case ACTION_NO_ACTION
:
797 case ACTION_RETRY_COMMAND_LATER
:
799 // retry the ReadCapacity later and continuously, until the condition
800 // no longer emerges.
801 // stall time is 100000us, or say 0.1 second.
809 // other cases, just retry the command
815 if ((Index
== MaxRetry
) && EFI_ERROR (ReadCapacityStatus
)) {
816 return EFI_DEVICE_ERROR
;
820 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
822 // Media change information got from the device
827 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
829 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
832 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
834 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
837 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
839 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
842 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
843 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
845 // when change from no media to media present, reset the MediaId to 1.
847 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
850 // when no media, reset the MediaId to zero.
852 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
863 Send out Inquiry command to Device.
865 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
866 @param NeedRetry Indicates if needs try again when error happens
868 @retval EFI_DEVICE_ERROR Indicates that error occurs
869 @retval EFI_SUCCESS Successfully to detect media
873 ScsiDiskInquiryDevice (
874 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
875 OUT BOOLEAN
*NeedRetry
878 UINT32 InquiryDataLength
;
879 UINT8 SenseDataLength
;
880 UINT8 HostAdapterStatus
;
882 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
883 UINTN NumberOfSenseKeys
;
888 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
891 Status
= ScsiInquiryCommand (
892 ScsiDiskDevice
->ScsiIo
,
893 EFI_TIMER_PERIOD_SECONDS (1),
898 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
903 // no need to check HostAdapterStatus and TargetStatus
905 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
906 ParseInquiryData (ScsiDiskDevice
);
909 } else if (Status
== EFI_NOT_READY
) {
911 return EFI_DEVICE_ERROR
;
913 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
915 return EFI_DEVICE_ERROR
;
918 // go ahead to check HostAdapterStatus and TargetStatus
919 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
922 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
923 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
925 return EFI_DEVICE_ERROR
;
926 } else if (Status
== EFI_DEVICE_ERROR
) {
928 // reset the scsi channel
930 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
932 return EFI_DEVICE_ERROR
;
935 Status
= CheckTargetStatus (TargetStatus
);
936 if (Status
== EFI_NOT_READY
) {
938 // reset the scsi device
940 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
942 return EFI_DEVICE_ERROR
;
944 } else if (Status
== EFI_DEVICE_ERROR
) {
946 return EFI_DEVICE_ERROR
;
950 // if goes here, meant ScsiInquiryCommand() failed.
951 // if ScsiDiskRequestSenseKeys() succeeds at last,
952 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
955 for (Index
= 0; Index
< MaxRetry
; Index
++) {
956 Status
= ScsiDiskRequestSenseKeys (
963 if (!EFI_ERROR (Status
)) {
965 return EFI_DEVICE_ERROR
;
969 return EFI_DEVICE_ERROR
;
973 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
974 // set *NeedRetry = FALSE to avoid the outside caller try again.
977 return EFI_DEVICE_ERROR
;
983 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
984 When Test Unit Ready command encounters any error caused by host adapter or
985 target, return error without retrieving Sense Keys.
987 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
988 @param NeedRetry The pointer of flag indicates try again
989 @param SenseDataArray The pointer of an array of sense data
990 @param NumberOfSenseKeys The pointer of the number of sense data array
992 @retval EFI_DEVICE_ERROR Indicates that error occurs
993 @retval EFI_SUCCESS Successfully to test unit
997 ScsiDiskTestUnitReady (
998 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
999 OUT BOOLEAN
*NeedRetry
,
1000 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1001 OUT UINTN
*NumberOfSenseKeys
1005 UINT8 SenseDataLength
;
1006 UINT8 HostAdapterStatus
;
1011 SenseDataLength
= 0;
1012 *NumberOfSenseKeys
= 0;
1015 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1017 Status
= ScsiTestUnitReadyCommand (
1018 ScsiDiskDevice
->ScsiIo
,
1019 EFI_TIMER_PERIOD_SECONDS (1),
1026 // no need to check HostAdapterStatus and TargetStatus
1028 if (Status
== EFI_NOT_READY
) {
1030 return EFI_DEVICE_ERROR
;
1032 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1034 return EFI_DEVICE_ERROR
;
1037 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1040 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1041 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1043 return EFI_DEVICE_ERROR
;
1045 } else if (Status
== EFI_DEVICE_ERROR
) {
1047 // reset the scsi channel
1049 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1051 return EFI_DEVICE_ERROR
;
1054 Status
= CheckTargetStatus (TargetStatus
);
1055 if (Status
== EFI_NOT_READY
) {
1057 // reset the scsi device
1059 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1061 return EFI_DEVICE_ERROR
;
1063 } else if (Status
== EFI_DEVICE_ERROR
) {
1065 return EFI_DEVICE_ERROR
;
1069 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1070 Status
= ScsiDiskRequestSenseKeys (
1077 if (!EFI_ERROR (Status
)) {
1082 return EFI_DEVICE_ERROR
;
1086 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1087 // set *NeedRetry = FALSE to avoid the outside caller try again.
1090 return EFI_DEVICE_ERROR
;
1094 Parsing Sense Keys which got from request sense command.
1096 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1097 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1098 @param NumberOfSenseKeys The number of sense key
1099 @param Action The pointer of action which indicates what is need to do next
1101 @retval EFI_DEVICE_ERROR Indicates that error occurs
1102 @retval EFI_SUCCESS Successfully to complete the parsing
1106 DetectMediaParsingSenseKeys (
1107 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1108 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1109 IN UINTN NumberOfSenseKeys
,
1116 // Default is to read capacity, unless..
1118 *Action
= ACTION_READ_CAPACITY
;
1120 if (NumberOfSenseKeys
== 0) {
1121 *Action
= ACTION_NO_ACTION
;
1125 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1127 // No Sense Key returned from last submitted command
1129 *Action
= ACTION_NO_ACTION
;
1133 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1134 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1135 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1136 *Action
= ACTION_NO_ACTION
;
1140 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1141 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1145 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1146 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1147 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1148 return EFI_DEVICE_ERROR
;
1151 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1152 return EFI_DEVICE_ERROR
;
1155 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1157 *Action
= ACTION_RETRY_COMMAND_LATER
;
1161 return EFI_DEVICE_ERROR
;
1169 Send read capacity command to device and get the device parameter.
1171 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1172 @param NeedRetry The pointer of flag indicates if need a retry
1173 @param SenseDataArray The pointer of an array of sense data
1174 @param NumberOfSenseKeys The number of sense key
1176 @retval EFI_DEVICE_ERROR Indicates that error occurs
1177 @retval EFI_SUCCESS Successfully to read capacity
1181 ScsiDiskReadCapacity (
1182 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1183 OUT BOOLEAN
*NeedRetry
,
1184 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1185 OUT UINTN
*NumberOfSenseKeys
1188 UINT8 HostAdapterStatus
;
1190 EFI_STATUS CommandStatus
;
1194 UINT8 SenseDataLength
;
1195 UINT32 DataLength10
;
1196 UINT32 DataLength16
;
1197 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10
;
1198 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16
;
1201 SenseDataLength
= 0;
1202 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1203 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1204 ZeroMem (&CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1205 ZeroMem (&CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1207 *NumberOfSenseKeys
= 0;
1211 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1212 // 16 byte command should be used to access large hard disk >2TB
1214 CommandStatus
= ScsiReadCapacityCommand (
1215 ScsiDiskDevice
->ScsiIo
,
1216 EFI_TIMER_PERIOD_SECONDS(1),
1221 (VOID
*) &CapacityData10
,
1226 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1227 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
.LastLba3
== 0xff) && (CapacityData10
.LastLba2
== 0xff) &&
1228 (CapacityData10
.LastLba1
== 0xff) && (CapacityData10
.LastLba0
== 0xff)) {
1230 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1232 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1234 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1235 // and LowestAlignedLba
1237 CommandStatus
= ScsiReadCapacity16Command (
1238 ScsiDiskDevice
->ScsiIo
,
1239 EFI_TIMER_PERIOD_SECONDS (1),
1244 (VOID
*) &CapacityData16
,
1251 // no need to check HostAdapterStatus and TargetStatus
1253 if (CommandStatus
== EFI_SUCCESS
) {
1254 GetMediaInfo (ScsiDiskDevice
, &CapacityData10
,&CapacityData16
);
1257 } else if (CommandStatus
== EFI_NOT_READY
) {
1259 return EFI_DEVICE_ERROR
;
1261 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1263 return EFI_DEVICE_ERROR
;
1266 // go ahead to check HostAdapterStatus and TargetStatus
1267 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1270 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1271 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1273 return EFI_DEVICE_ERROR
;
1275 } else if (Status
== EFI_DEVICE_ERROR
) {
1277 // reset the scsi channel
1279 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1281 return EFI_DEVICE_ERROR
;
1284 Status
= CheckTargetStatus (TargetStatus
);
1285 if (Status
== EFI_NOT_READY
) {
1287 // reset the scsi device
1289 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1291 return EFI_DEVICE_ERROR
;
1293 } else if (Status
== EFI_DEVICE_ERROR
) {
1295 return EFI_DEVICE_ERROR
;
1299 // if goes here, meant ScsiReadCapacityCommand() failed.
1300 // if ScsiDiskRequestSenseKeys() succeeds at last,
1301 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1304 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1306 Status
= ScsiDiskRequestSenseKeys (
1313 if (!EFI_ERROR (Status
)) {
1315 return EFI_DEVICE_ERROR
;
1319 return EFI_DEVICE_ERROR
;
1323 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1324 // set *NeedRetry = FALSE to avoid the outside caller try again.
1327 return EFI_DEVICE_ERROR
;
1331 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1333 @param HostAdapterStatus Host Adapter status
1335 @retval EFI_SUCCESS Host adapter is OK.
1336 @retval EFI_TIMEOUT Timeout.
1337 @retval EFI_NOT_READY Adapter NOT ready.
1338 @retval EFI_DEVICE_ERROR Adapter device error.
1342 CheckHostAdapterStatus (
1343 IN UINT8 HostAdapterStatus
1346 switch (HostAdapterStatus
) {
1347 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1350 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1351 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1352 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1355 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1356 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1357 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1358 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1359 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1360 return EFI_NOT_READY
;
1362 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1363 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1364 return EFI_DEVICE_ERROR
;
1373 Check the target status and re-interpret it in EFI_STATUS.
1375 @param TargetStatus Target status
1377 @retval EFI_NOT_READY Device is NOT ready.
1378 @retval EFI_DEVICE_ERROR
1384 IN UINT8 TargetStatus
1387 switch (TargetStatus
) {
1388 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1389 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1390 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1393 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1394 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1395 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1396 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1397 return EFI_NOT_READY
;
1399 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1400 return EFI_DEVICE_ERROR
;
1410 Retrieve all sense keys from the device.
1412 When encountering error during the process, if retrieve sense keys before
1413 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1414 and NeedRetry set to FALSE; otherwize, return the proper return status.
1416 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1417 @param NeedRetry The pointer of flag indicates if need a retry
1418 @param SenseDataArray The pointer of an array of sense data
1419 @param NumberOfSenseKeys The number of sense key
1420 @param AskResetIfError The flag indicates if need reset when error occurs
1422 @retval EFI_DEVICE_ERROR Indicates that error occurs
1423 @retval EFI_SUCCESS Successfully to request sense key
1427 ScsiDiskRequestSenseKeys (
1428 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1429 OUT BOOLEAN
*NeedRetry
,
1430 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1431 OUT UINTN
*NumberOfSenseKeys
,
1432 IN BOOLEAN AskResetIfError
1435 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1436 UINT8 SenseDataLength
;
1439 EFI_STATUS FallStatus
;
1440 UINT8 HostAdapterStatus
;
1443 FallStatus
= EFI_SUCCESS
;
1444 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1447 ScsiDiskDevice
->SenseData
,
1448 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1451 *NumberOfSenseKeys
= 0;
1452 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1453 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1455 for (SenseReq
= TRUE
; SenseReq
;) {
1456 Status
= ScsiRequestSenseCommand (
1457 ScsiDiskDevice
->ScsiIo
,
1458 EFI_TIMER_PERIOD_SECONDS (2),
1464 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1465 FallStatus
= EFI_SUCCESS
;
1467 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1469 FallStatus
= EFI_DEVICE_ERROR
;
1471 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1473 FallStatus
= EFI_DEVICE_ERROR
;
1475 } else if (Status
== EFI_DEVICE_ERROR
) {
1476 if (AskResetIfError
) {
1477 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1480 FallStatus
= EFI_DEVICE_ERROR
;
1483 if (EFI_ERROR (FallStatus
)) {
1484 if (*NumberOfSenseKeys
!= 0) {
1488 return EFI_DEVICE_ERROR
;
1492 (*NumberOfSenseKeys
) += 1;
1495 // no more sense key or number of sense keys exceeds predefined,
1498 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1499 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1509 Get information from media read capacity command.
1511 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1512 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1513 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1518 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1519 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1520 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1525 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1526 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 1;
1529 if (!ScsiDiskDevice
->Cdb16Byte
) {
1530 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1531 (Capacity10
->LastLba2
<< 16) |
1532 (Capacity10
->LastLba1
<< 8) |
1533 Capacity10
->LastLba0
;
1535 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1536 (Capacity10
->BlockSize2
<< 16) |
1537 (Capacity10
->BlockSize1
<< 8) |
1538 Capacity10
->BlockSize0
;
1539 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
1542 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1543 *Ptr
++ = Capacity16
->LastLba0
;
1544 *Ptr
++ = Capacity16
->LastLba1
;
1545 *Ptr
++ = Capacity16
->LastLba2
;
1546 *Ptr
++ = Capacity16
->LastLba3
;
1547 *Ptr
++ = Capacity16
->LastLba4
;
1548 *Ptr
++ = Capacity16
->LastLba5
;
1549 *Ptr
++ = Capacity16
->LastLba6
;
1550 *Ptr
= Capacity16
->LastLba7
;
1552 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1553 (Capacity16
->BlockSize2
<< 16) |
1554 (Capacity16
->BlockSize1
<< 8) |
1555 Capacity16
->BlockSize0
;
1557 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8)|(Capacity16
->LowestAlignLogic1
);
1558 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= Capacity16
->LogicPerPhysical
;
1559 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION2
;
1563 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1565 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1566 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1569 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1570 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1577 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1582 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1585 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1586 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1590 Read sector from SCSI Disk.
1592 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1593 @param Buffer The buffer to fill in the read out data
1594 @param Lba Logic block address
1595 @param NumberOfBlocks The number of blocks to read
1597 @retval EFI_DEVICE_ERROR Indicates a device error.
1598 @retval EFI_SUCCESS Operation is successful.
1602 ScsiDiskReadSectors (
1603 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1606 IN UINTN NumberOfBlocks
1609 UINTN BlocksRemaining
;
1620 EFI_SCSI_SENSE_DATA
*SenseData
;
1621 UINTN NumberOfSenseKeys
;
1624 NumberOfSenseKeys
= 0;
1626 Status
= EFI_SUCCESS
;
1628 BlocksRemaining
= NumberOfBlocks
;
1629 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1632 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1634 if (!ScsiDiskDevice
->Cdb16Byte
) {
1637 MaxBlock
= 0xFFFFFFFF;
1642 while (BlocksRemaining
> 0) {
1644 if (BlocksRemaining
<= MaxBlock
) {
1645 if (!ScsiDiskDevice
->Cdb16Byte
) {
1646 SectorCount
= (UINT16
) BlocksRemaining
;
1648 SectorCount
= (UINT32
) BlocksRemaining
;
1651 SectorCount
= MaxBlock
;
1654 ByteCount
= SectorCount
* BlockSize
;
1655 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1658 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1659 if (!ScsiDiskDevice
->Cdb16Byte
) {
1660 Status
= ScsiDiskRead10 (
1672 Status
= ScsiDiskRead16 (
1684 if (!EFI_ERROR (Status
)) {
1689 return EFI_DEVICE_ERROR
;
1694 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1695 return EFI_DEVICE_ERROR
;
1699 // actual transferred sectors
1701 SectorCount
= ByteCount
/ BlockSize
;
1704 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1705 BlocksRemaining
-= SectorCount
;
1712 Write sector to SCSI Disk.
1714 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1715 @param Buffer The buffer of data to be written into SCSI Disk
1716 @param Lba Logic block address
1717 @param NumberOfBlocks The number of blocks to read
1719 @retval EFI_DEVICE_ERROR Indicates a device error.
1720 @retval EFI_SUCCESS Operation is successful.
1724 ScsiDiskWriteSectors (
1725 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1728 IN UINTN NumberOfBlocks
1731 UINTN BlocksRemaining
;
1742 EFI_SCSI_SENSE_DATA
*SenseData
;
1743 UINTN NumberOfSenseKeys
;
1746 NumberOfSenseKeys
= 0;
1748 Status
= EFI_SUCCESS
;
1750 BlocksRemaining
= NumberOfBlocks
;
1751 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1754 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1756 if (!ScsiDiskDevice
->Cdb16Byte
) {
1759 MaxBlock
= 0xFFFFFFFF;
1764 while (BlocksRemaining
> 0) {
1766 if (BlocksRemaining
<= MaxBlock
) {
1767 if (!ScsiDiskDevice
->Cdb16Byte
) {
1768 SectorCount
= (UINT16
) BlocksRemaining
;
1770 SectorCount
= (UINT32
) BlocksRemaining
;
1773 SectorCount
= MaxBlock
;
1776 ByteCount
= SectorCount
* BlockSize
;
1777 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1779 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1780 if (!ScsiDiskDevice
->Cdb16Byte
) {
1781 Status
= ScsiDiskWrite10 (
1793 Status
= ScsiDiskWrite16 (
1805 if (!EFI_ERROR (Status
)) {
1810 return EFI_DEVICE_ERROR
;
1814 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1815 return EFI_DEVICE_ERROR
;
1818 // actual transferred sectors
1820 SectorCount
= ByteCount
/ BlockSize
;
1823 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1824 BlocksRemaining
-= SectorCount
;
1832 Submit Read(10) command.
1834 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1835 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1836 @param SenseDataArray NOT used yet in this function
1837 @param NumberOfSenseKeys The number of sense key
1838 @param Timeout The time to complete the command
1839 @param DataBuffer The buffer to fill with the read out data
1840 @param DataLength The length of buffer
1841 @param StartLba The start logic block address
1842 @param SectorSize The size of sector
1844 @return EFI_STATUS is returned by calling ScsiRead10Command().
1848 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1849 OUT BOOLEAN
*NeedRetry
,
1850 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1851 OUT UINTN
*NumberOfSenseKeys
,
1853 OUT UINT8
*DataBuffer
,
1854 IN OUT UINT32
*DataLength
,
1856 IN UINT32 SectorSize
1859 UINT8 SenseDataLength
;
1861 UINT8 HostAdapterStatus
;
1865 *NumberOfSenseKeys
= 0;
1866 SenseDataLength
= 0;
1867 Status
= ScsiRead10Command (
1868 ScsiDiskDevice
->ScsiIo
,
1884 Submit Write(10) Command.
1886 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1887 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1888 @param SenseDataArray NOT used yet in this function
1889 @param NumberOfSenseKeys The number of sense key
1890 @param Timeout The time to complete the command
1891 @param DataBuffer The buffer to fill with the read out data
1892 @param DataLength The length of buffer
1893 @param StartLba The start logic block address
1894 @param SectorSize The size of sector
1896 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1901 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1902 OUT BOOLEAN
*NeedRetry
,
1903 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1904 OUT UINTN
*NumberOfSenseKeys
,
1906 IN UINT8
*DataBuffer
,
1907 IN OUT UINT32
*DataLength
,
1909 IN UINT32 SectorSize
1913 UINT8 SenseDataLength
;
1914 UINT8 HostAdapterStatus
;
1918 *NumberOfSenseKeys
= 0;
1919 SenseDataLength
= 0;
1920 Status
= ScsiWrite10Command (
1921 ScsiDiskDevice
->ScsiIo
,
1937 Submit Read(16) command.
1939 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1940 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1941 @param SenseDataArray NOT used yet in this function
1942 @param NumberOfSenseKeys The number of sense key
1943 @param Timeout The time to complete the command
1944 @param DataBuffer The buffer to fill with the read out data
1945 @param DataLength The length of buffer
1946 @param StartLba The start logic block address
1947 @param SectorSize The size of sector
1949 @return EFI_STATUS is returned by calling ScsiRead10Command().
1953 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1954 OUT BOOLEAN
*NeedRetry
,
1955 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1956 OUT UINTN
*NumberOfSenseKeys
,
1958 OUT UINT8
*DataBuffer
,
1959 IN OUT UINT32
*DataLength
,
1961 IN UINT32 SectorSize
1964 UINT8 SenseDataLength
;
1966 UINT8 HostAdapterStatus
;
1970 *NumberOfSenseKeys
= 0;
1971 SenseDataLength
= 0;
1972 Status
= ScsiRead16Command (
1973 ScsiDiskDevice
->ScsiIo
,
1989 Submit Write(16) Command.
1991 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1992 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1993 @param SenseDataArray NOT used yet in this function
1994 @param NumberOfSenseKeys The number of sense key
1995 @param Timeout The time to complete the command
1996 @param DataBuffer The buffer to fill with the read out data
1997 @param DataLength The length of buffer
1998 @param StartLba The start logic block address
1999 @param SectorSize The size of sector
2001 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2006 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2007 OUT BOOLEAN
*NeedRetry
,
2008 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2009 OUT UINTN
*NumberOfSenseKeys
,
2011 IN UINT8
*DataBuffer
,
2012 IN OUT UINT32
*DataLength
,
2014 IN UINT32 SectorSize
2018 UINT8 SenseDataLength
;
2019 UINT8 HostAdapterStatus
;
2023 *NumberOfSenseKeys
= 0;
2024 SenseDataLength
= 0;
2025 Status
= ScsiWrite16Command (
2026 ScsiDiskDevice
->ScsiIo
,
2042 Check sense key to find if media presents.
2044 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2045 @param SenseCounts The number of sense key
2047 @retval TRUE NOT any media
2048 @retval FALSE Media presents
2052 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2053 IN UINTN SenseCounts
2056 EFI_SCSI_SENSE_DATA
*SensePtr
;
2061 SensePtr
= SenseData
;
2063 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2065 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2066 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2068 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
2069 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
2082 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2083 @param SenseCounts The number of sense key
2086 @retval FALSE NOT error
2090 ScsiDiskIsMediaError (
2091 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2092 IN UINTN SenseCounts
2095 EFI_SCSI_SENSE_DATA
*SensePtr
;
2100 SensePtr
= SenseData
;
2102 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2104 switch (SensePtr
->Sense_Key
) {
2106 case EFI_SCSI_SK_MEDIUM_ERROR
:
2108 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2110 switch (SensePtr
->Addnl_Sense_Code
) {
2115 case EFI_SCSI_ASC_MEDIA_ERR1
:
2120 case EFI_SCSI_ASC_MEDIA_ERR2
:
2125 case EFI_SCSI_ASC_MEDIA_ERR3
:
2126 case EFI_SCSI_ASC_MEDIA_ERR4
:
2136 case EFI_SCSI_SK_NOT_READY
:
2138 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2140 switch (SensePtr
->Addnl_Sense_Code
) {
2142 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2144 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2165 Check sense key to find if hardware error happens.
2167 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2168 @param SenseCounts The number of sense key
2170 @retval TRUE Hardware error exits.
2171 @retval FALSE NO error.
2175 ScsiDiskIsHardwareError (
2176 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2177 IN UINTN SenseCounts
2180 EFI_SCSI_SENSE_DATA
*SensePtr
;
2185 SensePtr
= SenseData
;
2187 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2190 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2192 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2204 Check sense key to find if media has changed.
2206 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2207 @param SenseCounts The number of sense key
2209 @retval TRUE Media is changed.
2210 @retval FALSE Media is NOT changed.
2213 ScsiDiskIsMediaChange (
2214 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2215 IN UINTN SenseCounts
2218 EFI_SCSI_SENSE_DATA
*SensePtr
;
2220 BOOLEAN IsMediaChanged
;
2222 IsMediaChanged
= FALSE
;
2223 SensePtr
= SenseData
;
2225 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2227 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2228 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2230 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2231 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2232 IsMediaChanged
= TRUE
;
2238 return IsMediaChanged
;
2242 Check sense key to find if reset happens.
2244 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2245 @param SenseCounts The number of sense key
2247 @retval TRUE It is reset before.
2248 @retval FALSE It is NOT reset before.
2252 ScsiDiskIsResetBefore (
2253 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2254 IN UINTN SenseCounts
2257 EFI_SCSI_SENSE_DATA
*SensePtr
;
2259 BOOLEAN IsResetBefore
;
2261 IsResetBefore
= FALSE
;
2262 SensePtr
= SenseData
;
2264 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2267 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2268 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2270 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2271 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2272 IsResetBefore
= TRUE
;
2278 return IsResetBefore
;
2282 Check sense key to find if the drive is ready.
2284 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2285 @param SenseCounts The number of sense key
2286 @param RetryLater The flag means if need a retry
2288 @retval TRUE Drive is ready.
2289 @retval FALSE Drive is NOT ready.
2293 ScsiDiskIsDriveReady (
2294 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2295 IN UINTN SenseCounts
,
2296 OUT BOOLEAN
*RetryLater
2299 EFI_SCSI_SENSE_DATA
*SensePtr
;
2304 *RetryLater
= FALSE
;
2305 SensePtr
= SenseData
;
2307 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2309 switch (SensePtr
->Sense_Key
) {
2311 case EFI_SCSI_SK_NOT_READY
:
2313 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2315 switch (SensePtr
->Addnl_Sense_Code
) {
2316 case EFI_SCSI_ASC_NOT_READY
:
2318 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2320 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2321 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2323 // Additional Sense Code Qualifier is
2324 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2332 *RetryLater
= FALSE
;
2353 Check sense key to find if it has sense key.
2355 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2356 @param SenseCounts - The number of sense key
2358 @retval TRUE It has sense key.
2359 @retval FALSE It has NOT any sense key.
2363 ScsiDiskHaveSenseKey (
2364 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2365 IN UINTN SenseCounts
2368 EFI_SCSI_SENSE_DATA
*SensePtr
;
2370 BOOLEAN HaveSenseKey
;
2372 if (SenseCounts
== 0) {
2373 HaveSenseKey
= FALSE
;
2375 HaveSenseKey
= TRUE
;
2378 SensePtr
= SenseData
;
2380 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2383 // Sense Key is SK_NO_SENSE (0x0)
2385 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2387 HaveSenseKey
= FALSE
;
2393 return HaveSenseKey
;
2397 Release resource about disk device.
2399 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2403 ReleaseScsiDiskDeviceResources (
2404 IN SCSI_DISK_DEV
*ScsiDiskDevice
2407 if (ScsiDiskDevice
== NULL
) {
2411 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2412 FreePool (ScsiDiskDevice
->SenseData
);
2413 ScsiDiskDevice
->SenseData
= NULL
;
2416 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2417 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2418 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2421 FreePool (ScsiDiskDevice
);
2423 ScsiDiskDevice
= NULL
;
2427 Determine if Block Io should be produced.
2430 @param ChildHandle Child Handle to retrieve Parent information.
2432 @retval TRUE Should produce Block Io.
2433 @retval FALSE Should not produce Block Io.
2437 DetermineInstallBlockIo (
2438 IN EFI_HANDLE ChildHandle
2441 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2442 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2445 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2446 // check its attribute, logic or physical.
2448 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2449 if (ExtScsiPassThru
!= NULL
) {
2450 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2456 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2457 // check its attribute, logic or physical.
2459 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2460 if (ScsiPassThru
!= NULL
) {
2461 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2470 Search protocol database and check to see if the protocol
2471 specified by ProtocolGuid is present on a ControllerHandle and opened by
2472 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2473 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2474 will be opened on it.
2477 @param ProtocolGuid ProtocolGuid pointer.
2478 @param ChildHandle Child Handle to retrieve Parent information.
2484 IN EFI_GUID
*ProtocolGuid
,
2485 IN EFI_HANDLE ChildHandle
2492 EFI_HANDLE
*HandleBuffer
;
2495 // Retrieve the list of all handles from the handle database
2497 Status
= gBS
->LocateHandleBuffer (
2505 if (EFI_ERROR (Status
)) {
2510 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
2512 for (Index
= 0; Index
< HandleCount
; Index
++) {
2513 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
2514 if (!EFI_ERROR (Status
)) {
2515 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
2516 if (!EFI_ERROR (Status
)) {
2517 gBS
->FreePool (HandleBuffer
);
2523 gBS
->FreePool (HandleBuffer
);
2528 Provides inquiry information for the controller type.
2530 This function is used by the IDE bus driver to get inquiry data. Data format
2531 of Identify data is defined by the Interface GUID.
2533 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2534 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
2535 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
2537 @retval EFI_SUCCESS The command was accepted without any errors.
2538 @retval EFI_NOT_FOUND Device does not support this data class
2539 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
2540 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
2545 ScsiDiskInfoInquiry (
2546 IN EFI_DISK_INFO_PROTOCOL
*This
,
2547 IN OUT VOID
*InquiryData
,
2548 IN OUT UINT32
*InquiryDataSize
2552 SCSI_DISK_DEV
*ScsiDiskDevice
;
2554 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2556 Status
= EFI_BUFFER_TOO_SMALL
;
2557 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
2558 Status
= EFI_SUCCESS
;
2559 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
2561 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
2567 Provides identify information for the controller type.
2569 This function is used by the IDE bus driver to get identify data. Data format
2570 of Identify data is defined by the Interface GUID.
2572 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
2574 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
2575 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
2578 @retval EFI_SUCCESS The command was accepted without any errors.
2579 @retval EFI_NOT_FOUND Device does not support this data class
2580 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
2581 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
2586 ScsiDiskInfoIdentify (
2587 IN EFI_DISK_INFO_PROTOCOL
*This
,
2588 IN OUT VOID
*IdentifyData
,
2589 IN OUT UINT32
*IdentifyDataSize
2593 SCSI_DISK_DEV
*ScsiDiskDevice
;
2595 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2597 // Physical SCSI bus does not support this data class.
2599 return EFI_NOT_FOUND
;
2602 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2604 Status
= EFI_BUFFER_TOO_SMALL
;
2605 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
2606 Status
= EFI_SUCCESS
;
2607 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
2609 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
2614 Provides sense data information for the controller type.
2616 This function is used by the IDE bus driver to get sense data.
2617 Data format of Sense data is defined by the Interface GUID.
2619 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2620 @param[in, out] SenseData Pointer to the SenseData.
2621 @param[in, out] SenseDataSize Size of SenseData in bytes.
2622 @param[out] SenseDataNumber Pointer to the value for the sense data size.
2624 @retval EFI_SUCCESS The command was accepted without any errors.
2625 @retval EFI_NOT_FOUND Device does not support this data class.
2626 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
2627 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
2632 ScsiDiskInfoSenseData (
2633 IN EFI_DISK_INFO_PROTOCOL
*This
,
2634 IN OUT VOID
*SenseData
,
2635 IN OUT UINT32
*SenseDataSize
,
2636 OUT UINT8
*SenseDataNumber
2639 return EFI_NOT_FOUND
;
2644 This function is used by the IDE bus driver to get controller information.
2646 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2647 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
2648 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
2650 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
2651 @retval EFI_UNSUPPORTED This is not an IDE device.
2656 ScsiDiskInfoWhichIde (
2657 IN EFI_DISK_INFO_PROTOCOL
*This
,
2658 OUT UINT32
*IdeChannel
,
2659 OUT UINT32
*IdeDevice
2662 SCSI_DISK_DEV
*ScsiDiskDevice
;
2664 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2666 // This is not an IDE physical device.
2668 return EFI_UNSUPPORTED
;
2671 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2672 *IdeChannel
= ScsiDiskDevice
->Channel
;
2673 *IdeDevice
= ScsiDiskDevice
->Device
;
2680 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
2682 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
2683 implement Identify() interface for DiskInfo protocol. The ATA command is sent
2684 via SCSI Request Packet.
2686 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2688 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
2689 @retval others Some error occurred during the identification that ATAPI device.
2693 AtapiIdentifyDevice (
2694 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2697 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
2701 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
2703 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
2704 ZeroMem (Cdb
, sizeof (Cdb
));
2706 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
2707 CommandPacket
.Timeout
= EFI_TIMER_PERIOD_SECONDS (1);
2708 CommandPacket
.Cdb
= Cdb
;
2709 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
2710 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
2711 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
2713 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
2718 Initialize the installation of DiskInfo protocol.
2720 This function prepares for the installation of DiskInfo protocol on the child handle.
2721 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
2722 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
2723 to be IDE/AHCI interface GUID.
2725 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2726 @param ChildHandle Child handle to install DiskInfo protocol.
2730 InitializeInstallDiskInfo (
2731 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2732 IN EFI_HANDLE ChildHandle
2736 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2737 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
2738 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
2739 SATA_DEVICE_PATH
*SataDevicePath
;
2740 UINTN IdentifyRetry
;
2742 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
2744 // Device Path protocol must be installed on the device handle.
2746 ASSERT_EFI_ERROR (Status
);
2748 // Copy the DiskInfo protocol template.
2750 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
2752 while (!IsDevicePathEnd (DevicePathNode
)) {
2753 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
2754 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
2755 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
2756 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
2757 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
2758 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
2763 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
2764 // with IDE/AHCI interface GUID.
2766 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
2767 if (!EFI_ERROR (Status
)) {
2768 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
2770 // We find the valid ATAPI device path
2772 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
2773 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
2774 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
2776 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
2778 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
2781 // We find the valid SATA device path
2783 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
2784 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
2785 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
2787 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
2789 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
2793 } while (--IdentifyRetry
> 0);
2795 DevicePathNode
= ChildDevicePathNode
;