2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. 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.
19 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
20 ScsiDiskDriverBindingSupported
,
21 ScsiDiskDriverBindingStart
,
22 ScsiDiskDriverBindingStop
,
29 The user Entry Point for module ScsiDisk.
31 The user code starts with this function.
33 @param ImageHandle The firmware allocated handle for the EFI image.
34 @param SystemTable A pointer to the EFI System Table.
36 @retval EFI_SUCCESS The entry point is executed successfully.
37 @retval other Some error occurs when executing this entry point.
43 IN EFI_HANDLE ImageHandle
,
44 IN EFI_SYSTEM_TABLE
*SystemTable
50 // Install driver model protocol(s).
52 Status
= EfiLibInstallDriverBindingComponentName2 (
55 &gScsiDiskDriverBinding
,
57 &gScsiDiskComponentName
,
58 &gScsiDiskComponentName2
60 ASSERT_EFI_ERROR (Status
);
67 Test to see if this driver supports ControllerHandle.
69 This service is called by the EFI boot service ConnectController(). In order
70 to make drivers as small as possible, there are a few calling restrictions for
71 this service. ConnectController() must follow these calling restrictions.
72 If any other agent wishes to call Supported() it must also follow these
75 @param This Protocol instance pointer.
76 @param ControllerHandle Handle of device to test
77 @param RemainingDevicePath Optional parameter use to pick a specific child
80 @retval EFI_SUCCESS This driver supports this device
81 @retval EFI_ALREADY_STARTED This driver is already running on this device
82 @retval other This driver does not support this device
87 ScsiDiskDriverBindingSupported (
88 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
89 IN EFI_HANDLE Controller
,
90 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
94 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
97 Status
= gBS
->OpenProtocol (
99 &gEfiScsiIoProtocolGuid
,
101 This
->DriverBindingHandle
,
103 EFI_OPEN_PROTOCOL_BY_DRIVER
105 if (EFI_ERROR (Status
)) {
109 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
110 if (!EFI_ERROR (Status
)) {
111 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
112 Status
= EFI_SUCCESS
;
114 Status
= EFI_UNSUPPORTED
;
120 &gEfiScsiIoProtocolGuid
,
121 This
->DriverBindingHandle
,
129 Start this driver on ControllerHandle.
131 This service is called by the EFI boot service ConnectController(). In order
132 to make drivers as small as possible, there are a few calling restrictions for
133 this service. ConnectController() must follow these calling restrictions. If
134 any other agent wishes to call Start() it must also follow these calling
137 @param This Protocol instance pointer.
138 @param ControllerHandle Handle of device to bind driver to
139 @param RemainingDevicePath Optional parameter use to pick a specific child
142 @retval EFI_SUCCESS This driver is added to ControllerHandle
143 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
144 @retval other This driver does not support this device
149 ScsiDiskDriverBindingStart (
150 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
151 IN EFI_HANDLE Controller
,
152 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
156 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
157 SCSI_DISK_DEV
*ScsiDiskDevice
;
163 Status
= gBS
->AllocatePool (
165 sizeof (SCSI_DISK_DEV
),
166 (VOID
**) &ScsiDiskDevice
168 if (EFI_ERROR (Status
)) {
172 ZeroMem (ScsiDiskDevice
, sizeof (SCSI_DISK_DEV
));
174 Status
= gBS
->OpenProtocol (
176 &gEfiScsiIoProtocolGuid
,
178 This
->DriverBindingHandle
,
180 EFI_OPEN_PROTOCOL_BY_DRIVER
182 if (EFI_ERROR (Status
)) {
183 gBS
->FreePool (ScsiDiskDevice
);
187 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
188 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
189 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
190 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
191 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
192 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
193 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
194 ScsiDiskDevice
->Handle
= Controller
;
196 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
197 switch (ScsiDiskDevice
->DeviceType
) {
198 case EFI_SCSI_TYPE_DISK
:
199 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
202 case EFI_SCSI_TYPE_CDROM
:
203 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
207 // The Sense Data Array's initial size is 6
209 ScsiDiskDevice
->SenseDataNumber
= 6;
210 Status
= gBS
->AllocatePool (
212 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
,
213 (VOID
**) &(ScsiDiskDevice
->SenseData
)
215 if (EFI_ERROR (Status
)) {
218 &gEfiScsiIoProtocolGuid
,
219 This
->DriverBindingHandle
,
222 gBS
->FreePool (ScsiDiskDevice
);
227 ScsiDiskDevice
->SenseData
,
228 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
232 // Retrive device information
235 for (Index
= 0; Index
< MaxRetry
; Index
++) {
236 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
237 if (!EFI_ERROR (Status
)) {
242 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
245 &gEfiScsiIoProtocolGuid
,
246 This
->DriverBindingHandle
,
249 gBS
->FreePool (ScsiDiskDevice
);
250 return EFI_DEVICE_ERROR
;
254 // The second parameter "TRUE" means must
255 // retrieve media capacity
257 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, TRUE
, &Temp
);
258 if (!EFI_ERROR (Status
)) {
259 Status
= gBS
->InstallMultipleProtocolInterfaces (
261 &gEfiBlockIoProtocolGuid
,
262 &ScsiDiskDevice
->BlkIo
,
267 if (EFI_ERROR (Status
)) {
268 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
271 &gEfiScsiIoProtocolGuid
,
272 This
->DriverBindingHandle
,
275 gBS
->FreePool (ScsiDiskDevice
);
279 ScsiDiskDevice
->ControllerNameTable
= NULL
;
282 gScsiDiskComponentName
.SupportedLanguages
,
283 &ScsiDiskDevice
->ControllerNameTable
,
289 gScsiDiskComponentName2
.SupportedLanguages
,
290 &ScsiDiskDevice
->ControllerNameTable
,
302 Stop this driver on ControllerHandle.
304 This service is called by the EFI boot service DisconnectController().
305 In order to make drivers as small as possible, there are a few calling
306 restrictions for this service. DisconnectController() must follow these
307 calling restrictions. If any other agent wishes to call Stop() it must
308 also follow these calling restrictions.
310 @param This Protocol instance pointer.
311 @param ControllerHandle Handle of device to stop driver on
312 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
313 children is zero stop the entire bus driver.
314 @param ChildHandleBuffer List of Child Handles to Stop.
316 @retval EFI_SUCCESS This driver is removed ControllerHandle
317 @retval other This driver was not removed from this device
322 ScsiDiskDriverBindingStop (
323 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
324 IN EFI_HANDLE Controller
,
325 IN UINTN NumberOfChildren
,
326 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
329 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
330 SCSI_DISK_DEV
*ScsiDiskDevice
;
333 Status
= gBS
->OpenProtocol (
335 &gEfiBlockIoProtocolGuid
,
337 This
->DriverBindingHandle
,
339 EFI_OPEN_PROTOCOL_GET_PROTOCOL
341 if (EFI_ERROR (Status
)) {
345 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
346 Status
= gBS
->UninstallProtocolInterface (
348 &gEfiBlockIoProtocolGuid
,
349 &ScsiDiskDevice
->BlkIo
351 if (!EFI_ERROR (Status
)) {
354 &gEfiScsiIoProtocolGuid
,
355 This
->DriverBindingHandle
,
359 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
373 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
374 @param ExtendedVerification The flag about if extend verificate
376 @retval EFI_SUCCESS The device was reset.
377 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
379 @return EFI_STATUS is retured from EFI_SCSI_IO_PROTOCOL.ResetDevice().
385 IN EFI_BLOCK_IO_PROTOCOL
*This
,
386 IN BOOLEAN ExtendedVerification
390 SCSI_DISK_DEV
*ScsiDiskDevice
;
393 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
395 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
397 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
399 if (!ExtendedVerification
) {
403 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
406 gBS
->RestoreTPL (OldTpl
);
411 The function is to Read Block from SCSI Disk.
413 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
414 @param MediaId The Id of Media detected
415 @param Lba The logic block address
416 @param BufferSize The size of Buffer
417 @param Buffer The buffer to fill the read out data
419 @retval EFI_SUCCESS Successfully to read out block.
420 @retval EFI_DEVICE_ERROR Fail to detect media.
421 @retval EFI_NO_MEDIA Media is not present.
422 @retval EFI_MEDIA_CHANGED Media has changed.
423 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
424 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
430 IN EFI_BLOCK_IO_PROTOCOL
*This
,
437 SCSI_DISK_DEV
*ScsiDiskDevice
;
438 EFI_BLOCK_IO_MEDIA
*Media
;
441 UINTN NumberOfBlocks
;
446 if (Buffer
== NULL
) {
447 return EFI_INVALID_PARAMETER
;
450 if (BufferSize
== 0) {
454 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
456 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
458 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
460 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
461 if (EFI_ERROR (Status
)) {
462 Status
= EFI_DEVICE_ERROR
;
467 gBS
->ReinstallProtocolInterface (
468 ScsiDiskDevice
->Handle
,
469 &gEfiBlockIoProtocolGuid
,
470 &ScsiDiskDevice
->BlkIo
,
471 &ScsiDiskDevice
->BlkIo
476 // Get the intrinsic block size
478 Media
= ScsiDiskDevice
->BlkIo
.Media
;
479 BlockSize
= Media
->BlockSize
;
481 NumberOfBlocks
= BufferSize
/ BlockSize
;
483 if (!(Media
->MediaPresent
)) {
484 Status
= EFI_NO_MEDIA
;
488 if (MediaId
!= Media
->MediaId
) {
489 Status
= EFI_MEDIA_CHANGED
;
493 if (BufferSize
% BlockSize
!= 0) {
494 Status
= EFI_BAD_BUFFER_SIZE
;
498 if (Lba
> Media
->LastBlock
) {
499 Status
= EFI_INVALID_PARAMETER
;
503 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
504 Status
= EFI_INVALID_PARAMETER
;
508 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
509 Status
= EFI_INVALID_PARAMETER
;
514 // If all the parameters are valid, then perform read sectors command
515 // to transfer data from device to host.
517 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
520 gBS
->RestoreTPL (OldTpl
);
525 The function is to Write Block to SCSI Disk.
527 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
528 @param MediaId The Id of Media detected
529 @param Lba The logic block address
530 @param BufferSize The size of Buffer
531 @param Buffer The buffer to fill the read out data
533 @retval EFI_SUCCESS Successfully to read out block.
534 @retval EFI_WRITE_PROTECTED The device can not be written to.
535 @retval EFI_DEVICE_ERROR Fail to detect media.
536 @retval EFI_NO_MEDIA Media is not present.
537 @retval EFI_MEDIA_CHNAGED Media has changed.
538 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
539 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
544 ScsiDiskWriteBlocks (
545 IN EFI_BLOCK_IO_PROTOCOL
*This
,
552 SCSI_DISK_DEV
*ScsiDiskDevice
;
553 EFI_BLOCK_IO_MEDIA
*Media
;
556 UINTN NumberOfBlocks
;
561 if (Buffer
== NULL
) {
562 return EFI_INVALID_PARAMETER
;
565 if (BufferSize
== 0) {
569 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
571 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
573 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
575 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
576 if (EFI_ERROR (Status
)) {
577 Status
= EFI_DEVICE_ERROR
;
582 gBS
->ReinstallProtocolInterface (
583 ScsiDiskDevice
->Handle
,
584 &gEfiBlockIoProtocolGuid
,
585 &ScsiDiskDevice
->BlkIo
,
586 &ScsiDiskDevice
->BlkIo
591 // Get the intrinsic block size
593 Media
= ScsiDiskDevice
->BlkIo
.Media
;
594 BlockSize
= Media
->BlockSize
;
596 NumberOfBlocks
= BufferSize
/ BlockSize
;
598 if (!(Media
->MediaPresent
)) {
599 Status
= EFI_NO_MEDIA
;
603 if (MediaId
!= Media
->MediaId
) {
604 Status
= EFI_MEDIA_CHANGED
;
608 if (BufferSize
% BlockSize
!= 0) {
609 Status
= EFI_BAD_BUFFER_SIZE
;
613 if (Lba
> Media
->LastBlock
) {
614 Status
= EFI_INVALID_PARAMETER
;
618 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
619 Status
= EFI_INVALID_PARAMETER
;
623 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
624 Status
= EFI_INVALID_PARAMETER
;
628 // if all the parameters are valid, then perform read sectors command
629 // to transfer data from device to host.
631 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
634 gBS
->RestoreTPL (OldTpl
);
641 EFI_SUCCESS is returned directly.
643 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
645 @retval EFI_SUCCESS All outstanding data was written to the device
650 ScsiDiskFlushBlocks (
651 IN EFI_BLOCK_IO_PROTOCOL
*This
662 Dectect Device and read out capacity ,if error occurs, parse the sense key.
664 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
665 @param MustReadCapacity The flag about reading device capacity
666 @param MediaChange The pointer of flag indicates if media has changed
668 @retval EFI_DEVICE_ERROR Indicates that error occurs
669 @retval EFI_SUCCESS Successfully to detect media
673 ScsiDiskDetectMedia (
674 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
675 IN BOOLEAN MustReadCapacity
,
676 OUT BOOLEAN
*MediaChange
680 EFI_STATUS ReadCapacityStatus
;
681 EFI_SCSI_SENSE_DATA
*SenseData
;
682 UINTN NumberOfSenseKeys
;
684 BOOLEAN NeedReadCapacity
;
687 EFI_BLOCK_IO_MEDIA OldMedia
;
690 Status
= EFI_SUCCESS
;
691 ReadCapacityStatus
= EFI_SUCCESS
;
693 NumberOfSenseKeys
= 0;
694 NeedReadCapacity
= FALSE
;
695 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
696 *MediaChange
= FALSE
;
699 for (Index
= 0; Index
< MaxRetry
; Index
++) {
700 Status
= ScsiDiskTestUnitReady (
706 if (!EFI_ERROR (Status
)) {
715 if ((Index
== MaxRetry
) && EFI_ERROR (Status
)) {
716 return EFI_DEVICE_ERROR
;
719 Status
= DetectMediaParsingSenseKeys (
725 if (EFI_ERROR (Status
)) {
729 // ACTION_NO_ACTION: need not read capacity
730 // other action code: need read capacity
732 if (Action
== ACTION_NO_ACTION
) {
733 NeedReadCapacity
= FALSE
;
735 NeedReadCapacity
= TRUE
;
739 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
740 // retrieve capacity via Read Capacity command
742 if (NeedReadCapacity
|| MustReadCapacity
) {
744 // retrieve media information
747 for (Index
= 0; Index
< MaxRetry
; Index
++) {
749 ReadCapacityStatus
= ScsiDiskReadCapacity (
755 if (EFI_ERROR (ReadCapacityStatus
) && !NeedRetry
) {
756 return EFI_DEVICE_ERROR
;
759 // analyze sense key to action
761 Status
= DetectMediaParsingSenseKeys (
768 // if Status is error, it may indicate crisis error,
769 // so return without retry.
771 if (EFI_ERROR (Status
)) {
776 case ACTION_NO_ACTION
:
783 case ACTION_RETRY_COMMAND_LATER
:
785 // retry the ReadCapacity later and continuously, until the condition
786 // no longer emerges.
787 // stall time is 100000us, or say 0.1 second.
795 // other cases, just retry the command
801 if ((Index
== MaxRetry
) && EFI_ERROR (ReadCapacityStatus
)) {
802 return EFI_DEVICE_ERROR
;
806 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
808 // Media change information got from the device
813 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
815 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
818 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
820 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
823 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
825 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
828 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
829 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
831 // when change from no media to media present, reset the MediaId to 1.
833 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
836 // when no media, reset the MediaId to zero.
838 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
849 Send out Inquiry command to Device.
851 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
852 @param NeedRetry Indicates if needs try again when error happens
854 @retval EFI_DEVICE_ERROR Indicates that error occurs
855 @retval EFI_SUCCESS Successfully to detect media
859 ScsiDiskInquiryDevice (
860 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
861 OUT BOOLEAN
*NeedRetry
864 UINT32 InquiryDataLength
;
865 UINT8 SenseDataLength
;
866 UINT8 HostAdapterStatus
;
868 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
869 UINTN NumberOfSenseKeys
;
874 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
877 Status
= ScsiInquiryCommand (
878 ScsiDiskDevice
->ScsiIo
,
879 EFI_TIMER_PERIOD_SECONDS (1),
884 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
889 // no need to check HostAdapterStatus and TargetStatus
891 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
892 ParseInquiryData (ScsiDiskDevice
);
895 } else if (Status
== EFI_NOT_READY
) {
897 return EFI_DEVICE_ERROR
;
899 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
901 return EFI_DEVICE_ERROR
;
904 // go ahead to check HostAdapterStatus and TargetStatus
905 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
908 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
909 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
911 return EFI_DEVICE_ERROR
;
912 } else if (Status
== EFI_DEVICE_ERROR
) {
914 // reset the scsi channel
916 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
918 return EFI_DEVICE_ERROR
;
921 Status
= CheckTargetStatus (TargetStatus
);
922 if (Status
== EFI_NOT_READY
) {
924 // reset the scsi device
926 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
928 return EFI_DEVICE_ERROR
;
930 } else if (Status
== EFI_DEVICE_ERROR
) {
932 return EFI_DEVICE_ERROR
;
936 // if goes here, meant SubmitInquiryCommand() failed.
937 // if ScsiDiskRequestSenseKeys() succeeds at last,
938 // better retry SubmitInquiryCommand(). (by setting *NeedRetry = TRUE)
941 for (Index
= 0; Index
< MaxRetry
; Index
++) {
942 Status
= ScsiDiskRequestSenseKeys (
949 if (!EFI_ERROR (Status
)) {
951 return EFI_DEVICE_ERROR
;
955 return EFI_DEVICE_ERROR
;
959 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
960 // set *NeedRetry = FALSE to avoid the outside caller try again.
963 return EFI_DEVICE_ERROR
;
969 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
970 When Test Unit Ready command encounters any error caused by host adapter or
971 target, return error without retrieving Sense Keys.
973 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
974 @param NeedRetry The pointer of flag indicates try again
975 @param SenseDataArray The pointer of an array of sense data
976 @param NumberOfSenseKeys The pointer of the number of sense data array
978 @retval EFI_DEVICE_ERROR Indicates that error occurs
979 @retval EFI_SUCCESS Successfully to test unit
983 ScsiDiskTestUnitReady (
984 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
985 OUT BOOLEAN
*NeedRetry
,
986 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
987 OUT UINTN
*NumberOfSenseKeys
991 UINT8 SenseDataLength
;
992 UINT8 HostAdapterStatus
;
998 *NumberOfSenseKeys
= 0;
1001 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1003 Status
= ScsiTestUnitReadyCommand (
1004 ScsiDiskDevice
->ScsiIo
,
1005 EFI_TIMER_PERIOD_SECONDS (1),
1012 // no need to check HostAdapterStatus and TargetStatus
1014 if (Status
== EFI_NOT_READY
) {
1016 return EFI_DEVICE_ERROR
;
1018 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1020 return EFI_DEVICE_ERROR
;
1023 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1026 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1027 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1029 return EFI_DEVICE_ERROR
;
1031 } else if (Status
== EFI_DEVICE_ERROR
) {
1033 // reset the scsi channel
1035 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1037 return EFI_DEVICE_ERROR
;
1040 Status
= CheckTargetStatus (TargetStatus
);
1041 if (Status
== EFI_NOT_READY
) {
1043 // reset the scsi device
1045 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1047 return EFI_DEVICE_ERROR
;
1049 } else if (Status
== EFI_DEVICE_ERROR
) {
1051 return EFI_DEVICE_ERROR
;
1055 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1056 Status
= ScsiDiskRequestSenseKeys (
1063 if (!EFI_ERROR (Status
)) {
1068 return EFI_DEVICE_ERROR
;
1072 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1073 // set *NeedRetry = FALSE to avoid the outside caller try again.
1076 return EFI_DEVICE_ERROR
;
1080 Parsing Sense Keys which got from request sense command.
1082 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1083 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1084 @param NumberOfSenseKeys The number of sense key
1085 @param Action The pointer of action which indicates what is need to do next
1087 @retval EFI_DEVICE_ERROR Indicates that error occurs
1088 @retval EFI_SUCCESS Successfully to complete the parsing
1092 DetectMediaParsingSenseKeys (
1093 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1094 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1095 IN UINTN NumberOfSenseKeys
,
1102 // Default is to read capacity, unless..
1104 *Action
= ACTION_READ_CAPACITY
;
1106 if (NumberOfSenseKeys
== 0) {
1107 *Action
= ACTION_NO_ACTION
;
1111 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1113 // No Sense Key returned from last submitted command
1115 *Action
= ACTION_NO_ACTION
;
1119 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1120 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1121 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1122 *Action
= ACTION_NO_ACTION
;
1126 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1127 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1131 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1132 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1133 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1134 return EFI_DEVICE_ERROR
;
1137 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1138 return EFI_DEVICE_ERROR
;
1141 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1143 *Action
= ACTION_RETRY_COMMAND_LATER
;
1147 return EFI_DEVICE_ERROR
;
1155 Send read capacity command to device and get the device parameter.
1157 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1158 @param NeedRetry The pointer of flag indicates if need a retry
1159 @param SenseDataArray The pointer of an array of sense data
1160 @param NumberOfSenseKeys The number of sense key
1162 @retval EFI_DEVICE_ERROR Indicates that error occurs
1163 @retval EFI_SUCCESS Successfully to read capacity
1167 ScsiDiskReadCapacity (
1168 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1169 OUT BOOLEAN
*NeedRetry
,
1170 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1171 OUT UINTN
*NumberOfSenseKeys
1174 EFI_SCSI_DISK_CAPACITY_DATA CapacityData
;
1176 UINT8 HostAdapterStatus
;
1178 EFI_STATUS CommandStatus
;
1182 UINT8 SenseDataLength
;
1184 SenseDataLength
= 0;
1185 ZeroMem (&CapacityData
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1186 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1188 *NumberOfSenseKeys
= 0;
1191 // submit Read Capacity Command. in this call,not request sense data
1193 CommandStatus
= ScsiReadCapacityCommand (
1194 ScsiDiskDevice
->ScsiIo
,
1195 EFI_TIMER_PERIOD_SECONDS (1),
1200 (VOID
*) &CapacityData
,
1205 // no need to check HostAdapterStatus and TargetStatus
1207 if (CommandStatus
== EFI_SUCCESS
) {
1208 GetMediaInfo (ScsiDiskDevice
, &CapacityData
);
1211 } else if (CommandStatus
== EFI_NOT_READY
) {
1213 return EFI_DEVICE_ERROR
;
1215 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1217 return EFI_DEVICE_ERROR
;
1220 // go ahead to check HostAdapterStatus and TargetStatus
1221 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1224 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1225 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1227 return EFI_DEVICE_ERROR
;
1229 } else if (Status
== EFI_DEVICE_ERROR
) {
1231 // reset the scsi channel
1233 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1235 return EFI_DEVICE_ERROR
;
1238 Status
= CheckTargetStatus (TargetStatus
);
1239 if (Status
== EFI_NOT_READY
) {
1241 // reset the scsi device
1243 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1245 return EFI_DEVICE_ERROR
;
1247 } else if (Status
== EFI_DEVICE_ERROR
) {
1249 return EFI_DEVICE_ERROR
;
1253 // if goes here, meant SubmitReadCapacityCommand() failed.
1254 // if ScsiDiskRequestSenseKeys() succeeds at last,
1255 // better retry SubmitReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1258 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1260 Status
= ScsiDiskRequestSenseKeys (
1267 if (!EFI_ERROR (Status
)) {
1269 return EFI_DEVICE_ERROR
;
1273 return EFI_DEVICE_ERROR
;
1277 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1278 // set *NeedRetry = FALSE to avoid the outside caller try again.
1281 return EFI_DEVICE_ERROR
;
1285 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1287 @param HostAdapterStatus Host Adapter status
1289 @retval EFI_SUCCESS Host adapter is OK.
1290 @retval EFI_TIMEOUT Timeout.
1291 @retval EFI_NOT_READY Adapter NOT ready.
1292 @retval EFI_DEVICE_ERROR Adapter device error.
1296 CheckHostAdapterStatus (
1297 IN UINT8 HostAdapterStatus
1300 switch (HostAdapterStatus
) {
1301 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1304 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1305 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1306 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1309 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1310 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1311 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1312 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1313 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1314 return EFI_NOT_READY
;
1316 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1317 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1318 return EFI_DEVICE_ERROR
;
1327 Check the target status and re-interpret it in EFI_STATUS.
1329 @param TargetStatus Target status
1331 @retval EFI_NOT_READY Device is NOT ready.
1332 @retval EFI_DEVICE_ERROR
1338 IN UINT8 TargetStatus
1341 switch (TargetStatus
) {
1342 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1343 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1344 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1347 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1348 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1349 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1350 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1351 return EFI_NOT_READY
;
1353 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1354 return EFI_DEVICE_ERROR
;
1364 Retrieve all sense keys from the device.
1366 When encountering error during the process, if retrieve sense keys before
1367 error encounterred, it returns the sense keys with return status set to EFI_SUCCESS,
1368 and NeedRetry set to FALSE; otherwize, return the proper return status.
1370 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1371 @param NeedRetry The pointer of flag indicates if need a retry
1372 @param SenseDataArray The pointer of an array of sense data
1373 @param NumberOfSenseKeys The number of sense key
1374 @param AskResetIfError The flag indicates if need reset when error occurs
1376 @retval EFI_DEVICE_ERROR Indicates that error occurs
1377 @retval EFI_SUCCESS Successfully to request sense key
1381 ScsiDiskRequestSenseKeys (
1382 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1383 OUT BOOLEAN
*NeedRetry
,
1384 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1385 OUT UINTN
*NumberOfSenseKeys
,
1386 IN BOOLEAN AskResetIfError
1389 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1390 UINT8 SenseDataLength
;
1393 EFI_STATUS FallStatus
;
1394 UINT8 HostAdapterStatus
;
1397 FallStatus
= EFI_SUCCESS
;
1398 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1401 ScsiDiskDevice
->SenseData
,
1402 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1405 *NumberOfSenseKeys
= 0;
1406 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1407 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1409 for (SenseReq
= TRUE
; SenseReq
;) {
1410 Status
= ScsiRequestSenseCommand (
1411 ScsiDiskDevice
->ScsiIo
,
1412 EFI_TIMER_PERIOD_SECONDS (2),
1418 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1419 FallStatus
= EFI_SUCCESS
;
1421 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1423 FallStatus
= EFI_DEVICE_ERROR
;
1425 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1427 FallStatus
= EFI_DEVICE_ERROR
;
1429 } else if (Status
== EFI_DEVICE_ERROR
) {
1430 if (AskResetIfError
) {
1431 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1434 FallStatus
= EFI_DEVICE_ERROR
;
1437 if (EFI_ERROR (FallStatus
)) {
1438 if (*NumberOfSenseKeys
!= 0) {
1442 return EFI_DEVICE_ERROR
;
1446 (*NumberOfSenseKeys
) += 1;
1449 // no more sense key or number of sense keys exceeds predefined,
1452 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1453 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1463 Get information from media read capacity command.
1465 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1466 @param Capacity The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1471 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1472 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity
1475 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity
->LastLba3
<< 24) |
1476 (Capacity
->LastLba2
<< 16) |
1477 (Capacity
->LastLba1
<< 8) |
1480 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1481 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity
->BlockSize3
<< 24) |
1482 (Capacity
->BlockSize2
<< 16) |
1483 (Capacity
->BlockSize1
<< 8) |
1484 Capacity
->BlockSize0
;
1485 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1486 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1489 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1490 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1497 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1502 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1505 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) (ScsiDiskDevice
->InquiryData
.RMB
? 0 : 1);
1506 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1510 Read sector from SCSI Disk.
1512 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1513 @param Buffer The buffer to fill in the read out data
1514 @param Lba Logic block address
1515 @param NumberOfBlocks The number of blocks to read
1517 @retval EFI_DEVICE_ERROR Indicates a device error.
1518 @retval EFI_SUCCESS Operation is successful.
1522 ScsiDiskReadSectors (
1523 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1526 IN UINTN NumberOfBlocks
1529 UINTN BlocksRemaining
;
1541 EFI_SCSI_SENSE_DATA
*SenseData
;
1542 UINTN NumberOfSenseKeys
;
1545 NumberOfSenseKeys
= 0;
1547 Status
= EFI_SUCCESS
;
1549 BlocksRemaining
= NumberOfBlocks
;
1550 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1552 // limit the data bytes that can be transferred by one Read(10) Command
1557 Lba32
= (UINT32
) Lba
;
1559 while (BlocksRemaining
> 0) {
1561 if (BlocksRemaining
<= MaxBlock
) {
1563 SectorCount
= (UINT16
) BlocksRemaining
;
1566 SectorCount
= MaxBlock
;
1569 ByteCount
= SectorCount
* BlockSize
;
1570 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1573 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1575 Status
= ScsiDiskRead10 (
1586 if (!EFI_ERROR (Status
)) {
1591 return EFI_DEVICE_ERROR
;
1596 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1597 return EFI_DEVICE_ERROR
;
1601 // actual transferred sectors
1603 SectorCount
= ByteCount
/ BlockSize
;
1605 Lba32
+= SectorCount
;
1606 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1607 BlocksRemaining
-= SectorCount
;
1614 Write sector to SCSI Disk.
1616 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1617 @param Buffer The buffer of data to be written into SCSI Disk
1618 @param Lba Logic block address
1619 @param NumberOfBlocks The number of blocks to read
1621 @retval EFI_DEVICE_ERROR Indicates a device error.
1622 @retval EFI_SUCCESS Operation is successful.
1626 ScsiDiskWriteSectors (
1627 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1630 IN UINTN NumberOfBlocks
1633 UINTN BlocksRemaining
;
1645 EFI_SCSI_SENSE_DATA
*SenseData
;
1646 UINTN NumberOfSenseKeys
;
1649 NumberOfSenseKeys
= 0;
1651 Status
= EFI_SUCCESS
;
1653 BlocksRemaining
= NumberOfBlocks
;
1654 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1656 // limit the data bytes that can be transferred by one Write(10) Command
1661 Lba32
= (UINT32
) Lba
;
1663 while (BlocksRemaining
> 0) {
1665 if (BlocksRemaining
<= MaxBlock
) {
1667 SectorCount
= (UINT16
) BlocksRemaining
;
1670 SectorCount
= MaxBlock
;
1673 ByteCount
= SectorCount
* BlockSize
;
1674 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1676 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1677 Status
= ScsiDiskWrite10 (
1688 if (!EFI_ERROR (Status
)) {
1693 return EFI_DEVICE_ERROR
;
1697 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1698 return EFI_DEVICE_ERROR
;
1701 // actual transferred sectors
1703 SectorCount
= ByteCount
/ BlockSize
;
1705 Lba32
+= SectorCount
;
1706 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1707 BlocksRemaining
-= SectorCount
;
1715 Sumbmit Read command.
1717 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1718 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1719 @param SenseDataArray NOT used yet in this function
1720 @param NumberOfSenseKeys The number of sense key
1721 @param Timeout The time to complete the command
1722 @param DataBuffer The buffer to fill with the read out data
1723 @param DataLength The length of buffer
1724 @param StartLba The start logic block address
1725 @param SectorSize The size of sector
1727 @return EFI_STATUS is returned by calling ScsiRead10Command().
1731 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1732 OUT BOOLEAN
*NeedRetry
,
1733 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1734 OUT UINTN
*NumberOfSenseKeys
,
1736 OUT UINT8
*DataBuffer
,
1737 IN OUT UINT32
*DataLength
,
1739 IN UINT32 SectorSize
1742 UINT8 SenseDataLength
;
1744 UINT8 HostAdapterStatus
;
1748 *NumberOfSenseKeys
= 0;
1749 SenseDataLength
= 0;
1750 Status
= ScsiRead10Command (
1751 ScsiDiskDevice
->ScsiIo
,
1767 Submit Write Command.
1769 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1770 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1771 @param SenseDataArray NOT used yet in this function
1772 @param NumberOfSenseKeys The number of sense key
1773 @param Timeout The time to complete the command
1774 @param DataBuffer The buffer to fill with the read out data
1775 @param DataLength The length of buffer
1776 @param StartLba The start logic block address
1777 @param SectorSize The size of sector
1779 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1784 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1785 OUT BOOLEAN
*NeedRetry
,
1786 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1787 OUT UINTN
*NumberOfSenseKeys
,
1789 IN UINT8
*DataBuffer
,
1790 IN OUT UINT32
*DataLength
,
1792 IN UINT32 SectorSize
1796 UINT8 SenseDataLength
;
1797 UINT8 HostAdapterStatus
;
1801 *NumberOfSenseKeys
= 0;
1802 SenseDataLength
= 0;
1803 Status
= ScsiWrite10Command (
1804 ScsiDiskDevice
->ScsiIo
,
1820 Check sense key to find if media presents.
1822 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1823 @param SenseCounts The number of sense key
1825 @retval TRUE NOT any media
1826 @retval FALSE Media presents
1830 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1831 IN UINTN SenseCounts
1834 EFI_SCSI_SENSE_DATA
*SensePtr
;
1839 SensePtr
= SenseData
;
1841 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1843 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
1844 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
1846 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
1847 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
1860 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1861 @param SenseCounts The number of sense key
1864 @retval FALSE NOT error
1868 ScsiDiskIsMediaError (
1869 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1870 IN UINTN SenseCounts
1873 EFI_SCSI_SENSE_DATA
*SensePtr
;
1878 SensePtr
= SenseData
;
1880 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1882 switch (SensePtr
->Sense_Key
) {
1884 case EFI_SCSI_SK_MEDIUM_ERROR
:
1886 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
1888 switch (SensePtr
->Addnl_Sense_Code
) {
1893 case EFI_SCSI_ASC_MEDIA_ERR1
:
1898 case EFI_SCSI_ASC_MEDIA_ERR2
:
1903 case EFI_SCSI_ASC_MEDIA_ERR3
:
1904 case EFI_SCSI_ASC_MEDIA_ERR4
:
1914 case EFI_SCSI_SK_NOT_READY
:
1916 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
1918 switch (SensePtr
->Addnl_Sense_Code
) {
1920 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
1922 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
1943 Check sense key to find if hardware error happens.
1945 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1946 @param SenseCounts The number of sense key
1948 @retval TRUE Hardware error exits.
1949 @retval FALSE NO error.
1953 ScsiDiskIsHardwareError (
1954 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1955 IN UINTN SenseCounts
1958 EFI_SCSI_SENSE_DATA
*SensePtr
;
1963 SensePtr
= SenseData
;
1965 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1968 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
1970 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
1982 Check sense key to find if media has changed.
1984 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1985 @param SenseCounts The number of sense key
1987 @retval TRUE Media is changed.
1988 @retval FALSE Medit is NOT changed.
1991 ScsiDiskIsMediaChange (
1992 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1993 IN UINTN SenseCounts
1996 EFI_SCSI_SENSE_DATA
*SensePtr
;
1998 BOOLEAN IsMediaChanged
;
2000 IsMediaChanged
= FALSE
;
2001 SensePtr
= SenseData
;
2003 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2005 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2006 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2008 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2009 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2010 IsMediaChanged
= TRUE
;
2016 return IsMediaChanged
;
2020 Check sense key to find if reset happens.
2022 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2023 @param SenseCounts The number of sense key
2025 @retval TRUE It is reset before.
2026 @retval FALSE It is NOT reset before.
2030 ScsiDiskIsResetBefore (
2031 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2032 IN UINTN SenseCounts
2035 EFI_SCSI_SENSE_DATA
*SensePtr
;
2037 BOOLEAN IsResetBefore
;
2039 IsResetBefore
= FALSE
;
2040 SensePtr
= SenseData
;
2042 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2045 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2046 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2048 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2049 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2050 IsResetBefore
= TRUE
;
2056 return IsResetBefore
;
2060 Check sense key to find if the drive is ready.
2062 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2063 @param SenseCounts The number of sense key
2064 @param RetryLater The flag means if need a retry
2066 @retval TRUE Drive is ready.
2067 @retval FALSE Drive is NOT ready.
2071 ScsiDiskIsDriveReady (
2072 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2073 IN UINTN SenseCounts
,
2074 OUT BOOLEAN
*RetryLater
2077 EFI_SCSI_SENSE_DATA
*SensePtr
;
2082 *RetryLater
= FALSE
;
2083 SensePtr
= SenseData
;
2085 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2087 switch (SensePtr
->Sense_Key
) {
2089 case EFI_SCSI_SK_NOT_READY
:
2091 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2093 switch (SensePtr
->Addnl_Sense_Code
) {
2094 case EFI_SCSI_ASC_NOT_READY
:
2096 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2098 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2099 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2101 // Additional Sense Code Qualifier is
2102 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2110 *RetryLater
= FALSE
;
2131 Check sense key to find if it has sense key.
2133 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2134 @param SenseCounts - The number of sense key
2136 @retval TRUE It has sense key.
2137 @retval FALSE It has NOT any sense key.
2141 ScsiDiskHaveSenseKey (
2142 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2143 IN UINTN SenseCounts
2146 EFI_SCSI_SENSE_DATA
*SensePtr
;
2148 BOOLEAN HaveSenseKey
;
2150 if (SenseCounts
== 0) {
2151 HaveSenseKey
= FALSE
;
2153 HaveSenseKey
= TRUE
;
2156 SensePtr
= SenseData
;
2158 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2161 // Sense Key is SK_NO_SENSE (0x0)
2163 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2165 HaveSenseKey
= FALSE
;
2171 return HaveSenseKey
;
2175 Release resource about disk device.
2177 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2181 ReleaseScsiDiskDeviceResources (
2182 IN SCSI_DISK_DEV
*ScsiDiskDevice
2185 if (ScsiDiskDevice
== NULL
) {
2189 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2190 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
2191 ScsiDiskDevice
->SenseData
= NULL
;
2194 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2195 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2196 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2199 gBS
->FreePool (ScsiDiskDevice
);
2201 ScsiDiskDevice
= NULL
;