in storage/class/cdrom/src/sense.c [491:1077]
_Out_ _Deref_out_range_(0,100) ULONG* RetryIntervalInSeconds,
_Inout_ PERROR_LOG_CONTEXT LogContext
)
/*
This function will interpret error based on ASC/ASCQ.
If the error code is not processed in this function, e.g. return value is TRUE,
caller needs to call SenseInfoInterpretBySenseKey() for further interpret.
*/
{
BOOLEAN needFurtherInterpret = TRUE;
PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
// set default values for retry fields.
*Status = STATUS_IO_DEVICE_ERROR;
*Retry = TRUE;
*RetryIntervalInSeconds = 0;
switch (AdditionalSenseCode)
{
case SCSI_ADSENSE_LUN_NOT_READY:
{
TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Lun not ready\n"));
//
// Many non-WHQL certified drives (mostly CD-RW) return
// 2/4/0 when they have no media instead of the obvious choice of:
//
// SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
//
// These drives should not pass WHQL certification due to this discrepency.
//
// However, we have to retry on 2/4/0 (Not ready, LUN not ready, no info)
// and also 3/2/0 (no seek complete).
//
// These conditions occur when the shell tries to examine an
// injected CD (e.g. for autoplay) before the CD is spun up.
//
// The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
// (0x01) in order to comply with WHQL standards.
//
// The default retry timeout of one second is acceptable to balance
// these discrepencies. don't modify the status, though....
//
switch (AdditionalSenseCodeQual)
{
case SCSI_SENSEQ_OPERATION_IN_PROGRESS:
{
DEVICE_EVENT_BECOMING_READY notReady = {0};
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Operation In Progress\n"));
needFurtherInterpret = FALSE;
*Retry = TRUE;
*RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
*Status = STATUS_DEVICE_NOT_READY;
notReady.Version = 1;
notReady.Reason = 2;
notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10;
DeviceSendNotification(DeviceExtension,
&GUID_IO_DEVICE_BECOMING_READY,
sizeof(DEVICE_EVENT_BECOMING_READY),
¬Ready);
break;
}
case SCSI_SENSEQ_BECOMING_READY:
{
DEVICE_EVENT_BECOMING_READY notReady = {0};
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: In process of becoming ready\n"));
needFurtherInterpret = FALSE;
*Retry = TRUE;
*RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
*Status = STATUS_DEVICE_NOT_READY;
notReady.Version = 1;
notReady.Reason = 1;
notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10;
DeviceSendNotification(DeviceExtension,
&GUID_IO_DEVICE_BECOMING_READY,
sizeof(DEVICE_EVENT_BECOMING_READY),
¬Ready);
break;
}
case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS:
{
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Long write in progress\n"));
needFurtherInterpret = FALSE;
// This has been seen as a transcient failure on some drives
*Status = STATUS_DEVICE_NOT_READY;
*Retry = TRUE;
// Set retry interval to be 0 as the drive can be ready at anytime.
*RetryIntervalInSeconds = 0;
break;
}
case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
{
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Manual intervention required\n"));
needFurtherInterpret = FALSE;
*Status = STATUS_NO_MEDIA_IN_DEVICE;
*Retry = FALSE;
*RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
break;
}
case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
{
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Format in progress\n"));
needFurtherInterpret = FALSE;
*Status = STATUS_DEVICE_NOT_READY;
*Retry = FALSE;
*RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
break;
}
case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE:
case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
default:
{
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Initializing command required\n"));
needFurtherInterpret = FALSE;
*Status = STATUS_DEVICE_NOT_READY;
*Retry = TRUE;
*RetryIntervalInSeconds = 0;
// This sense code/additional sense code combination may indicate
// that the device needs to be started.
if (TEST_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT) &&
!TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY))
{
DeviceSendStartUnit(DeviceExtension->Device);
}
break;
}
} // end switch (AdditionalSenseCodeQual)
break;
} // end case (SCSI_ADSENSE_LUN_NOT_READY)
case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
{
TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: No Media in device.\n"));
needFurtherInterpret = FALSE;
*Status = STATUS_NO_MEDIA_IN_DEVICE;
*Retry = FALSE;
if (AdditionalSenseCodeQual == 0xCC)
{
// The IMAPIv1 filter returns this ASCQ value while it is burning CD media, and we want
// to preserve this functionality for compatibility reasons.
// We want to indicate that the media is not present to most applications;
// but RSM has to know that the media is still in the drive (i.e. the drive is not free).
DeviceSetMediaChangeStateEx(DeviceExtension, MediaUnavailable, NULL);
}
else
{
DeviceSetMediaChangeStateEx(DeviceExtension, MediaNotPresent, NULL);
}
break;
} // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
case SCSI_ADSENSE_INVALID_MEDIA:
{
switch (AdditionalSenseCodeQual)
{
case SCSI_SENSEQ_UNKNOWN_FORMAT:
{
needFurtherInterpret = FALSE;
// Log error only if this is a paging request
*Status = STATUS_UNRECOGNIZED_MEDIA;
*Retry = FALSE;
LogContext->LogError = TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING);
LogContext->UniqueErrorValue = 256;
LogContext->ErrorCode = IO_ERR_BAD_BLOCK;
break;
}
case SCSI_SENSEQ_INCOMPATIBLE_FORMAT:
{
needFurtherInterpret = FALSE;
*Status = STATUS_UNRECOGNIZED_MEDIA;
*Retry = FALSE;
LogContext->LogError = FALSE;
break;
}
case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED:
{
needFurtherInterpret = FALSE;
*Status = STATUS_CLEANER_CARTRIDGE_INSTALLED;
*Retry = FALSE;
LogContext->LogError = FALSE;
LogContext->UniqueErrorValue = 256;
LogContext->ErrorCode = IO_ERR_BAD_BLOCK;
break;
}
default:
{
needFurtherInterpret = TRUE;
break;
}
} // end case AdditionalSenseCodeQual
break;
} // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
case SCSI_ADSENSE_NO_SEEK_COMPLETE:
{
switch (AdditionalSenseCodeQual)
{
case 0x00:
{
needFurtherInterpret = FALSE;
*Status = STATUS_DEVICE_DATA_ERROR;
*Retry = TRUE;
*RetryIntervalInSeconds = 0;
LogContext->LogError = TRUE;
LogContext->UniqueErrorValue = 256;
LogContext->ErrorCode = IO_ERR_BAD_BLOCK;
break;
}
default:
{
needFurtherInterpret = TRUE;
break;
}
}
break;
} // end case SCSI_ADSENSE_NO_SEEK_COMPLETE
case SCSI_ADSENSE_LUN_COMMUNICATION:
{
switch (AdditionalSenseCodeQual)
{
case SCSI_SESNEQ_COMM_CRC_ERROR:
{
needFurtherInterpret = FALSE;
*Status = STATUS_IO_DEVICE_ERROR;
*Retry = TRUE;
*RetryIntervalInSeconds = 1;
LogContext->LogError = TRUE;
LogContext->UniqueErrorValue = 257;
LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR;
break;
}
default:
{
needFurtherInterpret = TRUE;
break;
}
}
break;
} // end case SCSI_ADSENSE_LUN_COMMUNICATION
case SCSI_ADSENSE_ILLEGAL_BLOCK:
{
needFurtherInterpret = FALSE;
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Illegal block address\n"));
*Status = STATUS_NONEXISTENT_SECTOR;
*Retry = FALSE;
break;
}
case SCSI_ADSENSE_INVALID_LUN:
{
needFurtherInterpret = FALSE;
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Invalid LUN\n"));
*Status = STATUS_NO_SUCH_DEVICE;
*Retry = FALSE;
break;
}
case SCSI_ADSENSE_COPY_PROTECTION_FAILURE:
{
needFurtherInterpret = FALSE;
*Retry = FALSE;
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Key - Copy protection failure\n"));
switch (AdditionalSenseCodeQual)
{
case SCSI_SENSEQ_AUTHENTICATION_FAILURE:
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Authentication failure\n"));
*Status = STATUS_CSS_AUTHENTICATION_FAILURE;
break;
case SCSI_SENSEQ_KEY_NOT_PRESENT:
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Key not present\n"));
*Status = STATUS_CSS_KEY_NOT_PRESENT;
break;
case SCSI_SENSEQ_KEY_NOT_ESTABLISHED:
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Key not established\n"));
*Status = STATUS_CSS_KEY_NOT_ESTABLISHED;
break;
case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION:
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Read of scrambled sector w/o authentication\n"));
*Status = STATUS_CSS_SCRAMBLED_SECTOR;
break;
case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT:
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Media region does not logical unit region\n"));
*Status = STATUS_CSS_REGION_MISMATCH;
break;
case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR:
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Region set error -- region may be permanent\n"));
*Status = STATUS_CSS_RESETS_EXHAUSTED;
break;
default:
*Status = STATUS_COPY_PROTECTION_FAILURE;
break;
} // end switch of ASCQ for COPY_PROTECTION_FAILURE
break;
}
case SCSI_ADSENSE_INVALID_CDB:
{
needFurtherInterpret = FALSE;
TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Key - Invalid CDB\n"));
*Status = STATUS_INVALID_DEVICE_REQUEST;
*Retry = FALSE;
// Note: the retry interval is not typically used.
// it is set here only because a ClassErrorHandler
// cannot set the RetryIntervalInSeconds, and the error may
// require a few commands to be sent to clear whatever
// caused this condition (i.e. disk clears the write
// cache, requiring at least two commands)
//
// hopefully, this shortcoming can be changed for blackcomb.
*RetryIntervalInSeconds = 3;
break;
}
case SCSI_ADSENSE_MEDIUM_CHANGED:
{
needFurtherInterpret = FALSE;
*RetryIntervalInSeconds = 0;
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
"SenseInfoInterpretByAdditionalSenseCode: Media changed\n"));
DeviceSetMediaChangeStateEx(DeviceExtension, MediaPresent, NULL);
// special process for Media Change
if (IsVolumeMounted(DeviceExtension->DeviceObject))
{
// Set bit to indicate that media may have changed and volume needs verification.
SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
*Status = STATUS_VERIFY_REQUIRED;
*Retry = FALSE;
}
else
{
*Status = STATUS_IO_DEVICE_ERROR;
*Retry = TRUE;
}
break;
}
case SCSI_ADSENSE_OPERATOR_REQUEST:
{
switch (AdditionalSenseCodeQual)
{
case SCSI_SENSEQ_MEDIUM_REMOVAL:
{
needFurtherInterpret = FALSE;
*RetryIntervalInSeconds = 0;
InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Ejection request received!\n"));
//Send eject notification.
DeviceSendNotification(DeviceExtension,
&GUID_IO_MEDIA_EJECT_REQUEST,
0,
NULL);
// special process for Media Change
if (IsVolumeMounted(DeviceExtension->DeviceObject))
{
// Set bit to indicate that media may have changed and volume needs verification.
SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
*Status = STATUS_VERIFY_REQUIRED;
*Retry = FALSE;
}
else
{
*Status = STATUS_IO_DEVICE_ERROR;
*Retry = TRUE;
}
break;
}
default:
{
needFurtherInterpret = TRUE;
break;
}
}
break;
}
case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED:
{
needFurtherInterpret = FALSE;
*RetryIntervalInSeconds = 5;
InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
// Device information has changed, we need to rescan the
// bus for changed information such as the capacity.
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Device information changed. Invalidate the bus\n"));
IoInvalidateDeviceRelations(DeviceExtension->LowerPdo, BusRelations);
// special process for Media Change
if (IsVolumeMounted(DeviceExtension->DeviceObject))
{
// Set bit to indicate that media may have changed and volume needs verification.
SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
*Status = STATUS_VERIFY_REQUIRED;
*Retry = FALSE;
}
else
{
*Status = STATUS_IO_DEVICE_ERROR;
*Retry = TRUE;
}
break;
} //end Case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED
case SCSI_ADSENSE_REC_DATA_NOECC:
case SCSI_ADSENSE_REC_DATA_ECC:
{
needFurtherInterpret = FALSE;
*Status = STATUS_SUCCESS;
*Retry = FALSE;
LogContext->LogError = TRUE;
LogContext->UniqueErrorValue = 258;
LogContext->ErrorCode = IO_RECOVERED_VIA_ECC;
if (senseBuffer->IncorrectLength)
{
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n"));
*Status = STATUS_INVALID_BLOCK_LENGTH ;
}
break;
}
case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED:
{
UCHAR wmiEventData[sizeof(ULONG)+sizeof(UCHAR)] = {0};
*((PULONG)wmiEventData) = sizeof(UCHAR);
wmiEventData[sizeof(ULONG)] = AdditionalSenseCodeQual;
needFurtherInterpret = FALSE;
// Don't log another eventlog if we have already logged once
// NOTE: this should have been interlocked, but the structure
// was publicly defined to use a BOOLEAN (char). Since
// media only reports these errors once per X minutes,
// the potential race condition is nearly non-existant.
// the worst case is duplicate log entries, so ignore.
*Status = STATUS_SUCCESS;
*Retry = FALSE;
LogContext->UniqueErrorValue = 258;
LogContext->LogError = TRUE;
LogContext->ErrorCode = IO_WRN_FAILURE_PREDICTED;
if (senseBuffer->IncorrectLength)
{
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
"SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n"));
*Status = STATUS_INVALID_BLOCK_LENGTH ;
}
break;
}
case 0x57:
{
// UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
// the Matshita CR-585 returns this for all read commands
// on blank CD-R and CD-RW media, and we need to handle
// this for READ_CD detection ability.
switch (AdditionalSenseCodeQual)
{
case 0x00:
{
needFurtherInterpret = FALSE;
*Status = STATUS_UNRECOGNIZED_MEDIA;
*Retry = FALSE;
break;
}
default:
{
needFurtherInterpret = TRUE;
break;
}
}
break;
} //end case Matshita specific error 0x57
default:
{
needFurtherInterpret = TRUE;
break;
}
}
return needFurtherInterpret;
}