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
)) {
248 // Determine if Block IO should be produced on this controller handle
250 if (DetermineInstallBlockIo(Controller
)) {
251 Status
= gBS
->InstallMultipleProtocolInterfaces (
253 &gEfiBlockIoProtocolGuid
,
254 &ScsiDiskDevice
->BlkIo
,
257 if (!EFI_ERROR(Status
)) {
258 ScsiDiskDevice
->ControllerNameTable
= NULL
;
261 gScsiDiskComponentName
.SupportedLanguages
,
262 &ScsiDiskDevice
->ControllerNameTable
,
268 gScsiDiskComponentName2
.SupportedLanguages
,
269 &ScsiDiskDevice
->ControllerNameTable
,
278 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
279 gBS
->FreePool (ScsiDiskDevice
);
282 &gEfiScsiIoProtocolGuid
,
283 This
->DriverBindingHandle
,
292 Stop this driver on ControllerHandle.
294 This service is called by the EFI boot service DisconnectController().
295 In order to make drivers as small as possible, there are a few calling
296 restrictions for this service. DisconnectController() must follow these
297 calling restrictions. If any other agent wishes to call Stop() it must
298 also follow these calling restrictions.
300 @param This Protocol instance pointer.
301 @param ControllerHandle Handle of device to stop driver on
302 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
303 children is zero stop the entire bus driver.
304 @param ChildHandleBuffer List of Child Handles to Stop.
306 @retval EFI_SUCCESS This driver is removed ControllerHandle
307 @retval other This driver was not removed from this device
312 ScsiDiskDriverBindingStop (
313 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
314 IN EFI_HANDLE Controller
,
315 IN UINTN NumberOfChildren
,
316 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
319 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
320 SCSI_DISK_DEV
*ScsiDiskDevice
;
323 Status
= gBS
->OpenProtocol (
325 &gEfiBlockIoProtocolGuid
,
327 This
->DriverBindingHandle
,
329 EFI_OPEN_PROTOCOL_GET_PROTOCOL
331 if (EFI_ERROR (Status
)) {
335 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (BlkIo
);
336 Status
= gBS
->UninstallProtocolInterface (
338 &gEfiBlockIoProtocolGuid
,
339 &ScsiDiskDevice
->BlkIo
341 if (!EFI_ERROR (Status
)) {
344 &gEfiScsiIoProtocolGuid
,
345 This
->DriverBindingHandle
,
349 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
363 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
364 @param ExtendedVerification The flag about if extend verificate
366 @retval EFI_SUCCESS The device was reset.
367 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
369 @return EFI_STATUS is retured from EFI_SCSI_IO_PROTOCOL.ResetDevice().
375 IN EFI_BLOCK_IO_PROTOCOL
*This
,
376 IN BOOLEAN ExtendedVerification
380 SCSI_DISK_DEV
*ScsiDiskDevice
;
383 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
385 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
387 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
389 if (!ExtendedVerification
) {
393 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
396 gBS
->RestoreTPL (OldTpl
);
401 The function is to Read Block from SCSI Disk.
403 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
404 @param MediaId The Id of Media detected
405 @param Lba The logic block address
406 @param BufferSize The size of Buffer
407 @param Buffer The buffer to fill the read out data
409 @retval EFI_SUCCESS Successfully to read out block.
410 @retval EFI_DEVICE_ERROR Fail to detect media.
411 @retval EFI_NO_MEDIA Media is not present.
412 @retval EFI_MEDIA_CHANGED Media has changed.
413 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
414 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
420 IN EFI_BLOCK_IO_PROTOCOL
*This
,
427 SCSI_DISK_DEV
*ScsiDiskDevice
;
428 EFI_BLOCK_IO_MEDIA
*Media
;
431 UINTN NumberOfBlocks
;
436 if (Buffer
== NULL
) {
437 return EFI_INVALID_PARAMETER
;
440 if (BufferSize
== 0) {
444 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
446 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
448 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
450 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
451 if (EFI_ERROR (Status
)) {
452 Status
= EFI_DEVICE_ERROR
;
457 gBS
->ReinstallProtocolInterface (
458 ScsiDiskDevice
->Handle
,
459 &gEfiBlockIoProtocolGuid
,
460 &ScsiDiskDevice
->BlkIo
,
461 &ScsiDiskDevice
->BlkIo
466 // Get the intrinsic block size
468 Media
= ScsiDiskDevice
->BlkIo
.Media
;
469 BlockSize
= Media
->BlockSize
;
471 NumberOfBlocks
= BufferSize
/ BlockSize
;
473 if (!(Media
->MediaPresent
)) {
474 Status
= EFI_NO_MEDIA
;
478 if (MediaId
!= Media
->MediaId
) {
479 Status
= EFI_MEDIA_CHANGED
;
483 if (BufferSize
% BlockSize
!= 0) {
484 Status
= EFI_BAD_BUFFER_SIZE
;
488 if (Lba
> Media
->LastBlock
) {
489 Status
= EFI_INVALID_PARAMETER
;
493 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
494 Status
= EFI_INVALID_PARAMETER
;
498 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
499 Status
= EFI_INVALID_PARAMETER
;
504 // If all the parameters are valid, then perform read sectors command
505 // to transfer data from device to host.
507 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
510 gBS
->RestoreTPL (OldTpl
);
515 The function is to Write Block to SCSI Disk.
517 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
518 @param MediaId The Id of Media detected
519 @param Lba The logic block address
520 @param BufferSize The size of Buffer
521 @param Buffer The buffer to fill the read out data
523 @retval EFI_SUCCESS Successfully to read out block.
524 @retval EFI_WRITE_PROTECTED The device can not be written to.
525 @retval EFI_DEVICE_ERROR Fail to detect media.
526 @retval EFI_NO_MEDIA Media is not present.
527 @retval EFI_MEDIA_CHNAGED Media has changed.
528 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
529 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
534 ScsiDiskWriteBlocks (
535 IN EFI_BLOCK_IO_PROTOCOL
*This
,
542 SCSI_DISK_DEV
*ScsiDiskDevice
;
543 EFI_BLOCK_IO_MEDIA
*Media
;
546 UINTN NumberOfBlocks
;
551 if (Buffer
== NULL
) {
552 return EFI_INVALID_PARAMETER
;
555 if (BufferSize
== 0) {
559 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
561 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_THIS (This
);
563 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
565 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
566 if (EFI_ERROR (Status
)) {
567 Status
= EFI_DEVICE_ERROR
;
572 gBS
->ReinstallProtocolInterface (
573 ScsiDiskDevice
->Handle
,
574 &gEfiBlockIoProtocolGuid
,
575 &ScsiDiskDevice
->BlkIo
,
576 &ScsiDiskDevice
->BlkIo
581 // Get the intrinsic block size
583 Media
= ScsiDiskDevice
->BlkIo
.Media
;
584 BlockSize
= Media
->BlockSize
;
586 NumberOfBlocks
= BufferSize
/ BlockSize
;
588 if (!(Media
->MediaPresent
)) {
589 Status
= EFI_NO_MEDIA
;
593 if (MediaId
!= Media
->MediaId
) {
594 Status
= EFI_MEDIA_CHANGED
;
598 if (BufferSize
% BlockSize
!= 0) {
599 Status
= EFI_BAD_BUFFER_SIZE
;
603 if (Lba
> Media
->LastBlock
) {
604 Status
= EFI_INVALID_PARAMETER
;
608 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
609 Status
= EFI_INVALID_PARAMETER
;
613 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
614 Status
= EFI_INVALID_PARAMETER
;
618 // if all the parameters are valid, then perform read sectors command
619 // to transfer data from device to host.
621 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
624 gBS
->RestoreTPL (OldTpl
);
631 EFI_SUCCESS is returned directly.
633 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
635 @retval EFI_SUCCESS All outstanding data was written to the device
640 ScsiDiskFlushBlocks (
641 IN EFI_BLOCK_IO_PROTOCOL
*This
652 Dectect Device and read out capacity ,if error occurs, parse the sense key.
654 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
655 @param MustReadCapacity The flag about reading device capacity
656 @param MediaChange The pointer of flag indicates if media has changed
658 @retval EFI_DEVICE_ERROR Indicates that error occurs
659 @retval EFI_SUCCESS Successfully to detect media
663 ScsiDiskDetectMedia (
664 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
665 IN BOOLEAN MustReadCapacity
,
666 OUT BOOLEAN
*MediaChange
670 EFI_STATUS ReadCapacityStatus
;
671 EFI_SCSI_SENSE_DATA
*SenseData
;
672 UINTN NumberOfSenseKeys
;
674 BOOLEAN NeedReadCapacity
;
677 EFI_BLOCK_IO_MEDIA OldMedia
;
680 Status
= EFI_SUCCESS
;
681 ReadCapacityStatus
= EFI_SUCCESS
;
683 NumberOfSenseKeys
= 0;
684 NeedReadCapacity
= FALSE
;
685 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
686 *MediaChange
= FALSE
;
689 for (Index
= 0; Index
< MaxRetry
; Index
++) {
690 Status
= ScsiDiskTestUnitReady (
696 if (!EFI_ERROR (Status
)) {
705 if ((Index
== MaxRetry
) && EFI_ERROR (Status
)) {
706 return EFI_DEVICE_ERROR
;
709 Status
= DetectMediaParsingSenseKeys (
715 if (EFI_ERROR (Status
)) {
719 // ACTION_NO_ACTION: need not read capacity
720 // other action code: need read capacity
722 if (Action
== ACTION_NO_ACTION
) {
723 NeedReadCapacity
= FALSE
;
725 NeedReadCapacity
= TRUE
;
729 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
730 // retrieve capacity via Read Capacity command
732 if (NeedReadCapacity
|| MustReadCapacity
) {
734 // retrieve media information
737 for (Index
= 0; Index
< MaxRetry
; Index
++) {
739 ReadCapacityStatus
= ScsiDiskReadCapacity (
745 if (EFI_ERROR (ReadCapacityStatus
) && !NeedRetry
) {
746 return EFI_DEVICE_ERROR
;
749 // analyze sense key to action
751 Status
= DetectMediaParsingSenseKeys (
758 // if Status is error, it may indicate crisis error,
759 // so return without retry.
761 if (EFI_ERROR (Status
)) {
766 case ACTION_NO_ACTION
:
773 case ACTION_RETRY_COMMAND_LATER
:
775 // retry the ReadCapacity later and continuously, until the condition
776 // no longer emerges.
777 // stall time is 100000us, or say 0.1 second.
785 // other cases, just retry the command
791 if ((Index
== MaxRetry
) && EFI_ERROR (ReadCapacityStatus
)) {
792 return EFI_DEVICE_ERROR
;
796 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
798 // Media change information got from the device
803 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
805 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
808 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
810 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
813 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
815 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
818 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
819 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
821 // when change from no media to media present, reset the MediaId to 1.
823 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
826 // when no media, reset the MediaId to zero.
828 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
839 Send out Inquiry command to Device.
841 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
842 @param NeedRetry Indicates if needs try again when error happens
844 @retval EFI_DEVICE_ERROR Indicates that error occurs
845 @retval EFI_SUCCESS Successfully to detect media
849 ScsiDiskInquiryDevice (
850 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
851 OUT BOOLEAN
*NeedRetry
854 UINT32 InquiryDataLength
;
855 UINT8 SenseDataLength
;
856 UINT8 HostAdapterStatus
;
858 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
859 UINTN NumberOfSenseKeys
;
864 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
867 Status
= ScsiInquiryCommand (
868 ScsiDiskDevice
->ScsiIo
,
869 EFI_TIMER_PERIOD_SECONDS (1),
874 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
879 // no need to check HostAdapterStatus and TargetStatus
881 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
882 ParseInquiryData (ScsiDiskDevice
);
885 } else if (Status
== EFI_NOT_READY
) {
887 return EFI_DEVICE_ERROR
;
889 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
891 return EFI_DEVICE_ERROR
;
894 // go ahead to check HostAdapterStatus and TargetStatus
895 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
898 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
899 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
901 return EFI_DEVICE_ERROR
;
902 } else if (Status
== EFI_DEVICE_ERROR
) {
904 // reset the scsi channel
906 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
908 return EFI_DEVICE_ERROR
;
911 Status
= CheckTargetStatus (TargetStatus
);
912 if (Status
== EFI_NOT_READY
) {
914 // reset the scsi device
916 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
918 return EFI_DEVICE_ERROR
;
920 } else if (Status
== EFI_DEVICE_ERROR
) {
922 return EFI_DEVICE_ERROR
;
926 // if goes here, meant ScsiInquiryCommand() failed.
927 // if ScsiDiskRequestSenseKeys() succeeds at last,
928 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
931 for (Index
= 0; Index
< MaxRetry
; Index
++) {
932 Status
= ScsiDiskRequestSenseKeys (
939 if (!EFI_ERROR (Status
)) {
941 return EFI_DEVICE_ERROR
;
945 return EFI_DEVICE_ERROR
;
949 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
950 // set *NeedRetry = FALSE to avoid the outside caller try again.
953 return EFI_DEVICE_ERROR
;
959 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
960 When Test Unit Ready command encounters any error caused by host adapter or
961 target, return error without retrieving Sense Keys.
963 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
964 @param NeedRetry The pointer of flag indicates try again
965 @param SenseDataArray The pointer of an array of sense data
966 @param NumberOfSenseKeys The pointer of the number of sense data array
968 @retval EFI_DEVICE_ERROR Indicates that error occurs
969 @retval EFI_SUCCESS Successfully to test unit
973 ScsiDiskTestUnitReady (
974 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
975 OUT BOOLEAN
*NeedRetry
,
976 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
977 OUT UINTN
*NumberOfSenseKeys
981 UINT8 SenseDataLength
;
982 UINT8 HostAdapterStatus
;
988 *NumberOfSenseKeys
= 0;
991 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
993 Status
= ScsiTestUnitReadyCommand (
994 ScsiDiskDevice
->ScsiIo
,
995 EFI_TIMER_PERIOD_SECONDS (1),
1002 // no need to check HostAdapterStatus and TargetStatus
1004 if (Status
== EFI_NOT_READY
) {
1006 return EFI_DEVICE_ERROR
;
1008 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1010 return EFI_DEVICE_ERROR
;
1013 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1016 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1017 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1019 return EFI_DEVICE_ERROR
;
1021 } else if (Status
== EFI_DEVICE_ERROR
) {
1023 // reset the scsi channel
1025 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1027 return EFI_DEVICE_ERROR
;
1030 Status
= CheckTargetStatus (TargetStatus
);
1031 if (Status
== EFI_NOT_READY
) {
1033 // reset the scsi device
1035 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1037 return EFI_DEVICE_ERROR
;
1039 } else if (Status
== EFI_DEVICE_ERROR
) {
1041 return EFI_DEVICE_ERROR
;
1045 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1046 Status
= ScsiDiskRequestSenseKeys (
1053 if (!EFI_ERROR (Status
)) {
1058 return EFI_DEVICE_ERROR
;
1062 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1063 // set *NeedRetry = FALSE to avoid the outside caller try again.
1066 return EFI_DEVICE_ERROR
;
1070 Parsing Sense Keys which got from request sense command.
1072 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1073 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1074 @param NumberOfSenseKeys The number of sense key
1075 @param Action The pointer of action which indicates what is need to do next
1077 @retval EFI_DEVICE_ERROR Indicates that error occurs
1078 @retval EFI_SUCCESS Successfully to complete the parsing
1082 DetectMediaParsingSenseKeys (
1083 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1084 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1085 IN UINTN NumberOfSenseKeys
,
1092 // Default is to read capacity, unless..
1094 *Action
= ACTION_READ_CAPACITY
;
1096 if (NumberOfSenseKeys
== 0) {
1097 *Action
= ACTION_NO_ACTION
;
1101 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1103 // No Sense Key returned from last submitted command
1105 *Action
= ACTION_NO_ACTION
;
1109 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1110 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1111 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1112 *Action
= ACTION_NO_ACTION
;
1116 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1117 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1121 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1122 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1123 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1124 return EFI_DEVICE_ERROR
;
1127 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1128 return EFI_DEVICE_ERROR
;
1131 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1133 *Action
= ACTION_RETRY_COMMAND_LATER
;
1137 return EFI_DEVICE_ERROR
;
1145 Send read capacity command to device and get the device parameter.
1147 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1148 @param NeedRetry The pointer of flag indicates if need a retry
1149 @param SenseDataArray The pointer of an array of sense data
1150 @param NumberOfSenseKeys The number of sense key
1152 @retval EFI_DEVICE_ERROR Indicates that error occurs
1153 @retval EFI_SUCCESS Successfully to read capacity
1157 ScsiDiskReadCapacity (
1158 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1159 OUT BOOLEAN
*NeedRetry
,
1160 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1161 OUT UINTN
*NumberOfSenseKeys
1164 UINT8 HostAdapterStatus
;
1166 EFI_STATUS CommandStatus
;
1170 UINT8 SenseDataLength
;
1172 UINT32 DataLength10
;
1173 UINT32 DataLength16
;
1174 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10
;
1175 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16
;
1178 SenseDataLength
= 0;
1179 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1180 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1181 ZeroMem (&CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1182 ZeroMem (&CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1184 *NumberOfSenseKeys
= 0;
1186 ScsiVersion
= (UINT8
)(ScsiDiskDevice
->InquiryData
.Version
& 0x03);
1188 if (ScsiVersion
< SCSI_COMMAND_VERSION_3
) {
1190 // submit Read Capacity(10) Command. in this call,not request sense data
1192 CommandStatus
= ScsiReadCapacityCommand (
1193 ScsiDiskDevice
->ScsiIo
,
1194 EFI_TIMER_PERIOD_SECONDS(1),
1199 (VOID
*) &CapacityData10
,
1205 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1206 // and LowestAlignedLba
1208 CommandStatus
= ScsiReadCapacity16Command (
1209 ScsiDiskDevice
->ScsiIo
,
1210 EFI_TIMER_PERIOD_SECONDS (1),
1215 (VOID
*) &CapacityData16
,
1221 // no need to check HostAdapterStatus and TargetStatus
1223 if (CommandStatus
== EFI_SUCCESS
) {
1224 GetMediaInfo (ScsiDiskDevice
, &CapacityData10
,&CapacityData16
);
1227 } else if (CommandStatus
== EFI_NOT_READY
) {
1229 return EFI_DEVICE_ERROR
;
1231 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1233 return EFI_DEVICE_ERROR
;
1236 // go ahead to check HostAdapterStatus and TargetStatus
1237 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1240 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1241 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1243 return EFI_DEVICE_ERROR
;
1245 } else if (Status
== EFI_DEVICE_ERROR
) {
1247 // reset the scsi channel
1249 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1251 return EFI_DEVICE_ERROR
;
1254 Status
= CheckTargetStatus (TargetStatus
);
1255 if (Status
== EFI_NOT_READY
) {
1257 // reset the scsi device
1259 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1261 return EFI_DEVICE_ERROR
;
1263 } else if (Status
== EFI_DEVICE_ERROR
) {
1265 return EFI_DEVICE_ERROR
;
1269 // if goes here, meant ScsiReadCapacityCommand() failed.
1270 // if ScsiDiskRequestSenseKeys() succeeds at last,
1271 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1274 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1276 Status
= ScsiDiskRequestSenseKeys (
1283 if (!EFI_ERROR (Status
)) {
1285 return EFI_DEVICE_ERROR
;
1289 return EFI_DEVICE_ERROR
;
1293 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1294 // set *NeedRetry = FALSE to avoid the outside caller try again.
1297 return EFI_DEVICE_ERROR
;
1301 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1303 @param HostAdapterStatus Host Adapter status
1305 @retval EFI_SUCCESS Host adapter is OK.
1306 @retval EFI_TIMEOUT Timeout.
1307 @retval EFI_NOT_READY Adapter NOT ready.
1308 @retval EFI_DEVICE_ERROR Adapter device error.
1312 CheckHostAdapterStatus (
1313 IN UINT8 HostAdapterStatus
1316 switch (HostAdapterStatus
) {
1317 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1320 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1321 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1322 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1325 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1326 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1327 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1328 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1329 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1330 return EFI_NOT_READY
;
1332 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1333 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1334 return EFI_DEVICE_ERROR
;
1343 Check the target status and re-interpret it in EFI_STATUS.
1345 @param TargetStatus Target status
1347 @retval EFI_NOT_READY Device is NOT ready.
1348 @retval EFI_DEVICE_ERROR
1354 IN UINT8 TargetStatus
1357 switch (TargetStatus
) {
1358 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1359 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1360 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1363 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1364 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1365 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1366 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1367 return EFI_NOT_READY
;
1369 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1370 return EFI_DEVICE_ERROR
;
1380 Retrieve all sense keys from the device.
1382 When encountering error during the process, if retrieve sense keys before
1383 error encounterred, it returns the sense keys with return status set to EFI_SUCCESS,
1384 and NeedRetry set to FALSE; otherwize, return the proper return status.
1386 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1387 @param NeedRetry The pointer of flag indicates if need a retry
1388 @param SenseDataArray The pointer of an array of sense data
1389 @param NumberOfSenseKeys The number of sense key
1390 @param AskResetIfError The flag indicates if need reset when error occurs
1392 @retval EFI_DEVICE_ERROR Indicates that error occurs
1393 @retval EFI_SUCCESS Successfully to request sense key
1397 ScsiDiskRequestSenseKeys (
1398 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1399 OUT BOOLEAN
*NeedRetry
,
1400 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1401 OUT UINTN
*NumberOfSenseKeys
,
1402 IN BOOLEAN AskResetIfError
1405 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
1406 UINT8 SenseDataLength
;
1409 EFI_STATUS FallStatus
;
1410 UINT8 HostAdapterStatus
;
1413 FallStatus
= EFI_SUCCESS
;
1414 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
1417 ScsiDiskDevice
->SenseData
,
1418 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
1421 *NumberOfSenseKeys
= 0;
1422 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1423 PtrSenseData
= ScsiDiskDevice
->SenseData
;
1425 for (SenseReq
= TRUE
; SenseReq
;) {
1426 Status
= ScsiRequestSenseCommand (
1427 ScsiDiskDevice
->ScsiIo
,
1428 EFI_TIMER_PERIOD_SECONDS (2),
1434 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1435 FallStatus
= EFI_SUCCESS
;
1437 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1439 FallStatus
= EFI_DEVICE_ERROR
;
1441 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1443 FallStatus
= EFI_DEVICE_ERROR
;
1445 } else if (Status
== EFI_DEVICE_ERROR
) {
1446 if (AskResetIfError
) {
1447 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1450 FallStatus
= EFI_DEVICE_ERROR
;
1453 if (EFI_ERROR (FallStatus
)) {
1454 if (*NumberOfSenseKeys
!= 0) {
1458 return EFI_DEVICE_ERROR
;
1462 (*NumberOfSenseKeys
) += 1;
1465 // no more sense key or number of sense keys exceeds predefined,
1468 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
1469 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
1479 Get information from media read capacity command.
1481 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1482 @param Capacity The pointer of EFI_SCSI_DISK_CAPACITY_DATA
1487 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1488 EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
1489 EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
1495 ScsiVersion
= (UINT8
)(ScsiDiskDevice
->InquiryData
.Version
& 0x03);
1496 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
1497 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 1;
1500 if (ScsiVersion
< SCSI_COMMAND_VERSION_3
) {
1501 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
1502 (Capacity10
->LastLba2
<< 16) |
1503 (Capacity10
->LastLba1
<< 8) |
1504 Capacity10
->LastLba0
;
1506 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
1507 (Capacity10
->BlockSize2
<< 16) |
1508 (Capacity10
->BlockSize1
<< 8) |
1509 Capacity10
->BlockSize0
;
1510 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
1513 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
1514 *Ptr
++ = Capacity16
->LastLba0
;
1515 *Ptr
++ = Capacity16
->LastLba1
;
1516 *Ptr
++ = Capacity16
->LastLba2
;
1517 *Ptr
++ = Capacity16
->LastLba3
;
1518 *Ptr
++ = Capacity16
->LastLba4
;
1519 *Ptr
++ = Capacity16
->LastLba5
;
1520 *Ptr
++ = Capacity16
->LastLba6
;
1521 *Ptr
= Capacity16
->LastLba7
;
1523 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
1524 (Capacity16
->BlockSize2
<< 16) |
1525 (Capacity16
->BlockSize1
<< 8) |
1526 Capacity16
->BlockSize0
;
1528 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8)|(Capacity16
->LowestAlignLogic1
);
1529 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= Capacity16
->LogicPerPhysical
;
1530 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION2
;
1534 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
1536 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1537 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
1540 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_CDROM
) {
1541 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
1548 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1553 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
1556 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
1557 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
1561 Read sector from SCSI Disk.
1563 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1564 @param Buffer The buffer to fill in the read out data
1565 @param Lba Logic block address
1566 @param NumberOfBlocks The number of blocks to read
1568 @retval EFI_DEVICE_ERROR Indicates a device error.
1569 @retval EFI_SUCCESS Operation is successful.
1573 ScsiDiskReadSectors (
1574 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1577 IN UINTN NumberOfBlocks
1580 UINTN BlocksRemaining
;
1592 EFI_SCSI_SENSE_DATA
*SenseData
;
1593 UINTN NumberOfSenseKeys
;
1596 NumberOfSenseKeys
= 0;
1598 Status
= EFI_SUCCESS
;
1600 BlocksRemaining
= NumberOfBlocks
;
1601 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1603 // limit the data bytes that can be transferred by one Read(10) Command
1608 Lba32
= (UINT32
) Lba
;
1610 while (BlocksRemaining
> 0) {
1612 if (BlocksRemaining
<= MaxBlock
) {
1614 SectorCount
= (UINT16
) BlocksRemaining
;
1617 SectorCount
= MaxBlock
;
1620 ByteCount
= SectorCount
* BlockSize
;
1621 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1624 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1626 Status
= ScsiDiskRead10 (
1637 if (!EFI_ERROR (Status
)) {
1642 return EFI_DEVICE_ERROR
;
1647 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1648 return EFI_DEVICE_ERROR
;
1652 // actual transferred sectors
1654 SectorCount
= ByteCount
/ BlockSize
;
1656 Lba32
+= SectorCount
;
1657 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1658 BlocksRemaining
-= SectorCount
;
1665 Write sector to SCSI Disk.
1667 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV
1668 @param Buffer The buffer of data to be written into SCSI Disk
1669 @param Lba Logic block address
1670 @param NumberOfBlocks The number of blocks to read
1672 @retval EFI_DEVICE_ERROR Indicates a device error.
1673 @retval EFI_SUCCESS Operation is successful.
1677 ScsiDiskWriteSectors (
1678 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1681 IN UINTN NumberOfBlocks
1684 UINTN BlocksRemaining
;
1696 EFI_SCSI_SENSE_DATA
*SenseData
;
1697 UINTN NumberOfSenseKeys
;
1700 NumberOfSenseKeys
= 0;
1702 Status
= EFI_SUCCESS
;
1704 BlocksRemaining
= NumberOfBlocks
;
1705 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
1707 // limit the data bytes that can be transferred by one Write(10) Command
1712 Lba32
= (UINT32
) Lba
;
1714 while (BlocksRemaining
> 0) {
1716 if (BlocksRemaining
<= MaxBlock
) {
1718 SectorCount
= (UINT16
) BlocksRemaining
;
1721 SectorCount
= MaxBlock
;
1724 ByteCount
= SectorCount
* BlockSize
;
1725 Timeout
= EFI_TIMER_PERIOD_SECONDS (2);
1727 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1728 Status
= ScsiDiskWrite10 (
1739 if (!EFI_ERROR (Status
)) {
1744 return EFI_DEVICE_ERROR
;
1748 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
1749 return EFI_DEVICE_ERROR
;
1752 // actual transferred sectors
1754 SectorCount
= ByteCount
/ BlockSize
;
1756 Lba32
+= SectorCount
;
1757 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
1758 BlocksRemaining
-= SectorCount
;
1766 Sumbmit Read command.
1768 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1769 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1770 @param SenseDataArray NOT used yet in this function
1771 @param NumberOfSenseKeys The number of sense key
1772 @param Timeout The time to complete the command
1773 @param DataBuffer The buffer to fill with the read out data
1774 @param DataLength The length of buffer
1775 @param StartLba The start logic block address
1776 @param SectorSize The size of sector
1778 @return EFI_STATUS is returned by calling ScsiRead10Command().
1782 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1783 OUT BOOLEAN
*NeedRetry
,
1784 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1785 OUT UINTN
*NumberOfSenseKeys
,
1787 OUT UINT8
*DataBuffer
,
1788 IN OUT UINT32
*DataLength
,
1790 IN UINT32 SectorSize
1793 UINT8 SenseDataLength
;
1795 UINT8 HostAdapterStatus
;
1799 *NumberOfSenseKeys
= 0;
1800 SenseDataLength
= 0;
1801 Status
= ScsiRead10Command (
1802 ScsiDiskDevice
->ScsiIo
,
1818 Submit Write Command.
1820 @param ScsiDiskDevice The pointer of ScsiDiskDevice
1821 @param NeedRetry The pointer of flag indicates if needs retry if error happens
1822 @param SenseDataArray NOT used yet in this function
1823 @param NumberOfSenseKeys The number of sense key
1824 @param Timeout The time to complete the command
1825 @param DataBuffer The buffer to fill with the read out data
1826 @param DataLength The length of buffer
1827 @param StartLba The start logic block address
1828 @param SectorSize The size of sector
1830 @return EFI_STATUS is returned by calling ScsiWrite10Command().
1835 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1836 OUT BOOLEAN
*NeedRetry
,
1837 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
, OPTIONAL
1838 OUT UINTN
*NumberOfSenseKeys
,
1840 IN UINT8
*DataBuffer
,
1841 IN OUT UINT32
*DataLength
,
1843 IN UINT32 SectorSize
1847 UINT8 SenseDataLength
;
1848 UINT8 HostAdapterStatus
;
1852 *NumberOfSenseKeys
= 0;
1853 SenseDataLength
= 0;
1854 Status
= ScsiWrite10Command (
1855 ScsiDiskDevice
->ScsiIo
,
1871 Check sense key to find if media presents.
1873 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1874 @param SenseCounts The number of sense key
1876 @retval TRUE NOT any media
1877 @retval FALSE Media presents
1881 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1882 IN UINTN SenseCounts
1885 EFI_SCSI_SENSE_DATA
*SensePtr
;
1890 SensePtr
= SenseData
;
1892 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1894 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
1895 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
1897 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
1898 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
1911 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1912 @param SenseCounts The number of sense key
1915 @retval FALSE NOT error
1919 ScsiDiskIsMediaError (
1920 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1921 IN UINTN SenseCounts
1924 EFI_SCSI_SENSE_DATA
*SensePtr
;
1929 SensePtr
= SenseData
;
1931 for (Index
= 0; Index
< SenseCounts
; Index
++) {
1933 switch (SensePtr
->Sense_Key
) {
1935 case EFI_SCSI_SK_MEDIUM_ERROR
:
1937 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
1939 switch (SensePtr
->Addnl_Sense_Code
) {
1944 case EFI_SCSI_ASC_MEDIA_ERR1
:
1949 case EFI_SCSI_ASC_MEDIA_ERR2
:
1954 case EFI_SCSI_ASC_MEDIA_ERR3
:
1955 case EFI_SCSI_ASC_MEDIA_ERR4
:
1965 case EFI_SCSI_SK_NOT_READY
:
1967 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
1969 switch (SensePtr
->Addnl_Sense_Code
) {
1971 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
1973 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
1994 Check sense key to find if hardware error happens.
1996 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1997 @param SenseCounts The number of sense key
1999 @retval TRUE Hardware error exits.
2000 @retval FALSE NO error.
2004 ScsiDiskIsHardwareError (
2005 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2006 IN UINTN SenseCounts
2009 EFI_SCSI_SENSE_DATA
*SensePtr
;
2014 SensePtr
= SenseData
;
2016 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2019 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
2021 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
2033 Check sense key to find if media has changed.
2035 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2036 @param SenseCounts The number of sense key
2038 @retval TRUE Media is changed.
2039 @retval FALSE Medit is NOT changed.
2042 ScsiDiskIsMediaChange (
2043 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2044 IN UINTN SenseCounts
2047 EFI_SCSI_SENSE_DATA
*SensePtr
;
2049 BOOLEAN IsMediaChanged
;
2051 IsMediaChanged
= FALSE
;
2052 SensePtr
= SenseData
;
2054 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2056 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
2057 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
2059 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2060 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
2061 IsMediaChanged
= TRUE
;
2067 return IsMediaChanged
;
2071 Check sense key to find if reset happens.
2073 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2074 @param SenseCounts The number of sense key
2076 @retval TRUE It is reset before.
2077 @retval FALSE It is NOT reset before.
2081 ScsiDiskIsResetBefore (
2082 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2083 IN UINTN SenseCounts
2086 EFI_SCSI_SENSE_DATA
*SensePtr
;
2088 BOOLEAN IsResetBefore
;
2090 IsResetBefore
= FALSE
;
2091 SensePtr
= SenseData
;
2093 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2096 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
2097 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
2099 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
2100 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
2101 IsResetBefore
= TRUE
;
2107 return IsResetBefore
;
2111 Check sense key to find if the drive is ready.
2113 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2114 @param SenseCounts The number of sense key
2115 @param RetryLater The flag means if need a retry
2117 @retval TRUE Drive is ready.
2118 @retval FALSE Drive is NOT ready.
2122 ScsiDiskIsDriveReady (
2123 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2124 IN UINTN SenseCounts
,
2125 OUT BOOLEAN
*RetryLater
2128 EFI_SCSI_SENSE_DATA
*SensePtr
;
2133 *RetryLater
= FALSE
;
2134 SensePtr
= SenseData
;
2136 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2138 switch (SensePtr
->Sense_Key
) {
2140 case EFI_SCSI_SK_NOT_READY
:
2142 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
2144 switch (SensePtr
->Addnl_Sense_Code
) {
2145 case EFI_SCSI_ASC_NOT_READY
:
2147 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
2149 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
2150 case EFI_SCSI_ASCQ_IN_PROGRESS
:
2152 // Additional Sense Code Qualifier is
2153 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
2161 *RetryLater
= FALSE
;
2182 Check sense key to find if it has sense key.
2184 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
2185 @param SenseCounts - The number of sense key
2187 @retval TRUE It has sense key.
2188 @retval FALSE It has NOT any sense key.
2192 ScsiDiskHaveSenseKey (
2193 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2194 IN UINTN SenseCounts
2197 EFI_SCSI_SENSE_DATA
*SensePtr
;
2199 BOOLEAN HaveSenseKey
;
2201 if (SenseCounts
== 0) {
2202 HaveSenseKey
= FALSE
;
2204 HaveSenseKey
= TRUE
;
2207 SensePtr
= SenseData
;
2209 for (Index
= 0; Index
< SenseCounts
; Index
++) {
2212 // Sense Key is SK_NO_SENSE (0x0)
2214 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
2216 HaveSenseKey
= FALSE
;
2222 return HaveSenseKey
;
2226 Release resource about disk device.
2228 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2232 ReleaseScsiDiskDeviceResources (
2233 IN SCSI_DISK_DEV
*ScsiDiskDevice
2236 if (ScsiDiskDevice
== NULL
) {
2240 if (ScsiDiskDevice
->SenseData
!= NULL
) {
2241 FreePool (ScsiDiskDevice
->SenseData
);
2242 ScsiDiskDevice
->SenseData
= NULL
;
2245 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
2246 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
2247 ScsiDiskDevice
->ControllerNameTable
= NULL
;
2250 FreePool (ScsiDiskDevice
);
2252 ScsiDiskDevice
= NULL
;
2256 Determine if Block Io should be produced.
2259 @param ChildHandle Child Handle to retrive Parent information.
2261 @retval TRUE Should produce Block Io.
2262 @retval FALSE Should not produce Block Io.
2266 DetermineInstallBlockIo (
2267 IN EFI_HANDLE ChildHandle
2270 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
2271 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
2274 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
2275 // check its attribute, logic or physical.
2277 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
2278 if (ExtScsiPassThru
!= NULL
) {
2279 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2285 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
2286 // check its attribute, logic or physical.
2288 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
2289 if (ScsiPassThru
!= NULL
) {
2290 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
2299 Search protocol database and check to see if the protocol
2300 specified by ProtocolGuid is present on a ControllerHandle and opened by
2301 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
2302 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
2303 will be opened on it.
2306 @param ProtocolGuid ProtocolGuid pointer.
2307 @param ChildHandle Child Handle to retrieve Parent information.
2313 IN EFI_GUID
*ProtocolGuid
,
2314 IN EFI_HANDLE ChildHandle
2321 EFI_HANDLE
*HandleBuffer
;
2324 // Retrieve the list of all handles from the handle database
2326 Status
= gBS
->LocateHandleBuffer (
2334 if (EFI_ERROR (Status
)) {
2339 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
2341 for (Index
= 0; Index
< HandleCount
; Index
++) {
2342 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
2343 if (!EFI_ERROR (Status
)) {
2344 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
2345 if (!EFI_ERROR (Status
)) {
2346 gBS
->FreePool (HandleBuffer
);
2352 gBS
->FreePool (HandleBuffer
);