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
,
30 The user Entry Point for module ScsiDisk.
32 The user code starts with this function.
34 @param ImageHandle The firmware allocated handle for the EFI image.
35 @param SystemTable A pointer to the EFI System Table.
37 @retval EFI_SUCCESS The entry point is executed successfully.
38 @retval other Some error occurs when executing this entry point.
44 IN EFI_HANDLE ImageHandle
,
45 IN EFI_SYSTEM_TABLE
*SystemTable
51 // Install driver model protocol(s).
53 Status
= EfiLibInstallDriverBindingComponentName2 (
56 &gScsiDiskDriverBinding
,
58 &gScsiDiskComponentName
,
59 &gScsiDiskComponentName2
61 ASSERT_EFI_ERROR (Status
);
68 Test to see if this driver supports ControllerHandle.
70 This service is called by the EFI boot service ConnectController(). In order
71 to make drivers as small as possible, there are a few calling restrictions for
72 this service. ConnectController() must follow these calling restrictions.
73 If any other agent wishes to call Supported() it must also follow these
76 @param This Protocol instance pointer.
77 @param ControllerHandle Handle of device to test
78 @param RemainingDevicePath Optional parameter use to pick a specific child
81 @retval EFI_SUCCESS This driver supports this device
82 @retval EFI_ALREADY_STARTED This driver is already running on this device
83 @retval other This driver does not support this device
88 ScsiDiskDriverBindingSupported (
89 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
90 IN EFI_HANDLE Controller
,
91 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
95 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
98 Status
= gBS
->OpenProtocol (
100 &gEfiScsiIoProtocolGuid
,
102 This
->DriverBindingHandle
,
104 EFI_OPEN_PROTOCOL_BY_DRIVER
106 if (EFI_ERROR (Status
)) {
110 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
111 if (!EFI_ERROR (Status
)) {
112 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
113 Status
= EFI_SUCCESS
;
115 Status
= EFI_UNSUPPORTED
;
121 &gEfiScsiIoProtocolGuid
,
122 This
->DriverBindingHandle
,
130 Start this driver on ControllerHandle.
132 This service is called by the EFI boot service ConnectController(). In order
133 to make drivers as small as possible, there are a few calling restrictions for
134 this service. ConnectController() must follow these calling restrictions. If
135 any other agent wishes to call Start() it must also follow these calling
138 @param This Protocol instance pointer.
139 @param ControllerHandle Handle of device to bind driver to
140 @param RemainingDevicePath Optional parameter use to pick a specific child
143 @retval EFI_SUCCESS This driver is added to ControllerHandle
144 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
145 @retval other This driver does not support this device
150 ScsiDiskDriverBindingStart (
151 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
152 IN EFI_HANDLE Controller
,
153 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
157 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
158 SCSI_DISK_DEV
*ScsiDiskDevice
;
164 ScsiDiskDevice
= (SCSI_DISK_DEV
*) AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
165 if (ScsiDiskDevice
== NULL
) {
166 return EFI_OUT_OF_RESOURCES
;
169 Status
= gBS
->OpenProtocol (
171 &gEfiScsiIoProtocolGuid
,
173 This
->DriverBindingHandle
,
175 EFI_OPEN_PROTOCOL_BY_DRIVER
177 if (EFI_ERROR (Status
)) {
178 FreePool (ScsiDiskDevice
);
182 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
183 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
184 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
185 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
186 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
187 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
188 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
189 ScsiDiskDevice
->Handle
= Controller
;
191 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
192 switch (ScsiDiskDevice
->DeviceType
) {
193 case EFI_SCSI_TYPE_DISK
:
194 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
197 case EFI_SCSI_TYPE_CDROM
:
198 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
202 // The Sense Data Array's initial size is 6
204 ScsiDiskDevice
->SenseDataNumber
= 6;
205 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
206 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
208 if (ScsiDiskDevice
->SenseData
== NULL
) {
211 &gEfiScsiIoProtocolGuid
,
212 This
->DriverBindingHandle
,
215 FreePool (ScsiDiskDevice
);
216 return EFI_OUT_OF_RESOURCES
;
220 // Retrieve device information
223 for (Index
= 0; Index
< MaxRetry
; Index
++) {
224 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
225 if (!EFI_ERROR (Status
)) {
230 FreePool (ScsiDiskDevice
->SenseData
);
233 &gEfiScsiIoProtocolGuid
,
234 This
->DriverBindingHandle
,
237 FreePool (ScsiDiskDevice
);
238 return EFI_DEVICE_ERROR
;
242 // The second parameter "TRUE" means must
243 // retrieve media capacity
245 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, TRUE
, &Temp
);
246 if (!EFI_ERROR (Status
)) {
247 Status
= gBS
->InstallMultipleProtocolInterfaces (
249 &gEfiBlockIoProtocolGuid
,
250 &ScsiDiskDevice
->BlkIo
,
255 if (EFI_ERROR (Status
)) {
256 FreePool (ScsiDiskDevice
->SenseData
);
259 &gEfiScsiIoProtocolGuid
,
260 This
->DriverBindingHandle
,
263 FreePool (ScsiDiskDevice
);
267 ScsiDiskDevice
->ControllerNameTable
= NULL
;
270 gScsiDiskComponentName
.SupportedLanguages
,
271 &ScsiDiskDevice
->ControllerNameTable
,
277 gScsiDiskComponentName2
.SupportedLanguages
,
278 &ScsiDiskDevice
->ControllerNameTable
,
290 Stop this driver on ControllerHandle.
292 This service is called by the EFI boot service DisconnectController().
293 In order to make drivers as small as possible, there are a few calling
294 restrictions for this service. DisconnectController() must follow these
295 calling restrictions. If any other agent wishes to call Stop() it must
296 also follow these calling restrictions.
298 @param This Protocol instance pointer.
299 @param ControllerHandle Handle of device to stop driver on
300 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
301 children is zero stop the entire bus driver.
302 @param ChildHandleBuffer List of Child Handles to Stop.
304 @retval EFI_SUCCESS This driver is removed ControllerHandle
305 @retval other This driver was not removed from this device
310 ScsiDiskDriverBindingStop (
311 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
312 IN EFI_HANDLE Controller
,
313 IN UINTN NumberOfChildren
,
314 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
317 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
318 SCSI_DISK_DEV
*ScsiDiskDevice
;
321 Status
= gBS
->OpenProtocol (
323 &gEfiBlockIoProtocolGuid
,
325 This
->DriverBindingHandle
,
327 EFI_OPEN_PROTOCOL_GET_PROTOCOL
329 if (EFI_ERROR (Status
)) {
333 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
334 Status
= gBS
->UninstallProtocolInterface (
336 &gEfiBlockIoProtocolGuid
,
337 &ScsiDiskDevice
->BlkIo
339 if (!EFI_ERROR (Status
)) {
342 &gEfiScsiIoProtocolGuid
,
343 This
->DriverBindingHandle
,
347 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
361 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
362 @param ExtendedVerification The flag about if extend verificate
364 @retval EFI_SUCCESS The device was reset.
365 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
367 @return EFI_STATUS is retured from EFI_SCSI_IO_PROTOCOL.ResetDevice().
373 IN EFI_BLOCK_IO_PROTOCOL
*This
,
374 IN BOOLEAN ExtendedVerification
378 SCSI_DISK_DEV
*ScsiDiskDevice
;
381 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
383 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
385 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
387 if (!ExtendedVerification
) {
391 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
394 gBS
->RestoreTPL (OldTpl
);
399 The function is to Read Block from SCSI Disk.
401 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
402 @param MediaId The Id of Media detected
403 @param Lba The logic block address
404 @param BufferSize The size of Buffer
405 @param Buffer The buffer to fill the read out data
407 @retval EFI_SUCCESS Successfully to read out block.
408 @retval EFI_DEVICE_ERROR Fail to detect media.
409 @retval EFI_NO_MEDIA Media is not present.
410 @retval EFI_MEDIA_CHANGED Media has changed.
411 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
412 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
418 IN EFI_BLOCK_IO_PROTOCOL
*This
,
425 SCSI_DISK_DEV
*ScsiDiskDevice
;
426 EFI_BLOCK_IO_MEDIA
*Media
;
429 UINTN NumberOfBlocks
;
434 if (Buffer
== NULL
) {
435 return EFI_INVALID_PARAMETER
;
438 if (BufferSize
== 0) {
442 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
444 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
446 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
448 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
449 if (EFI_ERROR (Status
)) {
450 Status
= EFI_DEVICE_ERROR
;
455 gBS
->ReinstallProtocolInterface (
456 ScsiDiskDevice
->Handle
,
457 &gEfiBlockIoProtocolGuid
,
458 &ScsiDiskDevice
->BlkIo
,
459 &ScsiDiskDevice
->BlkIo
464 // Get the intrinsic block size
466 Media
= ScsiDiskDevice
->BlkIo
.Media
;
467 BlockSize
= Media
->BlockSize
;
469 NumberOfBlocks
= BufferSize
/ BlockSize
;
471 if (!(Media
->MediaPresent
)) {
472 Status
= EFI_NO_MEDIA
;
476 if (MediaId
!= Media
->MediaId
) {
477 Status
= EFI_MEDIA_CHANGED
;
481 if (BufferSize
% BlockSize
!= 0) {
482 Status
= EFI_BAD_BUFFER_SIZE
;
486 if (Lba
> Media
->LastBlock
) {
487 Status
= EFI_INVALID_PARAMETER
;
491 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
492 Status
= EFI_INVALID_PARAMETER
;
496 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
497 Status
= EFI_INVALID_PARAMETER
;
502 // If all the parameters are valid, then perform read sectors command
503 // to transfer data from device to host.
505 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
508 gBS
->RestoreTPL (OldTpl
);
513 The function is to Write Block to SCSI Disk.
515 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
516 @param MediaId The Id of Media detected
517 @param Lba The logic block address
518 @param BufferSize The size of Buffer
519 @param Buffer The buffer to fill the read out data
521 @retval EFI_SUCCESS Successfully to read out block.
522 @retval EFI_WRITE_PROTECTED The device can not be written to.
523 @retval EFI_DEVICE_ERROR Fail to detect media.
524 @retval EFI_NO_MEDIA Media is not present.
525 @retval EFI_MEDIA_CHNAGED Media has changed.
526 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
527 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
532 ScsiDiskWriteBlocks (
533 IN EFI_BLOCK_IO_PROTOCOL
*This
,
540 SCSI_DISK_DEV
*ScsiDiskDevice
;
541 EFI_BLOCK_IO_MEDIA
*Media
;
544 UINTN NumberOfBlocks
;
549 if (Buffer
== NULL
) {
550 return EFI_INVALID_PARAMETER
;
553 if (BufferSize
== 0) {
557 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
559 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
561 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
563 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
564 if (EFI_ERROR (Status
)) {
565 Status
= EFI_DEVICE_ERROR
;
570 gBS
->ReinstallProtocolInterface (
571 ScsiDiskDevice
->Handle
,
572 &gEfiBlockIoProtocolGuid
,
573 &ScsiDiskDevice
->BlkIo
,
574 &ScsiDiskDevice
->BlkIo
579 // Get the intrinsic block size
581 Media
= ScsiDiskDevice
->BlkIo
.Media
;
582 BlockSize
= Media
->BlockSize
;
584 NumberOfBlocks
= BufferSize
/ BlockSize
;
586 if (!(Media
->MediaPresent
)) {
587 Status
= EFI_NO_MEDIA
;
591 if (MediaId
!= Media
->MediaId
) {
592 Status
= EFI_MEDIA_CHANGED
;
596 if (BufferSize
% BlockSize
!= 0) {
597 Status
= EFI_BAD_BUFFER_SIZE
;
601 if (Lba
> Media
->LastBlock
) {
602 Status
= EFI_INVALID_PARAMETER
;
606 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
607 Status
= EFI_INVALID_PARAMETER
;
611 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
612 Status
= EFI_INVALID_PARAMETER
;
616 // if all the parameters are valid, then perform read sectors command
617 // to transfer data from device to host.
619 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
622 gBS
->RestoreTPL (OldTpl
);
629 EFI_SUCCESS is returned directly.
631 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
633 @retval EFI_SUCCESS All outstanding data was written to the device
638 ScsiDiskFlushBlocks (
639 IN EFI_BLOCK_IO_PROTOCOL
*This
650 Dectect Device and read out capacity ,if error occurs, parse the sense key.
652 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
653 @param MustReadCapacity The flag about reading device capacity
654 @param MediaChange The pointer of flag indicates if media has changed
656 @retval EFI_DEVICE_ERROR Indicates that error occurs
657 @retval EFI_SUCCESS Successfully to detect media
661 ScsiDiskDetectMedia (
662 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
663 IN BOOLEAN MustReadCapacity
,
664 OUT BOOLEAN
*MediaChange
668 EFI_STATUS ReadCapacityStatus
;
669 EFI_SCSI_SENSE_DATA
*SenseData
;
670 UINTN NumberOfSenseKeys
;
672 BOOLEAN NeedReadCapacity
;
675 EFI_BLOCK_IO_MEDIA OldMedia
;
678 Status
= EFI_SUCCESS
;
679 ReadCapacityStatus
= EFI_SUCCESS
;
681 NumberOfSenseKeys
= 0;
682 NeedReadCapacity
= FALSE
;
683 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
684 *MediaChange
= FALSE
;
687 for (Index
= 0; Index
< MaxRetry
; Index
++) {
688 Status
= ScsiDiskTestUnitReady (
694 if (!EFI_ERROR (Status
)) {
703 if ((Index
== MaxRetry
) && EFI_ERROR (Status
)) {
704 return EFI_DEVICE_ERROR
;
707 Status
= DetectMediaParsingSenseKeys (
713 if (EFI_ERROR (Status
)) {
717 // ACTION_NO_ACTION: need not read capacity
718 // other action code: need read capacity
720 if (Action
== ACTION_NO_ACTION
) {
721 NeedReadCapacity
= FALSE
;
723 NeedReadCapacity
= TRUE
;
727 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
728 // retrieve capacity via Read Capacity command
730 if (NeedReadCapacity
|| MustReadCapacity
) {
732 // retrieve media information
735 for (Index
= 0; Index
< MaxRetry
; Index
++) {
737 ReadCapacityStatus
= ScsiDiskReadCapacity (
743 if (EFI_ERROR (ReadCapacityStatus
) && !NeedRetry
) {
744 return EFI_DEVICE_ERROR
;
747 // analyze sense key to action
749 Status
= DetectMediaParsingSenseKeys (
756 // if Status is error, it may indicate crisis error,
757 // so return without retry.
759 if (EFI_ERROR (Status
)) {
764 case ACTION_NO_ACTION
:
771 case ACTION_RETRY_COMMAND_LATER
:
773 // retry the ReadCapacity later and continuously, until the condition
774 // no longer emerges.
775 // stall time is 100000us, or say 0.1 second.
783 // other cases, just retry the command
789 if ((Index
== MaxRetry
) && EFI_ERROR (ReadCapacityStatus
)) {
790 return EFI_DEVICE_ERROR
;
794 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
796 // Media change information got from the device
801 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
803 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
806 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
808 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
811 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
813 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
816 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
817 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
819 // when change from no media to media present, reset the MediaId to 1.
821 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
824 // when no media, reset the MediaId to zero.
826 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
837 Send out Inquiry command to Device.
839 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
840 @param NeedRetry Indicates if needs try again when error happens
842 @retval EFI_DEVICE_ERROR Indicates that error occurs
843 @retval EFI_SUCCESS Successfully to detect media
847 ScsiDiskInquiryDevice (
848 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
849 OUT BOOLEAN
*NeedRetry
852 UINT32 InquiryDataLength
;
853 UINT8 SenseDataLength
;
854 UINT8 HostAdapterStatus
;
856 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
857 UINTN NumberOfSenseKeys
;
862 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
865 Status
= ScsiInquiryCommand (
866 ScsiDiskDevice
->ScsiIo
,
867 EFI_TIMER_PERIOD_SECONDS (1),
872 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
877 // no need to check HostAdapterStatus and TargetStatus
879 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
880 ParseInquiryData (ScsiDiskDevice
);
883 } else if (Status
== EFI_NOT_READY
) {
885 return EFI_DEVICE_ERROR
;
887 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
889 return EFI_DEVICE_ERROR
;
892 // go ahead to check HostAdapterStatus and TargetStatus
893 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
896 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
897 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
899 return EFI_DEVICE_ERROR
;
900 } else if (Status
== EFI_DEVICE_ERROR
) {
902 // reset the scsi channel
904 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
906 return EFI_DEVICE_ERROR
;
909 Status
= CheckTargetStatus (TargetStatus
);
910 if (Status
== EFI_NOT_READY
) {
912 // reset the scsi device
914 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
916 return EFI_DEVICE_ERROR
;
918 } else if (Status
== EFI_DEVICE_ERROR
) {
920 return EFI_DEVICE_ERROR
;
924 // if goes here, meant SubmitInquiryCommand() failed.
925 // if ScsiDiskRequestSenseKeys() succeeds at last,
926 // better retry SubmitInquiryCommand(). (by setting *NeedRetry = TRUE)
929 for (Index
= 0; Index
< MaxRetry
; Index
++) {
930 Status
= ScsiDiskRequestSenseKeys (
937 if (!EFI_ERROR (Status
)) {
939 return EFI_DEVICE_ERROR
;
943 return EFI_DEVICE_ERROR
;
947 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
948 // set *NeedRetry = FALSE to avoid the outside caller try again.
951 return EFI_DEVICE_ERROR
;
957 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
958 When Test Unit Ready command encounters any error caused by host adapter or
959 target, return error without retrieving Sense Keys.
961 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
962 @param NeedRetry The pointer of flag indicates try again
963 @param SenseDataArray The pointer of an array of sense data
964 @param NumberOfSenseKeys The pointer of the number of sense data array
966 @retval EFI_DEVICE_ERROR Indicates that error occurs
967 @retval EFI_SUCCESS Successfully to test unit
971 ScsiDiskTestUnitReady (
972 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
973 OUT BOOLEAN
*NeedRetry
,
974 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
975 OUT UINTN
*NumberOfSenseKeys
979 UINT8 SenseDataLength
;
980 UINT8 HostAdapterStatus
;
986 *NumberOfSenseKeys
= 0;
989 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
991 Status
= ScsiTestUnitReadyCommand (
992 ScsiDiskDevice
->ScsiIo
,
993 EFI_TIMER_PERIOD_SECONDS (1),
1000 // no need to check HostAdapterStatus and TargetStatus
1002 if (Status
== EFI_NOT_READY
) {
1004 return EFI_DEVICE_ERROR
;
1006 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1008 return EFI_DEVICE_ERROR
;
1011 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1014 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1015 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1017 return EFI_DEVICE_ERROR
;
1019 } else if (Status
== EFI_DEVICE_ERROR
) {
1021 // reset the scsi channel
1023 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1025 return EFI_DEVICE_ERROR
;
1028 Status
= CheckTargetStatus (TargetStatus
);
1029 if (Status
== EFI_NOT_READY
) {
1031 // reset the scsi device
1033 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1035 return EFI_DEVICE_ERROR
;
1037 } else if (Status
== EFI_DEVICE_ERROR
) {
1039 return EFI_DEVICE_ERROR
;
1043 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1044 Status
= ScsiDiskRequestSenseKeys (
1051 if (!EFI_ERROR (Status
)) {
1056 return EFI_DEVICE_ERROR
;
1060 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1061 // set *NeedRetry = FALSE to avoid the outside caller try again.
1064 return EFI_DEVICE_ERROR
;
1068 Parsing Sense Keys which got from request sense command.
1070 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1071 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1072 @param NumberOfSenseKeys The number of sense key
1073 @param Action The pointer of action which indicates what is need to do next
1075 @retval EFI_DEVICE_ERROR Indicates that error occurs
1076 @retval EFI_SUCCESS Successfully to complete the parsing
1080 DetectMediaParsingSenseKeys (
1081 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1082 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1083 IN UINTN NumberOfSenseKeys
,
1090 // Default is to read capacity, unless..
1092 *Action
= ACTION_READ_CAPACITY
;
1094 if (NumberOfSenseKeys
== 0) {
1095 *Action
= ACTION_NO_ACTION
;
1099 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1101 // No Sense Key returned from last submitted command
1103 *Action
= ACTION_NO_ACTION
;
1107 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1108 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1109 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1110 *Action
= ACTION_NO_ACTION
;
1114 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1115 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1119 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1120 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1121 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1122 return EFI_DEVICE_ERROR
;
1125 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1126 return EFI_DEVICE_ERROR
;
1129 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1131 *Action
= ACTION_RETRY_COMMAND_LATER
;
1135 return EFI_DEVICE_ERROR
;
1143 Send read capacity command to device and get the device parameter.
1145 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1146 @param NeedRetry The pointer of flag indicates if need a retry
1147 @param SenseDataArray The pointer of an array of sense data
1148 @param NumberOfSenseKeys The number of sense key
1150 @retval EFI_DEVICE_ERROR Indicates that error occurs
1151 @retval EFI_SUCCESS Successfully to read capacity
1155 ScsiDiskReadCapacity (
1156 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1157 OUT BOOLEAN
*NeedRetry
,
1158 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1159 OUT UINTN
*NumberOfSenseKeys
1162 EFI_SCSI_DISK_CAPACITY_DATA CapacityData
;
1164 UINT8 HostAdapterStatus
;
1166 EFI_STATUS CommandStatus
;
1170 UINT8 SenseDataLength
;
1172 SenseDataLength
= 0;
1173 ZeroMem (&CapacityData
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1174 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1176 *NumberOfSenseKeys
= 0;
1179 // submit Read Capacity Command. in this call,not request sense data
1181 CommandStatus
= ScsiReadCapacityCommand (
1182 ScsiDiskDevice
->ScsiIo
,
1183 EFI_TIMER_PERIOD_SECONDS (1),
1188 (VOID
*) &CapacityData
,
1193 // no need to check HostAdapterStatus and TargetStatus
1195 if (CommandStatus
== EFI_SUCCESS
) {
1196 GetMediaInfo (ScsiDiskDevice
, &CapacityData
);
1199 } else if (CommandStatus
== EFI_NOT_READY
) {
1201 return EFI_DEVICE_ERROR
;
1203 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1205 return EFI_DEVICE_ERROR
;
1208 // go ahead to check HostAdapterStatus and TargetStatus
1209 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1212 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1213 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1215 return EFI_DEVICE_ERROR
;
1217 } else if (Status
== EFI_DEVICE_ERROR
) {
1219 // reset the scsi channel
1221 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1223 return EFI_DEVICE_ERROR
;
1226 Status
= CheckTargetStatus (TargetStatus
);
1227 if (Status
== EFI_NOT_READY
) {
1229 // reset the scsi device
1231 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1233 return EFI_DEVICE_ERROR
;
1235 } else if (Status
== EFI_DEVICE_ERROR
) {
1237 return EFI_DEVICE_ERROR
;
1241 // if goes here, meant SubmitReadCapacityCommand() failed.
1242 // if ScsiDiskRequestSenseKeys() succeeds at last,
1243 // better retry SubmitReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1246 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1248 Status
= ScsiDiskRequestSenseKeys (
1255 if (!EFI_ERROR (Status
)) {
1257 return EFI_DEVICE_ERROR
;
1261 return EFI_DEVICE_ERROR
;
1265 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1266 // set *NeedRetry = FALSE to avoid the outside caller try again.
1269 return EFI_DEVICE_ERROR
;
1273 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1275 @param HostAdapterStatus Host Adapter status
1277 @retval EFI_SUCCESS Host adapter is OK.
1278 @retval EFI_TIMEOUT Timeout.
1279 @retval EFI_NOT_READY Adapter NOT ready.
1280 @retval EFI_DEVICE_ERROR Adapter device error.
1284 CheckHostAdapterStatus (
1285 IN UINT8 HostAdapterStatus
1288 switch (HostAdapterStatus
) {
1289 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1292 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1293 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1294 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1297 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1298 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1299 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1300 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1301 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1302 return EFI_NOT_READY
;
1304 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1305 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1306 return EFI_DEVICE_ERROR
;
1315 Check the target status and re-interpret it in EFI_STATUS.
1317 @param TargetStatus Target status
1319 @retval EFI_NOT_READY Device is NOT ready.
1320 @retval EFI_DEVICE_ERROR
1326 IN UINT8 TargetStatus
1329 switch (TargetStatus
) {
1330 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1331 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1332 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1335 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1336 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1337 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1338 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1339 return EFI_NOT_READY
;
1341 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1342 return EFI_DEVICE_ERROR
;
1352 Retrieve all sense keys from the device.
1354 When encountering error during the process, if retrieve sense keys before
1355 error encounterred, it returns the sense keys with return status set to EFI_SUCCESS,
1356 and NeedRetry set to FALSE; otherwize, return the proper return status.
1358 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1359 @param NeedRetry The pointer of flag indicates if need a retry
1360 @param SenseDataArray The pointer of an array of sense data
1361 @param NumberOfSenseKeys The number of sense key
1362 @param AskResetIfError The flag indicates if need reset when error occurs
1364 @retval EFI_DEVICE_ERROR Indicates that error occurs
1365 @retval EFI_SUCCESS Successfully to request sense key
1369 ScsiDiskRequestSenseKeys (
1370 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1371 OUT BOOLEAN
*NeedRetry
,
1372 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1373 OUT UINTN
*NumberOfSenseKeys
,
1374 IN BOOLEAN AskResetIfError
1377 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1378 UINT8 SenseDataLength
;
1381 EFI_STATUS FallStatus
;
1382 UINT8 HostAdapterStatus
;
1385 FallStatus
= EFI_SUCCESS
;
1386 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1389 ScsiDiskDevice
->SenseData
,
1390 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1393 *NumberOfSenseKeys
= 0;
1394 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1395 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1397 for (SenseReq
= TRUE
; SenseReq
;) {
1398 Status
= ScsiRequestSenseCommand (
1399 ScsiDiskDevice
->ScsiIo
,
1400 EFI_TIMER_PERIOD_SECONDS (2),
1406 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1407 FallStatus
= EFI_SUCCESS
;
1409 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1411 FallStatus
= EFI_DEVICE_ERROR
;
1413 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1415 FallStatus
= EFI_DEVICE_ERROR
;
1417 } else if (Status
== EFI_DEVICE_ERROR
) {
1418 if (AskResetIfError
) {
1419 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1422 FallStatus
= EFI_DEVICE_ERROR
;
1425 if (EFI_ERROR (FallStatus
)) {
1426 if (*NumberOfSenseKeys
!= 0) {
1430 return EFI_DEVICE_ERROR
;
1434 (*NumberOfSenseKeys
) += 1;
1437 // no more sense key or number of sense keys exceeds predefined,
1440 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1441 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1451 Get information from media read capacity command.
1453 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1454 @param Capacity The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1459 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1460 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity
1463 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity
->LastLba3
<< 24) |
1464 (Capacity
->LastLba2
<< 16) |
1465 (Capacity
->LastLba1
<< 8) |
1468 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1469 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity
->BlockSize3
<< 24) |
1470 (Capacity
->BlockSize2
<< 16) |
1471 (Capacity
->BlockSize1
<< 8) |
1472 Capacity
->BlockSize0
;
1473 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1474 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1477 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1478 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1485 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1490 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1493 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) (ScsiDiskDevice
->InquiryData
.RMB
? 0 : 1);
1494 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1498 Read sector from SCSI Disk.
1500 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1501 @param Buffer The buffer to fill in the read out data
1502 @param Lba Logic block address
1503 @param NumberOfBlocks The number of blocks to read
1505 @retval EFI_DEVICE_ERROR Indicates a device error.
1506 @retval EFI_SUCCESS Operation is successful.
1510 ScsiDiskReadSectors (
1511 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1514 IN UINTN NumberOfBlocks
1517 UINTN BlocksRemaining
;
1529 EFI_SCSI_SENSE_DATA
*SenseData
;
1530 UINTN NumberOfSenseKeys
;
1533 NumberOfSenseKeys
= 0;
1535 Status
= EFI_SUCCESS
;
1537 BlocksRemaining
= NumberOfBlocks
;
1538 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1540 // limit the data bytes that can be transferred by one Read(10) Command
1545 Lba32
= (UINT32
) Lba
;
1547 while (BlocksRemaining
> 0) {
1549 if (BlocksRemaining
<= MaxBlock
) {
1551 SectorCount
= (UINT16
) BlocksRemaining
;
1554 SectorCount
= MaxBlock
;
1557 ByteCount
= SectorCount
* BlockSize
;
1558 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1561 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1563 Status
= ScsiDiskRead10 (
1574 if (!EFI_ERROR (Status
)) {
1579 return EFI_DEVICE_ERROR
;
1584 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1585 return EFI_DEVICE_ERROR
;
1589 // actual transferred sectors
1591 SectorCount
= ByteCount
/ BlockSize
;
1593 Lba32
+= SectorCount
;
1594 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1595 BlocksRemaining
-= SectorCount
;
1602 Write sector to SCSI Disk.
1604 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1605 @param Buffer The buffer of data to be written into SCSI Disk
1606 @param Lba Logic block address
1607 @param NumberOfBlocks The number of blocks to read
1609 @retval EFI_DEVICE_ERROR Indicates a device error.
1610 @retval EFI_SUCCESS Operation is successful.
1614 ScsiDiskWriteSectors (
1615 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1618 IN UINTN NumberOfBlocks
1621 UINTN BlocksRemaining
;
1633 EFI_SCSI_SENSE_DATA
*SenseData
;
1634 UINTN NumberOfSenseKeys
;
1637 NumberOfSenseKeys
= 0;
1639 Status
= EFI_SUCCESS
;
1641 BlocksRemaining
= NumberOfBlocks
;
1642 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1644 // limit the data bytes that can be transferred by one Write(10) Command
1649 Lba32
= (UINT32
) Lba
;
1651 while (BlocksRemaining
> 0) {
1653 if (BlocksRemaining
<= MaxBlock
) {
1655 SectorCount
= (UINT16
) BlocksRemaining
;
1658 SectorCount
= MaxBlock
;
1661 ByteCount
= SectorCount
* BlockSize
;
1662 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1664 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1665 Status
= ScsiDiskWrite10 (
1676 if (!EFI_ERROR (Status
)) {
1681 return EFI_DEVICE_ERROR
;
1685 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1686 return EFI_DEVICE_ERROR
;
1689 // actual transferred sectors
1691 SectorCount
= ByteCount
/ BlockSize
;
1693 Lba32
+= SectorCount
;
1694 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1695 BlocksRemaining
-= SectorCount
;
1703 Sumbmit Read command.
1705 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1706 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1707 @param SenseDataArray NOT used yet in this function
1708 @param NumberOfSenseKeys The number of sense key
1709 @param Timeout The time to complete the command
1710 @param DataBuffer The buffer to fill with the read out data
1711 @param DataLength The length of buffer
1712 @param StartLba The start logic block address
1713 @param SectorSize The size of sector
1715 @return EFI_STATUS is returned by calling ScsiRead10Command().
1719 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1720 OUT BOOLEAN
*NeedRetry
,
1721 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1722 OUT UINTN
*NumberOfSenseKeys
,
1724 OUT UINT8
*DataBuffer
,
1725 IN OUT UINT32
*DataLength
,
1727 IN UINT32 SectorSize
1730 UINT8 SenseDataLength
;
1732 UINT8 HostAdapterStatus
;
1736 *NumberOfSenseKeys
= 0;
1737 SenseDataLength
= 0;
1738 Status
= ScsiRead10Command (
1739 ScsiDiskDevice
->ScsiIo
,
1755 Submit Write Command.
1757 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1758 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1759 @param SenseDataArray NOT used yet in this function
1760 @param NumberOfSenseKeys The number of sense key
1761 @param Timeout The time to complete the command
1762 @param DataBuffer The buffer to fill with the read out data
1763 @param DataLength The length of buffer
1764 @param StartLba The start logic block address
1765 @param SectorSize The size of sector
1767 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1772 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1773 OUT BOOLEAN
*NeedRetry
,
1774 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1775 OUT UINTN
*NumberOfSenseKeys
,
1777 IN UINT8
*DataBuffer
,
1778 IN OUT UINT32
*DataLength
,
1780 IN UINT32 SectorSize
1784 UINT8 SenseDataLength
;
1785 UINT8 HostAdapterStatus
;
1789 *NumberOfSenseKeys
= 0;
1790 SenseDataLength
= 0;
1791 Status
= ScsiWrite10Command (
1792 ScsiDiskDevice
->ScsiIo
,
1808 Check sense key to find if media presents.
1810 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1811 @param SenseCounts The number of sense key
1813 @retval TRUE NOT any media
1814 @retval FALSE Media presents
1818 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1819 IN UINTN SenseCounts
1822 EFI_SCSI_SENSE_DATA
*SensePtr
;
1827 SensePtr
= SenseData
;
1829 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1831 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
1832 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
1834 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
1835 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
1848 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1849 @param SenseCounts The number of sense key
1852 @retval FALSE NOT error
1856 ScsiDiskIsMediaError (
1857 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1858 IN UINTN SenseCounts
1861 EFI_SCSI_SENSE_DATA
*SensePtr
;
1866 SensePtr
= SenseData
;
1868 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1870 switch (SensePtr
->Sense_Key
) {
1872 case EFI_SCSI_SK_MEDIUM_ERROR
:
1874 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
1876 switch (SensePtr
->Addnl_Sense_Code
) {
1881 case EFI_SCSI_ASC_MEDIA_ERR1
:
1886 case EFI_SCSI_ASC_MEDIA_ERR2
:
1891 case EFI_SCSI_ASC_MEDIA_ERR3
:
1892 case EFI_SCSI_ASC_MEDIA_ERR4
:
1902 case EFI_SCSI_SK_NOT_READY
:
1904 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
1906 switch (SensePtr
->Addnl_Sense_Code
) {
1908 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
1910 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
1931 Check sense key to find if hardware error happens.
1933 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1934 @param SenseCounts The number of sense key
1936 @retval TRUE Hardware error exits.
1937 @retval FALSE NO error.
1941 ScsiDiskIsHardwareError (
1942 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1943 IN UINTN SenseCounts
1946 EFI_SCSI_SENSE_DATA
*SensePtr
;
1951 SensePtr
= SenseData
;
1953 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1956 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
1958 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
1970 Check sense key to find if media has changed.
1972 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1973 @param SenseCounts The number of sense key
1975 @retval TRUE Media is changed.
1976 @retval FALSE Medit is NOT changed.
1979 ScsiDiskIsMediaChange (
1980 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1981 IN UINTN SenseCounts
1984 EFI_SCSI_SENSE_DATA
*SensePtr
;
1986 BOOLEAN IsMediaChanged
;
1988 IsMediaChanged
= FALSE
;
1989 SensePtr
= SenseData
;
1991 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1993 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
1994 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
1996 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
1997 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
1998 IsMediaChanged
= TRUE
;
2004 return IsMediaChanged
;
2008 Check sense key to find if reset happens.
2010 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2011 @param SenseCounts The number of sense key
2013 @retval TRUE It is reset before.
2014 @retval FALSE It is NOT reset before.
2018 ScsiDiskIsResetBefore (
2019 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2020 IN UINTN SenseCounts
2023 EFI_SCSI_SENSE_DATA
*SensePtr
;
2025 BOOLEAN IsResetBefore
;
2027 IsResetBefore
= FALSE
;
2028 SensePtr
= SenseData
;
2030 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2033 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2034 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2036 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2037 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2038 IsResetBefore
= TRUE
;
2044 return IsResetBefore
;
2048 Check sense key to find if the drive is ready.
2050 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2051 @param SenseCounts The number of sense key
2052 @param RetryLater The flag means if need a retry
2054 @retval TRUE Drive is ready.
2055 @retval FALSE Drive is NOT ready.
2059 ScsiDiskIsDriveReady (
2060 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2061 IN UINTN SenseCounts
,
2062 OUT BOOLEAN
*RetryLater
2065 EFI_SCSI_SENSE_DATA
*SensePtr
;
2070 *RetryLater
= FALSE
;
2071 SensePtr
= SenseData
;
2073 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2075 switch (SensePtr
->Sense_Key
) {
2077 case EFI_SCSI_SK_NOT_READY
:
2079 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2081 switch (SensePtr
->Addnl_Sense_Code
) {
2082 case EFI_SCSI_ASC_NOT_READY
:
2084 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2086 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2087 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2089 // Additional Sense Code Qualifier is
2090 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2098 *RetryLater
= FALSE
;
2119 Check sense key to find if it has sense key.
2121 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2122 @param SenseCounts - The number of sense key
2124 @retval TRUE It has sense key.
2125 @retval FALSE It has NOT any sense key.
2129 ScsiDiskHaveSenseKey (
2130 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2131 IN UINTN SenseCounts
2134 EFI_SCSI_SENSE_DATA
*SensePtr
;
2136 BOOLEAN HaveSenseKey
;
2138 if (SenseCounts
== 0) {
2139 HaveSenseKey
= FALSE
;
2141 HaveSenseKey
= TRUE
;
2144 SensePtr
= SenseData
;
2146 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2149 // Sense Key is SK_NO_SENSE (0x0)
2151 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2153 HaveSenseKey
= FALSE
;
2159 return HaveSenseKey
;
2163 Release resource about disk device.
2165 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2169 ReleaseScsiDiskDeviceResources (
2170 IN SCSI_DISK_DEV
*ScsiDiskDevice
2173 if (ScsiDiskDevice
== NULL
) {
2177 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2178 FreePool (ScsiDiskDevice
->SenseData
);
2179 ScsiDiskDevice
->SenseData
= NULL
;
2182 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2183 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2184 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2187 FreePool (ScsiDiskDevice
);
2189 ScsiDiskDevice
= NULL
;