#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct _MODE_SENSE_PASS_THROUGH { SCSI_PASS_THROUGH Srb; ULONG Reserved; UCHAR SenseData[32]; UCHAR DataBuffer[256]; } MODE_SENSE_PASS_THROUGH, *PMODE_SENSE_PASS_THROUGH; VOID Usage( VOID ); int __cdecl main( int argc, char **argv ) { ULONG portNumber = 0; ULONG physicalDrive = 0, selectedDrive = 0xFFFFFFFF; HANDLE volumeHandle,driveHandle; UNICODE_STRING unicodeString; OBJECT_ATTRIBUTES objectAttributes; NTSTATUS ntStatus; PSCSI_ADAPTER_BUS_INFO adapterInfo; PSCSI_BUS_DATA busData; PSCSI_INQUIRY_DATA inquiryData; PINQUIRYDATA deviceInquiryData; ULONG bytesTransferred; ULONG i, j; PCHAR pageData,pch; UCHAR modeOperation, cacheSettings; INT args; BOOLEAN disableCache = FALSE, enableCache = FALSE; BOOLEAN displayAll = TRUE; UCHAR buffer[32]; UCHAR driveBuffer[20]; CHAR driver[9]; MODE_SENSE_PASS_THROUGH modeSenseData; if ( argc > 3 ) { Usage(); exit(1); } else if (argc > 1 ) { displayAll = FALSE; args = 1; while ( args < argc ) { pch = argv[args]; if ( *pch == '-' ) { BOOL exitSwitch = FALSE; pch++; switch( *pch ) { case 'd': disableCache = TRUE; break; case 'e': enableCache = TRUE; break; case '?': Usage(); exit(1); break; default: Usage(); exit(1); } pch++; } else { if (!isdigit(*pch)) { Usage(); exit(1); } selectedDrive = atol(pch); } args++; } } printf("\nDrive Port Bus TID LUN Vendor ReadCache WriteCache\n"); printf( "--------------------------------------------------------------------"); while (TRUE) { memset( buffer, 0, sizeof( buffer ) ); sprintf( buffer,"\\\\.\\Scsi%d:",portNumber); // // Open the volume with the DOS name. // volumeHandle = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); if( volumeHandle == INVALID_HANDLE_VALUE ) { break; } // // Allocate memory to store the inquiry data. // adapterInfo = (PSCSI_ADAPTER_BUS_INFO)malloc( 0x400 ); if (adapterInfo == NULL) { printf( "Can't allocate memory for bus data\n" ); CloseHandle( volumeHandle ); return 1; } // // Issue device control to get configuration information. // if (!DeviceIoControl( volumeHandle, IOCTL_SCSI_GET_INQUIRY_DATA, NULL, 0, adapterInfo, 0x400, &bytesTransferred, NULL)) { fprintf(stderr, "IOCTL_SCSI_GET_INQUIRY_DATA failed [Error %d].\n", GetLastError() ); free(adapterInfo); CloseHandle( volumeHandle ); return 2; } // // Display devices on buses. // for (i=0; i < adapterInfo->NumberOfBuses; i++) { busData = &adapterInfo->BusData[i]; inquiryData = (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + busData->InquiryDataOffset); for (j=0; jNumberOfLogicalUnits; j++) { // // Make sure VendorId string is null terminated. // deviceInquiryData = (PINQUIRYDATA)&inquiryData->InquiryData[0]; // // Determine the perpherial type. // if (deviceInquiryData->DeviceType == DIRECT_ACCESS_DEVICE) { deviceInquiryData->ProductRevisionLevel[0] = '\0'; if (displayAll || (selectedDrive == physicalDrive)) { printf("\n%2d %2d %2d %2d %2d ", physicalDrive, portNumber, inquiryData->PathId, inquiryData->TargetId, inquiryData->Lun); // // Display product information. // printf(" %s", deviceInquiryData->VendorId); // // Open handle to the PhysicalDrive // sprintf(driveBuffer,"\\\\.\\PhysicalDrive%d",physicalDrive); driveHandle = CreateFile(driveBuffer, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (driveHandle == INVALID_HANDLE_VALUE) { printf("CreateFile for %s failed. Error = %x\n", driveBuffer, GetLastError() ); return 3; } // // Issue mode sense to see if caches are enabled. // ZeroMemory(&modeSenseData, sizeof(MODE_SENSE_PASS_THROUGH)); modeSenseData.Srb.Length = sizeof(SCSI_PASS_THROUGH); modeSenseData.Srb.CdbLength = 6; modeSenseData.Srb.DataIn = SCSI_IOCTL_DATA_IN; modeSenseData.Srb.DataBufferOffset = offsetof(MODE_SENSE_PASS_THROUGH, DataBuffer); modeSenseData.Srb.SenseInfoOffset = offsetof(MODE_SENSE_PASS_THROUGH, SenseData); modeSenseData.Srb.DataTransferLength = 0xFF; modeSenseData.Srb.TimeOutValue = 10; ZeroMemory(&modeSenseData.Srb.Cdb, 16); modeSenseData.Srb.Cdb[0] = 0x1A; modeSenseData.Srb.Cdb[2] = 8; modeSenseData.Srb.Cdb[4] = 0xFF; if (!DeviceIoControl(driveHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &modeSenseData, sizeof(modeSenseData), &modeSenseData, sizeof(modeSenseData), &bytesTransferred, FALSE)) { fprintf(stderr,"Mode sense failed. Error = %x\n", GetLastError() ); return 4; } // // Display current values // pageData = modeSenseData.DataBuffer; (ULONG_PTR)pageData += 6 + pageData[3]; cacheSettings = *pageData; if (displayAll || (physicalDrive == selectedDrive)) { printf(" %s ", (cacheSettings & 1) ? "Disabled" : "Enabled"); printf(" %s", (cacheSettings & 4) ? "Enabled" : "Disabled"); } if ((enableCache || disableCache) && (physicalDrive == selectedDrive)) { // // Build mode select - caching page. // // Clean out reserved areas of data buffer and update others // modeSenseData.Srb.SenseInfoLength = 32; pageData = modeSenseData.DataBuffer; modeSenseData.Srb.Cdb[4] = *pageData + 1; modeSenseData.Srb.Cdb[2] = 0x00; modeSenseData.Srb.Cdb[1] = 0x11; *pageData = 0; (ULONG_PTR)pageData += 4 + pageData[3]; *pageData &= 0x3F; pageData++; pageData++; *pageData &= 0x07; modeSenseData.DataBuffer[5] = 0x00; modeSenseData.DataBuffer[6] = 0x00; modeSenseData.DataBuffer[7] = 0x00; modeSenseData.Srb.DataIn = SCSI_IOCTL_DATA_OUT; modeSenseData.Srb.DataTransferLength = modeSenseData.Srb.Cdb[4]; if (disableCache) { // // Disable write cache // *pageData &= 0x03; } else { // // Enable the cache. // *pageData |= 0x04; } modeSenseData.Srb.Cdb[0] = 0x15; if (!DeviceIoControl(driveHandle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &modeSenseData, sizeof(modeSenseData), &modeSenseData, sizeof(modeSenseData), &bytesTransferred, FALSE)) { fprintf(stderr,"Mode select failed. Error = %x\n", GetLastError() ); } else { printf("\nWrite cache successfully %s\n", (enableCache ? "Enabled" : "Disabled")); } } CloseHandle(driveHandle ); } physicalDrive++; } // // Get next device data. // inquiryData = (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + inquiryData->NextInquiryDataOffset); } } free (adapterInfo); CloseHandle(volumeHandle ); portNumber++; } printf("\n"); return 0; } VOID Usage( VOID ) { fprintf(stderr,"WCACHE: Usage wcache [-options] \n"); fprintf(stderr,"\n"); fprintf(stderr," where options are: e - Enable Write Cache for the \n"); fprintf(stderr," d - Disable Write Cache for the \n"); fprintf(stderr," dumps current values for all drives when invoked with no options\n"); fprintf(stderr,"\n"); }