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 (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 if (Buffer
== NULL
) {
459 return EFI_INVALID_PARAMETER
;
462 if (BufferSize
== 0) {
466 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
468 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
470 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
472 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
473 if (EFI_ERROR (Status
)) {
474 Status
= EFI_DEVICE_ERROR
;
479 gBS
->ReinstallProtocolInterface (
480 ScsiDiskDevice
->Handle
,
481 &gEfiBlockIoProtocolGuid
,
482 &ScsiDiskDevice
->BlkIo
,
483 &ScsiDiskDevice
->BlkIo
488 // Get the intrinsic block size
490 Media
= ScsiDiskDevice
->BlkIo
.Media
;
491 BlockSize
= Media
->BlockSize
;
493 NumberOfBlocks
= BufferSize
/ BlockSize
;
495 if (!(Media
->MediaPresent
)) {
496 Status
= EFI_NO_MEDIA
;
500 if (MediaId
!= Media
->MediaId
) {
501 Status
= EFI_MEDIA_CHANGED
;
505 if (BufferSize
% BlockSize
!= 0) {
506 Status
= EFI_BAD_BUFFER_SIZE
;
510 if (Lba
> Media
->LastBlock
) {
511 Status
= EFI_INVALID_PARAMETER
;
515 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
516 Status
= EFI_INVALID_PARAMETER
;
520 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
521 Status
= EFI_INVALID_PARAMETER
;
526 // If all the parameters are valid, then perform read sectors command
527 // to transfer data from device to host.
529 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
532 gBS
->RestoreTPL (OldTpl
);
537 The function is to Write Block to SCSI Disk.
539 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
540 @param MediaId The Id of Media detected
541 @param Lba The logic block address
542 @param BufferSize The size of Buffer
543 @param Buffer The buffer to fill the read out data
545 @retval EFI_SUCCESS Successfully to read out block.
546 @retval EFI_WRITE_PROTECTED The device can not be written to.
547 @retval EFI_DEVICE_ERROR Fail to detect media.
548 @retval EFI_NO_MEDIA Media is not present.
549 @retval EFI_MEDIA_CHNAGED Media has changed.
550 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
551 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
556 ScsiDiskWriteBlocks (
557 IN EFI_BLOCK_IO_PROTOCOL
*This
,
564 SCSI_DISK_DEV
*ScsiDiskDevice
;
565 EFI_BLOCK_IO_MEDIA
*Media
;
568 UINTN NumberOfBlocks
;
573 if (Buffer
== NULL
) {
574 return EFI_INVALID_PARAMETER
;
577 if (BufferSize
== 0) {
581 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
583 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
585 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
587 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
588 if (EFI_ERROR (Status
)) {
589 Status
= EFI_DEVICE_ERROR
;
594 gBS
->ReinstallProtocolInterface (
595 ScsiDiskDevice
->Handle
,
596 &gEfiBlockIoProtocolGuid
,
597 &ScsiDiskDevice
->BlkIo
,
598 &ScsiDiskDevice
->BlkIo
603 // Get the intrinsic block size
605 Media
= ScsiDiskDevice
->BlkIo
.Media
;
606 BlockSize
= Media
->BlockSize
;
608 NumberOfBlocks
= BufferSize
/ BlockSize
;
610 if (!(Media
->MediaPresent
)) {
611 Status
= EFI_NO_MEDIA
;
615 if (MediaId
!= Media
->MediaId
) {
616 Status
= EFI_MEDIA_CHANGED
;
620 if (BufferSize
% BlockSize
!= 0) {
621 Status
= EFI_BAD_BUFFER_SIZE
;
625 if (Lba
> Media
->LastBlock
) {
626 Status
= EFI_INVALID_PARAMETER
;
630 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
631 Status
= EFI_INVALID_PARAMETER
;
635 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
636 Status
= EFI_INVALID_PARAMETER
;
640 // if all the parameters are valid, then perform read sectors command
641 // to transfer data from device to host.
643 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
646 gBS
->RestoreTPL (OldTpl
);
653 EFI_SUCCESS is returned directly.
655 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
657 @retval EFI_SUCCESS All outstanding data was written to the device
662 ScsiDiskFlushBlocks (
663 IN EFI_BLOCK_IO_PROTOCOL
*This
674 Detect Device and read out capacity ,if error occurs, parse the sense key.
676 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
677 @param MustReadCapacity The flag about reading device capacity
678 @param MediaChange The pointer of flag indicates if media has changed
680 @retval EFI_DEVICE_ERROR Indicates that error occurs
681 @retval EFI_SUCCESS Successfully to detect media
685 ScsiDiskDetectMedia (
686 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
687 IN BOOLEAN MustReadCapacity
,
688 OUT BOOLEAN
*MediaChange
692 EFI_STATUS ReadCapacityStatus
;
693 EFI_SCSI_SENSE_DATA
*SenseData
;
694 UINTN NumberOfSenseKeys
;
696 BOOLEAN NeedReadCapacity
;
699 EFI_BLOCK_IO_MEDIA OldMedia
;
702 Status
= EFI_SUCCESS
;
703 ReadCapacityStatus
= EFI_SUCCESS
;
705 NumberOfSenseKeys
= 0;
706 NeedReadCapacity
= FALSE
;
707 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
708 *MediaChange
= FALSE
;
711 for (Index
= 0; Index
< MaxRetry
; Index
++) {
712 Status
= ScsiDiskTestUnitReady (
718 if (!EFI_ERROR (Status
)) {
727 if ((Index
== MaxRetry
) && EFI_ERROR (Status
)) {
728 return EFI_DEVICE_ERROR
;
731 Status
= DetectMediaParsingSenseKeys (
737 if (EFI_ERROR (Status
)) {
741 // ACTION_NO_ACTION: need not read capacity
742 // other action code: need read capacity
744 if (Action
== ACTION_NO_ACTION
) {
745 NeedReadCapacity
= FALSE
;
747 NeedReadCapacity
= TRUE
;
751 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
752 // retrieve capacity via Read Capacity command
754 if (NeedReadCapacity
|| MustReadCapacity
) {
756 // retrieve media information
759 for (Index
= 0; Index
< MaxRetry
; Index
++) {
761 ReadCapacityStatus
= ScsiDiskReadCapacity (
767 if (EFI_ERROR (ReadCapacityStatus
) && !NeedRetry
) {
768 return EFI_DEVICE_ERROR
;
771 // analyze sense key to action
773 Status
= DetectMediaParsingSenseKeys (
780 // if Status is error, it may indicate crisis error,
781 // so return without retry.
783 if (EFI_ERROR (Status
)) {
788 case ACTION_NO_ACTION
:
795 case ACTION_RETRY_COMMAND_LATER
:
797 // retry the ReadCapacity later and continuously, until the condition
798 // no longer emerges.
799 // stall time is 100000us, or say 0.1 second.
807 // other cases, just retry the command
813 if ((Index
== MaxRetry
) && EFI_ERROR (ReadCapacityStatus
)) {
814 return EFI_DEVICE_ERROR
;
818 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
820 // Media change information got from the device
825 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
827 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
830 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
832 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
835 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
837 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
840 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
841 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
843 // when change from no media to media present, reset the MediaId to 1.
845 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
848 // when no media, reset the MediaId to zero.
850 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
861 Send out Inquiry command to Device.
863 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
864 @param NeedRetry Indicates if needs try again when error happens
866 @retval EFI_DEVICE_ERROR Indicates that error occurs
867 @retval EFI_SUCCESS Successfully to detect media
871 ScsiDiskInquiryDevice (
872 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
873 OUT BOOLEAN
*NeedRetry
876 UINT32 InquiryDataLength
;
877 UINT8 SenseDataLength
;
878 UINT8 HostAdapterStatus
;
880 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
881 UINTN NumberOfSenseKeys
;
886 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
889 Status
= ScsiInquiryCommand (
890 ScsiDiskDevice
->ScsiIo
,
891 EFI_TIMER_PERIOD_SECONDS (1),
896 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
901 // no need to check HostAdapterStatus and TargetStatus
903 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
904 ParseInquiryData (ScsiDiskDevice
);
907 } else if (Status
== EFI_NOT_READY
) {
909 return EFI_DEVICE_ERROR
;
911 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
913 return EFI_DEVICE_ERROR
;
916 // go ahead to check HostAdapterStatus and TargetStatus
917 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
920 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
921 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
923 return EFI_DEVICE_ERROR
;
924 } else if (Status
== EFI_DEVICE_ERROR
) {
926 // reset the scsi channel
928 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
930 return EFI_DEVICE_ERROR
;
933 Status
= CheckTargetStatus (TargetStatus
);
934 if (Status
== EFI_NOT_READY
) {
936 // reset the scsi device
938 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
940 return EFI_DEVICE_ERROR
;
942 } else if (Status
== EFI_DEVICE_ERROR
) {
944 return EFI_DEVICE_ERROR
;
948 // if goes here, meant ScsiInquiryCommand() failed.
949 // if ScsiDiskRequestSenseKeys() succeeds at last,
950 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
953 for (Index
= 0; Index
< MaxRetry
; Index
++) {
954 Status
= ScsiDiskRequestSenseKeys (
961 if (!EFI_ERROR (Status
)) {
963 return EFI_DEVICE_ERROR
;
967 return EFI_DEVICE_ERROR
;
971 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
972 // set *NeedRetry = FALSE to avoid the outside caller try again.
975 return EFI_DEVICE_ERROR
;
981 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
982 When Test Unit Ready command encounters any error caused by host adapter or
983 target, return error without retrieving Sense Keys.
985 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
986 @param NeedRetry The pointer of flag indicates try again
987 @param SenseDataArray The pointer of an array of sense data
988 @param NumberOfSenseKeys The pointer of the number of sense data array
990 @retval EFI_DEVICE_ERROR Indicates that error occurs
991 @retval EFI_SUCCESS Successfully to test unit
995 ScsiDiskTestUnitReady (
996 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
997 OUT BOOLEAN
*NeedRetry
,
998 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
999 OUT UINTN
*NumberOfSenseKeys
1003 UINT8 SenseDataLength
;
1004 UINT8 HostAdapterStatus
;
1009 SenseDataLength
= 0;
1010 *NumberOfSenseKeys
= 0;
1013 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1015 Status
= ScsiTestUnitReadyCommand (
1016 ScsiDiskDevice
->ScsiIo
,
1017 EFI_TIMER_PERIOD_SECONDS (1),
1024 // no need to check HostAdapterStatus and TargetStatus
1026 if (Status
== EFI_NOT_READY
) {
1028 return EFI_DEVICE_ERROR
;
1030 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1032 return EFI_DEVICE_ERROR
;
1035 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1038 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1039 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1041 return EFI_DEVICE_ERROR
;
1043 } else if (Status
== EFI_DEVICE_ERROR
) {
1045 // reset the scsi channel
1047 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1049 return EFI_DEVICE_ERROR
;
1052 Status
= CheckTargetStatus (TargetStatus
);
1053 if (Status
== EFI_NOT_READY
) {
1055 // reset the scsi device
1057 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1059 return EFI_DEVICE_ERROR
;
1061 } else if (Status
== EFI_DEVICE_ERROR
) {
1063 return EFI_DEVICE_ERROR
;
1067 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1068 Status
= ScsiDiskRequestSenseKeys (
1075 if (!EFI_ERROR (Status
)) {
1080 return EFI_DEVICE_ERROR
;
1084 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1085 // set *NeedRetry = FALSE to avoid the outside caller try again.
1088 return EFI_DEVICE_ERROR
;
1092 Parsing Sense Keys which got from request sense command.
1094 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1095 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1096 @param NumberOfSenseKeys The number of sense key
1097 @param Action The pointer of action which indicates what is need to do next
1099 @retval EFI_DEVICE_ERROR Indicates that error occurs
1100 @retval EFI_SUCCESS Successfully to complete the parsing
1104 DetectMediaParsingSenseKeys (
1105 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1106 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1107 IN UINTN NumberOfSenseKeys
,
1114 // Default is to read capacity, unless..
1116 *Action
= ACTION_READ_CAPACITY
;
1118 if (NumberOfSenseKeys
== 0) {
1119 *Action
= ACTION_NO_ACTION
;
1123 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1125 // No Sense Key returned from last submitted command
1127 *Action
= ACTION_NO_ACTION
;
1131 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1132 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1133 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1134 *Action
= ACTION_NO_ACTION
;
1138 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1139 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1143 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1144 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1145 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1146 return EFI_DEVICE_ERROR
;
1149 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1150 return EFI_DEVICE_ERROR
;
1153 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1155 *Action
= ACTION_RETRY_COMMAND_LATER
;
1159 return EFI_DEVICE_ERROR
;
1167 Send read capacity command to device and get the device parameter.
1169 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1170 @param NeedRetry The pointer of flag indicates if need a retry
1171 @param SenseDataArray The pointer of an array of sense data
1172 @param NumberOfSenseKeys The number of sense key
1174 @retval EFI_DEVICE_ERROR Indicates that error occurs
1175 @retval EFI_SUCCESS Successfully to read capacity
1179 ScsiDiskReadCapacity (
1180 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1181 OUT BOOLEAN
*NeedRetry
,
1182 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1183 OUT UINTN
*NumberOfSenseKeys
1186 UINT8 HostAdapterStatus
;
1188 EFI_STATUS CommandStatus
;
1192 UINT8 SenseDataLength
;
1193 UINT32 DataLength10
;
1194 UINT32 DataLength16
;
1195 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10
;
1196 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16
;
1199 SenseDataLength
= 0;
1200 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1201 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1202 ZeroMem (&CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1203 ZeroMem (&CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1205 *NumberOfSenseKeys
= 0;
1209 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1210 // 16 byte command should be used to access large hard disk >2TB
1212 CommandStatus
= ScsiReadCapacityCommand (
1213 ScsiDiskDevice
->ScsiIo
,
1214 EFI_TIMER_PERIOD_SECONDS(1),
1219 (VOID
*) &CapacityData10
,
1224 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1225 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
.LastLba3
== 0xff) && (CapacityData10
.LastLba2
== 0xff) &&
1226 (CapacityData10
.LastLba1
== 0xff) && (CapacityData10
.LastLba0
== 0xff)) {
1228 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1230 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1232 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1233 // and LowestAlignedLba
1235 CommandStatus
= ScsiReadCapacity16Command (
1236 ScsiDiskDevice
->ScsiIo
,
1237 EFI_TIMER_PERIOD_SECONDS (1),
1242 (VOID
*) &CapacityData16
,
1249 // no need to check HostAdapterStatus and TargetStatus
1251 if (CommandStatus
== EFI_SUCCESS
) {
1252 GetMediaInfo (ScsiDiskDevice
, &CapacityData10
,&CapacityData16
);
1255 } else if (CommandStatus
== EFI_NOT_READY
) {
1257 return EFI_DEVICE_ERROR
;
1259 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1261 return EFI_DEVICE_ERROR
;
1264 // go ahead to check HostAdapterStatus and TargetStatus
1265 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1268 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1269 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1271 return EFI_DEVICE_ERROR
;
1273 } else if (Status
== EFI_DEVICE_ERROR
) {
1275 // reset the scsi channel
1277 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1279 return EFI_DEVICE_ERROR
;
1282 Status
= CheckTargetStatus (TargetStatus
);
1283 if (Status
== EFI_NOT_READY
) {
1285 // reset the scsi device
1287 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1289 return EFI_DEVICE_ERROR
;
1291 } else if (Status
== EFI_DEVICE_ERROR
) {
1293 return EFI_DEVICE_ERROR
;
1297 // if goes here, meant ScsiReadCapacityCommand() failed.
1298 // if ScsiDiskRequestSenseKeys() succeeds at last,
1299 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1302 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1304 Status
= ScsiDiskRequestSenseKeys (
1311 if (!EFI_ERROR (Status
)) {
1313 return EFI_DEVICE_ERROR
;
1317 return EFI_DEVICE_ERROR
;
1321 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1322 // set *NeedRetry = FALSE to avoid the outside caller try again.
1325 return EFI_DEVICE_ERROR
;
1329 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1331 @param HostAdapterStatus Host Adapter status
1333 @retval EFI_SUCCESS Host adapter is OK.
1334 @retval EFI_TIMEOUT Timeout.
1335 @retval EFI_NOT_READY Adapter NOT ready.
1336 @retval EFI_DEVICE_ERROR Adapter device error.
1340 CheckHostAdapterStatus (
1341 IN UINT8 HostAdapterStatus
1344 switch (HostAdapterStatus
) {
1345 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1348 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1349 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1350 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1353 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1354 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1355 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1356 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1357 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1358 return EFI_NOT_READY
;
1360 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1361 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1362 return EFI_DEVICE_ERROR
;
1371 Check the target status and re-interpret it in EFI_STATUS.
1373 @param TargetStatus Target status
1375 @retval EFI_NOT_READY Device is NOT ready.
1376 @retval EFI_DEVICE_ERROR
1382 IN UINT8 TargetStatus
1385 switch (TargetStatus
) {
1386 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1387 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1388 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1391 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1392 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1393 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1394 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1395 return EFI_NOT_READY
;
1397 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1398 return EFI_DEVICE_ERROR
;
1408 Retrieve all sense keys from the device.
1410 When encountering error during the process, if retrieve sense keys before
1411 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
1412 and NeedRetry set to FALSE; otherwize, return the proper return status.
1414 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1415 @param NeedRetry The pointer of flag indicates if need a retry
1416 @param SenseDataArray The pointer of an array of sense data
1417 @param NumberOfSenseKeys The number of sense key
1418 @param AskResetIfError The flag indicates if need reset when error occurs
1420 @retval EFI_DEVICE_ERROR Indicates that error occurs
1421 @retval EFI_SUCCESS Successfully to request sense key
1425 ScsiDiskRequestSenseKeys (
1426 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1427 OUT BOOLEAN
*NeedRetry
,
1428 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1429 OUT UINTN
*NumberOfSenseKeys
,
1430 IN BOOLEAN AskResetIfError
1433 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1434 UINT8 SenseDataLength
;
1437 EFI_STATUS FallStatus
;
1438 UINT8 HostAdapterStatus
;
1441 FallStatus
= EFI_SUCCESS
;
1442 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
1445 ScsiDiskDevice
->SenseData
,
1446 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1449 *NumberOfSenseKeys
= 0;
1450 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1451 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1453 for (SenseReq
= TRUE
; SenseReq
;) {
1454 Status
= ScsiRequestSenseCommand (
1455 ScsiDiskDevice
->ScsiIo
,
1456 EFI_TIMER_PERIOD_SECONDS (2),
1462 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1463 FallStatus
= EFI_SUCCESS
;
1465 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1467 FallStatus
= EFI_DEVICE_ERROR
;
1469 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1471 FallStatus
= EFI_DEVICE_ERROR
;
1473 } else if (Status
== EFI_DEVICE_ERROR
) {
1474 if (AskResetIfError
) {
1475 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1478 FallStatus
= EFI_DEVICE_ERROR
;
1481 if (EFI_ERROR (FallStatus
)) {
1482 if (*NumberOfSenseKeys
!= 0) {
1486 return EFI_DEVICE_ERROR
;
1490 (*NumberOfSenseKeys
) += 1;
1493 // no more sense key or number of sense keys exceeds predefined,
1496 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1497 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1507 Get information from media read capacity command.
1509 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1510 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1511 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
1516 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1517 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1518 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1523 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1524 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 1;
1527 if (!ScsiDiskDevice
->Cdb16Byte
) {
1528 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1529 (Capacity10
->LastLba2
<< 16) |
1530 (Capacity10
->LastLba1
<< 8) |
1531 Capacity10
->LastLba0
;
1533 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1534 (Capacity10
->BlockSize2
<< 16) |
1535 (Capacity10
->BlockSize1
<< 8) |
1536 Capacity10
->BlockSize0
;
1537 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
1540 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1541 *Ptr
++ = Capacity16
->LastLba0
;
1542 *Ptr
++ = Capacity16
->LastLba1
;
1543 *Ptr
++ = Capacity16
->LastLba2
;
1544 *Ptr
++ = Capacity16
->LastLba3
;
1545 *Ptr
++ = Capacity16
->LastLba4
;
1546 *Ptr
++ = Capacity16
->LastLba5
;
1547 *Ptr
++ = Capacity16
->LastLba6
;
1548 *Ptr
= Capacity16
->LastLba7
;
1550 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1551 (Capacity16
->BlockSize2
<< 16) |
1552 (Capacity16
->BlockSize1
<< 8) |
1553 Capacity16
->BlockSize0
;
1555 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8)|(Capacity16
->LowestAlignLogic1
);
1556 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= Capacity16
->LogicPerPhysical
;
1557 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION2
;
1561 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1563 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1564 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1567 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1568 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1575 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1580 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1583 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1584 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1588 Read sector from SCSI Disk.
1590 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1591 @param Buffer The buffer to fill in the read out data
1592 @param Lba Logic block address
1593 @param NumberOfBlocks The number of blocks to read
1595 @retval EFI_DEVICE_ERROR Indicates a device error.
1596 @retval EFI_SUCCESS Operation is successful.
1600 ScsiDiskReadSectors (
1601 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1604 IN UINTN NumberOfBlocks
1607 UINTN BlocksRemaining
;
1618 EFI_SCSI_SENSE_DATA
*SenseData
;
1619 UINTN NumberOfSenseKeys
;
1622 NumberOfSenseKeys
= 0;
1624 Status
= EFI_SUCCESS
;
1626 BlocksRemaining
= NumberOfBlocks
;
1627 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1630 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1632 if (!ScsiDiskDevice
->Cdb16Byte
) {
1635 MaxBlock
= 0xFFFFFFFF;
1640 while (BlocksRemaining
> 0) {
1642 if (BlocksRemaining
<= MaxBlock
) {
1643 if (!ScsiDiskDevice
->Cdb16Byte
) {
1644 SectorCount
= (UINT16
) BlocksRemaining
;
1646 SectorCount
= (UINT32
) BlocksRemaining
;
1649 SectorCount
= MaxBlock
;
1652 ByteCount
= SectorCount
* BlockSize
;
1653 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1656 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1657 if (!ScsiDiskDevice
->Cdb16Byte
) {
1658 Status
= ScsiDiskRead10 (
1670 Status
= ScsiDiskRead16 (
1682 if (!EFI_ERROR (Status
)) {
1687 return EFI_DEVICE_ERROR
;
1692 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1693 return EFI_DEVICE_ERROR
;
1697 // actual transferred sectors
1699 SectorCount
= ByteCount
/ BlockSize
;
1702 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1703 BlocksRemaining
-= SectorCount
;
1710 Write sector to SCSI Disk.
1712 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1713 @param Buffer The buffer of data to be written into SCSI Disk
1714 @param Lba Logic block address
1715 @param NumberOfBlocks The number of blocks to read
1717 @retval EFI_DEVICE_ERROR Indicates a device error.
1718 @retval EFI_SUCCESS Operation is successful.
1722 ScsiDiskWriteSectors (
1723 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1726 IN UINTN NumberOfBlocks
1729 UINTN BlocksRemaining
;
1740 EFI_SCSI_SENSE_DATA
*SenseData
;
1741 UINTN NumberOfSenseKeys
;
1744 NumberOfSenseKeys
= 0;
1746 Status
= EFI_SUCCESS
;
1748 BlocksRemaining
= NumberOfBlocks
;
1749 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1752 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
1754 if (!ScsiDiskDevice
->Cdb16Byte
) {
1757 MaxBlock
= 0xFFFFFFFF;
1762 while (BlocksRemaining
> 0) {
1764 if (BlocksRemaining
<= MaxBlock
) {
1765 if (!ScsiDiskDevice
->Cdb16Byte
) {
1766 SectorCount
= (UINT16
) BlocksRemaining
;
1768 SectorCount
= (UINT32
) BlocksRemaining
;
1771 SectorCount
= MaxBlock
;
1774 ByteCount
= SectorCount
* BlockSize
;
1775 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1777 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1778 if (!ScsiDiskDevice
->Cdb16Byte
) {
1779 Status
= ScsiDiskWrite10 (
1791 Status
= ScsiDiskWrite16 (
1803 if (!EFI_ERROR (Status
)) {
1808 return EFI_DEVICE_ERROR
;
1812 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1813 return EFI_DEVICE_ERROR
;
1816 // actual transferred sectors
1818 SectorCount
= ByteCount
/ BlockSize
;
1821 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1822 BlocksRemaining
-= SectorCount
;
1830 Submit Read(10) command.
1832 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1833 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1834 @param SenseDataArray NOT used yet in this function
1835 @param NumberOfSenseKeys The number of sense key
1836 @param Timeout The time to complete the command
1837 @param DataBuffer The buffer to fill with the read out data
1838 @param DataLength The length of buffer
1839 @param StartLba The start logic block address
1840 @param SectorSize The size of sector
1842 @return EFI_STATUS is returned by calling ScsiRead10Command().
1846 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1847 OUT BOOLEAN
*NeedRetry
,
1848 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1849 OUT UINTN
*NumberOfSenseKeys
,
1851 OUT UINT8
*DataBuffer
,
1852 IN OUT UINT32
*DataLength
,
1854 IN UINT32 SectorSize
1857 UINT8 SenseDataLength
;
1859 UINT8 HostAdapterStatus
;
1863 *NumberOfSenseKeys
= 0;
1864 SenseDataLength
= 0;
1865 Status
= ScsiRead10Command (
1866 ScsiDiskDevice
->ScsiIo
,
1882 Submit Write(10) Command.
1884 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1885 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1886 @param SenseDataArray NOT used yet in this function
1887 @param NumberOfSenseKeys The number of sense key
1888 @param Timeout The time to complete the command
1889 @param DataBuffer The buffer to fill with the read out data
1890 @param DataLength The length of buffer
1891 @param StartLba The start logic block address
1892 @param SectorSize The size of sector
1894 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1899 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1900 OUT BOOLEAN
*NeedRetry
,
1901 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1902 OUT UINTN
*NumberOfSenseKeys
,
1904 IN UINT8
*DataBuffer
,
1905 IN OUT UINT32
*DataLength
,
1907 IN UINT32 SectorSize
1911 UINT8 SenseDataLength
;
1912 UINT8 HostAdapterStatus
;
1916 *NumberOfSenseKeys
= 0;
1917 SenseDataLength
= 0;
1918 Status
= ScsiWrite10Command (
1919 ScsiDiskDevice
->ScsiIo
,
1935 Submit Read(16) command.
1937 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1938 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1939 @param SenseDataArray NOT used yet in this function
1940 @param NumberOfSenseKeys The number of sense key
1941 @param Timeout The time to complete the command
1942 @param DataBuffer The buffer to fill with the read out data
1943 @param DataLength The length of buffer
1944 @param StartLba The start logic block address
1945 @param SectorSize The size of sector
1947 @return EFI_STATUS is returned by calling ScsiRead10Command().
1951 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1952 OUT BOOLEAN
*NeedRetry
,
1953 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1954 OUT UINTN
*NumberOfSenseKeys
,
1956 OUT UINT8
*DataBuffer
,
1957 IN OUT UINT32
*DataLength
,
1959 IN UINT32 SectorSize
1962 UINT8 SenseDataLength
;
1964 UINT8 HostAdapterStatus
;
1968 *NumberOfSenseKeys
= 0;
1969 SenseDataLength
= 0;
1970 Status
= ScsiRead16Command (
1971 ScsiDiskDevice
->ScsiIo
,
1987 Submit Write(16) Command.
1989 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1990 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1991 @param SenseDataArray NOT used yet in this function
1992 @param NumberOfSenseKeys The number of sense key
1993 @param Timeout The time to complete the command
1994 @param DataBuffer The buffer to fill with the read out data
1995 @param DataLength The length of buffer
1996 @param StartLba The start logic block address
1997 @param SectorSize The size of sector
1999 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2004 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2005 OUT BOOLEAN
*NeedRetry
,
2006 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
2007 OUT UINTN
*NumberOfSenseKeys
,
2009 IN UINT8
*DataBuffer
,
2010 IN OUT UINT32
*DataLength
,
2012 IN UINT32 SectorSize
2016 UINT8 SenseDataLength
;
2017 UINT8 HostAdapterStatus
;
2021 *NumberOfSenseKeys
= 0;
2022 SenseDataLength
= 0;
2023 Status
= ScsiWrite16Command (
2024 ScsiDiskDevice
->ScsiIo
,
2040 Check sense key to find if media presents.
2042 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2043 @param SenseCounts The number of sense key
2045 @retval TRUE NOT any media
2046 @retval FALSE Media presents
2050 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2051 IN UINTN SenseCounts
2054 EFI_SCSI_SENSE_DATA
*SensePtr
;
2059 SensePtr
= SenseData
;
2061 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2063 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
2064 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
2066 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
2067 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
2080 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2081 @param SenseCounts The number of sense key
2084 @retval FALSE NOT error
2088 ScsiDiskIsMediaError (
2089 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2090 IN UINTN SenseCounts
2093 EFI_SCSI_SENSE_DATA
*SensePtr
;
2098 SensePtr
= SenseData
;
2100 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2102 switch (SensePtr
->Sense_Key
) {
2104 case EFI_SCSI_SK_MEDIUM_ERROR
:
2106 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2108 switch (SensePtr
->Addnl_Sense_Code
) {
2113 case EFI_SCSI_ASC_MEDIA_ERR1
:
2118 case EFI_SCSI_ASC_MEDIA_ERR2
:
2123 case EFI_SCSI_ASC_MEDIA_ERR3
:
2124 case EFI_SCSI_ASC_MEDIA_ERR4
:
2134 case EFI_SCSI_SK_NOT_READY
:
2136 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2138 switch (SensePtr
->Addnl_Sense_Code
) {
2140 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2142 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2163 Check sense key to find if hardware error happens.
2165 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2166 @param SenseCounts The number of sense key
2168 @retval TRUE Hardware error exits.
2169 @retval FALSE NO error.
2173 ScsiDiskIsHardwareError (
2174 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2175 IN UINTN SenseCounts
2178 EFI_SCSI_SENSE_DATA
*SensePtr
;
2183 SensePtr
= SenseData
;
2185 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2188 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2190 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2202 Check sense key to find if media has changed.
2204 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2205 @param SenseCounts The number of sense key
2207 @retval TRUE Media is changed.
2208 @retval FALSE Media is NOT changed.
2211 ScsiDiskIsMediaChange (
2212 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2213 IN UINTN SenseCounts
2216 EFI_SCSI_SENSE_DATA
*SensePtr
;
2218 BOOLEAN IsMediaChanged
;
2220 IsMediaChanged
= FALSE
;
2221 SensePtr
= SenseData
;
2223 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2225 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2226 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2228 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2229 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2230 IsMediaChanged
= TRUE
;
2236 return IsMediaChanged
;
2240 Check sense key to find if reset happens.
2242 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2243 @param SenseCounts The number of sense key
2245 @retval TRUE It is reset before.
2246 @retval FALSE It is NOT reset before.
2250 ScsiDiskIsResetBefore (
2251 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2252 IN UINTN SenseCounts
2255 EFI_SCSI_SENSE_DATA
*SensePtr
;
2257 BOOLEAN IsResetBefore
;
2259 IsResetBefore
= FALSE
;
2260 SensePtr
= SenseData
;
2262 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2265 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2266 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2268 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2269 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2270 IsResetBefore
= TRUE
;
2276 return IsResetBefore
;
2280 Check sense key to find if the drive is ready.
2282 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2283 @param SenseCounts The number of sense key
2284 @param RetryLater The flag means if need a retry
2286 @retval TRUE Drive is ready.
2287 @retval FALSE Drive is NOT ready.
2291 ScsiDiskIsDriveReady (
2292 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2293 IN UINTN SenseCounts
,
2294 OUT BOOLEAN
*RetryLater
2297 EFI_SCSI_SENSE_DATA
*SensePtr
;
2302 *RetryLater
= FALSE
;
2303 SensePtr
= SenseData
;
2305 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2307 switch (SensePtr
->Sense_Key
) {
2309 case EFI_SCSI_SK_NOT_READY
:
2311 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2313 switch (SensePtr
->Addnl_Sense_Code
) {
2314 case EFI_SCSI_ASC_NOT_READY
:
2316 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2318 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2319 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2321 // Additional Sense Code Qualifier is
2322 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2330 *RetryLater
= FALSE
;
2351 Check sense key to find if it has sense key.
2353 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2354 @param SenseCounts - The number of sense key
2356 @retval TRUE It has sense key.
2357 @retval FALSE It has NOT any sense key.
2361 ScsiDiskHaveSenseKey (
2362 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2363 IN UINTN SenseCounts
2366 EFI_SCSI_SENSE_DATA
*SensePtr
;
2368 BOOLEAN HaveSenseKey
;
2370 if (SenseCounts
== 0) {
2371 HaveSenseKey
= FALSE
;
2373 HaveSenseKey
= TRUE
;
2376 SensePtr
= SenseData
;
2378 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2381 // Sense Key is SK_NO_SENSE (0x0)
2383 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2385 HaveSenseKey
= FALSE
;
2391 return HaveSenseKey
;
2395 Release resource about disk device.
2397 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2401 ReleaseScsiDiskDeviceResources (
2402 IN SCSI_DISK_DEV
*ScsiDiskDevice
2405 if (ScsiDiskDevice
== NULL
) {
2409 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2410 FreePool (ScsiDiskDevice
->SenseData
);
2411 ScsiDiskDevice
->SenseData
= NULL
;
2414 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2415 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2416 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2419 FreePool (ScsiDiskDevice
);
2421 ScsiDiskDevice
= NULL
;
2425 Determine if Block Io should be produced.
2428 @param ChildHandle Child Handle to retrieve Parent information.
2430 @retval TRUE Should produce Block Io.
2431 @retval FALSE Should not produce Block Io.
2435 DetermineInstallBlockIo (
2436 IN EFI_HANDLE ChildHandle
2439 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2440 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2443 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2444 // check its attribute, logic or physical.
2446 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2447 if (ExtScsiPassThru
!= NULL
) {
2448 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2454 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2455 // check its attribute, logic or physical.
2457 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2458 if (ScsiPassThru
!= NULL
) {
2459 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2468 Search protocol database and check to see if the protocol
2469 specified by ProtocolGuid is present on a ControllerHandle and opened by
2470 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2471 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2472 will be opened on it.
2475 @param ProtocolGuid ProtocolGuid pointer.
2476 @param ChildHandle Child Handle to retrieve Parent information.
2482 IN EFI_GUID
*ProtocolGuid
,
2483 IN EFI_HANDLE ChildHandle
2490 EFI_HANDLE
*HandleBuffer
;
2493 // Retrieve the list of all handles from the handle database
2495 Status
= gBS
->LocateHandleBuffer (
2503 if (EFI_ERROR (Status
)) {
2508 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
2510 for (Index
= 0; Index
< HandleCount
; Index
++) {
2511 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
2512 if (!EFI_ERROR (Status
)) {
2513 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
2514 if (!EFI_ERROR (Status
)) {
2515 gBS
->FreePool (HandleBuffer
);
2521 gBS
->FreePool (HandleBuffer
);
2526 Provides inquiry information for the controller type.
2528 This function is used by the IDE bus driver to get inquiry data. Data format
2529 of Identify data is defined by the Interface GUID.
2531 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2532 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
2533 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
2535 @retval EFI_SUCCESS The command was accepted without any errors.
2536 @retval EFI_NOT_FOUND Device does not support this data class
2537 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
2538 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
2543 ScsiDiskInfoInquiry (
2544 IN EFI_DISK_INFO_PROTOCOL
*This
,
2545 IN OUT VOID
*InquiryData
,
2546 IN OUT UINT32
*InquiryDataSize
2550 SCSI_DISK_DEV
*ScsiDiskDevice
;
2552 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2554 Status
= EFI_BUFFER_TOO_SMALL
;
2555 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
2556 Status
= EFI_SUCCESS
;
2557 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
2559 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
2565 Provides identify information for the controller type.
2567 This function is used by the IDE bus driver to get identify data. Data format
2568 of Identify data is defined by the Interface GUID.
2570 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
2572 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
2573 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
2576 @retval EFI_SUCCESS The command was accepted without any errors.
2577 @retval EFI_NOT_FOUND Device does not support this data class
2578 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
2579 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
2584 ScsiDiskInfoIdentify (
2585 IN EFI_DISK_INFO_PROTOCOL
*This
,
2586 IN OUT VOID
*IdentifyData
,
2587 IN OUT UINT32
*IdentifyDataSize
2591 SCSI_DISK_DEV
*ScsiDiskDevice
;
2593 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2595 // Physical SCSI bus does not support this data class.
2597 return EFI_NOT_FOUND
;
2600 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2602 Status
= EFI_BUFFER_TOO_SMALL
;
2603 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
2604 Status
= EFI_SUCCESS
;
2605 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
2607 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
2612 Provides sense data information for the controller type.
2614 This function is used by the IDE bus driver to get sense data.
2615 Data format of Sense data is defined by the Interface GUID.
2617 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2618 @param[in, out] SenseData Pointer to the SenseData.
2619 @param[in, out] SenseDataSize Size of SenseData in bytes.
2620 @param[out] SenseDataNumber Pointer to the value for the sense data size.
2622 @retval EFI_SUCCESS The command was accepted without any errors.
2623 @retval EFI_NOT_FOUND Device does not support this data class.
2624 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
2625 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
2630 ScsiDiskInfoSenseData (
2631 IN EFI_DISK_INFO_PROTOCOL
*This
,
2632 IN OUT VOID
*SenseData
,
2633 IN OUT UINT32
*SenseDataSize
,
2634 OUT UINT8
*SenseDataNumber
2637 return EFI_NOT_FOUND
;
2642 This function is used by the IDE bus driver to get controller information.
2644 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
2645 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
2646 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
2648 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
2649 @retval EFI_UNSUPPORTED This is not an IDE device.
2654 ScsiDiskInfoWhichIde (
2655 IN EFI_DISK_INFO_PROTOCOL
*This
,
2656 OUT UINT32
*IdeChannel
,
2657 OUT UINT32
*IdeDevice
2660 SCSI_DISK_DEV
*ScsiDiskDevice
;
2662 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
)) {
2664 // This is not an IDE physical device.
2666 return EFI_UNSUPPORTED
;
2669 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
2670 *IdeChannel
= ScsiDiskDevice
->Channel
;
2671 *IdeDevice
= ScsiDiskDevice
->Device
;
2678 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
2680 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
2681 implement Identify() interface for DiskInfo protocol. The ATA command is sent
2682 via SCSI Request Packet.
2684 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2686 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
2687 @retval others Some error occurred during the identification that ATAPI device.
2691 AtapiIdentifyDevice (
2692 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2695 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
2699 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
2701 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
2702 ZeroMem (Cdb
, sizeof (Cdb
));
2704 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
2705 CommandPacket
.Timeout
= EFI_TIMER_PERIOD_SECONDS (1);
2706 CommandPacket
.Cdb
= Cdb
;
2707 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
2708 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
2709 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
2711 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
2716 Initialize the installation of DiskInfo protocol.
2718 This function prepares for the installation of DiskInfo protocol on the child handle.
2719 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
2720 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
2721 to be IDE/AHCI interface GUID.
2723 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2724 @param ChildHandle Child handle to install DiskInfo protocol.
2728 InitializeInstallDiskInfo (
2729 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2730 IN EFI_HANDLE ChildHandle
2734 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2735 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
2736 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
2737 SATA_DEVICE_PATH
*SataDevicePath
;
2738 UINTN IdentifyRetry
;
2740 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
2742 // Device Path protocol must be installed on the device handle.
2744 ASSERT_EFI_ERROR (Status
);
2746 // Copy the DiskInfo protocol template.
2748 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
2750 while (!IsDevicePathEnd (DevicePathNode
)) {
2751 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
2752 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
2753 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
2754 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
2755 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
2756 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
2761 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
2762 // with IDE/AHCI interface GUID.
2764 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
2765 if (!EFI_ERROR (Status
)) {
2766 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
2768 // We find the valid ATAPI device path
2770 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
2771 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
2772 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
2774 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
2776 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
2779 // We find the valid SATA device path
2781 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
2782 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
2783 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
2785 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
2787 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
2791 } while (--IdentifyRetry
> 0);
2793 DevicePathNode
= ChildDevicePathNode
;