Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
12 KiB

  1. #include <nt.h>
  2. #include <ntddscsi.h>
  3. #include <ntdddisk.h>
  4. #include <ntddcdrm.h>
  5. #include <ntrtl.h>
  6. #include <nturtl.h>
  7. #include <windows.h>
  8. #include <stdio.h>
  9. #include <process.h>
  10. #include <memory.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <stddef.h>
  14. #include <string.h>
  15. #include <scsi.h>
  16. typedef struct _MODE_SENSE_PASS_THROUGH {
  17. SCSI_PASS_THROUGH Srb;
  18. ULONG Reserved;
  19. UCHAR SenseData[32];
  20. UCHAR DataBuffer[256];
  21. } MODE_SENSE_PASS_THROUGH, *PMODE_SENSE_PASS_THROUGH;
  22. VOID
  23. Usage(
  24. VOID
  25. );
  26. int __cdecl
  27. main( int argc, char **argv )
  28. {
  29. ULONG portNumber = 0;
  30. ULONG physicalDrive = 0,
  31. selectedDrive = 0xFFFFFFFF;
  32. HANDLE volumeHandle,driveHandle;
  33. UNICODE_STRING unicodeString;
  34. OBJECT_ATTRIBUTES objectAttributes;
  35. NTSTATUS ntStatus;
  36. PSCSI_ADAPTER_BUS_INFO adapterInfo;
  37. PSCSI_BUS_DATA busData;
  38. PSCSI_INQUIRY_DATA inquiryData;
  39. PINQUIRYDATA deviceInquiryData;
  40. ULONG bytesTransferred;
  41. ULONG i, j;
  42. PCHAR pageData,pch;
  43. UCHAR modeOperation,
  44. cacheSettings;
  45. INT args;
  46. BOOLEAN disableCache = FALSE,
  47. enableCache = FALSE;
  48. BOOLEAN displayAll = TRUE;
  49. UCHAR buffer[32];
  50. UCHAR driveBuffer[20];
  51. CHAR driver[9];
  52. MODE_SENSE_PASS_THROUGH modeSenseData;
  53. if ( argc > 3 ) {
  54. Usage();
  55. exit(1);
  56. } else if (argc > 1 ) {
  57. displayAll = FALSE;
  58. args = 1;
  59. while ( args < argc ) {
  60. pch = argv[args];
  61. if ( *pch == '-' ) {
  62. BOOL exitSwitch = FALSE;
  63. pch++;
  64. switch( *pch ) {
  65. case 'd':
  66. disableCache = TRUE;
  67. break;
  68. case 'e':
  69. enableCache = TRUE;
  70. break;
  71. case '?':
  72. Usage();
  73. exit(1);
  74. break;
  75. default:
  76. Usage();
  77. exit(1);
  78. }
  79. pch++;
  80. } else {
  81. if (!isdigit(*pch)) {
  82. Usage();
  83. exit(1);
  84. }
  85. selectedDrive = atol(pch);
  86. }
  87. args++;
  88. }
  89. }
  90. printf("\nDrive Port Bus TID LUN Vendor ReadCache WriteCache\n");
  91. printf( "--------------------------------------------------------------------");
  92. while (TRUE) {
  93. memset( buffer, 0, sizeof( buffer ) );
  94. sprintf( buffer,"\\\\.\\Scsi%d:",portNumber);
  95. //
  96. // Open the volume with the DOS name.
  97. //
  98. volumeHandle = CreateFile(buffer,
  99. GENERIC_READ,
  100. FILE_SHARE_READ | FILE_SHARE_WRITE,
  101. NULL,
  102. OPEN_EXISTING,
  103. 0,
  104. 0);
  105. if( volumeHandle == INVALID_HANDLE_VALUE ) {
  106. break;
  107. }
  108. //
  109. // Allocate memory to store the inquiry data.
  110. //
  111. adapterInfo = (PSCSI_ADAPTER_BUS_INFO)malloc( 0x400 );
  112. if (adapterInfo == NULL) {
  113. printf( "Can't allocate memory for bus data\n" );
  114. CloseHandle( volumeHandle );
  115. return 1;
  116. }
  117. //
  118. // Issue device control to get configuration information.
  119. //
  120. if (!DeviceIoControl( volumeHandle,
  121. IOCTL_SCSI_GET_INQUIRY_DATA,
  122. NULL,
  123. 0,
  124. adapterInfo,
  125. 0x400,
  126. &bytesTransferred,
  127. NULL)) {
  128. fprintf(stderr, "IOCTL_SCSI_GET_INQUIRY_DATA failed [Error %d].\n", GetLastError() );
  129. free(adapterInfo);
  130. CloseHandle( volumeHandle );
  131. return 2;
  132. }
  133. //
  134. // Display devices on buses.
  135. //
  136. for (i=0; i < adapterInfo->NumberOfBuses; i++) {
  137. busData = &adapterInfo->BusData[i];
  138. inquiryData = (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + busData->InquiryDataOffset);
  139. for (j=0; j<busData->NumberOfLogicalUnits; j++) {
  140. //
  141. // Make sure VendorId string is null terminated.
  142. //
  143. deviceInquiryData = (PINQUIRYDATA)&inquiryData->InquiryData[0];
  144. //
  145. // Determine the perpherial type.
  146. //
  147. if (deviceInquiryData->DeviceType == DIRECT_ACCESS_DEVICE) {
  148. deviceInquiryData->ProductRevisionLevel[0] = '\0';
  149. if (displayAll || (selectedDrive == physicalDrive)) {
  150. printf("\n%2d %2d %2d %2d %2d ",
  151. physicalDrive,
  152. portNumber,
  153. inquiryData->PathId,
  154. inquiryData->TargetId,
  155. inquiryData->Lun);
  156. //
  157. // Display product information.
  158. //
  159. printf(" %s", deviceInquiryData->VendorId);
  160. //
  161. // Open handle to the PhysicalDrive
  162. //
  163. sprintf(driveBuffer,"\\\\.\\PhysicalDrive%d",physicalDrive);
  164. driveHandle = CreateFile(driveBuffer,
  165. GENERIC_READ | GENERIC_WRITE,
  166. FILE_SHARE_READ | FILE_SHARE_WRITE,
  167. NULL,
  168. OPEN_EXISTING,
  169. 0,
  170. NULL);
  171. if (driveHandle == INVALID_HANDLE_VALUE) {
  172. printf("CreateFile for %s failed. Error = %x\n",
  173. driveBuffer,
  174. GetLastError() );
  175. return 3;
  176. }
  177. //
  178. // Issue mode sense to see if caches are enabled.
  179. //
  180. ZeroMemory(&modeSenseData, sizeof(MODE_SENSE_PASS_THROUGH));
  181. modeSenseData.Srb.Length = sizeof(SCSI_PASS_THROUGH);
  182. modeSenseData.Srb.CdbLength = 6;
  183. modeSenseData.Srb.DataIn = SCSI_IOCTL_DATA_IN;
  184. modeSenseData.Srb.DataBufferOffset = offsetof(MODE_SENSE_PASS_THROUGH, DataBuffer);
  185. modeSenseData.Srb.SenseInfoOffset = offsetof(MODE_SENSE_PASS_THROUGH, SenseData);
  186. modeSenseData.Srb.DataTransferLength = 0xFF;
  187. modeSenseData.Srb.TimeOutValue = 10;
  188. ZeroMemory(&modeSenseData.Srb.Cdb, 16);
  189. modeSenseData.Srb.Cdb[0] = 0x1A;
  190. modeSenseData.Srb.Cdb[2] = 8;
  191. modeSenseData.Srb.Cdb[4] = 0xFF;
  192. if (!DeviceIoControl(driveHandle,
  193. IOCTL_SCSI_PASS_THROUGH_DIRECT,
  194. &modeSenseData,
  195. sizeof(modeSenseData),
  196. &modeSenseData,
  197. sizeof(modeSenseData),
  198. &bytesTransferred,
  199. FALSE)) {
  200. fprintf(stderr,"Mode sense failed. Error = %x\n",
  201. GetLastError() );
  202. return 4;
  203. }
  204. //
  205. // Display current values
  206. //
  207. pageData = modeSenseData.DataBuffer;
  208. (ULONG_PTR)pageData += 6 + pageData[3];
  209. cacheSettings = *pageData;
  210. if (displayAll || (physicalDrive == selectedDrive)) {
  211. printf(" %s ", (cacheSettings & 1) ? "Disabled" : "Enabled");
  212. printf(" %s", (cacheSettings & 4) ? "Enabled" : "Disabled");
  213. }
  214. if ((enableCache || disableCache) && (physicalDrive == selectedDrive)) {
  215. //
  216. // Build mode select - caching page.
  217. //
  218. // Clean out reserved areas of data buffer and update others
  219. //
  220. modeSenseData.Srb.SenseInfoLength = 32;
  221. pageData = modeSenseData.DataBuffer;
  222. modeSenseData.Srb.Cdb[4] = *pageData + 1;
  223. modeSenseData.Srb.Cdb[2] = 0x00;
  224. modeSenseData.Srb.Cdb[1] = 0x11;
  225. *pageData = 0;
  226. (ULONG_PTR)pageData += 4 + pageData[3];
  227. *pageData &= 0x3F;
  228. pageData++;
  229. pageData++;
  230. *pageData &= 0x07;
  231. modeSenseData.DataBuffer[5] = 0x00;
  232. modeSenseData.DataBuffer[6] = 0x00;
  233. modeSenseData.DataBuffer[7] = 0x00;
  234. modeSenseData.Srb.DataIn = SCSI_IOCTL_DATA_OUT;
  235. modeSenseData.Srb.DataTransferLength = modeSenseData.Srb.Cdb[4];
  236. if (disableCache) {
  237. //
  238. // Disable write cache
  239. //
  240. *pageData &= 0x03;
  241. } else {
  242. //
  243. // Enable the cache.
  244. //
  245. *pageData |= 0x04;
  246. }
  247. modeSenseData.Srb.Cdb[0] = 0x15;
  248. if (!DeviceIoControl(driveHandle,
  249. IOCTL_SCSI_PASS_THROUGH_DIRECT,
  250. &modeSenseData,
  251. sizeof(modeSenseData),
  252. &modeSenseData,
  253. sizeof(modeSenseData),
  254. &bytesTransferred,
  255. FALSE)) {
  256. fprintf(stderr,"Mode select failed. Error = %x\n",
  257. GetLastError() );
  258. } else {
  259. printf("\nWrite cache successfully %s\n", (enableCache ? "Enabled" : "Disabled"));
  260. }
  261. }
  262. CloseHandle(driveHandle );
  263. }
  264. physicalDrive++;
  265. }
  266. //
  267. // Get next device data.
  268. //
  269. inquiryData =
  270. (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + inquiryData->NextInquiryDataOffset);
  271. }
  272. }
  273. free (adapterInfo);
  274. CloseHandle(volumeHandle );
  275. portNumber++;
  276. }
  277. printf("\n");
  278. return 0;
  279. }
  280. VOID Usage(
  281. VOID
  282. ) {
  283. fprintf(stderr,"WCACHE: Usage wcache [-options] <PhysicalDrive Number>\n");
  284. fprintf(stderr,"\n");
  285. fprintf(stderr," where options are: e - Enable Write Cache for the <PhysicalDrive>\n");
  286. fprintf(stderr," d - Disable Write Cache for the <PhysicalDrive>\n");
  287. fprintf(stderr," dumps current values for all drives when invoked with no options\n");
  288. fprintf(stderr,"\n");
  289. }