2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2010, 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 (!ExtendedVerification
) {
405 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
408 gBS
->RestoreTPL (OldTpl
);
413 The function is to Read Block from SCSI Disk.
415 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
416 @param MediaId The Id of Media detected
417 @param Lba The logic block address
418 @param BufferSize The size of Buffer
419 @param Buffer The buffer to fill the read out data
421 @retval EFI_SUCCESS Successfully to read out block.
422 @retval EFI_DEVICE_ERROR Fail to detect media.
423 @retval EFI_NO_MEDIA Media is not present.
424 @retval EFI_MEDIA_CHANGED Media has changed.
425 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
426 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
432 IN EFI_BLOCK_IO_PROTOCOL
*This
,
439 SCSI_DISK_DEV
*ScsiDiskDevice
;
440 EFI_BLOCK_IO_MEDIA
*Media
;
443 UINTN NumberOfBlocks
;
448 if (Buffer
== NULL
) {
449 return EFI_INVALID_PARAMETER
;
452 if (BufferSize
== 0) {
456 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
458 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
460 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
462 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
463 if (EFI_ERROR (Status
)) {
464 Status
= EFI_DEVICE_ERROR
;
469 gBS
->ReinstallProtocolInterface (
470 ScsiDiskDevice
->Handle
,
471 &gEfiBlockIoProtocolGuid
,
472 &ScsiDiskDevice
->BlkIo
,
473 &ScsiDiskDevice
->BlkIo
478 // Get the intrinsic block size
480 Media
= ScsiDiskDevice
->BlkIo
.Media
;
481 BlockSize
= Media
->BlockSize
;
483 NumberOfBlocks
= BufferSize
/ BlockSize
;
485 if (!(Media
->MediaPresent
)) {
486 Status
= EFI_NO_MEDIA
;
490 if (MediaId
!= Media
->MediaId
) {
491 Status
= EFI_MEDIA_CHANGED
;
495 if (BufferSize
% BlockSize
!= 0) {
496 Status
= EFI_BAD_BUFFER_SIZE
;
500 if (Lba
> Media
->LastBlock
) {
501 Status
= EFI_INVALID_PARAMETER
;
505 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
506 Status
= EFI_INVALID_PARAMETER
;
510 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
511 Status
= EFI_INVALID_PARAMETER
;
516 // If all the parameters are valid, then perform read sectors command
517 // to transfer data from device to host.
519 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
522 gBS
->RestoreTPL (OldTpl
);
527 The function is to Write Block to SCSI Disk.
529 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
530 @param MediaId The Id of Media detected
531 @param Lba The logic block address
532 @param BufferSize The size of Buffer
533 @param Buffer The buffer to fill the read out data
535 @retval EFI_SUCCESS Successfully to read out block.
536 @retval EFI_WRITE_PROTECTED The device can not be written to.
537 @retval EFI_DEVICE_ERROR Fail to detect media.
538 @retval EFI_NO_MEDIA Media is not present.
539 @retval EFI_MEDIA_CHNAGED Media has changed.
540 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
541 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
546 ScsiDiskWriteBlocks (
547 IN EFI_BLOCK_IO_PROTOCOL
*This
,
554 SCSI_DISK_DEV
*ScsiDiskDevice
;
555 EFI_BLOCK_IO_MEDIA
*Media
;
558 UINTN NumberOfBlocks
;
563 if (Buffer
== NULL
) {
564 return EFI_INVALID_PARAMETER
;
567 if (BufferSize
== 0) {
571 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
573 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
575 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
577 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
578 if (EFI_ERROR (Status
)) {
579 Status
= EFI_DEVICE_ERROR
;
584 gBS
->ReinstallProtocolInterface (
585 ScsiDiskDevice
->Handle
,
586 &gEfiBlockIoProtocolGuid
,
587 &ScsiDiskDevice
->BlkIo
,
588 &ScsiDiskDevice
->BlkIo
593 // Get the intrinsic block size
595 Media
= ScsiDiskDevice
->BlkIo
.Media
;
596 BlockSize
= Media
->BlockSize
;
598 NumberOfBlocks
= BufferSize
/ BlockSize
;
600 if (!(Media
->MediaPresent
)) {
601 Status
= EFI_NO_MEDIA
;
605 if (MediaId
!= Media
->MediaId
) {
606 Status
= EFI_MEDIA_CHANGED
;
610 if (BufferSize
% BlockSize
!= 0) {
611 Status
= EFI_BAD_BUFFER_SIZE
;
615 if (Lba
> Media
->LastBlock
) {
616 Status
= EFI_INVALID_PARAMETER
;
620 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
621 Status
= EFI_INVALID_PARAMETER
;
625 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
626 Status
= EFI_INVALID_PARAMETER
;
630 // if all the parameters are valid, then perform read sectors command
631 // to transfer data from device to host.
633 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
636 gBS
->RestoreTPL (OldTpl
);
643 EFI_SUCCESS is returned directly.
645 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
647 @retval EFI_SUCCESS All outstanding data was written to the device
652 ScsiDiskFlushBlocks (
653 IN EFI_BLOCK_IO_PROTOCOL
*This
664 Detect Device and read out capacity ,if error occurs, parse the sense key.
666 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
667 @param MustReadCapacity The flag about reading device capacity
668 @param MediaChange The pointer of flag indicates if media has changed
670 @retval EFI_DEVICE_ERROR Indicates that error occurs
671 @retval EFI_SUCCESS Successfully to detect media
675 ScsiDiskDetectMedia (
676 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
677 IN BOOLEAN MustReadCapacity
,
678 OUT BOOLEAN
*MediaChange
682 EFI_STATUS ReadCapacityStatus
;
683 EFI_SCSI_SENSE_DATA
*SenseData
;
684 UINTN NumberOfSenseKeys
;
686 BOOLEAN NeedReadCapacity
;
689 EFI_BLOCK_IO_MEDIA OldMedia
;
692 Status
= EFI_SUCCESS
;
693 ReadCapacityStatus
= EFI_SUCCESS
;
695 NumberOfSenseKeys
= 0;
696 NeedReadCapacity
= FALSE
;
697 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
698 *MediaChange
= FALSE
;
701 for (Index
= 0; Index
< MaxRetry
; Index
++) {
702 Status
= ScsiDiskTestUnitReady (
708 if (!EFI_ERROR (Status
)) {
717 if ((Index
== MaxRetry
) && EFI_ERROR (Status
)) {
718 return EFI_DEVICE_ERROR
;
721 Status
= DetectMediaParsingSenseKeys (
727 if (EFI_ERROR (Status
)) {
731 // ACTION_NO_ACTION: need not read capacity
732 // other action code: need read capacity
734 if (Action
== ACTION_NO_ACTION
) {
735 NeedReadCapacity
= FALSE
;
737 NeedReadCapacity
= TRUE
;
741 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
742 // retrieve capacity via Read Capacity command
744 if (NeedReadCapacity
|| MustReadCapacity
) {
746 // retrieve media information
749 for (Index
= 0; Index
< MaxRetry
; Index
++) {
751 ReadCapacityStatus
= ScsiDiskReadCapacity (
757 if (EFI_ERROR (ReadCapacityStatus
) && !NeedRetry
) {
758 return EFI_DEVICE_ERROR
;
761 // analyze sense key to action
763 Status
= DetectMediaParsingSenseKeys (
770 // if Status is error, it may indicate crisis error,
771 // so return without retry.
773 if (EFI_ERROR (Status
)) {
778 case ACTION_NO_ACTION
:
785 case ACTION_RETRY_COMMAND_LATER
:
787 // retry the ReadCapacity later and continuously, until the condition
788 // no longer emerges.
789 // stall time is 100000us, or say 0.1 second.
797 // other cases, just retry the command
803 if ((Index
== MaxRetry
) && EFI_ERROR (ReadCapacityStatus
)) {
804 return EFI_DEVICE_ERROR
;
808 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
810 // Media change information got from the device
815 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
817 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
820 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
822 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
825 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
827 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
830 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
831 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
833 // when change from no media to media present, reset the MediaId to 1.
835 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
838 // when no media, reset the MediaId to zero.
840 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
851 Send out Inquiry command to Device.
853 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
854 @param NeedRetry Indicates if needs try again when error happens
856 @retval EFI_DEVICE_ERROR Indicates that error occurs
857 @retval EFI_SUCCESS Successfully to detect media
861 ScsiDiskInquiryDevice (
862 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
863 OUT BOOLEAN
*NeedRetry
866 UINT32 InquiryDataLength
;
867 UINT8 SenseDataLength
;
868 UINT8 HostAdapterStatus
;
870 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
871 UINTN NumberOfSenseKeys
;
876 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
879 Status
= ScsiInquiryCommand (
880 ScsiDiskDevice
->ScsiIo
,
881 EFI_TIMER_PERIOD_SECONDS (1),
886 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
891 // no need to check HostAdapterStatus and TargetStatus
893 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
894 ParseInquiryData (ScsiDiskDevice
);
897 } else if (Status
== EFI_NOT_READY
) {
899 return EFI_DEVICE_ERROR
;
901 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
903 return EFI_DEVICE_ERROR
;
906 // go ahead to check HostAdapterStatus and TargetStatus
907 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
910 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
911 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
913 return EFI_DEVICE_ERROR
;
914 } else if (Status
== EFI_DEVICE_ERROR
) {
916 // reset the scsi channel
918 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
920 return EFI_DEVICE_ERROR
;
923 Status
= CheckTargetStatus (TargetStatus
);
924 if (Status
== EFI_NOT_READY
) {
926 // reset the scsi device
928 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
930 return EFI_DEVICE_ERROR
;
932 } else if (Status
== EFI_DEVICE_ERROR
) {
934 return EFI_DEVICE_ERROR
;
938 // if goes here, meant ScsiInquiryCommand() failed.
939 // if ScsiDiskRequestSenseKeys() succeeds at last,
940 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
943 for (Index
= 0; Index
< MaxRetry
; Index
++) {
944 Status
= ScsiDiskRequestSenseKeys (
951 if (!EFI_ERROR (Status
)) {
953 return EFI_DEVICE_ERROR
;
957 return EFI_DEVICE_ERROR
;
961 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
962 // set *NeedRetry = FALSE to avoid the outside caller try again.
965 return EFI_DEVICE_ERROR
;
971 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
972 When Test Unit Ready command encounters any error caused by host adapter or
973 target, return error without retrieving Sense Keys.
975 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
976 @param NeedRetry The pointer of flag indicates try again
977 @param SenseDataArray The pointer of an array of sense data
978 @param NumberOfSenseKeys The pointer of the number of sense data array
980 @retval EFI_DEVICE_ERROR Indicates that error occurs
981 @retval EFI_SUCCESS Successfully to test unit
985 ScsiDiskTestUnitReady (
986 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
987 OUT BOOLEAN
*NeedRetry
,
988 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
989 OUT UINTN
*NumberOfSenseKeys
993 UINT8 SenseDataLength
;
994 UINT8 HostAdapterStatus
;
1000 *NumberOfSenseKeys
= 0;
1003 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1005 Status
= ScsiTestUnitReadyCommand (
1006 ScsiDiskDevice
->ScsiIo
,
1007 EFI_TIMER_PERIOD_SECONDS (1),
1014 // no need to check HostAdapterStatus and TargetStatus
1016 if (Status
== EFI_NOT_READY
) {
1018 return EFI_DEVICE_ERROR
;
1020 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1022 return EFI_DEVICE_ERROR
;
1025 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1028 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1029 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1031 return EFI_DEVICE_ERROR
;
1033 } else if (Status
== EFI_DEVICE_ERROR
) {
1035 // reset the scsi channel
1037 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1039 return EFI_DEVICE_ERROR
;
1042 Status
= CheckTargetStatus (TargetStatus
);
1043 if (Status
== EFI_NOT_READY
) {
1045 // reset the scsi device
1047 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1049 return EFI_DEVICE_ERROR
;
1051 } else if (Status
== EFI_DEVICE_ERROR
) {
1053 return EFI_DEVICE_ERROR
;
1057 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1058 Status
= ScsiDiskRequestSenseKeys (
1065 if (!EFI_ERROR (Status
)) {
1070 return EFI_DEVICE_ERROR
;
1074 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1075 // set *NeedRetry = FALSE to avoid the outside caller try again.
1078 return EFI_DEVICE_ERROR
;
1082 Parsing Sense Keys which got from request sense command.
1084 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1085 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1086 @param NumberOfSenseKeys The number of sense key
1087 @param Action The pointer of action which indicates what is need to do next
1089 @retval EFI_DEVICE_ERROR Indicates that error occurs
1090 @retval EFI_SUCCESS Successfully to complete the parsing
1094 DetectMediaParsingSenseKeys (
1095 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1096 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1097 IN UINTN NumberOfSenseKeys
,
1104 // Default is to read capacity, unless..
1106 *Action
= ACTION_READ_CAPACITY
;
1108 if (NumberOfSenseKeys
== 0) {
1109 *Action
= ACTION_NO_ACTION
;
1113 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1115 // No Sense Key returned from last submitted command
1117 *Action
= ACTION_NO_ACTION
;
1121 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1122 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1123 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1124 *Action
= ACTION_NO_ACTION
;
1128 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1129 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1133 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1134 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1135 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1136 return EFI_DEVICE_ERROR
;
1139 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1140 return EFI_DEVICE_ERROR
;
1143 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1145 *Action
= ACTION_RETRY_COMMAND_LATER
;
1149 return EFI_DEVICE_ERROR
;
1157 Send read capacity command to device and get the device parameter.
1159 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1160 @param NeedRetry The pointer of flag indicates if need a retry
1161 @param SenseDataArray The pointer of an array of sense data
1162 @param NumberOfSenseKeys The number of sense key
1164 @retval EFI_DEVICE_ERROR Indicates that error occurs
1165 @retval EFI_SUCCESS Successfully to read capacity
1169 ScsiDiskReadCapacity (
1170 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1171 OUT BOOLEAN
*NeedRetry
,
1172 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1173 OUT UINTN
*NumberOfSenseKeys
1176 UINT8 HostAdapterStatus
;
1178 EFI_STATUS CommandStatus
;
1182 UINT8 SenseDataLength
;
1183 UINT32 DataLength10
;
1184 UINT32 DataLength16
;
1185 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10
;
1186 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16
;
1189 SenseDataLength
= 0;
1190 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1191 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1192 ZeroMem (&CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1193 ZeroMem (&CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1195 *NumberOfSenseKeys
= 0;
1199 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1200 // 16 byte command should be used to access large hard disk >2TB
1202 CommandStatus
= ScsiReadCapacityCommand (
1203 ScsiDiskDevice
->ScsiIo
,
1204 EFI_TIMER_PERIOD_SECONDS(1),
1209 (VOID
*) &CapacityData10
,
1214 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1215 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
.LastLba3
== 0xff) && (CapacityData10
.LastLba2
== 0xff) &&
1216 (CapacityData10
.LastLba1
== 0xff) && (CapacityData10
.LastLba0
== 0xff)) {
1218 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1220 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1222 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1223 // and LowestAlignedLba
1225 CommandStatus
= ScsiReadCapacity16Command (
1226 ScsiDiskDevice
->ScsiIo
,
1227 EFI_TIMER_PERIOD_SECONDS (1),
1232 (VOID
*) &CapacityData16
,
1239 // no need to check HostAdapterStatus and TargetStatus
1241 if (CommandStatus
== EFI_SUCCESS
) {
1242 GetMediaInfo (ScsiDiskDevice
, &CapacityData10
,&CapacityData16
);
1245 } else if (CommandStatus
== EFI_NOT_READY
) {
1247 return EFI_DEVICE_ERROR
;
1249 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1251 return EFI_DEVICE_ERROR
;
1254 // go ahead to check HostAdapterStatus and TargetStatus
1255 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1258 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1259 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1261 return EFI_DEVICE_ERROR
;
1263 } else if (Status
== EFI_DEVICE_ERROR
) {
1265 // reset the scsi channel
1267 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1269 return EFI_DEVICE_ERROR
;
1272 Status
= CheckTargetStatus (TargetStatus
);
1273 if (Status
== EFI_NOT_READY
) {
1275 // reset the scsi device
1277 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1279 return EFI_DEVICE_ERROR
;
1281 } else if (Status
== EFI_DEVICE_ERROR
) {
1283 return EFI_DEVICE_ERROR
;
1287 // if goes here, meant ScsiReadCapacityCommand() failed.
1288 // if ScsiDiskRequestSenseKeys() succeeds at last,
1289 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1292 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1294 Status
= ScsiDiskRequestSenseKeys (
1301 if (!EFI_ERROR (Status
)) {
1303 return EFI_DEVICE_ERROR
;
1307 return EFI_DEVICE_ERROR
;
1311 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1312 // set *NeedRetry = FALSE to avoid the outside caller try again.
1315 return EFI_DEVICE_ERROR
;
1319 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1321 @param HostAdapterStatus Host Adapter status
1323 @retval EFI_SUCCESS Host adapter is OK.
1324 @retval EFI_TIMEOUT Timeout.
1325 @retval EFI_NOT_READY Adapter NOT ready.
1326 @retval EFI_DEVICE_ERROR Adapter device error.
1330 CheckHostAdapterStatus (
1331 IN UINT8 HostAdapterStatus
1334 switch (HostAdapterStatus
) {
1335 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1338 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1339 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1340 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1343 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1344 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1345 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1346 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1347 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1348 return EFI_NOT_READY
;
1350 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1351 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1352 return EFI_DEVICE_ERROR
;
1361 Check the target status and re-interpret it in EFI_STATUS.
1363 @param TargetStatus Target status
1365 @retval EFI_NOT_READY Device is NOT ready.
1366 @retval EFI_DEVICE_ERROR
1372 IN UINT8 TargetStatus
1375 switch (TargetStatus
) {
1376 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1377 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1378 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1381 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1382 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1383 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1384 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1385 return EFI_NOT_READY
;
1387 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1388 return EFI_DEVICE_ERROR
;
1398 Retrieve all sense keys from the device.
1400 When encountering error during the process, if retrieve sense keys before
1401 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1402 and NeedRetry set to FALSE; otherwize, return the proper return status.
1404 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1405 @param NeedRetry The pointer of flag indicates if need a retry
1406 @param SenseDataArray The pointer of an array of sense data
1407 @param NumberOfSenseKeys The number of sense key
1408 @param AskResetIfError The flag indicates if need reset when error occurs
1410 @retval EFI_DEVICE_ERROR Indicates that error occurs
1411 @retval EFI_SUCCESS Successfully to request sense key
1415 ScsiDiskRequestSenseKeys (
1416 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1417 OUT BOOLEAN
*NeedRetry
,
1418 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1419 OUT UINTN
*NumberOfSenseKeys
,
1420 IN BOOLEAN AskResetIfError
1423 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1424 UINT8 SenseDataLength
;
1427 EFI_STATUS FallStatus
;
1428 UINT8 HostAdapterStatus
;
1431 FallStatus
= EFI_SUCCESS
;
1432 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1435 ScsiDiskDevice
->SenseData
,
1436 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1439 *NumberOfSenseKeys
= 0;
1440 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1441 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1443 for (SenseReq
= TRUE
; SenseReq
;) {
1444 Status
= ScsiRequestSenseCommand (
1445 ScsiDiskDevice
->ScsiIo
,
1446 EFI_TIMER_PERIOD_SECONDS (2),
1452 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1453 FallStatus
= EFI_SUCCESS
;
1455 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1457 FallStatus
= EFI_DEVICE_ERROR
;
1459 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1461 FallStatus
= EFI_DEVICE_ERROR
;
1463 } else if (Status
== EFI_DEVICE_ERROR
) {
1464 if (AskResetIfError
) {
1465 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1468 FallStatus
= EFI_DEVICE_ERROR
;
1471 if (EFI_ERROR (FallStatus
)) {
1472 if (*NumberOfSenseKeys
!= 0) {
1476 return EFI_DEVICE_ERROR
;
1480 (*NumberOfSenseKeys
) += 1;
1483 // no more sense key or number of sense keys exceeds predefined,
1486 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1487 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1497 Get information from media read capacity command.
1499 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1500 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1501 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1506 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1507 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1508 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1513 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1514 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 1;
1517 if (!ScsiDiskDevice
->Cdb16Byte
) {
1518 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1519 (Capacity10
->LastLba2
<< 16) |
1520 (Capacity10
->LastLba1
<< 8) |
1521 Capacity10
->LastLba0
;
1523 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1524 (Capacity10
->BlockSize2
<< 16) |
1525 (Capacity10
->BlockSize1
<< 8) |
1526 Capacity10
->BlockSize0
;
1527 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
1530 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1531 *Ptr
++ = Capacity16
->LastLba0
;
1532 *Ptr
++ = Capacity16
->LastLba1
;
1533 *Ptr
++ = Capacity16
->LastLba2
;
1534 *Ptr
++ = Capacity16
->LastLba3
;
1535 *Ptr
++ = Capacity16
->LastLba4
;
1536 *Ptr
++ = Capacity16
->LastLba5
;
1537 *Ptr
++ = Capacity16
->LastLba6
;
1538 *Ptr
= Capacity16
->LastLba7
;
1540 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1541 (Capacity16
->BlockSize2
<< 16) |
1542 (Capacity16
->BlockSize1
<< 8) |
1543 Capacity16
->BlockSize0
;
1545 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8)|(Capacity16
->LowestAlignLogic1
);
1546 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= Capacity16
->LogicPerPhysical
;
1547 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION2
;
1551 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1553 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1554 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1557 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1558 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1565 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1570 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1573 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1574 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1578 Read sector from SCSI Disk.
1580 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1581 @param Buffer The buffer to fill in the read out data
1582 @param Lba Logic block address
1583 @param NumberOfBlocks The number of blocks to read
1585 @retval EFI_DEVICE_ERROR Indicates a device error.
1586 @retval EFI_SUCCESS Operation is successful.
1590 ScsiDiskReadSectors (
1591 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1594 IN UINTN NumberOfBlocks
1597 UINTN BlocksRemaining
;
1608 EFI_SCSI_SENSE_DATA
*SenseData
;
1609 UINTN NumberOfSenseKeys
;
1612 NumberOfSenseKeys
= 0;
1614 Status
= EFI_SUCCESS
;
1616 BlocksRemaining
= NumberOfBlocks
;
1617 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1620 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1622 if (!ScsiDiskDevice
->Cdb16Byte
) {
1625 MaxBlock
= 0xFFFFFFFF;
1630 while (BlocksRemaining
> 0) {
1632 if (BlocksRemaining
<= MaxBlock
) {
1633 if (!ScsiDiskDevice
->Cdb16Byte
) {
1634 SectorCount
= (UINT16
) BlocksRemaining
;
1636 SectorCount
= (UINT32
) BlocksRemaining
;
1639 SectorCount
= MaxBlock
;
1642 ByteCount
= SectorCount
* BlockSize
;
1643 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1646 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1647 if (!ScsiDiskDevice
->Cdb16Byte
) {
1648 Status
= ScsiDiskRead10 (
1660 Status
= ScsiDiskRead16 (
1672 if (!EFI_ERROR (Status
)) {
1677 return EFI_DEVICE_ERROR
;
1682 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1683 return EFI_DEVICE_ERROR
;
1687 // actual transferred sectors
1689 SectorCount
= ByteCount
/ BlockSize
;
1692 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1693 BlocksRemaining
-= SectorCount
;
1700 Write sector to SCSI Disk.
1702 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1703 @param Buffer The buffer of data to be written into SCSI Disk
1704 @param Lba Logic block address
1705 @param NumberOfBlocks The number of blocks to read
1707 @retval EFI_DEVICE_ERROR Indicates a device error.
1708 @retval EFI_SUCCESS Operation is successful.
1712 ScsiDiskWriteSectors (
1713 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1716 IN UINTN NumberOfBlocks
1719 UINTN BlocksRemaining
;
1730 EFI_SCSI_SENSE_DATA
*SenseData
;
1731 UINTN NumberOfSenseKeys
;
1734 NumberOfSenseKeys
= 0;
1736 Status
= EFI_SUCCESS
;
1738 BlocksRemaining
= NumberOfBlocks
;
1739 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1742 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1744 if (!ScsiDiskDevice
->Cdb16Byte
) {
1747 MaxBlock
= 0xFFFFFFFF;
1752 while (BlocksRemaining
> 0) {
1754 if (BlocksRemaining
<= MaxBlock
) {
1755 if (!ScsiDiskDevice
->Cdb16Byte
) {
1756 SectorCount
= (UINT16
) BlocksRemaining
;
1758 SectorCount
= (UINT32
) BlocksRemaining
;
1761 SectorCount
= MaxBlock
;
1764 ByteCount
= SectorCount
* BlockSize
;
1765 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1767 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1768 if (!ScsiDiskDevice
->Cdb16Byte
) {
1769 Status
= ScsiDiskWrite10 (
1781 Status
= ScsiDiskWrite16 (
1793 if (!EFI_ERROR (Status
)) {
1798 return EFI_DEVICE_ERROR
;
1802 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1803 return EFI_DEVICE_ERROR
;
1806 // actual transferred sectors
1808 SectorCount
= ByteCount
/ BlockSize
;
1811 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1812 BlocksRemaining
-= SectorCount
;
1820 Submit Read(10) command.
1822 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1823 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1824 @param SenseDataArray NOT used yet in this function
1825 @param NumberOfSenseKeys The number of sense key
1826 @param Timeout The time to complete the command
1827 @param DataBuffer The buffer to fill with the read out data
1828 @param DataLength The length of buffer
1829 @param StartLba The start logic block address
1830 @param SectorSize The size of sector
1832 @return EFI_STATUS is returned by calling ScsiRead10Command().
1836 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1837 OUT BOOLEAN
*NeedRetry
,
1838 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1839 OUT UINTN
*NumberOfSenseKeys
,
1841 OUT UINT8
*DataBuffer
,
1842 IN OUT UINT32
*DataLength
,
1844 IN UINT32 SectorSize
1847 UINT8 SenseDataLength
;
1849 UINT8 HostAdapterStatus
;
1853 *NumberOfSenseKeys
= 0;
1854 SenseDataLength
= 0;
1855 Status
= ScsiRead10Command (
1856 ScsiDiskDevice
->ScsiIo
,
1872 Submit Write(10) Command.
1874 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1875 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1876 @param SenseDataArray NOT used yet in this function
1877 @param NumberOfSenseKeys The number of sense key
1878 @param Timeout The time to complete the command
1879 @param DataBuffer The buffer to fill with the read out data
1880 @param DataLength The length of buffer
1881 @param StartLba The start logic block address
1882 @param SectorSize The size of sector
1884 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1889 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1890 OUT BOOLEAN
*NeedRetry
,
1891 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1892 OUT UINTN
*NumberOfSenseKeys
,
1894 IN UINT8
*DataBuffer
,
1895 IN OUT UINT32
*DataLength
,
1897 IN UINT32 SectorSize
1901 UINT8 SenseDataLength
;
1902 UINT8 HostAdapterStatus
;
1906 *NumberOfSenseKeys
= 0;
1907 SenseDataLength
= 0;
1908 Status
= ScsiWrite10Command (
1909 ScsiDiskDevice
->ScsiIo
,
1925 Submit Read(16) command.
1927 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1928 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1929 @param SenseDataArray NOT used yet in this function
1930 @param NumberOfSenseKeys The number of sense key
1931 @param Timeout The time to complete the command
1932 @param DataBuffer The buffer to fill with the read out data
1933 @param DataLength The length of buffer
1934 @param StartLba The start logic block address
1935 @param SectorSize The size of sector
1937 @return EFI_STATUS is returned by calling ScsiRead10Command().
1941 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1942 OUT BOOLEAN
*NeedRetry
,
1943 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1944 OUT UINTN
*NumberOfSenseKeys
,
1946 OUT UINT8
*DataBuffer
,
1947 IN OUT UINT32
*DataLength
,
1949 IN UINT32 SectorSize
1952 UINT8 SenseDataLength
;
1954 UINT8 HostAdapterStatus
;
1958 *NumberOfSenseKeys
= 0;
1959 SenseDataLength
= 0;
1960 Status
= ScsiRead16Command (
1961 ScsiDiskDevice
->ScsiIo
,
1977 Submit Write(16) Command.
1979 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1980 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1981 @param SenseDataArray NOT used yet in this function
1982 @param NumberOfSenseKeys The number of sense key
1983 @param Timeout The time to complete the command
1984 @param DataBuffer The buffer to fill with the read out data
1985 @param DataLength The length of buffer
1986 @param StartLba The start logic block address
1987 @param SectorSize The size of sector
1989 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1994 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1995 OUT BOOLEAN
*NeedRetry
,
1996 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1997 OUT UINTN
*NumberOfSenseKeys
,
1999 IN UINT8
*DataBuffer
,
2000 IN OUT UINT32
*DataLength
,
2002 IN UINT32 SectorSize
2006 UINT8 SenseDataLength
;
2007 UINT8 HostAdapterStatus
;
2011 *NumberOfSenseKeys
= 0;
2012 SenseDataLength
= 0;
2013 Status
= ScsiWrite16Command (
2014 ScsiDiskDevice
->ScsiIo
,
2030 Check sense key to find if media presents.
2032 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2033 @param SenseCounts The number of sense key
2035 @retval TRUE NOT any media
2036 @retval FALSE Media presents
2040 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2041 IN UINTN SenseCounts
2044 EFI_SCSI_SENSE_DATA
*SensePtr
;
2049 SensePtr
= SenseData
;
2051 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2053 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2054 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2056 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
2057 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
2070 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2071 @param SenseCounts The number of sense key
2074 @retval FALSE NOT error
2078 ScsiDiskIsMediaError (
2079 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2080 IN UINTN SenseCounts
2083 EFI_SCSI_SENSE_DATA
*SensePtr
;
2088 SensePtr
= SenseData
;
2090 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2092 switch (SensePtr
->Sense_Key
) {
2094 case EFI_SCSI_SK_MEDIUM_ERROR
:
2096 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2098 switch (SensePtr
->Addnl_Sense_Code
) {
2103 case EFI_SCSI_ASC_MEDIA_ERR1
:
2108 case EFI_SCSI_ASC_MEDIA_ERR2
:
2113 case EFI_SCSI_ASC_MEDIA_ERR3
:
2114 case EFI_SCSI_ASC_MEDIA_ERR4
:
2124 case EFI_SCSI_SK_NOT_READY
:
2126 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2128 switch (SensePtr
->Addnl_Sense_Code
) {
2130 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2132 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2153 Check sense key to find if hardware error happens.
2155 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2156 @param SenseCounts The number of sense key
2158 @retval TRUE Hardware error exits.
2159 @retval FALSE NO error.
2163 ScsiDiskIsHardwareError (
2164 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2165 IN UINTN SenseCounts
2168 EFI_SCSI_SENSE_DATA
*SensePtr
;
2173 SensePtr
= SenseData
;
2175 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2178 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2180 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2192 Check sense key to find if media has changed.
2194 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2195 @param SenseCounts The number of sense key
2197 @retval TRUE Media is changed.
2198 @retval FALSE Media is NOT changed.
2201 ScsiDiskIsMediaChange (
2202 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2203 IN UINTN SenseCounts
2206 EFI_SCSI_SENSE_DATA
*SensePtr
;
2208 BOOLEAN IsMediaChanged
;
2210 IsMediaChanged
= FALSE
;
2211 SensePtr
= SenseData
;
2213 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2215 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2216 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2218 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2219 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2220 IsMediaChanged
= TRUE
;
2226 return IsMediaChanged
;
2230 Check sense key to find if reset happens.
2232 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2233 @param SenseCounts The number of sense key
2235 @retval TRUE It is reset before.
2236 @retval FALSE It is NOT reset before.
2240 ScsiDiskIsResetBefore (
2241 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2242 IN UINTN SenseCounts
2245 EFI_SCSI_SENSE_DATA
*SensePtr
;
2247 BOOLEAN IsResetBefore
;
2249 IsResetBefore
= FALSE
;
2250 SensePtr
= SenseData
;
2252 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2255 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2256 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2258 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2259 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2260 IsResetBefore
= TRUE
;
2266 return IsResetBefore
;
2270 Check sense key to find if the drive is ready.
2272 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2273 @param SenseCounts The number of sense key
2274 @param RetryLater The flag means if need a retry
2276 @retval TRUE Drive is ready.
2277 @retval FALSE Drive is NOT ready.
2281 ScsiDiskIsDriveReady (
2282 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2283 IN UINTN SenseCounts
,
2284 OUT BOOLEAN
*RetryLater
2287 EFI_SCSI_SENSE_DATA
*SensePtr
;
2292 *RetryLater
= FALSE
;
2293 SensePtr
= SenseData
;
2295 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2297 switch (SensePtr
->Sense_Key
) {
2299 case EFI_SCSI_SK_NOT_READY
:
2301 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2303 switch (SensePtr
->Addnl_Sense_Code
) {
2304 case EFI_SCSI_ASC_NOT_READY
:
2306 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2308 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2309 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2311 // Additional Sense Code Qualifier is
2312 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2320 *RetryLater
= FALSE
;
2341 Check sense key to find if it has sense key.
2343 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2344 @param SenseCounts - The number of sense key
2346 @retval TRUE It has sense key.
2347 @retval FALSE It has NOT any sense key.
2351 ScsiDiskHaveSenseKey (
2352 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2353 IN UINTN SenseCounts
2356 EFI_SCSI_SENSE_DATA
*SensePtr
;
2358 BOOLEAN HaveSenseKey
;
2360 if (SenseCounts
== 0) {
2361 HaveSenseKey
= FALSE
;
2363 HaveSenseKey
= TRUE
;
2366 SensePtr
= SenseData
;
2368 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2371 // Sense Key is SK_NO_SENSE (0x0)
2373 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2375 HaveSenseKey
= FALSE
;
2381 return HaveSenseKey
;
2385 Release resource about disk device.
2387 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2391 ReleaseScsiDiskDeviceResources (
2392 IN SCSI_DISK_DEV
*ScsiDiskDevice
2395 if (ScsiDiskDevice
== NULL
) {
2399 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2400 FreePool (ScsiDiskDevice
->SenseData
);
2401 ScsiDiskDevice
->SenseData
= NULL
;
2404 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2405 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2406 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2409 FreePool (ScsiDiskDevice
);
2411 ScsiDiskDevice
= NULL
;
2415 Determine if Block Io should be produced.
2418 @param ChildHandle Child Handle to retrieve Parent information.
2420 @retval TRUE Should produce Block Io.
2421 @retval FALSE Should not produce Block Io.
2425 DetermineInstallBlockIo (
2426 IN EFI_HANDLE ChildHandle
2429 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2430 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2433 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2434 // check its attribute, logic or physical.
2436 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2437 if (ExtScsiPassThru
!= NULL
) {
2438 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2444 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2445 // check its attribute, logic or physical.
2447 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2448 if (ScsiPassThru
!= NULL
) {
2449 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2458 Search protocol database and check to see if the protocol
2459 specified by ProtocolGuid is present on a ControllerHandle and opened by
2460 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2461 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2462 will be opened on it.
2465 @param ProtocolGuid ProtocolGuid pointer.
2466 @param ChildHandle Child Handle to retrieve Parent information.
2472 IN EFI_GUID
*ProtocolGuid
,
2473 IN EFI_HANDLE ChildHandle
2480 EFI_HANDLE
*HandleBuffer
;
2483 // Retrieve the list of all handles from the handle database
2485 Status
= gBS
->LocateHandleBuffer (
2493 if (EFI_ERROR (Status
)) {
2498 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
2500 for (Index
= 0; Index
< HandleCount
; Index
++) {
2501 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
2502 if (!EFI_ERROR (Status
)) {
2503 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
2504 if (!EFI_ERROR (Status
)) {
2505 gBS
->FreePool (HandleBuffer
);
2511 gBS
->FreePool (HandleBuffer
);
2516 Provides inquiry information for the controller type.
2518 This function is used by the IDE bus driver to get inquiry data. Data format
2519 of Identify data is defined by the Interface GUID.
2521 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2522 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
2523 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
2525 @retval EFI_SUCCESS The command was accepted without any errors.
2526 @retval EFI_NOT_FOUND Device does not support this data class
2527 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
2528 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
2533 ScsiDiskInfoInquiry (
2534 IN EFI_DISK_INFO_PROTOCOL
*This
,
2535 IN OUT VOID
*InquiryData
,
2536 IN OUT UINT32
*InquiryDataSize
2540 SCSI_DISK_DEV
*ScsiDiskDevice
;
2542 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2544 Status
= EFI_BUFFER_TOO_SMALL
;
2545 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
2546 Status
= EFI_SUCCESS
;
2547 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
2549 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
2555 Provides identify information for the controller type.
2557 This function is used by the IDE bus driver to get identify data. Data format
2558 of Identify data is defined by the Interface GUID.
2560 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
2562 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
2563 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
2566 @retval EFI_SUCCESS The command was accepted without any errors.
2567 @retval EFI_NOT_FOUND Device does not support this data class
2568 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
2569 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
2574 ScsiDiskInfoIdentify (
2575 IN EFI_DISK_INFO_PROTOCOL
*This
,
2576 IN OUT VOID
*IdentifyData
,
2577 IN OUT UINT32
*IdentifyDataSize
2581 SCSI_DISK_DEV
*ScsiDiskDevice
;
2583 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2585 // Physical SCSI bus does not support this data class.
2587 return EFI_NOT_FOUND
;
2590 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2592 Status
= EFI_BUFFER_TOO_SMALL
;
2593 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
2594 Status
= EFI_SUCCESS
;
2595 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
2597 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
2602 Provides sense data information for the controller type.
2604 This function is used by the IDE bus driver to get sense data.
2605 Data format of Sense data is defined by the Interface GUID.
2607 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2608 @param[in, out] SenseData Pointer to the SenseData.
2609 @param[in, out] SenseDataSize Size of SenseData in bytes.
2610 @param[out] SenseDataNumber Pointer to the value for the sense data size.
2612 @retval EFI_SUCCESS The command was accepted without any errors.
2613 @retval EFI_NOT_FOUND Device does not support this data class.
2614 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
2615 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
2620 ScsiDiskInfoSenseData (
2621 IN EFI_DISK_INFO_PROTOCOL
*This
,
2622 IN OUT VOID
*SenseData
,
2623 IN OUT UINT32
*SenseDataSize
,
2624 OUT UINT8
*SenseDataNumber
2627 return EFI_NOT_FOUND
;
2632 This function is used by the IDE bus driver to get controller information.
2634 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2635 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
2636 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
2638 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
2639 @retval EFI_UNSUPPORTED This is not an IDE device.
2644 ScsiDiskInfoWhichIde (
2645 IN EFI_DISK_INFO_PROTOCOL
*This
,
2646 OUT UINT32
*IdeChannel
,
2647 OUT UINT32
*IdeDevice
2650 SCSI_DISK_DEV
*ScsiDiskDevice
;
2652 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2654 // This is not an IDE physical device.
2656 return EFI_UNSUPPORTED
;
2659 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2660 *IdeChannel
= ScsiDiskDevice
->Channel
;
2661 *IdeDevice
= ScsiDiskDevice
->Device
;
2668 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
2670 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
2671 implement Identify() interface for DiskInfo protocol. The ATA command is sent
2672 via SCSI Request Packet.
2674 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2676 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
2677 @retval others Some error occurred during the identification that ATAPI device.
2681 AtapiIdentifyDevice (
2682 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2685 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
2689 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
2691 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
2692 ZeroMem (Cdb
, sizeof (Cdb
));
2694 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
2695 CommandPacket
.Timeout
= EFI_TIMER_PERIOD_SECONDS (1);
2696 CommandPacket
.Cdb
= Cdb
;
2697 CommandPacket
.CdbLength
= sizeof (Cdb
);
2698 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
2699 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
2701 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
2706 Initialize the installation of DiskInfo protocol.
2708 This function prepares for the installation of DiskInfo protocol on the child handle.
2709 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
2710 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
2711 to be IDE/AHCI interface GUID.
2713 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2714 @param ChildHandle Child handle to install DiskInfo protocol.
2718 InitializeInstallDiskInfo (
2719 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2720 IN EFI_HANDLE ChildHandle
2724 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2725 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
2726 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
2727 SATA_DEVICE_PATH
*SataDevicePath
;
2728 UINTN IdentifyRetry
;
2730 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
2732 // Device Path protocol must be installed on the device handle.
2734 ASSERT_EFI_ERROR (Status
);
2736 // Copy the DiskInfo protocol template.
2738 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
2740 while (!IsDevicePathEnd (DevicePathNode
)) {
2741 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
2742 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
2743 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
2744 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
2745 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
2746 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
2751 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
2752 // with IDE/AHCI interface GUID.
2754 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
2755 if (!EFI_ERROR (Status
)) {
2756 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
2758 // We find the valid ATAPI device path
2760 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
2761 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
2762 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
2764 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
2766 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
2769 // We find the valid SATA device path
2771 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
2772 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
2773 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
2775 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
2777 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
2781 } while (--IdentifyRetry
> 0);
2783 DevicePathNode
= ChildDevicePathNode
;