3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 #include <Protocol/ScsiIo.h>
24 #include <Protocol/ComponentName.h>
25 #include <Protocol/BlockIo.h>
26 #include <Protocol/DriverBinding.h>
27 #include <Protocol/ScsiPassThruExt.h>
29 #include <Library/DebugLib.h>
30 #include <Library/UefiDriverEntryPoint.h>
31 #include <Library/UefiLib.h>
32 #include <Library/BaseMemoryLib.h>
33 #include <Library/ScsiLib.h>
34 #include <Library/UefiBootServicesTableLib.h>
38 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
39 ScsiDiskDriverBindingSupported
,
40 ScsiDiskDriverBindingStart
,
41 ScsiDiskDriverBindingStop
,
48 The user Entry Point for module ScsiDisk. The user code starts with this function.
50 @param[in] ImageHandle The firmware allocated handle for the EFI image.
51 @param[in] SystemTable A pointer to the EFI System Table.
53 @retval EFI_SUCCESS The entry point is executed successfully.
54 @retval other Some error occurs when executing this entry point.
60 IN EFI_HANDLE ImageHandle
,
61 IN EFI_SYSTEM_TABLE
*SystemTable
67 // Install driver model protocol(s).
69 Status
= EfiLibInstallDriverBindingComponentName2 (
72 &gScsiDiskDriverBinding
,
74 &gScsiDiskComponentName
,
75 &gScsiDiskComponentName2
77 ASSERT_EFI_ERROR (Status
);
85 ScsiDiskDriverBindingSupported (
86 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
87 IN EFI_HANDLE Controller
,
88 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
94 Test to see if this driver supports ControllerHandle. Any ControllerHandle
95 that has ScsiIoProtocol installed will be supported.
99 This - Protocol instance pointer.
100 Controller - Handle of device to test
101 RemainingDevicePath - Not used
105 EFI_SUCCESS - This driver supports this device.
106 EFI_UNSUPPORTED - This driver does not support this device.
112 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
115 Status
= gBS
->OpenProtocol (
117 &gEfiScsiIoProtocolGuid
,
119 This
->DriverBindingHandle
,
121 EFI_OPEN_PROTOCOL_BY_DRIVER
123 if (EFI_ERROR (Status
)) {
127 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
128 if (!EFI_ERROR (Status
)) {
129 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
130 Status
= EFI_SUCCESS
;
132 Status
= EFI_UNSUPPORTED
;
138 &gEfiScsiIoProtocolGuid
,
139 This
->DriverBindingHandle
,
147 ScsiDiskDriverBindingStart (
148 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
149 IN EFI_HANDLE Controller
,
150 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
156 Start SCSI Disk Driver, and attach BlockIoProtocol to it.
160 This - Protocol instance pointer.
161 Controller - Handle of device to test
162 RemainingDevicePath - Not used
166 EFI_SUCCESS - This driver supports this device.
167 EFI_UNSUPPORTED - This driver does not support this device.
173 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
174 SCSI_DISK_DEV
*ScsiDiskDevice
;
180 Status
= gBS
->AllocatePool (
182 sizeof (SCSI_DISK_DEV
),
183 (VOID
**) &ScsiDiskDevice
185 if (EFI_ERROR (Status
)) {
189 ZeroMem (ScsiDiskDevice
, sizeof (SCSI_DISK_DEV
));
191 Status
= gBS
->OpenProtocol (
193 &gEfiScsiIoProtocolGuid
,
195 This
->DriverBindingHandle
,
197 EFI_OPEN_PROTOCOL_BY_DRIVER
199 if (EFI_ERROR (Status
)) {
200 gBS
->FreePool (ScsiDiskDevice
);
204 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
205 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
206 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
207 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
208 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
209 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
210 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
211 ScsiDiskDevice
->Handle
= Controller
;
213 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
214 switch (ScsiDiskDevice
->DeviceType
) {
215 case EFI_SCSI_TYPE_DISK
:
216 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
219 case EFI_SCSI_TYPE_CDROM
:
220 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
224 // The Sense Data Array's initial size is 6
226 ScsiDiskDevice
->SenseDataNumber
= 6;
227 Status
= gBS
->AllocatePool (
229 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
,
230 (VOID
**) &(ScsiDiskDevice
->SenseData
)
232 if (EFI_ERROR (Status
)) {
235 &gEfiScsiIoProtocolGuid
,
236 This
->DriverBindingHandle
,
239 gBS
->FreePool (ScsiDiskDevice
);
244 ScsiDiskDevice
->SenseData
,
245 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
249 // Retrive device information
252 for (Index
= 0; Index
< MaxRetry
; Index
++) {
253 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
254 if (!EFI_ERROR (Status
)) {
259 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
262 &gEfiScsiIoProtocolGuid
,
263 This
->DriverBindingHandle
,
266 gBS
->FreePool (ScsiDiskDevice
);
267 return EFI_DEVICE_ERROR
;
271 // The second parameter "TRUE" means must
272 // retrieve media capacity
274 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, TRUE
, &Temp
);
275 if (!EFI_ERROR (Status
)) {
276 Status
= gBS
->InstallMultipleProtocolInterfaces (
278 &gEfiBlockIoProtocolGuid
,
279 &ScsiDiskDevice
->BlkIo
,
284 if (EFI_ERROR (Status
)) {
285 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
288 &gEfiScsiIoProtocolGuid
,
289 This
->DriverBindingHandle
,
292 gBS
->FreePool (ScsiDiskDevice
);
296 ScsiDiskDevice
->ControllerNameTable
= NULL
;
299 gScsiDiskComponentName
.SupportedLanguages
,
300 &ScsiDiskDevice
->ControllerNameTable
,
306 gScsiDiskComponentName2
.SupportedLanguages
,
307 &ScsiDiskDevice
->ControllerNameTable
,
319 ScsiDiskDriverBindingStop (
320 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
321 IN EFI_HANDLE Controller
,
322 IN UINTN NumberOfChildren
,
323 IN EFI_HANDLE
*ChildHandleBuffer
329 Stop this driver on ControllerHandle. Support stoping any child handles
330 created by this driver.
334 This - Protocol instance pointer.
335 Controller - Handle of device to stop driver on
336 NumberOfChildren - Number of Children in the ChildHandleBuffer
337 ChildHandleBuffer - List of handles for the children we need to stop.
347 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
348 SCSI_DISK_DEV
*ScsiDiskDevice
;
351 Status
= gBS
->OpenProtocol (
353 &gEfiBlockIoProtocolGuid
,
355 This
->DriverBindingHandle
,
357 EFI_OPEN_PROTOCOL_GET_PROTOCOL
359 if (EFI_ERROR (Status
)) {
363 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
364 Status
= gBS
->UninstallProtocolInterface (
366 &gEfiBlockIoProtocolGuid
,
367 &ScsiDiskDevice
->BlkIo
369 if (!EFI_ERROR (Status
)) {
372 &gEfiScsiIoProtocolGuid
,
373 This
->DriverBindingHandle
,
377 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
391 IN EFI_BLOCK_IO_PROTOCOL
*This
,
392 IN BOOLEAN ExtendedVerification
402 This - The pointer of EFI_BLOCK_IO_PROTOCOL
403 ExtendedVerification - The flag about if extend verificate
412 SCSI_DISK_DEV
*ScsiDiskDevice
;
415 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
417 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
419 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
421 if (!ExtendedVerification
) {
425 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
428 gBS
->RestoreTPL (OldTpl
);
435 IN EFI_BLOCK_IO_PROTOCOL
*This
,
445 The function is to Read Block from SCSI Disk
449 This - The pointer of EFI_BLOCK_IO_PROTOCOL
450 MediaId - The Id of Media detected
451 LBA - The logic block address
452 BufferSize - The size of Buffer
453 Buffer - The buffer to fill the read out data
457 EFI_INVALID_PARAMETER - Invalid parameter passed in.
458 EFI_SUCCESS - Successfully to read out block.
459 EFI_DEVICE_ERROR - Fail to detect media.
460 EFI_NO_MEDIA - Media is not present.
461 EFI_MEDIA_CHANGED - Media has changed.
462 EFI_BAD_BUFFER_SIZE - The buffer size is not multiple of BlockSize.
466 SCSI_DISK_DEV
*ScsiDiskDevice
;
467 EFI_BLOCK_IO_MEDIA
*Media
;
470 UINTN NumberOfBlocks
;
476 return EFI_INVALID_PARAMETER
;
479 if (BufferSize
== 0) {
483 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
485 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
487 if (!IsDeviceFixed (ScsiDiskDevice
)) {
489 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
490 if (EFI_ERROR (Status
)) {
491 Status
= EFI_DEVICE_ERROR
;
496 gBS
->ReinstallProtocolInterface (
497 ScsiDiskDevice
->Handle
,
498 &gEfiBlockIoProtocolGuid
,
499 &ScsiDiskDevice
->BlkIo
,
500 &ScsiDiskDevice
->BlkIo
505 // Get the intrinsic block size
507 Media
= ScsiDiskDevice
->BlkIo
.Media
;
508 BlockSize
= Media
->BlockSize
;
510 NumberOfBlocks
= BufferSize
/ BlockSize
;
512 if (!(Media
->MediaPresent
)) {
513 Status
= EFI_NO_MEDIA
;
517 if (MediaId
!= Media
->MediaId
) {
518 Status
= EFI_MEDIA_CHANGED
;
522 if (BufferSize
% BlockSize
!= 0) {
523 Status
= EFI_BAD_BUFFER_SIZE
;
527 if (LBA
> Media
->LastBlock
) {
528 Status
= EFI_INVALID_PARAMETER
;
532 if ((LBA
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
533 Status
= EFI_INVALID_PARAMETER
;
537 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
538 Status
= EFI_INVALID_PARAMETER
;
543 // If all the parameters are valid, then perform read sectors command
544 // to transfer data from device to host.
546 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, LBA
, NumberOfBlocks
);
549 gBS
->RestoreTPL (OldTpl
);
555 ScsiDiskWriteBlocks (
556 IN EFI_BLOCK_IO_PROTOCOL
*This
,
566 The function is to Write Block to SCSI Disk
570 This - The pointer of EFI_BLOCK_IO_PROTOCOL
571 MediaId - The Id of Media detected
572 LBA - The logic block address
573 BufferSize - The size of Buffer
574 Buffer - The buffer to fill the read out data
578 EFI_INVALID_PARAMETER - Invalid parameter passed in.
579 EFI_SUCCESS - Successfully to read out block.
580 EFI_DEVICE_ERROR - Fail to detect media.
581 EFI_NO_MEDIA - Media is not present.
582 EFI_MEDIA_CHANGED - Media has changed.
583 EFI_BAD_BUFFER_SIZE - The buffer size is not multiple of BlockSize.
587 SCSI_DISK_DEV
*ScsiDiskDevice
;
588 EFI_BLOCK_IO_MEDIA
*Media
;
591 UINTN NumberOfBlocks
;
597 return EFI_INVALID_PARAMETER
;
600 if (BufferSize
== 0) {
604 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
606 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
608 if (!IsDeviceFixed (ScsiDiskDevice
)) {
610 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
611 if (EFI_ERROR (Status
)) {
612 Status
= EFI_DEVICE_ERROR
;
617 gBS
->ReinstallProtocolInterface (
618 ScsiDiskDevice
->Handle
,
619 &gEfiBlockIoProtocolGuid
,
620 &ScsiDiskDevice
->BlkIo
,
621 &ScsiDiskDevice
->BlkIo
626 // Get the intrinsic block size
628 Media
= ScsiDiskDevice
->BlkIo
.Media
;
629 BlockSize
= Media
->BlockSize
;
631 NumberOfBlocks
= BufferSize
/ BlockSize
;
633 if (!(Media
->MediaPresent
)) {
634 Status
= EFI_NO_MEDIA
;
638 if (MediaId
!= Media
->MediaId
) {
639 Status
= EFI_MEDIA_CHANGED
;
643 if (BufferSize
% BlockSize
!= 0) {
644 Status
= EFI_BAD_BUFFER_SIZE
;
648 if (LBA
> Media
->LastBlock
) {
649 Status
= EFI_INVALID_PARAMETER
;
653 if ((LBA
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
654 Status
= EFI_INVALID_PARAMETER
;
658 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
659 Status
= EFI_INVALID_PARAMETER
;
663 // if all the parameters are valid, then perform read sectors command
664 // to transfer data from device to host.
666 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, LBA
, NumberOfBlocks
);
669 gBS
->RestoreTPL (OldTpl
);
675 ScsiDiskFlushBlocks (
676 IN EFI_BLOCK_IO_PROTOCOL
*This
686 This - The pointer of EFI_BLOCK_IO_PROTOCOL
701 ScsiDiskDetectMedia (
702 SCSI_DISK_DEV
*ScsiDiskDevice
,
703 BOOLEAN MustReadCapacity
,
710 Dectect Device and read out capacity ,if error occurs, parse the sense key.
714 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
715 MustReadCapacity - The flag about reading device capacity
716 MediaChange - The pointer of flag indicates if media has changed
720 EFI_DEVICE_ERROR - Indicates that error occurs
721 EFI_SUCCESS - Successfully to detect media
726 EFI_STATUS ReadCapacityStatus
;
727 EFI_SCSI_SENSE_DATA
*SenseData
;
728 UINTN NumberOfSenseKeys
;
730 BOOLEAN NeedReadCapacity
;
733 EFI_BLOCK_IO_MEDIA OldMedia
;
736 Status
= EFI_SUCCESS
;
737 ReadCapacityStatus
= EFI_SUCCESS
;
739 NumberOfSenseKeys
= 0;
740 NeedReadCapacity
= FALSE
;
741 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
742 *MediaChange
= FALSE
;
745 for (Index
= 0; Index
< MaxRetry
; Index
++) {
746 Status
= ScsiDiskTestUnitReady (
752 if (!EFI_ERROR (Status
)) {
761 if ((Index
== MaxRetry
) && EFI_ERROR (Status
)) {
762 return EFI_DEVICE_ERROR
;
765 Status
= DetectMediaParsingSenseKeys (
771 if (EFI_ERROR (Status
)) {
775 // ACTION_NO_ACTION: need not read capacity
776 // other action code: need read capacity
778 if (Action
== ACTION_NO_ACTION
) {
779 NeedReadCapacity
= FALSE
;
781 NeedReadCapacity
= TRUE
;
785 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
786 // retrieve capacity via Read Capacity command
788 if (NeedReadCapacity
|| MustReadCapacity
) {
790 // retrieve media information
793 for (Index
= 0; Index
< MaxRetry
; Index
++) {
795 ReadCapacityStatus
= ScsiDiskReadCapacity (
801 if (EFI_ERROR (ReadCapacityStatus
) && !NeedRetry
) {
802 return EFI_DEVICE_ERROR
;
805 // analyze sense key to action
807 Status
= DetectMediaParsingSenseKeys (
814 // if Status is error, it may indicate crisis error,
815 // so return without retry.
817 if (EFI_ERROR (Status
)) {
822 case ACTION_NO_ACTION
:
829 case ACTION_RETRY_COMMAND_LATER
:
831 // retry the ReadCapacity later and continuously, until the condition
832 // no longer emerges.
833 // stall time is 100000us, or say 0.1 second.
841 // other cases, just retry the command
847 if ((Index
== MaxRetry
) && EFI_ERROR (ReadCapacityStatus
)) {
848 return EFI_DEVICE_ERROR
;
852 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
854 // Media change information got from the device
859 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
861 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
864 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
866 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
869 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
871 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
874 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
875 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
877 // when change from no media to media present, reset the MediaId to 1.
879 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
882 // when no media, reset the MediaId to zero.
884 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
894 ScsiDiskInquiryDevice (
895 SCSI_DISK_DEV
*ScsiDiskDevice
,
902 Send out Inquiry command to Device
906 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
907 NeedRetry - Indicates if needs try again when error happens
911 EFI_DEVICE_ERROR - Indicates that error occurs
912 EFI_SUCCESS - Successfully to detect media
916 UINT32 InquiryDataLength
;
917 UINT8 SenseDataLength
;
918 UINT8 HostAdapterStatus
;
920 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
921 UINTN NumberOfSenseKeys
;
926 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
929 Status
= ScsiInquiryCommand (
930 ScsiDiskDevice
->ScsiIo
,
931 EfiScsiStallSeconds (1),
936 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
941 // no need to check HostAdapterStatus and TargetStatus
943 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
944 ParseInquiryData (ScsiDiskDevice
);
947 } else if (Status
== EFI_NOT_READY
) {
949 return EFI_DEVICE_ERROR
;
951 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
953 return EFI_DEVICE_ERROR
;
956 // go ahead to check HostAdapterStatus and TargetStatus
957 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
960 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
961 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
963 return EFI_DEVICE_ERROR
;
964 } else if (Status
== EFI_DEVICE_ERROR
) {
966 // reset the scsi channel
968 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
970 return EFI_DEVICE_ERROR
;
973 Status
= CheckTargetStatus (TargetStatus
);
974 if (Status
== EFI_NOT_READY
) {
976 // reset the scsi device
978 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
980 return EFI_DEVICE_ERROR
;
982 } else if (Status
== EFI_DEVICE_ERROR
) {
984 return EFI_DEVICE_ERROR
;
988 // if goes here, meant SubmitInquiryCommand() failed.
989 // if ScsiDiskRequestSenseKeys() succeeds at last,
990 // better retry SubmitInquiryCommand(). (by setting *NeedRetry = TRUE)
993 for (Index
= 0; Index
< MaxRetry
; Index
++) {
994 Status
= ScsiDiskRequestSenseKeys (
1001 if (!EFI_ERROR (Status
)) {
1003 return EFI_DEVICE_ERROR
;
1007 return EFI_DEVICE_ERROR
;
1011 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1012 // set *NeedRetry = FALSE to avoid the outside caller try again.
1015 return EFI_DEVICE_ERROR
;
1019 ScsiDiskTestUnitReady (
1020 SCSI_DISK_DEV
*ScsiDiskDevice
,
1022 EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1023 UINTN
*NumberOfSenseKeys
1027 Routine Description:
1029 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1030 When Test Unit Ready command encounters any error caused by host adapter or
1031 target, return error without retrieving Sense Keys.
1035 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
1036 NeedRetry - The pointer of flag indicates try again
1037 SenseDataArray - The pointer of an array of sense data
1038 NumberOfSenseKeys - The pointer of the number of sense data array
1042 EFI_DEVICE_ERROR - Indicates that error occurs
1043 EFI_SUCCESS - Successfully to test unit
1048 UINT8 SenseDataLength
;
1049 UINT8 HostAdapterStatus
;
1054 SenseDataLength
= 0;
1055 *NumberOfSenseKeys
= 0;
1058 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1060 Status
= ScsiTestUnitReadyCommand (
1061 ScsiDiskDevice
->ScsiIo
,
1062 EfiScsiStallSeconds (1),
1069 // no need to check HostAdapterStatus and TargetStatus
1071 if (Status
== EFI_NOT_READY
) {
1073 return EFI_DEVICE_ERROR
;
1075 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1077 return EFI_DEVICE_ERROR
;
1080 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1083 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1084 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1086 return EFI_DEVICE_ERROR
;
1088 } else if (Status
== EFI_DEVICE_ERROR
) {
1090 // reset the scsi channel
1092 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1094 return EFI_DEVICE_ERROR
;
1097 Status
= CheckTargetStatus (TargetStatus
);
1098 if (Status
== EFI_NOT_READY
) {
1100 // reset the scsi device
1102 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1104 return EFI_DEVICE_ERROR
;
1106 } else if (Status
== EFI_DEVICE_ERROR
) {
1108 return EFI_DEVICE_ERROR
;
1112 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1113 Status
= ScsiDiskRequestSenseKeys (
1120 if (!EFI_ERROR (Status
)) {
1125 return EFI_DEVICE_ERROR
;
1129 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1130 // set *NeedRetry = FALSE to avoid the outside caller try again.
1133 return EFI_DEVICE_ERROR
;
1137 DetectMediaParsingSenseKeys (
1138 SCSI_DISK_DEV
*ScsiDiskDevice
,
1139 EFI_SCSI_SENSE_DATA
*SenseData
,
1140 UINTN NumberOfSenseKeys
,
1145 Routine Description:
1147 Parsing Sense Keys which got from request sense command.
1151 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
1152 SenseData - The pointer of EFI_SCSI_SENSE_DATA
1153 NumberOfSenseKeys - The number of sense key
1154 Action - The pointer of action which indicates what is need to do next
1158 EFI_DEVICE_ERROR - Indicates that error occurs
1159 EFI_SUCCESS - Successfully to complete the parsing
1166 // Default is to read capacity, unless..
1168 *Action
= ACTION_READ_CAPACITY
;
1170 if (NumberOfSenseKeys
== 0) {
1171 *Action
= ACTION_NO_ACTION
;
1175 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1177 // No Sense Key returned from last submitted command
1179 *Action
= ACTION_NO_ACTION
;
1183 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1184 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1185 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1186 *Action
= ACTION_NO_ACTION
;
1190 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1191 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1195 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1196 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1197 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1198 return EFI_DEVICE_ERROR
;
1201 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1202 return EFI_DEVICE_ERROR
;
1205 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1207 *Action
= ACTION_RETRY_COMMAND_LATER
;
1211 return EFI_DEVICE_ERROR
;
1218 ScsiDiskReadCapacity (
1219 SCSI_DISK_DEV
*ScsiDiskDevice
,
1221 EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1222 UINTN
*NumberOfSenseKeys
1226 Routine Description:
1228 Send read capacity command to device and get the device parameter
1232 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
1233 NeedRetry - The pointer of flag indicates if need a retry
1234 SenseDataArray - The pointer of an array of sense data
1235 NumberOfSenseKeys - The number of sense key
1239 EFI_DEVICE_ERROR - Indicates that error occurs
1240 EFI_SUCCESS - Successfully to read capacity
1244 EFI_SCSI_DISK_CAPACITY_DATA CapacityData
;
1246 UINT8 HostAdapterStatus
;
1248 EFI_STATUS CommandStatus
;
1252 UINT8 SenseDataLength
;
1254 SenseDataLength
= 0;
1255 ZeroMem (&CapacityData
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1256 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1258 *NumberOfSenseKeys
= 0;
1261 // submit Read Capacity Command. in this call,not request sense data
1263 CommandStatus
= ScsiReadCapacityCommand (
1264 ScsiDiskDevice
->ScsiIo
,
1265 EfiScsiStallSeconds (1),
1270 (VOID
*) &CapacityData
,
1275 // no need to check HostAdapterStatus and TargetStatus
1277 if (CommandStatus
== EFI_SUCCESS
) {
1278 GetMediaInfo (ScsiDiskDevice
, &CapacityData
);
1281 } else if (CommandStatus
== EFI_NOT_READY
) {
1283 return EFI_DEVICE_ERROR
;
1285 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1287 return EFI_DEVICE_ERROR
;
1290 // go ahead to check HostAdapterStatus and TargetStatus
1291 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1294 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1295 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1297 return EFI_DEVICE_ERROR
;
1299 } else if (Status
== EFI_DEVICE_ERROR
) {
1301 // reset the scsi channel
1303 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1305 return EFI_DEVICE_ERROR
;
1308 Status
= CheckTargetStatus (TargetStatus
);
1309 if (Status
== EFI_NOT_READY
) {
1311 // reset the scsi device
1313 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1315 return EFI_DEVICE_ERROR
;
1317 } else if (Status
== EFI_DEVICE_ERROR
) {
1319 return EFI_DEVICE_ERROR
;
1323 // if goes here, meant SubmitReadCapacityCommand() failed.
1324 // if ScsiDiskRequestSenseKeys() succeeds at last,
1325 // better retry SubmitReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1328 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1330 Status
= ScsiDiskRequestSenseKeys (
1337 if (!EFI_ERROR (Status
)) {
1339 return EFI_DEVICE_ERROR
;
1343 return EFI_DEVICE_ERROR
;
1347 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1348 // set *NeedRetry = FALSE to avoid the outside caller try again.
1351 return EFI_DEVICE_ERROR
;
1355 CheckHostAdapterStatus (
1356 UINT8 HostAdapterStatus
1360 Routine Description:
1362 Check the HostAdapter status
1366 HostAdapterStatus - Host Adapter status
1377 switch (HostAdapterStatus
) {
1378 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1381 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1382 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1383 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1386 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1387 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1388 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1389 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1390 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1391 return EFI_NOT_READY
;
1393 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1394 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1395 return EFI_DEVICE_ERROR
;
1408 Routine Description:
1410 Check the target status
1414 TargetStatus - Target status
1424 switch (TargetStatus
) {
1425 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1426 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1427 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1430 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1431 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1432 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1433 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1434 return EFI_NOT_READY
;
1436 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1437 return EFI_DEVICE_ERROR
;
1446 ScsiDiskRequestSenseKeys (
1447 SCSI_DISK_DEV
*ScsiDiskDevice
,
1449 EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1450 UINTN
*NumberOfSenseKeys
,
1451 BOOLEAN AskResetIfError
1455 Routine Description:
1457 Retrieve all sense keys from the device.
1458 When encountering error during the process,
1459 if retrieve sense keys before error encounterred,
1460 return the sense keys with return status set to EFI_SUCCESS,
1461 and NeedRetry set to FALSE; otherwize, return the proper return
1466 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
1467 NeedRetry - The pointer of flag indicates if need a retry
1468 SenseDataArray - The pointer of an array of sense data
1469 NumberOfSenseKeys - The number of sense key
1470 AskResetIfError - The flag indicates if need reset when error occurs
1474 EFI_DEVICE_ERROR - Indicates that error occurs
1475 EFI_SUCCESS - Successfully to request sense key
1479 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1480 UINT8 SenseDataLength
;
1483 EFI_STATUS FallStatus
;
1484 UINT8 HostAdapterStatus
;
1487 FallStatus
= EFI_SUCCESS
;
1488 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1491 ScsiDiskDevice
->SenseData
,
1492 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1495 *NumberOfSenseKeys
= 0;
1496 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1497 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1499 for (SenseReq
= TRUE
; SenseReq
;) {
1500 Status
= ScsiRequestSenseCommand (
1501 ScsiDiskDevice
->ScsiIo
,
1502 EfiScsiStallSeconds (2),
1508 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1509 FallStatus
= EFI_SUCCESS
;
1511 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1513 FallStatus
= EFI_DEVICE_ERROR
;
1515 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1517 FallStatus
= EFI_DEVICE_ERROR
;
1519 } else if (Status
== EFI_DEVICE_ERROR
) {
1520 if (AskResetIfError
) {
1521 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1524 FallStatus
= EFI_DEVICE_ERROR
;
1527 if (EFI_ERROR (FallStatus
)) {
1528 if (*NumberOfSenseKeys
!= 0) {
1532 return EFI_DEVICE_ERROR
;
1536 (*NumberOfSenseKeys
) += 1;
1539 // no more sense key or number of sense keys exceeds predefined,
1542 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1543 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1553 SCSI_DISK_DEV
*ScsiDiskDevice
,
1554 EFI_SCSI_DISK_CAPACITY_DATA
*Capacity
1558 Routine Description:
1560 Get information from media read capacity command
1564 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
1565 Capacity - The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1573 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity
->LastLba3
<< 24) |
1574 (Capacity
->LastLba2
<< 16) |
1575 (Capacity
->LastLba1
<< 8) |
1578 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1579 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity
->BlockSize3
<< 24) |
1580 (Capacity
->BlockSize2
<< 16) |
1581 (Capacity
->BlockSize1
<< 8) |
1582 Capacity
->BlockSize0
;
1583 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1584 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1587 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1588 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1594 SCSI_DISK_DEV
*ScsiDiskDevice
1598 Routine Description:
1604 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
1612 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) (ScsiDiskDevice
->InquiryData
.RMB
? 0 : 1);
1613 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1618 ScsiDiskReadSectors (
1619 SCSI_DISK_DEV
*ScsiDiskDevice
,
1622 UINTN NumberOfBlocks
1626 Routine Description:
1628 Read sector from SCSI Disk
1632 ScsiDiskDevice - The poiniter of SCSI_DISK_DEV
1633 Buffer - The buffer to fill in the read out data
1634 Lba - Logic block address
1635 NumberOfBlocks - The number of blocks to read
1644 UINTN BlocksRemaining
;
1656 EFI_SCSI_SENSE_DATA
*SenseData
;
1657 UINTN NumberOfSenseKeys
;
1660 NumberOfSenseKeys
= 0;
1662 Status
= EFI_SUCCESS
;
1664 BlocksRemaining
= NumberOfBlocks
;
1665 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1667 // limit the data bytes that can be transferred by one Read(10) Command
1672 Lba32
= (UINT32
) Lba
;
1674 while (BlocksRemaining
> 0) {
1676 if (BlocksRemaining
<= MaxBlock
) {
1678 SectorCount
= (UINT16
) BlocksRemaining
;
1681 SectorCount
= MaxBlock
;
1684 ByteCount
= SectorCount
* BlockSize
;
1685 Timeout
= EfiScsiStallSeconds (2);
1688 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1690 Status
= ScsiDiskRead10 (
1701 if (!EFI_ERROR (Status
)) {
1706 return EFI_DEVICE_ERROR
;
1711 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1712 return EFI_DEVICE_ERROR
;
1716 // actual transferred sectors
1718 SectorCount
= ByteCount
/ BlockSize
;
1720 Lba32
+= SectorCount
;
1721 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1722 BlocksRemaining
-= SectorCount
;
1729 ScsiDiskWriteSectors (
1730 SCSI_DISK_DEV
*ScsiDiskDevice
,
1733 UINTN NumberOfBlocks
1737 Routine Description:
1739 Write SCSI Disk sectors
1743 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
1744 Buffer - The data buffer to write sector
1745 Lba - Logic block address
1746 NumberOfBlocks - The number of blocks to write
1755 UINTN BlocksRemaining
;
1767 EFI_SCSI_SENSE_DATA
*SenseData
;
1768 UINTN NumberOfSenseKeys
;
1771 NumberOfSenseKeys
= 0;
1773 Status
= EFI_SUCCESS
;
1775 BlocksRemaining
= NumberOfBlocks
;
1776 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1778 // limit the data bytes that can be transferred by one Write(10) Command
1783 Lba32
= (UINT32
) Lba
;
1785 while (BlocksRemaining
> 0) {
1787 if (BlocksRemaining
<= MaxBlock
) {
1789 SectorCount
= (UINT16
) BlocksRemaining
;
1792 SectorCount
= MaxBlock
;
1795 ByteCount
= SectorCount
* BlockSize
;
1796 Timeout
= EfiScsiStallSeconds (2);
1798 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1799 Status
= ScsiDiskWrite10 (
1810 if (!EFI_ERROR (Status
)) {
1815 return EFI_DEVICE_ERROR
;
1819 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1820 return EFI_DEVICE_ERROR
;
1823 // actual transferred sectors
1825 SectorCount
= ByteCount
/ BlockSize
;
1827 Lba32
+= SectorCount
;
1828 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1829 BlocksRemaining
-= SectorCount
;
1837 SCSI_DISK_DEV
*ScsiDiskDevice
,
1839 EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1840 UINTN
*NumberOfSenseKeys
,
1849 Routine Description:
1851 Sumbmit Read command
1855 ScsiDiskDevice - The pointer of ScsiDiskDevice
1856 NeedRetry - The pointer of flag indicates if needs retry if error happens
1857 SenseDataArray - The pointer of an array of sense data
1858 NumberOfSenseKeys - The number of sense key
1859 Timeout - The time to complete the command
1860 DataBuffer - The buffer to fill with the read out data
1861 DataLength - The length of buffer
1862 StartLba - The start logic block address
1863 SectorSize - The size of sector
1871 UINT8 SenseDataLength
;
1873 UINT8 HostAdapterStatus
;
1877 *NumberOfSenseKeys
= 0;
1878 SenseDataLength
= 0;
1879 Status
= ScsiRead10Command (
1880 ScsiDiskDevice
->ScsiIo
,
1896 SCSI_DISK_DEV
*ScsiDiskDevice
,
1898 EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1899 UINTN
*NumberOfSenseKeys
,
1908 Routine Description:
1910 Submit Write Command
1914 ScsiDiskDevice - The pointer of ScsiDiskDevice
1915 NeedRetry - The pointer of flag indicates if needs retry if error happens
1916 SenseDataArray - The pointer of an array of sense data
1917 NumberOfSenseKeys - The number of sense key
1918 Timeout - The time to complete the command
1919 DataBuffer - The buffer to fill with the read out data
1920 DataLength - The length of buffer
1921 StartLba - The start logic block address
1922 SectorSize - The size of sector
1931 UINT8 SenseDataLength
;
1932 UINT8 HostAdapterStatus
;
1936 *NumberOfSenseKeys
= 0;
1937 SenseDataLength
= 0;
1938 Status
= ScsiWrite10Command (
1939 ScsiDiskDevice
->ScsiIo
,
1955 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1956 IN UINTN SenseCounts
1960 Routine Description:
1962 Check sense key to find if media presents
1966 SenseData - The pointer of EFI_SCSI_SENSE_DATA
1967 SenseCounts - The number of sense key
1975 EFI_SCSI_SENSE_DATA
*SensePtr
;
1980 SensePtr
= SenseData
;
1982 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1984 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
1985 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
1987 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
1988 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
1998 ScsiDiskIsMediaError (
1999 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2000 IN UINTN SenseCounts
2004 Routine Description:
2010 SenseData - The pointer of EFI_SCSI_SENSE_DATA
2011 SenseCounts - The number of sense key
2019 EFI_SCSI_SENSE_DATA
*SensePtr
;
2024 SensePtr
= SenseData
;
2026 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2028 switch (SensePtr
->Sense_Key
) {
2030 case EFI_SCSI_SK_MEDIUM_ERROR
:
2032 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
2034 switch (SensePtr
->Addnl_Sense_Code
) {
2039 case EFI_SCSI_ASC_MEDIA_ERR1
:
2044 case EFI_SCSI_ASC_MEDIA_ERR2
:
2049 case EFI_SCSI_ASC_MEDIA_ERR3
:
2050 case EFI_SCSI_ASC_MEDIA_ERR4
:
2060 case EFI_SCSI_SK_NOT_READY
:
2062 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2064 switch (SensePtr
->Addnl_Sense_Code
) {
2066 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
2068 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
2088 ScsiDiskIsHardwareError (
2089 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2090 IN UINTN SenseCounts
2094 Routine Description:
2096 Check sense key to find if hardware error happens
2100 SenseData - The pointer of EFI_SCSI_SENSE_DATA
2101 SenseCounts - The number of sense key
2109 EFI_SCSI_SENSE_DATA
*SensePtr
;
2114 SensePtr
= SenseData
;
2116 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2119 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2121 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2132 ScsiDiskIsMediaChange (
2133 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2134 IN UINTN SenseCounts
2138 Routine Description:
2140 Check sense key to find if media has changed
2144 SenseData - The pointer of EFI_SCSI_SENSE_DATA
2145 SenseCounts - The number of sense key
2153 EFI_SCSI_SENSE_DATA
*SensePtr
;
2155 BOOLEAN IsMediaChanged
;
2157 IsMediaChanged
= FALSE
;
2158 SensePtr
= SenseData
;
2160 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2162 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2163 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2165 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2166 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2167 IsMediaChanged
= TRUE
;
2173 return IsMediaChanged
;
2177 ScsiDiskIsResetBefore (
2178 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2179 IN UINTN SenseCounts
2183 Routine Description:
2185 Check sense key to find if reset happens
2189 SenseData - The pointer of EFI_SCSI_SENSE_DATA
2190 SenseCounts - The number of sense key
2198 EFI_SCSI_SENSE_DATA
*SensePtr
;
2200 BOOLEAN IsResetBefore
;
2202 IsResetBefore
= FALSE
;
2203 SensePtr
= SenseData
;
2205 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2208 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2209 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2211 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2212 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2213 IsResetBefore
= TRUE
;
2219 return IsResetBefore
;
2223 ScsiDiskIsDriveReady (
2224 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2225 IN UINTN SenseCounts
,
2226 OUT BOOLEAN
*RetryLater
2230 Routine Description:
2232 Check sense key to find if the drive is ready
2236 SenseData - The pointer of EFI_SCSI_SENSE_DATA
2237 SenseCounts - The number of sense key
2238 RetryLater - The flag means if need a retry
2246 EFI_SCSI_SENSE_DATA
*SensePtr
;
2251 *RetryLater
= FALSE
;
2252 SensePtr
= SenseData
;
2254 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2256 switch (SensePtr
->Sense_Key
) {
2258 case EFI_SCSI_SK_NOT_READY
:
2260 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2262 switch (SensePtr
->Addnl_Sense_Code
) {
2263 case EFI_SCSI_ASC_NOT_READY
:
2265 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2267 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2268 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2270 // Additional Sense Code Qualifier is
2271 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2279 *RetryLater
= FALSE
;
2300 ScsiDiskHaveSenseKey (
2301 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2302 IN UINTN SenseCounts
2306 Routine Description:
2308 Check sense key to find if it has sense key
2312 SenseData - The pointer of EFI_SCSI_SENSE_DATA
2313 SenseCounts - The number of sense key
2321 EFI_SCSI_SENSE_DATA
*SensePtr
;
2323 BOOLEAN HaveSenseKey
;
2325 if (SenseCounts
== 0) {
2326 HaveSenseKey
= FALSE
;
2328 HaveSenseKey
= TRUE
;
2331 SensePtr
= SenseData
;
2333 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2336 // Sense Key is SK_NO_SENSE (0x0)
2338 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2340 HaveSenseKey
= FALSE
;
2346 return HaveSenseKey
;
2350 ReleaseScsiDiskDeviceResources (
2351 IN SCSI_DISK_DEV
*ScsiDiskDevice
2355 Routine Description:
2357 Release resource about disk device
2361 ScsiDiskDevice - The pointer of SCSI_DISK_DEV
2369 if (ScsiDiskDevice
== NULL
) {
2373 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2374 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
2375 ScsiDiskDevice
->SenseData
= NULL
;
2378 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2379 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2380 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2383 gBS
->FreePool (ScsiDiskDevice
);
2385 ScsiDiskDevice
= NULL
;