windows-nt/Source/XPSP1/NT/sdktools/spt/lib/sptlib.c

1008 lines
26 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
spt.c
Abstract:
A user mode library that allows simple commands to be sent to a
selected scsi device.
Environment:
User mode only
Revision History:
4/10/2000 - created
--*/
#include "sptlibp.h"
BOOL
SptUtilValidateCdbLength(
IN PCDB Cdb,
IN UCHAR CdbSize
)
{
UCHAR commandGroup = (Cdb->AsByte[0] >> 5) & 0x7;
switch (commandGroup) {
case 0:
return (CdbSize == 6);
case 1:
case 2:
return (CdbSize == 10);
case 5:
return (CdbSize == 12);
default:
return TRUE;
}
}
BOOL
SptSendCdbToDevice(
IN HANDLE DeviceHandle,
IN PCDB Cdb,
IN UCHAR CdbSize,
IN PUCHAR Buffer,
IN OUT PDWORD BufferSize,
IN BOOLEAN GetDataFromDevice
)
{
return SptSendCdbToDeviceEx(DeviceHandle,
Cdb,
CdbSize,
Buffer,
BufferSize,
NULL,
0,
GetDataFromDevice,
SPT_DEFAULT_TIMEOUT
);
}
/*++
Routine Description:
Arguments:
Return Value:
--*/
BOOL
SptSendCdbToDeviceEx(
IN HANDLE DeviceHandle,
IN PCDB Cdb,
IN UCHAR CdbSize,
IN OUT PUCHAR Buffer,
IN OUT PDWORD BufferSize,
OUT PSENSE_DATA SenseData OPTIONAL,
IN UCHAR SenseDataSize,
IN BOOLEAN GetDataFromDevice,
IN DWORD TimeOut // in seconds
)
{
PSPT_WITH_BUFFERS p;
DWORD packetSize;
DWORD returnedBytes;
BOOL returnValue;
PSENSE_DATA senseBuffer;
BOOL copyData;
if ((SenseDataSize == 0) && (SenseData != NULL)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((SenseDataSize != 0) && (SenseData == NULL)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (SenseData && SenseDataSize) {
RtlZeroMemory(SenseData, SenseDataSize);
}
if (Cdb == NULL) {
// cannot send NULL cdb
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (CdbSize < 1 || CdbSize > 16) {
// Cdb size too large or too small for this library currently
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!SptUtilValidateCdbLength(Cdb, CdbSize)) {
// OpCode Cdb->AsByte[0] is not size CdbSize
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (BufferSize == NULL) {
// BufferSize pointer cannot be NULL
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((*BufferSize != 0) && (Buffer == NULL)) {
// buffer cannot be NULL if *BufferSize is non-zero
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((*BufferSize == 0) && (Buffer != NULL)) {
// buffer must be NULL if *BufferSize is zero
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((*BufferSize) && GetDataFromDevice) {
//
// pre-zero output buffer (not input buffer)
//
memset(Buffer, 0, (*BufferSize));
}
packetSize = sizeof(SPT_WITH_BUFFERS) + (*BufferSize);
p = (PSPT_WITH_BUFFERS)LocalAlloc(LPTR, packetSize);
if (p == NULL) {
// could not allocate memory for pass-through
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
//
// this has the side effect of pre-zeroing the output buffer
// if DataIn is TRUE, the SenseData (always), etc.
//
memset(p, 0, packetSize);
memcpy(p->Spt.Cdb, Cdb, CdbSize);
p->Spt.Length = sizeof(SCSI_PASS_THROUGH);
p->Spt.CdbLength = CdbSize;
p->Spt.SenseInfoLength = SENSE_BUFFER_SIZE;
p->Spt.DataIn = (GetDataFromDevice ? 1 : 0);
p->Spt.DataTransferLength = (*BufferSize);
p->Spt.TimeOutValue = TimeOut;
p->Spt.SenseInfoOffset =
FIELD_OFFSET(SPT_WITH_BUFFERS, SenseInfoBuffer[0]);
p->Spt.DataBufferOffset =
FIELD_OFFSET(SPT_WITH_BUFFERS, DataBuffer[0]);
if ((*BufferSize != 0) && (!GetDataFromDevice)) {
//
// if we're sending the device data, copy the user's buffer
//
RtlCopyMemory(&(p->DataBuffer[0]), Buffer, *BufferSize);
}
returnedBytes = 0;
returnValue = DeviceIoControl(DeviceHandle,
IOCTL_SCSI_PASS_THROUGH,
p,
packetSize,
p,
packetSize,
&returnedBytes,
FALSE);
senseBuffer = (PSENSE_DATA)p->SenseInfoBuffer;
copyData = FALSE;
if (senseBuffer->SenseKey & 0xf) {
UCHAR length;
// determine appropriate length to return
length = senseBuffer->AdditionalSenseLength;
length += RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength);
if (length > SENSE_BUFFER_SIZE) {
length = SENSE_BUFFER_SIZE;
}
length = min(length, SenseDataSize);
// copy the sense data back to the user regardless
RtlCopyMemory(SenseData, senseBuffer, length);
returnValue = FALSE; // some error (possibly recovered) occurred
copyData = TRUE; // copy data anyways
} else if (p->Spt.ScsiStatus != 0) { // scsi protocol error
returnValue = FALSE; // command failed
} else if (!returnValue) {
// returnValue = returnValue;
} else {
copyData = TRUE;
}
if (copyData && GetDataFromDevice) {
//
// upon successful completion of a command getting data from the
// device, copy the returned data back to the user.
//
if (*BufferSize > p->Spt.DataTransferLength) {
*BufferSize = p->Spt.DataTransferLength;
}
memcpy(Buffer, p->DataBuffer, *BufferSize);
}
//
// free our memory and return
//
LocalFree(p);
return returnValue;
}
/*++
Routine Description:
Arguments:
Return Value:
--*/
VOID
SptDeleteModePageInfo(
IN PSPT_MODE_PAGE_INFO ModePageInfo
)
{
// ASSERT(ModePageInfo != NULL); BUGBUG
// ASSERT(ModePageInfo->Signature == SPT_MODE_PAGE_INFO_SIGNATURE); BUGBUG
LocalFree(ModePageInfo);
return;
}
/*++
Routine Description:
Arguments:
Return Value:
--*/
BOOL
SptUpdateModePageInfo(
IN HANDLE DeviceHandle,
IN PSPT_MODE_PAGE_INFO ModePageInfo
)
{
SENSE_DATA senseData;
BOOLEAN retry = FALSE;
DWORD error;
DWORD delay;
CDB cdb;
DWORD attemptNumber = 0;
BOOL success;
if ((DeviceHandle == INVALID_HANDLE_VALUE) ||
(ModePageInfo == NULL) ||
(!ModePageInfo->IsInitialized) ||
(ModePageInfo->Signature != SPT_MODE_PAGE_INFO_SIGNATURE)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((ModePageInfo->ModePageSize != SptModePageSizeModeSense6) &&
(ModePageInfo->ModePageSize != SptModePageSizeModeSense10)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
RetryUpdateModePage:
attemptNumber ++;
RtlZeroMemory(&cdb, sizeof(CDB));
RtlZeroMemory(&senseData, sizeof(SENSE_DATA));
if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
DWORD sizeToGet = sizeof(MODE_PARAMETER_HEADER);
cdb.MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
cdb.MODE_SENSE.PageCode = 0x3f;
cdb.MODE_SENSE.AllocationLength = sizeof(MODE_PARAMETER_HEADER);
success = SptSendCdbToDeviceEx(DeviceHandle,
&cdb,
6,
&(ModePageInfo->H.AsChar),
&sizeToGet,
&senseData,
sizeof(SENSE_DATA),
TRUE,
SPT_MODE_SENSE_TIMEOUT);
} else {
DWORD sizeToGet = sizeof(MODE_PARAMETER_HEADER10);
cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
cdb.MODE_SENSE10.PageCode = 0x3f;
cdb.MODE_SENSE10.AllocationLength[0] = sizeof(MODE_PARAMETER_HEADER10);
success = SptSendCdbToDeviceEx(DeviceHandle,
&cdb,
10,
&(ModePageInfo->H.AsChar),
&sizeToGet,
&senseData,
sizeof(SENSE_DATA),
TRUE,
SPT_MODE_SENSE_TIMEOUT);
}
if (!success) {
return FALSE;
}
//
// if the pass-through succeeded, we need to still determine if the
// actual CDB succeeded. use the InterpretSenseInfo() routine.
//
SptUtilInterpretSenseInfo(&senseData,
sizeof(SENSE_DATA),
&error,
&retry,
&delay);
if (error != ERROR_SUCCESS) {
if (retry && (attemptNumber < MAXIMUM_DEFAULT_RETRIES)) {
if (delay != 0) {
// sleep?
}
goto RetryUpdateModePage;
}
// else the error was not worth retrying, or we've retried too often.
SetLastError(error);
return FALSE;
}
//
// the command succeeded.
//
if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
ModePageInfo->H.Header6.ModeDataLength = 0;
} else {
ModePageInfo->H.Header10.ModeDataLength[0] = 0;
ModePageInfo->H.Header10.ModeDataLength[1] = 0;
}
return TRUE;
}
/*++
Routine Description:
Arguments:
Return Value:
--*/
PSPT_MODE_PAGE_INFO
SptInitializeModePageInfo(
IN HANDLE DeviceHandle
)
{
PSPT_MODE_PAGE_INFO localInfo;
DWORD i;
localInfo = LocalAlloc(LPTR, sizeof(SPT_MODE_PAGE_INFO));
if (localInfo == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
//
// try both 10 and 6 byte mode sense commands
//
for (i = 0; i < 2; i++) {
RtlZeroMemory(localInfo, sizeof(SPT_MODE_PAGE_INFO));
localInfo->IsInitialized = TRUE;
localInfo->Signature = SPT_MODE_PAGE_INFO_SIGNATURE;
if ( i == 0 ) {
localInfo->ModePageSize = SptModePageSizeModeSense10;
} else {
localInfo->ModePageSize = SptModePageSizeModeSense6;
}
if (SptUpdateModePageInfo(DeviceHandle, localInfo)) {
return localInfo;
}
}
LocalFree(localInfo);
return NULL;
}
/*++
Routine Description:
Arguments:
Return Value:
--*/
BOOL
SptGetModePage(
IN HANDLE DeviceHandle,
IN PSPT_MODE_PAGE_INFO ModePageInfo,
IN UCHAR ModePage,
OUT PUCHAR Buffer,
IN OUT PDWORD BufferSize,
OUT PDWORD AvailableModePageData OPTIONAL
)
{
PUCHAR localBuffer = NULL;
DWORD localBufferSize = 0;
SENSE_DATA senseData;
CDB cdb;
DWORD thisAttempt = 0;
BOOL success;
DWORD finalPageSize;
PUCHAR finalPageStart;
if ((DeviceHandle == INVALID_HANDLE_VALUE) ||
(ModePageInfo == NULL) ||
(!ModePageInfo->IsInitialized) ||
(ModePageInfo->Signature != SPT_MODE_PAGE_INFO_SIGNATURE) ||
(ModePageInfo->ModePageSize == SptModePageSizeUndefined) ||
(ModePage & 0xC0)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (((BufferSize == 0) && (Buffer != NULL)) ||
((BufferSize != 0) && (Buffer == NULL))) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((ModePageInfo->ModePageSize != SptModePageSizeModeSense6) &&
(ModePageInfo->ModePageSize != SptModePageSizeModeSense10)) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
localBufferSize = 0;
if (BufferSize != NULL) {
localBufferSize += *BufferSize;
}
if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
localBufferSize += sizeof(MODE_PARAMETER_HEADER);
localBufferSize += ModePageInfo->H.Header6.BlockDescriptorLength;
if (localBufferSize > 0xff) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
} else {
localBufferSize += sizeof(MODE_PARAMETER_HEADER);
localBufferSize += ModePageInfo->H.Header10.BlockDescriptorLength[0] * 256;
localBufferSize += ModePageInfo->H.Header10.BlockDescriptorLength[1];
if (localBufferSize > 0xffff) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
localBuffer = LocalAlloc(LPTR, localBufferSize);
if (localBuffer == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
RetryGetModePage:
thisAttempt ++;
RtlZeroMemory(&cdb, sizeof(CDB));
RtlZeroMemory(&senseData, sizeof(SENSE_DATA));
RtlZeroMemory(localBuffer, localBufferSize);
if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
DWORD sizeToGet = localBufferSize;
cdb.MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
cdb.MODE_SENSE.PageCode = ModePage;
cdb.MODE_SENSE.AllocationLength = (UCHAR)localBufferSize;
success = SptSendCdbToDeviceEx(DeviceHandle,
&cdb,
6,
localBuffer,
&sizeToGet,
&senseData,
sizeof(SENSE_DATA),
TRUE,
SPT_MODE_SENSE_TIMEOUT);
} else {
DWORD sizeToGet = localBufferSize;
cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
cdb.MODE_SENSE10.PageCode = ModePage;
cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(localBufferSize >> 8);
cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(localBufferSize & 0xff);
success = SptSendCdbToDeviceEx(DeviceHandle,
&cdb,
10,
localBuffer,
&sizeToGet,
&senseData,
sizeof(SENSE_DATA),
TRUE,
SPT_MODE_SENSE_TIMEOUT);
}
//
// if the pass-through failed, we need to still determine if the
// actual CDB succeeded. use the InterpretSenseInfo() routine.
//
if (!success) {
LocalFree( localBuffer );
return FALSE;
}
{
DWORD interpretedError;
BOOLEAN retry;
DWORD delay;
SptUtilInterpretSenseInfo(&senseData,
sizeof(SENSE_DATA),
&interpretedError,
&retry,
&delay);
if (interpretedError != ERROR_SUCCESS) {
if ((retry == FALSE) || (thisAttempt > MAXIMUM_DEFAULT_RETRIES)){
SetLastError(interpretedError);
LocalFree( localBuffer );
return FALSE;
}
// BUGBUG - sleep?
goto RetryGetModePage;
}
}
//
// the transfer succeeded. now to transfer the info back to
// the caller.
//
if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
PMODE_PARAMETER_HEADER header6 = (PMODE_PARAMETER_HEADER)localBuffer;
finalPageSize = header6->ModeDataLength + 1; // length field itself.
finalPageStart = localBuffer;
finalPageStart += sizeof(MODE_PARAMETER_HEADER);
finalPageSize -= sizeof(MODE_PARAMETER_HEADER);
finalPageStart += header6->BlockDescriptorLength;
finalPageSize -= header6->BlockDescriptorLength;
} else {
PMODE_PARAMETER_HEADER10 header10 = (PMODE_PARAMETER_HEADER10)localBuffer;
finalPageSize = header10->ModeDataLength[0] * 256;
finalPageSize += header10->ModeDataLength[1];
finalPageSize += 2; // length field itself.
finalPageStart = localBuffer;
finalPageStart += sizeof(MODE_PARAMETER_HEADER10);
finalPageSize -= sizeof(MODE_PARAMETER_HEADER10);
finalPageStart += header10->BlockDescriptorLength[0] * 256;
finalPageStart += header10->BlockDescriptorLength[1];
finalPageSize -= header10->BlockDescriptorLength[0] * 256;
finalPageSize -= header10->BlockDescriptorLength[1];
}
//
// finalPageStart now points to the page start
// finalPageSize says how much of the data is valid
//
//
// allow the user to distinguish between available data
// and the amount we actually returned that was usable.
//
if (AvailableModePageData != NULL) {
*AvailableModePageData = finalPageSize;
}
//
// if the expected buffer size is greater than the device
// returned, update the user's available size info
//
if (*BufferSize > finalPageSize) {
*BufferSize = finalPageSize;
}
//
// finally, copy whatever data is available to the user's buffer.
//
if (*BufferSize != 0) {
RtlCopyMemory(Buffer, localBuffer, *BufferSize);
}
return TRUE;
}
/*++
Routine Description:
Arguments:
Return Value:
--*/
BOOL
SptSetModePage(
IN HANDLE DeviceHandle,
IN PSPT_MODE_PAGE_INFO ModePageSize,
IN SPT_MODE_PAGE_TYPE ModePageType,
IN UCHAR ModePage,
OUT PUCHAR Buffer,
IN OUT PDWORD BufferSize
)
{
SetLastError(ERROR_INVALID_FUNCTION);
return FALSE;
}
/*++
Routine Description:
NOTE: we default to RETRY==TRUE except for known error classes
Arguments:
Return Value:
--*/
VOID
SptUtilInterpretSenseInfo(
IN PSENSE_DATA SenseData,
IN UCHAR SenseDataSize,
OUT PDWORD ErrorValue, // from WinError.h
OUT PBOOLEAN SuggestRetry OPTIONAL,
OUT PDWORD SuggestRetryDelay OPTIONAL
)
{
DWORD error;
DWORD retryDelay;
BOOLEAN retry;
UCHAR senseKey;
UCHAR asc;
UCHAR ascq;
if (SenseDataSize == 0) {
retry = FALSE;
retryDelay = 0;
error = ERROR_IO_DEVICE;
goto SetAndExit;
}
//
// default to suggesting a retry in 1/10 of a second,
// with a status of ERROR_IO_DEVICE.
//
retry = TRUE;
retryDelay = 1;
error = ERROR_IO_DEVICE;
//
// if the device didn't provide any sense this time, return.
//
if ((SenseData->SenseKey & 0xf) == 0) {
retry = FALSE;
retryDelay = 0;
error = ERROR_SUCCESS;
goto SetAndExit;
}
//
// if we can't even see the sense key, just return.
// can't use bitfields in these macros, so use next field.
//
if (SenseDataSize < FIELD_OFFSET(SENSE_DATA, Information)) {
goto SetAndExit;
}
senseKey = SenseData->SenseKey;
{ // set the size to what's actually useful.
UCHAR validLength;
// figure out what we could have gotten with a large sense buffer
if (SenseDataSize <
RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength)) {
validLength = SenseDataSize;
} else {
validLength =
RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength);
validLength += SenseData->AdditionalSenseLength;
}
// use the smaller of the two values.
SenseDataSize = min(SenseDataSize, validLength);
}
if (SenseDataSize <
RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) {
asc = SCSI_ADSENSE_NO_SENSE;
} else {
asc = SenseData->AdditionalSenseCode;
}
if (SenseDataSize <
RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) {
ascq = SCSI_SENSEQ_CAUSE_NOT_REPORTABLE; // 0x00
} else {
ascq = SenseData->AdditionalSenseCodeQualifier;
}
//
// interpret :P
//
switch (senseKey & 0xf) {
case SCSI_SENSE_RECOVERED_ERROR: { // 0x01
if (SenseData->IncorrectLength) {
error = ERROR_INVALID_BLOCK_LENGTH;
} else {
error = ERROR_SUCCESS;
}
retry = FALSE;
break;
} // end SCSI_SENSE_RECOVERED_ERROR
case SCSI_SENSE_NOT_READY: { // 0x02
error = ERROR_NOT_READY;
switch (asc) {
case SCSI_ADSENSE_LUN_NOT_READY: {
switch (ascq) {
case SCSI_SENSEQ_BECOMING_READY:
case SCSI_SENSEQ_OPERATION_IN_PROGRESS: {
retryDelay = SPT_NOT_READY_RETRY_INTERVAL;
break;
}
case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE:
case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: {
retry = FALSE;
break;
}
case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: {
retry = FALSE;
break;
}
} // end switch (senseBuffer->AdditionalSenseCodeQualifier)
break;
}
case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: {
error = ERROR_NOT_READY;
retry = FALSE;
break;
}
} // end switch (senseBuffer->AdditionalSenseCode)
break;
} // end SCSI_SENSE_NOT_READY
case SCSI_SENSE_MEDIUM_ERROR: { // 0x03
error = ERROR_CRC;
retry = FALSE;
//
// Check if this error is due to unknown format
//
if (asc == SCSI_ADSENSE_INVALID_MEDIA) {
switch (ascq) {
case SCSI_SENSEQ_UNKNOWN_FORMAT: {
error = ERROR_UNRECOGNIZED_MEDIA;
break;
}
case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: {
error = ERROR_UNRECOGNIZED_MEDIA;
//error = ERROR_CLEANER_CARTRIDGE_INSTALLED;
break;
}
} // end switch AdditionalSenseCodeQualifier
} // end SCSI_ADSENSE_INVALID_MEDIA
break;
} // end SCSI_SENSE_MEDIUM_ERROR
case SCSI_SENSE_ILLEGAL_REQUEST: { // 0x05
error = ERROR_INVALID_FUNCTION;
retry = FALSE;
switch (asc) {
case SCSI_ADSENSE_ILLEGAL_BLOCK: {
error = ERROR_SECTOR_NOT_FOUND;
break;
}
case SCSI_ADSENSE_INVALID_LUN: {
error = ERROR_FILE_NOT_FOUND;
break;
}
case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: {
error = ERROR_FILE_ENCRYPTED;
//error = ERROR_SPT_LIB_COPY_PROTECTION_FAILURE;
switch (ascq) {
case SCSI_SENSEQ_AUTHENTICATION_FAILURE:
//error = ERROR_SPT_LIB_AUTHENTICATION_FAILURE;
break;
case SCSI_SENSEQ_KEY_NOT_PRESENT:
//error = ERROR_SPT_LIB_KEY_NOT_PRESENT;
break;
case SCSI_SENSEQ_KEY_NOT_ESTABLISHED:
//error = ERROR_SPT_LIB_KEY_NOT_ESTABLISHED;
break;
case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION:
//error = ERROR_SPT_LIB_SCRAMBLED_SECTOR;
break;
case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT:
//error = ERROR_SPT_LIB_REGION_MISMATCH;
break;
case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR:
//error = ERROR_SPT_LIB_RESETS_EXHAUSTED;
break;
} // end switch of ASCQ for COPY_PROTECTION_FAILURE
break;
}
} // end switch (senseBuffer->AdditionalSenseCode)
break;
} // end SCSI_SENSE_ILLEGAL_REQUEST
case SCSI_SENSE_DATA_PROTECT: { // 0x07
error = ERROR_WRITE_PROTECT;
retry = FALSE;
break;
} // end SCSI_SENSE_DATA_PROTECT
case SCSI_SENSE_BLANK_CHECK: { // 0x08
error = ERROR_NO_DATA_DETECTED;
break;
} // end SCSI_SENSE_BLANK_CHECK
case SCSI_SENSE_NO_SENSE: { // 0x00
if (SenseData->IncorrectLength) {
error = ERROR_INVALID_BLOCK_LENGTH;
retry = FALSE;
} else {
error = ERROR_IO_DEVICE;
}
break;
} // end SCSI_SENSE_NO_SENSE
case SCSI_SENSE_HARDWARE_ERROR: // 0x04
case SCSI_SENSE_UNIT_ATTENTION: // 0x06
case SCSI_SENSE_UNIQUE: // 0x09
case SCSI_SENSE_COPY_ABORTED: // 0x0A
case SCSI_SENSE_ABORTED_COMMAND: // 0x0B
case SCSI_SENSE_EQUAL: // 0x0C
case SCSI_SENSE_VOL_OVERFLOW: // 0x0D
case SCSI_SENSE_MISCOMPARE: // 0x0E
case SCSI_SENSE_RESERVED: // 0x0F
default: {
error = ERROR_IO_DEVICE;
break;
}
} // end switch(SenseKey)
SetAndExit:
if (ARGUMENT_PRESENT(SuggestRetry)) {
*SuggestRetry = retry;
}
if (ARGUMENT_PRESENT(SuggestRetryDelay)) {
*SuggestRetryDelay = retryDelay;
}
*ErrorValue = error;
return;
}
/*++
Routine Description:
Arguments:
Return Value:
--*/