948 lines
24 KiB
C
948 lines
24 KiB
C
#include <windows.h>
|
|
#include <winioctl.h>
|
|
#include <ntddscsi.h>
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "modesel.h"
|
|
|
|
/*
|
|
* This program was written initially by M. Calligaro for entirely
|
|
* different purposes. Mistreated by A. Forin and M. Lucovsky.
|
|
* None of the above thinks this code should look like this.
|
|
*/
|
|
|
|
VOID
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
|
|
{
|
|
SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
|
|
DWORD accessMode,
|
|
shareMode;
|
|
HANDLE fileHandle;
|
|
UCHAR string[25];
|
|
UCHAR szDriveNum[4];
|
|
ULONG errorCode;
|
|
BOOLEAN changeSet = FALSE;
|
|
ULONG i;
|
|
ULONG driveNumber,
|
|
sensePage,
|
|
senseValues,
|
|
saveAction;
|
|
UCHAR changeBits[0x24];
|
|
ULONG pageLength;
|
|
|
|
if (argc > 4 || (argc > 1 && argv[1][0] == '?')) {
|
|
printf("Usage: %s [ModePage [Action [WhichValues]]]\n", argv[0] );
|
|
return;
|
|
}
|
|
|
|
shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; // default
|
|
accessMode = GENERIC_WRITE | GENERIC_READ; // default
|
|
|
|
printf("\nWindows NT SCSI Mode Sense and Select Utility\n");
|
|
|
|
selectDisk:
|
|
|
|
printf("\n");
|
|
|
|
for (i=0;;i++) {
|
|
sprintf(string, "\\\\.\\PhysicalDrive%d", i);
|
|
|
|
fileHandle = CreateFile(string,
|
|
accessMode,
|
|
shareMode,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
|
|
if (i == 0) {
|
|
|
|
printf("Error opening PhysicalDrive0. Error: %d\n",
|
|
errorCode = GetLastError());
|
|
PrintError(errorCode);
|
|
return;
|
|
|
|
} else {
|
|
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
printf("Disk %d is a ", i);
|
|
DoInquiry(&sptwb, fileHandle);
|
|
printf("at SCSI ID %d\n", sptwb.spt.TargetId);
|
|
CloseHandle(fileHandle);
|
|
}
|
|
}
|
|
|
|
printf("Enter '99' to exit program\n\n");
|
|
|
|
while (TRUE) {
|
|
|
|
printf("Which disk(0-%d)? ", i-1);
|
|
scanf("%d", &driveNumber);
|
|
|
|
if ((driveNumber >= 0) && (driveNumber < i)) {
|
|
break;
|
|
} else if (driveNumber == 99) {
|
|
exit(0);
|
|
} else {
|
|
printf("There is no disk %d\n",driveNumber);
|
|
}
|
|
}
|
|
|
|
newPage:
|
|
|
|
printf("\n");
|
|
|
|
printf(" 0:Unit Attention Page\n");
|
|
printf(" 1:Error Recovery Page\n");
|
|
printf(" 2:Disconnect Page\n");
|
|
printf(" 3:Format Device Page\n");
|
|
printf(" 4:Rigid Geometry Page\n");
|
|
printf(" 5:Flexible Page\n");
|
|
printf(" 7:Verify Error Page\n");
|
|
printf(" 8:Caching Page\n");
|
|
printf(" 9:Peripheral Page\n");
|
|
printf("10:Control Page\n");
|
|
printf("11:Medium Types Page\n");
|
|
printf("12:Notch Partition Page\n");
|
|
printf("15:Data Compression Page\n");
|
|
printf("16:Device Configuration Page\n");
|
|
printf("17:Medium Partition Page\n");
|
|
printf("99:Select disk\n");
|
|
|
|
printf("\nWhich page? ");
|
|
scanf("%d", &sensePage);
|
|
|
|
if (sensePage > 17) {
|
|
goto selectDisk;
|
|
}
|
|
|
|
printf("\n0:Get current values\n");
|
|
printf("1:Get default values\n");
|
|
printf("2:Get saved values\n");
|
|
printf("3:Get changable values\n");
|
|
if (sensePage == 8) {
|
|
printf("4:Enable write cache\n");
|
|
printf("5:Disable write cache\n");
|
|
}
|
|
printf("99:New page\n");
|
|
|
|
printf("\nWhat action? ");
|
|
scanf("%d", &senseValues);
|
|
|
|
if (senseValues > 5 ||
|
|
(sensePage != 8 && senseValues >3)) {
|
|
goto newPage;
|
|
}
|
|
|
|
strcpy(string,"\\\\.\\PhysicalDrive");
|
|
sprintf(szDriveNum, "%d",driveNumber);
|
|
strcat(string,szDriveNum);
|
|
|
|
fileHandle = CreateFile(string,
|
|
accessMode,
|
|
shareMode,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL);
|
|
|
|
printf("\nMode Sense ");
|
|
|
|
switch (sensePage) {
|
|
case 0:
|
|
printf("Unit Attention Page ");
|
|
break;
|
|
case 1:
|
|
printf("Error Recovery Page ");
|
|
break;
|
|
case 2:
|
|
printf("Disconnect Page ");
|
|
break;
|
|
case 3:
|
|
printf("Format Device Page ");
|
|
break;
|
|
case 4:
|
|
printf("Rigid Geometry Page ");
|
|
break;
|
|
case 5:
|
|
printf("Flexible Page ");
|
|
break;
|
|
case 7:
|
|
printf("Verify Error Page ");
|
|
break;
|
|
case 8:
|
|
printf("Caching Page ");
|
|
break;
|
|
case 9:
|
|
printf("Peripheral Page ");
|
|
break;
|
|
case 10:
|
|
printf("Control Page ");
|
|
break;
|
|
case 11:
|
|
printf("Medium Types Page ");
|
|
break;
|
|
case 12:
|
|
printf("Notch Partition Page ");
|
|
break;
|
|
case 15:
|
|
printf("Data Compression Page ");
|
|
break;
|
|
case 16:
|
|
printf("Device Configuration Page ");
|
|
break;
|
|
case 17:
|
|
printf("Medium Partition Page ");
|
|
break;
|
|
default:
|
|
printf("Unknown Page ");
|
|
break;
|
|
}
|
|
|
|
switch (senseValues) {
|
|
case 0:
|
|
printf("(current values)\n");
|
|
DoModeSense(&sptwb, fileHandle, sensePage | MODE_SENSE_CURRENT_VALUES);
|
|
break;
|
|
case 1:
|
|
printf("(default values)\n");
|
|
DoModeSense(&sptwb, fileHandle, sensePage | MODE_SENSE_DEFAULT_VALUES);
|
|
break;
|
|
case 2:
|
|
printf("(saved values)\n");
|
|
DoModeSense(&sptwb, fileHandle, sensePage | MODE_SENSE_SAVED_VALUES);
|
|
break;
|
|
case 3:
|
|
printf("(changable values)\n");
|
|
DoModeSense(&sptwb, fileHandle, sensePage | MODE_SENSE_CHANGEABLE_VALUES);
|
|
memcpy(changeBits, sptwb.ucDataBuf, sptwb.ucDataBuf[4+1]);
|
|
pageLength = changeBits[4+1];
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
goto cachePage;
|
|
default:
|
|
printf("(no values)\n");
|
|
break;
|
|
}
|
|
|
|
goto newPage;
|
|
|
|
cachePage:
|
|
|
|
//
|
|
// Get changable fields mask.
|
|
//
|
|
|
|
printf("(changable values)\n");
|
|
DoModeSense(&sptwb,
|
|
fileHandle,
|
|
sensePage | MODE_SENSE_CHANGEABLE_VALUES);
|
|
|
|
//
|
|
// Set up change mask.
|
|
//
|
|
|
|
memcpy(changeBits, sptwb.ucDataBuf, sptwb.ucDataBuf[4+1]);
|
|
pageLength = changeBits[4+1];
|
|
|
|
//
|
|
// Get current values.
|
|
//
|
|
|
|
printf("\nMode Sense Caching Page (old current values)\n");
|
|
DoModeSense(&sptwb, fileHandle, sensePage | MODE_SENSE_CURRENT_VALUES);
|
|
|
|
//
|
|
// Clear fields that can't be changed.
|
|
//
|
|
|
|
VerifyModePage(&sptwb.ucDataBuf[0], changeBits, pageLength);
|
|
|
|
//
|
|
// Set or clear write cache enable bit.
|
|
//
|
|
|
|
if (senseValues == 4)
|
|
sptwb.ucDataBuf[4 + 2] |= 0x4;
|
|
else
|
|
sptwb.ucDataBuf[4+2] &= ~0x4;
|
|
|
|
//
|
|
// Determine whether this change should be saved.
|
|
//
|
|
|
|
while (TRUE) {
|
|
printf("\n0:Do not save page\n");
|
|
printf("1:Save page\n");
|
|
printf("99:Select page\n");
|
|
|
|
printf("\nSave action? ");
|
|
scanf("%d", &saveAction);
|
|
|
|
if (saveAction == 99) {
|
|
goto newPage;
|
|
}
|
|
|
|
if (saveAction == 0 ||
|
|
saveAction == 1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
DoModeSelect(&sptwb,
|
|
fileHandle,
|
|
saveAction,
|
|
pageLength + 6);
|
|
|
|
//
|
|
// Get new current values.
|
|
//
|
|
|
|
printf("\nMode Sense Caching Page (new current values)\n");
|
|
DoModeSense(&sptwb, fileHandle, sensePage | MODE_SENSE_CURRENT_VALUES);
|
|
|
|
goto newPage;
|
|
}
|
|
|
|
BOOL SetDiscPage(PUCHAR dataBuffer, PUCHAR mask, ULONG pageLength)
|
|
{
|
|
if (((dataBuffer[4+0] & 0x3f) != MODE_PAGE_DISCONNECT) ||
|
|
dataBuffer[4+1] != 0x0e) {
|
|
return FALSE;
|
|
}
|
|
|
|
dataBuffer[4+2] = 0x80; /* buffer full ratio */
|
|
dataBuffer[4+3] = 0x80; /* buffer empty ratio */
|
|
|
|
VerifyModePage(dataBuffer, mask, pageLength);
|
|
|
|
return( TRUE);
|
|
}
|
|
|
|
|
|
BOOL EnableWriteCache(PUCHAR dataBuffer, ULONG onoff, PUCHAR mask, ULONG pageLength)
|
|
{
|
|
if (((dataBuffer[4+0] & 0x3f) != MODE_PAGE_CACHING) ||
|
|
dataBuffer[4+1] != pageLength) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL VerifyModePage( PUCHAR dataBuffer, PUCHAR mask, ULONG length)
|
|
{
|
|
ULONG i;
|
|
|
|
/* reserved, mbz, no block descs */
|
|
dataBuffer[0] = dataBuffer[2] = dataBuffer[1] = dataBuffer[3] = 0;
|
|
|
|
/* Turn off what cannot be set back the way it was */
|
|
for (i = 0; i < length; i++)
|
|
dataBuffer[4+i] &= mask[4+i];
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID DoInquiry(PSCSI_PASS_THROUGH_WITH_BUFFERS psptwb, HANDLE fileHandle)
|
|
{
|
|
ULONG length,
|
|
returned;
|
|
BOOLEAN status;
|
|
|
|
|
|
ZeroMemory(psptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
|
|
|
|
psptwb->spt.Length = sizeof(SCSI_PASS_THROUGH);
|
|
psptwb->spt.PathId = 0;
|
|
psptwb->spt.TargetId = 0; /* kernel fixes this */
|
|
psptwb->spt.Lun = 0;
|
|
psptwb->spt.CdbLength = CDB6GENERIC_LENGTH;
|
|
psptwb->spt.SenseInfoLength = 24;
|
|
psptwb->spt.DataIn = SCSI_IOCTL_DATA_IN;
|
|
psptwb->spt.DataTransferLength = 36;
|
|
psptwb->spt.TimeOutValue = 2;
|
|
psptwb->spt.DataBufferOffset =
|
|
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
|
|
psptwb->spt.SenseInfoOffset =
|
|
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
|
|
psptwb->spt.Cdb[0] = SCSIOP_INQUIRY;
|
|
psptwb->spt.Cdb[1] = 0x0;
|
|
psptwb->spt.Cdb[2] = 0x0;
|
|
psptwb->spt.Cdb[3] = 0x0;
|
|
psptwb->spt.Cdb[4] = 36;
|
|
psptwb->spt.Cdb[5] = 0x0;
|
|
length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
|
|
psptwb->spt.DataTransferLength;
|
|
|
|
status = DeviceIoControl(fileHandle,
|
|
IOCTL_SCSI_PASS_THROUGH,
|
|
psptwb,
|
|
sizeof(SCSI_PASS_THROUGH),
|
|
psptwb,
|
|
length,
|
|
&returned,
|
|
FALSE);
|
|
|
|
PrintInquiryStatusResults(status,returned,psptwb,length);
|
|
}
|
|
|
|
|
|
VOID
|
|
DisplayModeSenseData(
|
|
BOOLEAN status,
|
|
DWORD returned,
|
|
PSCSI_PASS_THROUGH_WITH_BUFFERS psptwb,
|
|
ULONG length
|
|
)
|
|
|
|
{
|
|
ULONG errorCode;
|
|
ULONG count;
|
|
|
|
if (!status ) {
|
|
|
|
printf( "Error: %d ",
|
|
errorCode = GetLastError() );
|
|
PrintError(errorCode);
|
|
return;
|
|
}
|
|
|
|
if (psptwb->spt.ScsiStatus) {
|
|
|
|
PrintSenseInfo(psptwb);
|
|
return;
|
|
|
|
} else {
|
|
|
|
switch ((((PUCHAR)psptwb->ucDataBuf)[4] & 0x0F)) {
|
|
case MODE_PAGE_FORMAT_DEVICE:
|
|
{
|
|
PMODE_FORMAT_PAGE formatPage =
|
|
(PMODE_FORMAT_PAGE)(((PUCHAR)psptwb->ucDataBuf) +
|
|
sizeof(SCSI_MODE_HEADER));
|
|
|
|
printf("\nTracks per zone %x\n",
|
|
formatPage->TracksPerZone[1] |
|
|
formatPage->TracksPerZone[0] << 8);
|
|
|
|
printf("Alternate sectors per zone %x\n",
|
|
formatPage->AlternateSectorsPerZone[1] |
|
|
formatPage->AlternateSectorsPerZone[0] << 8);
|
|
|
|
printf("Alternate tracks per zone %x\n",
|
|
formatPage->AlternateTracksPerZone[1] |
|
|
formatPage->AlternateTracksPerZone[0] << 8);
|
|
|
|
printf("Alternate tracks per logical unit %x\n",
|
|
formatPage->AlternateTracksPerLogicalUnit[1] |
|
|
formatPage->AlternateTracksPerLogicalUnit[0] << 8);
|
|
|
|
printf("Sectors per track %x\n",
|
|
formatPage->SectorsPerTrack[1] |
|
|
formatPage->SectorsPerTrack[0] << 8);
|
|
|
|
printf("Data bytes per physical sector %x\n",
|
|
formatPage->BytesPerPhysicalSector[1] |
|
|
formatPage->BytesPerPhysicalSector[0] << 8);
|
|
|
|
printf("Interleave %x\n",
|
|
formatPage->Interleave[1] |
|
|
formatPage->Interleave[0] << 8);
|
|
|
|
printf("Track skew factor %x\n",
|
|
formatPage->TrackSkewFactor[1] |
|
|
formatPage->TrackSkewFactor[0] << 8);
|
|
|
|
printf("Cylinder skew factor %x\n",
|
|
formatPage->CylinderSkewFactor[1] |
|
|
formatPage->CylinderSkewFactor[0] << 8);
|
|
|
|
if (formatPage->SurfaceFirst) {
|
|
printf("Surface first ");
|
|
}
|
|
|
|
if (formatPage->RemovableMedia) {
|
|
printf("Removable media ");
|
|
}
|
|
|
|
if (formatPage->HardSectorFormating) {
|
|
printf("Hard sector formatting ");
|
|
}
|
|
|
|
if (formatPage->SoftSectorFormating) {
|
|
printf("Soft sector formatting ");
|
|
}
|
|
|
|
printf("\n\n");
|
|
break;
|
|
}
|
|
|
|
case MODE_PAGE_CACHING:
|
|
|
|
{
|
|
PMODE_CACHING_PAGE cachingPage =
|
|
(PMODE_CACHING_PAGE)(((PUCHAR)psptwb->ucDataBuf) +
|
|
sizeof(SCSI_MODE_HEADER));
|
|
|
|
if (cachingPage->PageSavable) {
|
|
printf("Page savable\n");
|
|
}
|
|
|
|
if (cachingPage->ReadDisableCache) {
|
|
printf("Read cache disabled\n");
|
|
} else {
|
|
printf("Read cache enabled\n");
|
|
}
|
|
|
|
if (cachingPage->WriteCacheEnable) {
|
|
printf("Write cache enabled\n");
|
|
} else {
|
|
printf("Write cache disabled\n");
|
|
}
|
|
|
|
if (cachingPage->MultiplicationFactor) {
|
|
printf("Multiplication factor\n");
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
|
|
printf("Bytes returned: %Xh, ",
|
|
psptwb->spt.ScsiStatus,returned);
|
|
|
|
printf("Data buffer length: %Xh\n\n\n",
|
|
psptwb->spt.DataTransferLength);
|
|
|
|
printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
|
|
printf(" ---------------------------------------------------------------\n");
|
|
|
|
for (count = 0;
|
|
count < length - offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
|
|
count++) {
|
|
|
|
if ((count) % 16 == 0) {
|
|
printf(" %03X ",count);
|
|
}
|
|
|
|
printf("%02X ", ((PUCHAR)psptwb->ucDataBuf)[count]);
|
|
|
|
if ((count+1) % 8 == 0) {
|
|
printf(" ");
|
|
}
|
|
if ((count+1) % 16 == 0) {
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
printf("\n\n");
|
|
break;
|
|
|
|
} // end switch
|
|
} // end else
|
|
} // end DisplayModeSenseData()
|
|
|
|
VOID
|
|
DoModeSense(
|
|
PSCSI_PASS_THROUGH_WITH_BUFFERS psptwb,
|
|
HANDLE fileHandle,
|
|
ULONG senseType)
|
|
|
|
{
|
|
ULONG length,
|
|
returned;
|
|
BOOLEAN status;
|
|
char *pt[4] = { "current", "changeable", "default", "saved" };
|
|
|
|
|
|
//printf("Here is a MODE SENSE to return Mode Page %d, %s values\n",
|
|
// senseType & 0x3f, pt[(senseType >> 6) & 0x3]);
|
|
|
|
ZeroMemory(psptwb,
|
|
sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
|
|
|
|
psptwb->spt.Length = sizeof(SCSI_PASS_THROUGH);
|
|
psptwb->spt.PathId = 0;
|
|
psptwb->spt.TargetId = 0; /* kernel fixes this */
|
|
psptwb->spt.Lun = 0;
|
|
psptwb->spt.CdbLength = CDB6GENERIC_LENGTH;
|
|
psptwb->spt.SenseInfoLength = 24;
|
|
psptwb->spt.DataIn = SCSI_IOCTL_DATA_IN;
|
|
psptwb->spt.DataTransferLength = 0x1c;
|
|
psptwb->spt.TimeOutValue = 2;
|
|
psptwb->spt.DataBufferOffset =
|
|
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
|
|
psptwb->spt.SenseInfoOffset =
|
|
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
|
|
psptwb->spt.Cdb[0] = SCSIOP_MODE_SENSE;
|
|
psptwb->spt.Cdb[1] = MODE_SENSE_DISABLE_BLOCK_DESCRIPTORS;
|
|
psptwb->spt.Cdb[2] = (UCHAR)senseType;
|
|
psptwb->spt.Cdb[3] = 0x0;
|
|
psptwb->spt.Cdb[4] = 0x1c;
|
|
psptwb->spt.Cdb[5] = 0x0;
|
|
length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
|
|
psptwb->spt.DataTransferLength;
|
|
|
|
status = DeviceIoControl(fileHandle,
|
|
IOCTL_SCSI_PASS_THROUGH,
|
|
psptwb,
|
|
sizeof(SCSI_PASS_THROUGH),
|
|
psptwb,
|
|
length,
|
|
&returned,
|
|
FALSE);
|
|
|
|
DisplayModeSenseData(status,returned,psptwb,length);
|
|
}
|
|
|
|
|
|
VOID
|
|
DoModeSelect(
|
|
PSCSI_PASS_THROUGH_WITH_BUFFERS psptwb,
|
|
HANDLE fileHandle,
|
|
ULONG save,
|
|
ULONG datalength)
|
|
|
|
{
|
|
ULONG length,
|
|
returned;
|
|
|
|
psptwb->spt.Length = sizeof(SCSI_PASS_THROUGH);
|
|
psptwb->spt.PathId = 0;
|
|
psptwb->spt.TargetId = 0; /* kernel fixes this */
|
|
psptwb->spt.Lun = 0;
|
|
psptwb->spt.CdbLength = CDB6GENERIC_LENGTH;
|
|
psptwb->spt.SenseInfoLength = 26;
|
|
psptwb->spt.DataIn = SCSI_IOCTL_DATA_OUT;
|
|
psptwb->spt.DataTransferLength = datalength;
|
|
psptwb->spt.TimeOutValue = 2000;
|
|
psptwb->spt.DataBufferOffset =
|
|
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
|
|
psptwb->spt.SenseInfoOffset =
|
|
offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
|
|
psptwb->spt.Cdb[0] = SCSIOP_MODE_SELECT;
|
|
psptwb->spt.Cdb[1] = (UCHAR)save;
|
|
psptwb->spt.Cdb[2] = 0x0;
|
|
psptwb->spt.Cdb[3] = 0x0;
|
|
psptwb->spt.Cdb[4] = (UCHAR)datalength;
|
|
psptwb->spt.Cdb[5] = 0x0;
|
|
|
|
length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
|
|
psptwb->spt.DataTransferLength;
|
|
|
|
DeviceIoControl(fileHandle,
|
|
IOCTL_SCSI_PASS_THROUGH,
|
|
psptwb,
|
|
length,
|
|
psptwb,
|
|
length,
|
|
&returned,
|
|
FALSE);
|
|
}
|
|
VOID
|
|
PrintError(ULONG ErrorCode)
|
|
{
|
|
UCHAR errorBuffer[80];
|
|
ULONG count;
|
|
|
|
count = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
ErrorCode,
|
|
0,
|
|
errorBuffer,
|
|
sizeof(errorBuffer),
|
|
NULL
|
|
);
|
|
|
|
if (count != 0) {
|
|
printf("%s\n", errorBuffer);
|
|
} else {
|
|
printf("Format message failed. Error: %d\n", GetLastError());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
PrintInquiryStatusResults(
|
|
BOOLEAN status,DWORD returned,PSCSI_PASS_THROUGH_WITH_BUFFERS psptwb,
|
|
ULONG length)
|
|
{
|
|
ULONG errorCode;
|
|
|
|
if (!status ) {
|
|
printf( "Error: %d ",
|
|
errorCode = GetLastError() );
|
|
PrintError(errorCode);
|
|
return;
|
|
}
|
|
if (psptwb->spt.ScsiStatus) {
|
|
PrintSenseInfo(psptwb);
|
|
return;
|
|
} else {
|
|
printf("%s", &psptwb->ucDataBuf[8]);
|
|
return;
|
|
PrintInquiryDataBuffer((PUCHAR)psptwb->ucDataBuf,
|
|
length - offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf));
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
PrintInquiryDataBuffer(PUCHAR DataBuffer, ULONG BufferLength)
|
|
{
|
|
char string[9];
|
|
|
|
printf("%s\n", &DataBuffer[8]);
|
|
return;
|
|
strncpy(string,&DataBuffer[8],8);
|
|
string[8]= '\0';
|
|
printf(" %s ",string);
|
|
strncpy(string,&DataBuffer[16],8);
|
|
string[8]= '\0';
|
|
printf("%s ",string);
|
|
strncpy(string,&DataBuffer[32],8);
|
|
string[8]= '\0';
|
|
printf("%s ",string);
|
|
}
|
|
|
|
|
|
VOID
|
|
PrintErrorStatus(
|
|
PSCSI_PASS_THROUGH_WITH_BUFFERS psptwb
|
|
)
|
|
|
|
{
|
|
PrintError(GetLastError());
|
|
|
|
if (psptwb->spt.ScsiStatus) {
|
|
PrintSenseInfo(psptwb);
|
|
return;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PrintSenseInfo(PSCSI_PASS_THROUGH_WITH_BUFFERS psptwb)
|
|
{
|
|
PSENSE_DATA senseBuffer = (PSENSE_DATA)psptwb->ucSenseBuf;
|
|
|
|
printf("SCSI request sense data\n");
|
|
|
|
if (psptwb->spt.SenseInfoLength == 0) {
|
|
printf("No sense data\n");
|
|
return;
|
|
}
|
|
|
|
printf("Error code is %x\n",
|
|
senseBuffer->ErrorCode);
|
|
printf("Sense key is %x\n",
|
|
senseBuffer->SenseKey);
|
|
printf("Additional sense code is %x\n",
|
|
senseBuffer->AdditionalSenseCode);
|
|
printf("Additional sense code qualifier is %x\n",
|
|
senseBuffer->AdditionalSenseCodeQualifier);
|
|
|
|
printf("\n\n");
|
|
|
|
|
|
switch (senseBuffer->SenseKey & 0xf) {
|
|
|
|
case SCSI_SENSE_NOT_READY:
|
|
|
|
printf("Device not ready\n");
|
|
|
|
switch (senseBuffer->AdditionalSenseCode) {
|
|
|
|
case SCSI_ADSENSE_LUN_NOT_READY:
|
|
|
|
printf("Lun not ready\n");
|
|
|
|
switch (senseBuffer->AdditionalSenseCodeQualifier) {
|
|
|
|
case SCSI_SENSEQ_BECOMING_READY:
|
|
|
|
printf("In process of becoming ready\n");
|
|
break;
|
|
|
|
case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
|
|
|
|
printf("Manual intervention required\n");
|
|
break;
|
|
|
|
case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
|
|
|
|
printf("Format in progress\n");
|
|
break;
|
|
|
|
case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
|
|
default:
|
|
|
|
printf("Initializing command required\n");
|
|
break;
|
|
|
|
} // end switch (senseBuffer->AdditionalSenseCodeQualifier)
|
|
|
|
break;
|
|
|
|
case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
|
|
|
|
printf(" No Media in device.\n");
|
|
break;
|
|
|
|
} // end switch (senseBuffer->AdditionalSenseCode)
|
|
|
|
break;
|
|
|
|
case SCSI_SENSE_DATA_PROTECT:
|
|
|
|
printf("Media write protected\n");
|
|
break;
|
|
|
|
case SCSI_SENSE_MEDIUM_ERROR:
|
|
|
|
printf("Bad media\n");
|
|
break;
|
|
|
|
case SCSI_SENSE_HARDWARE_ERROR:
|
|
|
|
printf("Hardware error\n");
|
|
break;
|
|
|
|
case SCSI_SENSE_ILLEGAL_REQUEST:
|
|
|
|
printf("Illegal SCSI request\n");
|
|
|
|
switch (senseBuffer->AdditionalSenseCode) {
|
|
|
|
case SCSI_ADSENSE_ILLEGAL_COMMAND:
|
|
printf("Illegal command\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_ILLEGAL_BLOCK:
|
|
printf("Illegal block address\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_INVALID_LUN:
|
|
printf("Invalid LUN\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_MUSIC_AREA:
|
|
printf("Music area\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_DATA_AREA:
|
|
printf("Data area\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_VOLUME_OVERFLOW:
|
|
printf("Volume overflow\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_INVALID_CDB:
|
|
printf("Invalid field in CDB\n");
|
|
break;
|
|
|
|
} // end switch (senseBuffer->AdditionalSenseCode)
|
|
|
|
break;
|
|
|
|
case SCSI_SENSE_UNIT_ATTENTION:
|
|
|
|
switch (senseBuffer->AdditionalSenseCode) {
|
|
case SCSI_ADSENSE_MEDIUM_CHANGED:
|
|
printf("Media changed\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_BUS_RESET:
|
|
printf("Bus reset\n");
|
|
break;
|
|
|
|
default:
|
|
printf("Unit attention\n");
|
|
break;
|
|
|
|
} // end switch (senseBuffer->AdditionalSenseCode)
|
|
|
|
break;
|
|
|
|
case SCSI_SENSE_ABORTED_COMMAND:
|
|
|
|
printf("Command aborted\n");
|
|
break;
|
|
|
|
case SCSI_SENSE_RECOVERED_ERROR:
|
|
|
|
printf("Recovered error\n");
|
|
|
|
switch(senseBuffer->AdditionalSenseCode) {
|
|
case SCSI_ADSENSE_SEEK_ERROR:
|
|
printf("Seek error\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_TRACK_ERROR:
|
|
printf("Track error\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_REC_DATA_NOECC:
|
|
printf("Recovered data - no ECC\n");
|
|
break;
|
|
|
|
case SCSI_ADSENSE_REC_DATA_ECC:
|
|
printf("Recovered data - ECC\n");
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
} // end switch(senseBuffer->AdditionalSenseCode)
|
|
|
|
if (senseBuffer->IncorrectLength) {
|
|
printf("Incorrect length detected.\n");
|
|
}
|
|
|
|
break;
|
|
|
|
case SCSI_SENSE_NO_SENSE:
|
|
|
|
//
|
|
// Check other indicators.
|
|
//
|
|
|
|
if (senseBuffer->IncorrectLength) {
|
|
|
|
printf("Incorrect length detected.\n");
|
|
|
|
} else {
|
|
|
|
printf("No specific sense key\n");
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("Unrecognized sense code\n");
|
|
break;
|
|
|
|
} // end switch (senseBuffer->SenseKey & 0xf)
|
|
}
|