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.

549 lines
17 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. spti.c
  5. Abstract:
  6. Win32 application that can communicate directly with SCSI devices via
  7. IOCTLs.
  8. Author:
  9. Environment:
  10. User mode.
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include <windows.h>
  15. #include <devioctl.h>
  16. #include <ntdddisk.h>
  17. #include <ntddscsi.h>
  18. #include <stdio.h>
  19. #include <stddef.h>
  20. #include <stdlib.h>
  21. #include "spti.h"
  22. VOID
  23. __cdecl
  24. main(
  25. int argc,
  26. char *argv[]
  27. )
  28. {
  29. BOOL status = 0;
  30. DWORD accessMode = 0, shareMode = 0;
  31. HANDLE fileHandle = NULL;
  32. IO_SCSI_CAPABILITIES capabilities;
  33. PUCHAR dataBuffer = NULL;
  34. SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
  35. SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptdwb;
  36. UCHAR buffer[2048];
  37. UCHAR string[25];
  38. ULONG length = 0,
  39. errorCode = 0,
  40. returned = 0,
  41. sectorSize = 512;
  42. if ((argc < 2) || (argc > 3)) {
  43. printf("Usage: %s <port-name> [-mode]\n", argv[0] );
  44. printf("Examples:\n");
  45. printf(" spti g: (open the SCSI disk class driver in SHARED READ/WRITE mode)\n");
  46. printf(" spti Scsi2: (open the SCSI miniport driver for the 3rd host adapter)\n");
  47. printf(" spti Tape0 w (open the SCSI tape class driver in SHARED WRITE mode)\n");
  48. printf(" spti i: c (open the SCSI CD-ROM class driver in SHARED READ mode)\n");
  49. return;
  50. }
  51. strcpy(string,"\\\\.\\");
  52. strcat(string,argv[1]);
  53. shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; // default
  54. accessMode = GENERIC_WRITE | GENERIC_READ; // default
  55. if (argc == 3) {
  56. if (!_stricmp("r", argv[2])) {
  57. shareMode = FILE_SHARE_READ;
  58. }
  59. if (!_stricmp("w", argv[2])) {
  60. shareMode = FILE_SHARE_WRITE;
  61. }
  62. if (!_stricmp("c",argv[2])) {
  63. shareMode = FILE_SHARE_READ;
  64. sectorSize = 2048;
  65. }
  66. }
  67. fileHandle = CreateFile(string,
  68. accessMode,
  69. shareMode,
  70. NULL,
  71. OPEN_EXISTING,
  72. 0,
  73. NULL);
  74. if (fileHandle == INVALID_HANDLE_VALUE) {
  75. printf("Error opening %s. Error: %d\n",
  76. argv[1], errorCode = GetLastError());
  77. PrintError(errorCode);
  78. return;
  79. }
  80. //
  81. // Get the inquiry data.
  82. //
  83. status = DeviceIoControl(fileHandle,
  84. IOCTL_SCSI_GET_INQUIRY_DATA,
  85. NULL,
  86. 0,
  87. buffer,
  88. sizeof(buffer),
  89. &returned,
  90. FALSE);
  91. if (!status) {
  92. printf( "Error reading inquiry data information; error was %d\n",
  93. errorCode = GetLastError());
  94. PrintError(errorCode);
  95. return;
  96. }
  97. printf("Read %Xh bytes of inquiry data Information.\n\n",returned);
  98. PrintInquiryData(buffer);
  99. //
  100. // Get the capabilities structure.
  101. //
  102. status = DeviceIoControl(fileHandle,
  103. IOCTL_SCSI_GET_CAPABILITIES,
  104. NULL,
  105. 0,
  106. &capabilities,
  107. sizeof(IO_SCSI_CAPABILITIES),
  108. &returned,
  109. FALSE);
  110. if (!status ) {
  111. printf( "Error in io control; error was %d\n",
  112. errorCode = GetLastError() );
  113. PrintError(errorCode);
  114. return;
  115. }
  116. printf(" ***** MODE SENSE -- return all pages *****\n");
  117. printf(" ***** with SenseInfo buffer *****\n\n");
  118. ZeroMemory(&sptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
  119. sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH);
  120. sptwb.spt.PathId = 0;
  121. sptwb.spt.TargetId = 1;
  122. sptwb.spt.Lun = 0;
  123. sptwb.spt.CdbLength = CDB6GENERIC_LENGTH;
  124. sptwb.spt.SenseInfoLength = 24;
  125. sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
  126. sptwb.spt.DataTransferLength = 192;
  127. sptwb.spt.TimeOutValue = 2;
  128. sptwb.spt.DataBufferOffset =
  129. offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
  130. sptwb.spt.SenseInfoOffset =
  131. offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
  132. sptwb.spt.Cdb[0] = SCSIOP_MODE_SENSE;
  133. sptwb.spt.Cdb[2] = MODE_SENSE_RETURN_ALL;
  134. sptwb.spt.Cdb[4] = 192;
  135. length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
  136. sptwb.spt.DataTransferLength;
  137. status = DeviceIoControl(fileHandle,
  138. IOCTL_SCSI_PASS_THROUGH,
  139. &sptwb,
  140. sizeof(SCSI_PASS_THROUGH),
  141. &sptwb,
  142. length,
  143. &returned,
  144. FALSE);
  145. PrintStatusResults(status,returned,&sptwb,length);
  146. printf(" ***** MODE SENSE -- return all pages *****\n");
  147. printf(" ***** without SenseInfo buffer *****\n\n");
  148. ZeroMemory(&sptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
  149. sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH);
  150. sptwb.spt.PathId = 0;
  151. sptwb.spt.TargetId = 1;
  152. sptwb.spt.Lun = 0;
  153. sptwb.spt.CdbLength = CDB6GENERIC_LENGTH;
  154. sptwb.spt.SenseInfoLength = 0;
  155. sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
  156. sptwb.spt.DataTransferLength = 192;
  157. sptwb.spt.TimeOutValue = 2;
  158. sptwb.spt.DataBufferOffset =
  159. offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
  160. sptwb.spt.SenseInfoOffset =
  161. offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
  162. sptwb.spt.Cdb[0] = SCSIOP_MODE_SENSE;
  163. sptwb.spt.Cdb[2] = MODE_SENSE_RETURN_ALL;
  164. sptwb.spt.Cdb[4] = 192;
  165. length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
  166. sptwb.spt.DataTransferLength;
  167. status = DeviceIoControl(fileHandle,
  168. IOCTL_SCSI_PASS_THROUGH,
  169. &sptwb,
  170. sizeof(SCSI_PASS_THROUGH),
  171. &sptwb,
  172. length,
  173. &returned,
  174. FALSE);
  175. PrintStatusResults(status,returned,&sptwb,length);
  176. printf(" ***** TEST UNIT READY *****\n");
  177. printf(" ***** DataBufferLength = 0 *****\n\n");
  178. ZeroMemory(&sptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
  179. sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH);
  180. sptwb.spt.PathId = 0;
  181. sptwb.spt.TargetId = 1;
  182. sptwb.spt.Lun = 0;
  183. sptwb.spt.CdbLength = CDB6GENERIC_LENGTH;
  184. sptwb.spt.SenseInfoLength = 24;
  185. sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
  186. sptwb.spt.DataTransferLength = 0;
  187. sptwb.spt.TimeOutValue = 2;
  188. sptwb.spt.DataBufferOffset =
  189. offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
  190. sptwb.spt.SenseInfoOffset =
  191. offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
  192. sptwb.spt.Cdb[0] = SCSIOP_TEST_UNIT_READY;
  193. length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
  194. status = DeviceIoControl(fileHandle,
  195. IOCTL_SCSI_PASS_THROUGH,
  196. &sptwb,
  197. sizeof(SCSI_PASS_THROUGH),
  198. &sptwb,
  199. length,
  200. &returned,
  201. FALSE);
  202. PrintStatusResults(status,returned,&sptwb,length);
  203. //
  204. // Do a mode sense with a bad data buffer offset. This should fail.
  205. //
  206. printf(" ***** MODE SENSE -- return all pages *****\n");
  207. printf(" ***** bad DataBufferOffset -- should fail *****\n\n");
  208. ZeroMemory(&sptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
  209. sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH);
  210. sptwb.spt.PathId = 0;
  211. sptwb.spt.TargetId = 1;
  212. sptwb.spt.Lun = 0;
  213. sptwb.spt.CdbLength = CDB6GENERIC_LENGTH;
  214. sptwb.spt.SenseInfoLength = 0;
  215. sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
  216. sptwb.spt.DataTransferLength = 192;
  217. sptwb.spt.TimeOutValue = 2;
  218. sptwb.spt.DataBufferOffset = 0;
  219. sptwb.spt.SenseInfoOffset =
  220. offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
  221. sptwb.spt.Cdb[0] = SCSIOP_MODE_SENSE;
  222. sptwb.spt.Cdb[2] = MODE_SENSE_RETURN_ALL;
  223. sptwb.spt.Cdb[4] = 192;
  224. length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
  225. sptwb.spt.DataTransferLength;
  226. status = DeviceIoControl(fileHandle,
  227. IOCTL_SCSI_PASS_THROUGH,
  228. &sptwb,
  229. sizeof(SCSI_PASS_THROUGH),
  230. &sptwb,
  231. length,
  232. &returned,
  233. FALSE);
  234. PrintStatusResults(status,returned,&sptwb,length);
  235. //
  236. // Get caching mode sense page.
  237. //
  238. printf(" ***** MODE SENSE *****\n");
  239. printf(" ***** return caching mode sense page *****\n\n");
  240. ZeroMemory(&sptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
  241. sptwb.spt.Length = sizeof(SCSI_PASS_THROUGH);
  242. sptwb.spt.PathId = 0;
  243. sptwb.spt.TargetId = 1;
  244. sptwb.spt.Lun = 0;
  245. sptwb.spt.CdbLength = CDB6GENERIC_LENGTH;
  246. sptwb.spt.SenseInfoLength = 24;
  247. sptwb.spt.DataIn = SCSI_IOCTL_DATA_IN;
  248. sptwb.spt.DataTransferLength = 192;
  249. sptwb.spt.TimeOutValue = 2;
  250. sptwb.spt.DataBufferOffset =
  251. offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
  252. sptwb.spt.SenseInfoOffset =
  253. offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
  254. sptwb.spt.Cdb[0] = SCSIOP_MODE_SENSE;
  255. sptwb.spt.Cdb[1] = 0x08; // target shall not return any block descriptors
  256. sptwb.spt.Cdb[2] = MODE_PAGE_CACHING;
  257. sptwb.spt.Cdb[4] = 192;
  258. length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) +
  259. sptwb.spt.DataTransferLength;
  260. status = DeviceIoControl(fileHandle,
  261. IOCTL_SCSI_PASS_THROUGH,
  262. &sptwb,
  263. sizeof(SCSI_PASS_THROUGH),
  264. &sptwb,
  265. length,
  266. &returned,
  267. FALSE);
  268. PrintStatusResults(status,returned,&sptwb,length);
  269. printf(" ***** WRITE DATA BUFFER operation *****\n");
  270. ZeroMemory(&sptdwb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER));
  271. dataBuffer = AllocateAlignedBuffer(sectorSize,capabilities.AlignmentMask);
  272. FillMemory(dataBuffer,sectorSize/2,'N');
  273. FillMemory(dataBuffer + sectorSize/2,sectorSize/2,'T');
  274. sptdwb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
  275. sptdwb.sptd.PathId = 0;
  276. sptdwb.sptd.TargetId = 1;
  277. sptdwb.sptd.Lun = 0;
  278. sptdwb.sptd.CdbLength = CDB10GENERIC_LENGTH;
  279. sptdwb.sptd.SenseInfoLength = 24;
  280. sptdwb.sptd.DataIn = SCSI_IOCTL_DATA_OUT;
  281. sptdwb.sptd.DataTransferLength = sectorSize;
  282. sptdwb.sptd.TimeOutValue = 2;
  283. sptdwb.sptd.DataBuffer = dataBuffer;
  284. sptdwb.sptd.SenseInfoOffset =
  285. offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf);
  286. sptdwb.sptd.Cdb[0] = SCSIOP_WRITE_DATA_BUFF;
  287. sptdwb.sptd.Cdb[1] = 2; // Data mode
  288. sptdwb.sptd.Cdb[7] = (UCHAR)(sectorSize >> 8); // Parameter List length
  289. sptdwb.sptd.Cdb[8] = 0;
  290. length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
  291. status = DeviceIoControl(fileHandle,
  292. IOCTL_SCSI_PASS_THROUGH_DIRECT,
  293. &sptdwb,
  294. length,
  295. &sptdwb,
  296. length,
  297. &returned,
  298. FALSE);
  299. PrintStatusResults(status,returned,
  300. (PSCSI_PASS_THROUGH_WITH_BUFFERS)&sptdwb,length);
  301. if ((sptdwb.sptd.ScsiStatus == 0) && (status != 0)) {
  302. PrintDataBuffer(dataBuffer,sptdwb.sptd.DataTransferLength);
  303. }
  304. printf(" ***** READ DATA BUFFER operation *****\n");
  305. ZeroMemory(&sptdwb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER));
  306. ZeroMemory(dataBuffer,sectorSize);
  307. sptdwb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
  308. sptdwb.sptd.PathId = 0;
  309. sptdwb.sptd.TargetId = 1;
  310. sptdwb.sptd.Lun = 0;
  311. sptdwb.sptd.CdbLength = CDB10GENERIC_LENGTH;
  312. sptdwb.sptd.DataIn = SCSI_IOCTL_DATA_IN;
  313. sptdwb.sptd.SenseInfoLength = 24;
  314. sptdwb.sptd.DataTransferLength = sectorSize;
  315. sptdwb.sptd.TimeOutValue = 2;
  316. sptdwb.sptd.DataBuffer = dataBuffer;
  317. sptdwb.sptd.SenseInfoOffset =
  318. offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf);
  319. sptdwb.sptd.Cdb[0] = SCSIOP_READ_DATA_BUFF;
  320. sptdwb.sptd.Cdb[1] = 2; // Data mode
  321. sptdwb.sptd.Cdb[7] = (UCHAR)(sectorSize >> 8); // Parameter List length
  322. sptdwb.sptd.Cdb[8] = 0;
  323. length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
  324. status = DeviceIoControl(fileHandle,
  325. IOCTL_SCSI_PASS_THROUGH_DIRECT,
  326. &sptdwb,
  327. length,
  328. &sptdwb,
  329. length,
  330. &returned,
  331. FALSE);
  332. PrintStatusResults(status,returned,
  333. (PSCSI_PASS_THROUGH_WITH_BUFFERS)&sptdwb,length);
  334. if ((sptdwb.sptd.ScsiStatus == 0) && (status != 0)) {
  335. PrintDataBuffer(dataBuffer,sptdwb.sptd.DataTransferLength);
  336. }
  337. }
  338. VOID
  339. PrintError(ULONG ErrorCode)
  340. {
  341. UCHAR errorBuffer[80];
  342. ULONG count;
  343. count = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  344. NULL,
  345. ErrorCode,
  346. 0,
  347. errorBuffer,
  348. sizeof(errorBuffer),
  349. NULL
  350. );
  351. if (count != 0) {
  352. printf("%s\n", errorBuffer);
  353. } else {
  354. printf("Format message failed. Error: %d\n", GetLastError());
  355. }
  356. }
  357. VOID
  358. PrintDataBuffer(PUCHAR DataBuffer, ULONG BufferLength)
  359. {
  360. ULONG Cnt;
  361. printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
  362. printf(" ---------------------------------------------------------------\n");
  363. for (Cnt = 0; Cnt < BufferLength; Cnt++) {
  364. if ((Cnt) % 16 == 0) {
  365. printf(" %03X ",Cnt);
  366. }
  367. printf("%02X ", DataBuffer[Cnt]);
  368. if ((Cnt+1) % 8 == 0) {
  369. printf(" ");
  370. }
  371. if ((Cnt+1) % 16 == 0) {
  372. printf("\n");
  373. }
  374. }
  375. printf("\n\n");
  376. }
  377. VOID
  378. PrintInquiryData(PCHAR DataBuffer)
  379. {
  380. PSCSI_ADAPTER_BUS_INFO adapterInfo;
  381. PSCSI_INQUIRY_DATA inquiryData;
  382. ULONG i,
  383. j;
  384. adapterInfo = (PSCSI_ADAPTER_BUS_INFO) DataBuffer;
  385. printf("Bus\n");
  386. printf("Num TID LUN Claimed String Inquiry Header\n");
  387. printf("--- --- --- ------- ---------------------------- -----------------------\n");
  388. for (i = 0; i < adapterInfo->NumberOfBuses; i++) {
  389. inquiryData = (PSCSI_INQUIRY_DATA) (DataBuffer +
  390. adapterInfo->BusData[i].InquiryDataOffset);
  391. while (adapterInfo->BusData[i].InquiryDataOffset) {
  392. printf(" %d %d %3d %s %.28s ",
  393. i,
  394. inquiryData->TargetId,
  395. inquiryData->Lun,
  396. (inquiryData->DeviceClaimed) ? "Y" : "N",
  397. &inquiryData->InquiryData[8]);
  398. for (j = 0; j < 8; j++) {
  399. printf("%02X ", inquiryData->InquiryData[j]);
  400. }
  401. printf("\n");
  402. if (inquiryData->NextInquiryDataOffset == 0) {
  403. break;
  404. }
  405. inquiryData = (PSCSI_INQUIRY_DATA) (DataBuffer +
  406. inquiryData->NextInquiryDataOffset);
  407. }
  408. }
  409. printf("\n\n");
  410. }
  411. PUCHAR
  412. AllocateAlignedBuffer(ULONG size, ULONG Align)
  413. {
  414. PUCHAR ptr;
  415. UINT_PTR Align64 = (UINT_PTR)Align;
  416. if (!Align) {
  417. ptr = malloc(size);
  418. }
  419. else {
  420. ptr = malloc(size + Align);
  421. ptr = (PUCHAR)(((UINT_PTR)ptr + Align64) & ~Align64);
  422. }
  423. if (ptr == NULL) {
  424. printf("Memory allocation error. Terminating program\n");
  425. exit(1);
  426. }
  427. else {
  428. return ptr;
  429. }
  430. }
  431. VOID
  432. PrintStatusResults(
  433. BOOL status,DWORD returned,PSCSI_PASS_THROUGH_WITH_BUFFERS psptwb,
  434. ULONG length)
  435. {
  436. ULONG errorCode;
  437. if (!status ) {
  438. printf( "Error: %d ",
  439. errorCode = GetLastError() );
  440. PrintError(errorCode);
  441. return;
  442. }
  443. if (psptwb->spt.ScsiStatus) {
  444. PrintSenseInfo(psptwb);
  445. return;
  446. }
  447. else {
  448. printf("Scsi status: %02Xh, Bytes returned: %Xh, ",
  449. psptwb->spt.ScsiStatus,returned);
  450. printf("Data buffer length: %Xh\n\n\n",
  451. psptwb->spt.DataTransferLength);
  452. PrintDataBuffer((PUCHAR)psptwb,length);
  453. }
  454. }
  455. VOID
  456. PrintSenseInfo(PSCSI_PASS_THROUGH_WITH_BUFFERS psptwb)
  457. {
  458. int i;
  459. printf("Scsi status: %02Xh\n\n",psptwb->spt.ScsiStatus);
  460. if (psptwb->spt.SenseInfoLength == 0) {
  461. return;
  462. }
  463. printf("Sense Info -- consult SCSI spec for details\n");
  464. printf("-------------------------------------------------------------\n");
  465. for (i=0; i < psptwb->spt.SenseInfoLength; i++) {
  466. printf("%02X ",psptwb->ucSenseBuf[i]);
  467. }
  468. printf("\n\n");
  469. }