Media detection logic is enhanced to be more robust.

Signed-off-by: erictian
Reviewed-by: hhuan13
Reviewed-by: mdkinney

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12289 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
erictian 2011-09-07 08:11:42 +00:00
parent ec2bb58802
commit ae5dc79532
1 changed files with 86 additions and 70 deletions

View File

@ -697,27 +697,50 @@ ScsiDiskDetectMedia (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_STATUS ReadCapacityStatus;
EFI_SCSI_SENSE_DATA *SenseData; EFI_SCSI_SENSE_DATA *SenseData;
UINTN NumberOfSenseKeys; UINTN NumberOfSenseKeys;
BOOLEAN NeedRetry; BOOLEAN NeedRetry;
BOOLEAN NeedReadCapacity; BOOLEAN NeedReadCapacity;
UINT8 Index; UINT8 Retry;
UINT8 MaxRetry; UINT8 MaxRetry;
EFI_BLOCK_IO_MEDIA OldMedia; EFI_BLOCK_IO_MEDIA OldMedia;
UINTN Action; UINTN Action;
EFI_EVENT TimeoutEvt;
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
ReadCapacityStatus = EFI_SUCCESS;
SenseData = NULL; SenseData = NULL;
NumberOfSenseKeys = 0; NumberOfSenseKeys = 0;
NeedReadCapacity = FALSE; Retry = 0;
CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
*MediaChange = FALSE;
MaxRetry = 3; MaxRetry = 3;
Action = ACTION_NO_ACTION; Action = ACTION_NO_ACTION;
NeedReadCapacity = FALSE;
*MediaChange = FALSE;
TimeoutEvt = NULL;
for (Index = 0; Index < MaxRetry; Index++) { CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
Status = gBS->CreateEvent (
EVT_TIMER,
TPL_CALLBACK,
NULL,
NULL,
&TimeoutEvt
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));
if (EFI_ERROR (Status)) {
goto EXIT;
}
//
// Sending Test_Unit cmd to poll device status.
// If the sense data shows the drive is not ready or reset before, we need poll the device status again.
// We limit the upper boundary to 120 seconds.
//
while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
Status = ScsiDiskTestUnitReady ( Status = ScsiDiskTestUnitReady (
ScsiDiskDevice, ScsiDiskDevice,
&NeedRetry, &NeedRetry,
@ -732,21 +755,22 @@ ScsiDiskDetectMedia (
&Action &Action
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; goto EXIT;
} else if (Action == ACTION_RETRY_COMMAND_LATER) { } else if (Action == ACTION_RETRY_COMMAND_LATER) {
continue; continue;
} else { } else {
break; break;
} }
} } else {
Retry++;
if (!NeedRetry) { if (!NeedRetry || (Retry >= MaxRetry)) {
return Status; goto EXIT;
}
} }
} }
if ((Index == MaxRetry) && EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR; goto EXIT;
} }
// //
@ -765,63 +789,45 @@ ScsiDiskDetectMedia (
// //
// retrieve media information // retrieve media information
// //
MaxRetry = 3; for (Retry = 0; Retry < MaxRetry; Retry++) {
for (Index = 0; Index < MaxRetry; Index++) { Status = ScsiDiskReadCapacity (
ScsiDiskDevice,
ReadCapacityStatus = ScsiDiskReadCapacity ( &NeedRetry,
ScsiDiskDevice, &SenseData,
&NeedRetry, &NumberOfSenseKeys
&SenseData, );
&NumberOfSenseKeys if (!EFI_ERROR (Status)) {
);
if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) {
return EFI_DEVICE_ERROR;
}
//
// analyze sense key to action
//
Status = DetectMediaParsingSenseKeys (
ScsiDiskDevice,
SenseData,
NumberOfSenseKeys,
&Action
);
//
// if Status is error, it may indicate crisis error,
// so return without retry.
//
if (EFI_ERROR (Status)) {
return Status;
}
switch (Action) {
case ACTION_NO_ACTION:
// //
// no retry // analyze sense key to action
// //
Index = MaxRetry; Status = DetectMediaParsingSenseKeys (
break; ScsiDiskDevice,
SenseData,
case ACTION_RETRY_COMMAND_LATER: NumberOfSenseKeys,
// &Action
// retry the ReadCapacity later and continuously, until the condition );
// no longer emerges. if (EFI_ERROR (Status)) {
// stall time is 100000us, or say 0.1 second. //
// // if Status is error, it may indicate crisis error,
gBS->Stall (100000); // so return without retry.
Index = 0; //
break; goto EXIT;
} else if (Action == ACTION_RETRY_COMMAND_LATER) {
default: Retry = 0;
// continue;
// other cases, just retry the command } else {
// break;
break; }
} else {
Retry++;
if (!NeedRetry || (Retry >= MaxRetry)) {
goto EXIT;
}
} }
} }
if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) { if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR; goto EXIT;
} }
} }
@ -863,7 +869,11 @@ ScsiDiskDetectMedia (
*MediaChange = TRUE; *MediaChange = TRUE;
} }
return EFI_SUCCESS; EXIT:
if (TimeoutEvt != NULL) {
gBS->CloseEvent (TimeoutEvt);
}
return Status;
} }
@ -1188,7 +1198,9 @@ DetectMediaParsingSenseKeys (
*Action = ACTION_READ_CAPACITY; *Action = ACTION_READ_CAPACITY;
if (NumberOfSenseKeys == 0) { if (NumberOfSenseKeys == 0) {
*Action = ACTION_NO_ACTION; if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
*Action = ACTION_NO_ACTION;
}
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -1196,7 +1208,9 @@ DetectMediaParsingSenseKeys (
// //
// No Sense Key returned from last submitted command // No Sense Key returned from last submitted command
// //
*Action = ACTION_NO_ACTION; if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
*Action = ACTION_NO_ACTION;
}
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -1220,10 +1234,12 @@ DetectMediaParsingSenseKeys (
if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) { if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE; ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
ScsiDiskDevice->BlkIo.Media->LastBlock = 0; ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
*Action = ACTION_NO_ACTION;
return EFI_DEVICE_ERROR; return EFI_DEVICE_ERROR;
} }
if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) { if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
*Action = ACTION_NO_ACTION;
return EFI_DEVICE_ERROR; return EFI_DEVICE_ERROR;
} }
@ -1232,7 +1248,7 @@ DetectMediaParsingSenseKeys (
*Action = ACTION_RETRY_COMMAND_LATER; *Action = ACTION_RETRY_COMMAND_LATER;
return EFI_SUCCESS; return EFI_SUCCESS;
} }
*Action = ACTION_NO_ACTION;
return EFI_DEVICE_ERROR; return EFI_DEVICE_ERROR;
} }