Leaked source code of windows server 2003
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.

2969 lines
88 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. cdp.c
  5. Abstract:
  6. A user mode app that allows simple commands to be sent to a
  7. selected scsi device.
  8. Environment:
  9. User mode only
  10. Revision History:
  11. 03-26-96 : Created
  12. --*/
  13. //
  14. // this module may be compiled at warning level 4 with the following
  15. // warnings disabled:
  16. //
  17. #pragma warning(disable:4200) // array[0]
  18. #pragma warning(disable:4201) // nameless struct/unions
  19. #pragma warning(disable:4214) // bit fields other than int
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <assert.h>
  24. #include <windows.h>
  25. #include <devioctl.h>
  26. #include <ntddscsi.h>
  27. #include <ntddstor.h>
  28. #include <ntddcdrm.h>
  29. #include <ntdddisk.h>
  30. #include <ntddcdvd.h>
  31. #include <ntddmmc.h>
  32. #define _NTSRB_ // to keep srb.h from being included
  33. #include <scsi.h>
  34. #include "sptlib.h"
  35. #include "cmdhelp.h"
  36. #define MAX_IOCTL_INPUT_SIZE 0x040
  37. #define MAX_IOCTL_OUTPUT_SIZE 0x930 // IOCTL_CDROM_RAW_READ is this large
  38. #define MAX_IOCTL_BUFFER_SIZE (max(MAX_IOCTL_INPUT_SIZE, MAX_IOCTL_OUTPUT_SIZE))
  39. // read no more than 64k at a time -- lots of things just don't support it.
  40. #define MAX_READ_SIZE (64 * 1024)
  41. #define CDRW_WRITE_SECTORS (32)
  42. #define CDRW_WRITE_BYTES (CDRW_WRITE_SECTORS*2048)
  43. ////////////////////////////////////////////////////////////////////////////////
  44. #define MSF_TO_LBA(Minutes,Seconds,Frames) \
  45. (ULONG)((60 * 75 * (Minutes) ) + (75 * (Seconds)) + ((Frames) - 150))
  46. #define LBA_TO_MSF(Lba, Minutes, Seconds, Frames) \
  47. { \
  48. (Minutes) = (UCHAR)( ((Lba) + 150) / (60 * 75) ); \
  49. (Seconds) = (UCHAR)((((Lba) + 150) % (60 * 75)) / 75); \
  50. (Frames) = (UCHAR)((((Lba) + 150) % (60 * 75)) % 75); \
  51. }
  52. ////////////////////////////////////////////////////////////////////////////////
  53. #ifdef DBG
  54. #define dbg(x) x
  55. #define HELP_ME() fprintf(stderr, "Reached line %4d\n", __LINE__)
  56. #else
  57. #define dbg(x) /* x */
  58. #define HELP_ME() /* printf("Reached line %4d\n", __LINE__) */
  59. #endif
  60. #define ARGUMENT_USED(x) (x == NULL)
  61. typedef struct {
  62. char *Name;
  63. char *Description;
  64. DWORD (*Function)(HANDLE device, int argc, char *argv[]);
  65. } COMMAND;
  66. typedef struct {
  67. SCSI_PASS_THROUGH Spt;
  68. char SenseInfoBuffer[18];
  69. char DataBuffer[0]; // Allocate buffer space
  70. // after this
  71. } SPT_WITH_BUFFERS, *PSPT_WITH_BUFFERS;
  72. DWORD WaitForReadDiscInfoCommand(HANDLE device, int argc, char *argv[]);
  73. DWORD ShowMrwProgressCommand(HANDLE device, int argc, char *argv[]);
  74. DWORD FormatMrwCommand(HANDLE device, int argc, char *argv[]);
  75. DWORD DvdReadStructure(HANDLE device, int argc, char *argv[]);
  76. DWORD StartStopCommand(HANDLE device, int argc, char *argv[]);
  77. DWORD TestCommand(HANDLE device, int argc, char *argv[]);
  78. DWORD ReadTOCCommand(HANDLE device, int argc, char *argv[]);
  79. DWORD ReadTOCExCommand(HANDLE device, int argc, char *argv[]);
  80. DWORD ReadCdTextCommand(HANDLE device, int argc, char *argv[]);
  81. DWORD PlayCommand(HANDLE device, int argc, char *argv[]);
  82. DWORD PauseResumeCommand(HANDLE device, int argc, char *argv[]);
  83. DWORD SendCommand(HANDLE device, int argc, char *argv[]);
  84. DWORD IoctlCommand(HANDLE device, int argc, char *argv[]);
  85. DWORD ListCommand(HANDLE device, int argc, char *argv[]);
  86. DWORD DiskGetPartitionInfo( HANDLE device, int argc, char *argv[]);
  87. DWORD FormatErrorCommand(HANDLE device, int argc, char *argv[]);
  88. DWORD ImageDiskCommand(HANDLE device, int argc, char *argv[]);
  89. DWORD MrwInitTestPatternCommand(HANDLE device, int argc, char *argv[]);
  90. DWORD MrwInitGaaFileSystem(HANDLE device, int argc, char *argv[]);
  91. //
  92. // List of commands
  93. // all command names are case sensitive
  94. // arguments are passed into command routines
  95. // list must be terminated with NULL command
  96. // command will not be listed in help if description == NULL
  97. //
  98. COMMAND CommandArray[] = {
  99. {"cdtext", "read cd text info ", ReadCdTextCommand },
  100. {"dvdstruct", "Reads a dvd structure from the drive ", DvdReadStructure },
  101. {"eject", "spins down and ejects the specified drive ", StartStopCommand },
  102. {"error", "provides the error text for a winerror ", FormatErrorCommand },
  103. {"help", "help for all commands ", ListCommand },
  104. {"ioctl", "ioctl [quoted hex input] [output] sends an arbitrary ioctl", IoctlCommand },
  105. {"image", "<file> images the storage device into the file ", ImageDiskCommand },
  106. {"load", "loads the specified drive ", StartStopCommand },
  107. {"mrwformat", NULL , FormatMrwCommand },
  108. {"mrwgaa", NULL , MrwInitGaaFileSystem },
  109. {"mrwprogress", NULL , ShowMrwProgressCommand },
  110. {"mrwtest", NULL , MrwInitTestPatternCommand },
  111. {"partition", "reads partition information ", DiskGetPartitionInfo },
  112. {"pause", "pauses audio playback ", PauseResumeCommand },
  113. {"play", "[start track [end track]] plays audio tracks ", PlayCommand },
  114. {"resume", "resumes paused audio playback ", PauseResumeCommand },
  115. {"send", NULL , SendCommand },
  116. {"start", "spins up the drive ", StartStopCommand },
  117. {"stop", "spinds down the drive ", StartStopCommand },
  118. {"test", NULL , TestCommand },
  119. {"toc", "prints the table of contents ", ReadTOCCommand },
  120. {"tocex", NULL , ReadTOCExCommand },
  121. {"wait", "Waits for the READ_DISC_INFO command to work ", WaitForReadDiscInfoCommand},
  122. // {"tocex", "[Format [Session/Track [MSF]]] Read toc/cdtext/atip/etc.", ReadTOCExCommand},
  123. {NULL, NULL, NULL}
  124. };
  125. #define STATUS_SUCCESS 0
  126. VOID PrintChar( IN UCHAR Char ) {
  127. if ( (Char >= 0x21) && (Char <= 0x7E) ) {
  128. printf("%c", Char);
  129. } else {
  130. printf("%c", '.');
  131. }
  132. }
  133. VOID UpdatePercentageDisplay(IN ULONG Numerator, IN ULONG Denominator) {
  134. ULONG percent;
  135. ULONG i;
  136. if (Numerator > Denominator) {
  137. return;
  138. }
  139. // NOTE: Overflow possibility exists for large numerators.
  140. percent = (Numerator * 100) / Denominator;
  141. for (i=0;i<90;i++) {
  142. putchar('\b');
  143. }
  144. printf("Complete: ");
  145. // each block is 2%
  146. // ----=----1----=----2----=----3----=----4----=----5----=----6----=----7----=----8
  147. // Complete: �.....................
  148. for (i=1; i<100; i+=2) {
  149. if (i < percent) {
  150. putchar(178);
  151. } else if (i == percent) {
  152. putchar(177);
  153. } else {
  154. putchar(176);
  155. }
  156. }
  157. printf(" %d%% (%8x/%8x)", percent, Numerator, Denominator);
  158. }
  159. int __cdecl main(int argc, char *argv[])
  160. {
  161. int i = 0;
  162. HANDLE h;
  163. char buffer[80]; // ~50 chars for mountvol names
  164. if(argc < 3) {
  165. printf("Usage: cdp <drive> <command> [parameters]\n");
  166. printf("possible commands: \n");
  167. ListCommand(NULL, argc, argv);
  168. printf("\n");
  169. return -1;
  170. }
  171. sprintf(buffer, "\\\\.\\%s", argv[1]);
  172. dbg(printf("Sending command %s to drive %s\n", argv[2], buffer));
  173. h = CreateFile(buffer,
  174. GENERIC_READ | GENERIC_WRITE,
  175. FILE_SHARE_READ | FILE_SHARE_WRITE,
  176. NULL,
  177. OPEN_EXISTING,
  178. FILE_ATTRIBUTE_NORMAL,
  179. NULL);
  180. if(h == INVALID_HANDLE_VALUE) {
  181. printf("Error %d opening device %s\n", GetLastError(), buffer);
  182. return -2;
  183. }
  184. //
  185. // Iterate through the command array and find the correct function to
  186. // call.
  187. //
  188. while(CommandArray[i].Name != NULL) {
  189. if(strcmp(argv[2], CommandArray[i].Name) == 0) {
  190. (CommandArray[i].Function)(h, (argc - 2), &(argv[2]));
  191. break;
  192. }
  193. i++;
  194. }
  195. if(CommandArray[i].Name == NULL) {
  196. printf("Unknown command %s\n", argv[2]);
  197. }
  198. CloseHandle(h);
  199. return 0;
  200. }
  201. //
  202. // take a PVOID as input -- it's cleaner throughout
  203. //
  204. VOID
  205. PrintBuffer(
  206. IN PVOID InputBuffer,
  207. IN SIZE_T Size
  208. )
  209. {
  210. DWORD offset = 0;
  211. PUCHAR buffer = InputBuffer;
  212. while (Size >= 0x10) {
  213. DWORD i;
  214. printf( "%08x:"
  215. " %02x %02x %02x %02x %02x %02x %02x %02x"
  216. " %02x %02x %02x %02x %02x %02x %02x %02x"
  217. " ",
  218. offset,
  219. *(buffer + 0), *(buffer + 1), *(buffer + 2), *(buffer + 3),
  220. *(buffer + 4), *(buffer + 5), *(buffer + 6), *(buffer + 7),
  221. *(buffer + 8), *(buffer + 9), *(buffer + 10), *(buffer + 11),
  222. *(buffer + 12), *(buffer + 13), *(buffer + 14), *(buffer + 15)
  223. );
  224. for (i=0; i < 0x10; i++) {
  225. PrintChar(*(buffer+i));
  226. }
  227. printf("\n");
  228. Size -= 0x10;
  229. offset += 0x10;
  230. buffer += 0x10;
  231. }
  232. if (Size != 0) {
  233. DWORD i;
  234. printf("%08x:", offset);
  235. //
  236. // print the hex values
  237. //
  238. for (i=0; i<Size; i++) {
  239. if ((i%8)==0) {
  240. printf(" "); // extra space every eight chars
  241. }
  242. printf(" %02x", *(buffer+i));
  243. }
  244. //
  245. // fill in the blanks
  246. //
  247. for (; i < 0x10; i++) {
  248. printf(" ");
  249. }
  250. printf(" ");
  251. //
  252. // print the ascii
  253. //
  254. for (i=0; i<Size; i++) {
  255. PrintChar(*(buffer+i));
  256. }
  257. printf("\n");
  258. }
  259. return;
  260. }
  261. DWORD StartStopCommand(HANDLE device, int argc, char *argv[])
  262. /*++
  263. Routine Description:
  264. Sends down a startstop command.
  265. Arguments:
  266. device - a file handle to send the ioctl to
  267. argc - the number of additional arguments. should be zero
  268. argv[0] - "eject", "load", "start" or "stop"
  269. Return Value:
  270. STATUS_SUCCESS if successful
  271. The value of GetLastError() from the point of failure
  272. --*/
  273. {
  274. DWORD errorValue = STATUS_SUCCESS;
  275. DWORD bufferSize;
  276. CDB cdb;
  277. UCHAR loadEject = 0;
  278. UCHAR start = 0;
  279. UNREFERENCED_PARAMETER(argc);
  280. if(strcmp("eject", argv[0]) == 0) {
  281. loadEject = 1;
  282. start = 0;
  283. } else if(strcmp("load", argv[0]) == 0) {
  284. loadEject = 1;
  285. start = 1;
  286. } else if(strcmp("start", argv[0]) == 0) {
  287. loadEject = 0;
  288. start = 1;
  289. } else if(strcmp("stop", argv[0]) == 0) {
  290. loadEject = 0;
  291. start = 0;
  292. } else {
  293. assert(0);
  294. }
  295. memset(&cdb, 0, sizeof(CDB));
  296. cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  297. cdb.START_STOP.Immediate = 0;
  298. cdb.START_STOP.Start = start;
  299. cdb.START_STOP.LoadEject = loadEject;
  300. bufferSize = 0;
  301. if (!SptSendCdbToDevice(device, &cdb, 6, NULL, &bufferSize, FALSE)) {
  302. errorValue = GetLastError();
  303. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  304. }
  305. return errorValue;
  306. }
  307. DWORD ReadCdTextCommand(HANDLE device, int argc, char *argv[])
  308. /*++
  309. Routine Description:
  310. Reads and prints out the cdrom's table of contents,
  311. ATIP, PMA, or CDTEXT data
  312. Arguments:
  313. device - a file handle to send the ioctl to
  314. argc - the number of additional arguments. (1-4 is valid)
  315. argv - the additional arguments
  316. Return Value:
  317. STATUS_SUCCESS if successful
  318. The value of GetLastError() from the point of failure
  319. --*/
  320. {
  321. DWORD returned;
  322. LONG bufferSize = 4; // to get the header
  323. DWORD i;
  324. CDROM_READ_TOC_EX params;
  325. BOOLEAN isText = TRUE;
  326. PUCHAR buffer = NULL;
  327. UNREFERENCED_PARAMETER(argv);
  328. if (argc > 3) {
  329. printf("Too many args\n");
  330. return 1;
  331. }
  332. //
  333. // set defaults - FORMAT_TOC, 0, 0
  334. //
  335. RtlZeroMemory(&params, sizeof(CDROM_READ_TOC_EX));
  336. params.Msf = 0;
  337. params.SessionTrack = 1;
  338. params.Format = 5;
  339. if(argc > 1) params.SessionTrack = (char)atoi(argv[1]);
  340. printf("Session = 0x%x\n", params.SessionTrack);
  341. for (i = 0; i < 2; i++) {
  342. if (i != 0) {
  343. LocalFree(buffer);
  344. }
  345. buffer = LocalAlloc(LPTR, bufferSize);
  346. if (buffer == NULL) {
  347. printf("No Memory %d\n", __LINE__);
  348. return 1;
  349. }
  350. returned = 0;
  351. if (!DeviceIoControl(device,
  352. IOCTL_CDROM_READ_TOC_EX,
  353. &params,
  354. sizeof(CDROM_READ_TOC_EX),
  355. buffer,
  356. bufferSize,
  357. &returned,
  358. FALSE)) {
  359. DWORD errorValue = GetLastError();
  360. LocalFree(buffer);
  361. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  362. return errorValue;
  363. }
  364. bufferSize = (buffer[0] << 8) | (buffer[1]);
  365. bufferSize += 2;
  366. }
  367. if (argc > 2) {
  368. //
  369. // this block is for debugging the various idiosynchracies found
  370. // in CD-TEXT discs. Many discs encode multiple tracks in a single
  371. // block. ie. if one song is called "ABBA", the second "Baby", and
  372. // the third "Longer Name", the Text portion would be encoded as:
  373. // Track 1 'ABBA\0Baby\0Lo'
  374. // Track 3 'nger Name\0'
  375. // This effectively "skips" the name available for Track 2 ?!
  376. // How to work around this....
  377. //
  378. {
  379. HANDLE h;
  380. DWORD temp;
  381. h = CreateFile("OUTPUT.TXT",
  382. GENERIC_WRITE,
  383. 0,
  384. NULL,
  385. CREATE_NEW,
  386. FILE_ATTRIBUTE_NORMAL,
  387. NULL);
  388. if(h == INVALID_HANDLE_VALUE) {
  389. printf("Error %d creating new file \"OUTPUT.TXT\"\n",
  390. GetLastError());
  391. LocalFree(buffer);
  392. return GetLastError();
  393. }
  394. if (!WriteFile(h, buffer, bufferSize, &temp, NULL)) {
  395. printf("Error %d writing file to disk\n", GetLastError());
  396. LocalFree(buffer);
  397. return GetLastError();
  398. }
  399. // continue to output to screen....
  400. }
  401. for (i=0;
  402. FIELD_OFFSET(CDROM_TOC_CD_TEXT_DATA, Descriptors[i+1]) < bufferSize;
  403. i++) {
  404. PCDROM_TOC_CD_TEXT_DATA_BLOCK block;
  405. PCDROM_TOC_CD_TEXT_DATA_BLOCK prevBlock;
  406. DWORD j;
  407. block = (PCDROM_TOC_CD_TEXT_DATA_BLOCK)(buffer + 4);
  408. block += i;
  409. prevBlock = block - 1;
  410. if (block->Unicode) {
  411. continue; // ignore unicode -- this is examplary only
  412. }
  413. for (j=0;j<12;j++) {
  414. // replace NULLs with *, Tabs with hashes
  415. if (block->Text[j] == 0) block->Text[j] = '*';
  416. if (block->Text[j] == 9) block->Text[j] = '#';
  417. }
  418. if (block->SequenceNumber > 0x2b &&
  419. block->SequenceNumber < 0x32) {
  420. UCHAR text[13];
  421. RtlZeroMemory(text, 13);
  422. RtlCopyMemory(text, block->Text, 12);
  423. printf("PackType %02x TrackNo %02x ExtensionFlag %d\n"
  424. "Sequence Number %02x CharacterPosition %02x\n"
  425. "Text: \"%s\"\n\n",
  426. block->PackType,
  427. block->TrackNumber,
  428. block->ExtensionFlag,
  429. block->SequenceNumber,
  430. block->CharacterPosition,
  431. text
  432. );
  433. }
  434. }
  435. printf("\n");
  436. } else {
  437. for (i=0;
  438. FIELD_OFFSET(CDROM_TOC_CD_TEXT_DATA, Descriptors[i+1]) < bufferSize;
  439. i++) {
  440. PCDROM_TOC_CD_TEXT_DATA_BLOCK block;
  441. PCDROM_TOC_CD_TEXT_DATA_BLOCK prevBlock;
  442. DWORD j;
  443. block = (PCDROM_TOC_CD_TEXT_DATA_BLOCK)(buffer + 4);
  444. block += i;
  445. prevBlock = block - 1;
  446. if (block->Unicode) {
  447. continue; // ignore unicode -- this is examplary only
  448. }
  449. //
  450. // set the CRC's to zero so we can hack the data inside to more
  451. // easily handle wierd cases....
  452. //
  453. block->CRC[0] = block->CRC[1] = 0;
  454. //
  455. // set the tab characters to '*' for now.
  456. // i have not yet seen one using this "feature" of cd-text
  457. //
  458. for (j=0;j<12;j++) {
  459. if (block->Text[j] == 9) {
  460. block->Text[j] = '*';
  461. }
  462. }
  463. if ((i != 0) &&
  464. (prevBlock->PackType == block->PackType) &&
  465. (prevBlock->TrackNumber == block->TrackNumber)
  466. ) {
  467. // continuation of previous setting.
  468. } else
  469. if ((!(block->ExtensionFlag)) &&
  470. (block->TrackNumber != 0) &&
  471. (block->TrackNumber == (prevBlock->TrackNumber + 2)) &&
  472. (block->PackType == prevBlock->PackType)
  473. ) {
  474. UCHAR *goodText;
  475. UCHAR *midText;
  476. // printf("\"\n\"HACK DETECTED! (seq %x & %x)",
  477. // prevBlock->SequenceNumber, block->SequenceNumber);
  478. // hack for when prevBlock has two names encoded....
  479. // the TrackNumber/PackType are already equal, just
  480. // move the middle string to the start.
  481. midText = prevBlock->Text;
  482. while (*midText != '\0') {
  483. midText++;
  484. }
  485. midText++;
  486. goodText = prevBlock->Text;
  487. while (*midText != '\0') {
  488. *goodText++ = *midText++;
  489. }
  490. *goodText = '\0';
  491. // printf(" %s", prevBlock->Text);
  492. prevBlock->CharacterPosition = 0;
  493. prevBlock->TrackNumber++;
  494. prevBlock->ExtensionFlag = 1;
  495. i-= 2;
  496. continue; // re-run the previous, modified block
  497. } else {
  498. printf("\"\n");
  499. switch (block->PackType) {
  500. case CDROM_CD_TEXT_PACK_ALBUM_NAME: {
  501. if (block->TrackNumber == 0) {
  502. printf("%-12s", "Album Name");
  503. printf(" : \"");
  504. } else {
  505. printf("%-12s", "Track Name");
  506. printf("(%02d): \"", block->TrackNumber);
  507. }
  508. break;
  509. }
  510. case CDROM_CD_TEXT_PACK_PERFORMER: {
  511. printf("%-12s", "Performer");
  512. printf("(%02d): \"", block->TrackNumber);
  513. break;
  514. }
  515. case CDROM_CD_TEXT_PACK_SONGWRITER: {
  516. printf("%-12s", "Songwriter");
  517. printf("(%02d): \"", block->TrackNumber);
  518. break;
  519. }
  520. case CDROM_CD_TEXT_PACK_COMPOSER: {
  521. printf("%-12s", "Composer");
  522. printf("(%02d): \"", block->TrackNumber);
  523. break;
  524. }
  525. case CDROM_CD_TEXT_PACK_ARRANGER: {
  526. printf("%-12s", "Arranger");
  527. printf("(%02d): \"", block->TrackNumber);
  528. break;
  529. }
  530. case CDROM_CD_TEXT_PACK_MESSAGES: {
  531. printf("%-12s", "Messages");
  532. printf("(%02d): \"", block->TrackNumber);
  533. break;
  534. }
  535. case CDROM_CD_TEXT_PACK_DISC_ID: {
  536. printf("%-12s", "Disc ID");
  537. printf(" : \"");
  538. break;
  539. }
  540. case CDROM_CD_TEXT_PACK_GENRE: {
  541. printf("%-12s", "Genre");
  542. printf("(%02d): \"", block->TrackNumber);
  543. break;
  544. }
  545. case CDROM_CD_TEXT_PACK_UPC_EAN: {
  546. if (block->TrackNumber == 0) {
  547. printf("%-12s", "UPC/EAN");
  548. printf(" : \"");
  549. } else {
  550. printf("%-12s", "ISRC");
  551. printf("(%02d): \"", block->TrackNumber);
  552. }
  553. break;
  554. }
  555. case CDROM_CD_TEXT_PACK_TOC_INFO:
  556. case CDROM_CD_TEXT_PACK_TOC_INFO2:
  557. case CDROM_CD_TEXT_PACK_SIZE_INFO:
  558. default: {
  559. isText = FALSE;
  560. printf("Unknown type 0x%x: \"", block->PackType);
  561. }
  562. } // end switch
  563. //
  564. // have to print previous block's info, if available
  565. //
  566. if (isText && block->CharacterPosition != 0) {
  567. UCHAR text[13];
  568. RtlZeroMemory(text, sizeof(text));
  569. RtlCopyMemory(text,
  570. prevBlock->Text + 12 - block->CharacterPosition,
  571. block->CharacterPosition * sizeof(UCHAR));
  572. printf("%s", text);
  573. }
  574. } // end continuation case
  575. if (isText) {
  576. UCHAR text[13];
  577. RtlZeroMemory(text, sizeof(text));
  578. RtlCopyMemory(text, block->Text, 12);
  579. printf("%s", text);
  580. }
  581. } // end loop through all blocks
  582. printf("\n");
  583. } // end normal printout case
  584. return 0;
  585. }
  586. DWORD ReadTOCExCommand(HANDLE device, int argc, char *argv[])
  587. /*++
  588. Routine Description:
  589. Reads and prints out the cdrom's table of contents,
  590. ATIP, PMA, or CDTEXT data
  591. Arguments:
  592. device - a file handle to send the ioctl to
  593. argc - the number of additional arguments. (1-4 is valid)
  594. argv - the additional arguments
  595. Return Value:
  596. STATUS_SUCCESS if successful
  597. The value of GetLastError() from the point of failure
  598. --*/
  599. {
  600. DWORD returned;
  601. DWORD bufferSize = 4; // to get the header
  602. DWORD i;
  603. CDROM_READ_TOC_EX params;
  604. UNREFERENCED_PARAMETER(argv);
  605. if (argc > 4) {
  606. printf("Too many args\n");
  607. return 1;
  608. }
  609. //
  610. // set defaults - FORMAT_TOC, 0, 0
  611. //
  612. RtlZeroMemory(&params, sizeof(CDROM_READ_TOC_EX));
  613. if(argc > 3) params.Msf = (char)atoi(argv[3]);
  614. if(argc > 2) params.SessionTrack = (char)atoi(argv[2]);
  615. if(argc > 1) params.Format = (char)atoi(argv[1]);
  616. printf("Params.Format = 0x%x\n", params.Format);
  617. printf("Params.SessionTrack = 0x%x\n", params.SessionTrack);
  618. printf("Params.MSF = 0x%x\n", params.Msf);
  619. for (i = 0; i < 2; i++) {
  620. PUCHAR buffer = LocalAlloc(LPTR, bufferSize);
  621. if (buffer == NULL) {
  622. printf("No Memory %d\n", __LINE__);
  623. return 1;
  624. }
  625. returned = 0;
  626. if (!DeviceIoControl(device,
  627. IOCTL_CDROM_READ_TOC_EX,
  628. &params,
  629. sizeof(CDROM_READ_TOC_EX),
  630. buffer,
  631. bufferSize,
  632. &returned,
  633. FALSE)) {
  634. DWORD errorValue = GetLastError();
  635. LocalFree(buffer);
  636. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  637. return errorValue;
  638. }
  639. printf("Successfully got %x bytes:\n", returned);
  640. PrintBuffer(buffer, returned);
  641. bufferSize = (buffer[0] << 8) | (buffer[1]);
  642. LocalFree(buffer);
  643. bufferSize += 2;
  644. printf("Now getting %x bytes:\n", bufferSize);
  645. }
  646. return 0;
  647. }
  648. DWORD ReadTOCCommand(HANDLE device, int argc, char *argv[])
  649. /*++
  650. Routine Description:
  651. Reads and prints out the cdrom's table of contents
  652. Arguments:
  653. device - a file handle to send the ioctl to
  654. argc - the number of additional arguments. should be zero
  655. argv - the additional arguments
  656. Return Value:
  657. STATUS_SUCCESS if successful
  658. The value of GetLastError() from the point of failure
  659. --*/
  660. {
  661. DWORD errorValue = STATUS_SUCCESS;
  662. DWORD returned = 0;
  663. CDB cdb;
  664. CDROM_TOC toc;
  665. int numTracks, i;
  666. PTRACK_DATA track;
  667. UNREFERENCED_PARAMETER(argc);
  668. UNREFERENCED_PARAMETER(argv);
  669. printf("Reading Table of Contents\n");
  670. //
  671. // Get the 4 byte TOC header
  672. //
  673. returned = FIELD_OFFSET(CDROM_TOC, TrackData[0]);
  674. memset(&cdb, 0, sizeof(CDB));
  675. cdb.READ_TOC.OperationCode = SCSIOP_READ_TOC;
  676. cdb.READ_TOC.Msf = 0;
  677. cdb.READ_TOC.StartingTrack = 0;
  678. cdb.READ_TOC.AllocationLength[0] = (UCHAR)(returned >> 8);
  679. cdb.READ_TOC.AllocationLength[1] = (UCHAR)(returned & 0xff);
  680. if (!SptSendCdbToDevice(device, &cdb, 10, (PUCHAR)&toc, &returned, TRUE)) {
  681. errorValue = GetLastError();
  682. printf("Error %d sending READ_TOC pass through\n", errorValue);
  683. return errorValue;
  684. }
  685. dbg(printf("READ_TOC pass through returned %d bytes\n", returned));
  686. numTracks = toc.LastTrack - toc.FirstTrack + 1;
  687. dbg(printf("Getting %d tracks\n", numTracks));
  688. returned =
  689. FIELD_OFFSET(CDROM_TOC, TrackData[0]) +
  690. (numTracks * sizeof(TRACK_DATA));
  691. memset(&cdb, 0, sizeof(CDB));
  692. cdb.READ_TOC.OperationCode = SCSIOP_READ_TOC;
  693. cdb.READ_TOC.Msf = 0;
  694. cdb.READ_TOC.StartingTrack = 1;
  695. cdb.READ_TOC.AllocationLength[0] = (UCHAR)(returned >> 8);
  696. cdb.READ_TOC.AllocationLength[1] = (UCHAR)(returned & 0xff);
  697. if (!SptSendCdbToDevice(device, &cdb, 10, (PUCHAR)&toc, &returned, TRUE)) {
  698. errorValue = GetLastError();
  699. printf("Error %d sending READ_TOC pass through\n", errorValue);
  700. return errorValue;
  701. }
  702. dbg(printf("READ_TOC pass through returned %d bytes\n", returned));
  703. printf("TOC Data Length: %d\n", (toc.Length[0] << 16) | (toc.Length[1]));
  704. printf("First Track Number: %d\n", toc.FirstTrack);
  705. printf("Last Track Number: %d\n", toc.LastTrack);
  706. track = &(toc.TrackData[0]);
  707. printf("Number ADR Control Address (LBA)\n");
  708. printf("------ --- ------- -------------\n");
  709. for(i = 0; i < numTracks; i++) {
  710. DWORD lba =
  711. (track->Address[0] << 24) |
  712. (track->Address[1] << 16) |
  713. (track->Address[2] << 8) |
  714. (track->Address[3] << 0);
  715. UCHAR m,s,f;
  716. LBA_TO_MSF(lba, m, s, f);
  717. printf("%6d %3d %7d %3d:%02d:%02d\n",
  718. track->TrackNumber, track->Adr, track->Control,
  719. m,s,f);
  720. track++;
  721. }
  722. return errorValue;
  723. }
  724. DWORD PlayCommand(HANDLE device, int argc, char *argv[])
  725. /*++
  726. Routine Description:
  727. Plays an audio track
  728. Arguments:
  729. device - a file handle to send the ioctl to
  730. argc - the number of additional arguments.
  731. argv[1] - the starting track. Starts at zero if this is not here
  732. argv[2] - the ending track. Let track if not specified
  733. Return Value:
  734. STATUS_SUCCESS if successful
  735. The value of GetLastError() from the point of failure
  736. --*/
  737. {
  738. UNREFERENCED_PARAMETER(argc);
  739. UNREFERENCED_PARAMETER(argv);
  740. UNREFERENCED_PARAMETER(device);
  741. printf("This command is not implemented\n");
  742. return 1;
  743. }
  744. DWORD PauseResumeCommand(HANDLE device, int argc, char *argv[])
  745. /*++
  746. Routine Description:
  747. pauses or resumes audio playback
  748. Arguments:
  749. device - a file handle to send the ioctl to
  750. argc - the number of additional arguments.
  751. argv[0] - "pause" or "resume"
  752. Return Value:
  753. STATUS_SUCCESS if successful
  754. The value of GetLastError() from the point of failure
  755. --*/
  756. {
  757. DWORD errorValue = STATUS_SUCCESS;
  758. CDB cdb;
  759. char resume;
  760. UNREFERENCED_PARAMETER(argc);
  761. if(strcmp("pause", argv[0]) == 0) {
  762. resume = 0;
  763. } else {
  764. resume = 1;
  765. }
  766. printf("%s cdrom playback\n", (resume ? "Resuming" : "Pausing"));
  767. //
  768. // Unfortunately no one defined the PLAY_INDEX command for us so
  769. // cheat and use MSF
  770. //
  771. memset(&cdb, 0, sizeof(CDB));
  772. cdb.PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
  773. cdb.PAUSE_RESUME.Action = resume;
  774. if (!SptSendCdbToDevice(device, &cdb, 10, NULL, 0, FALSE)) {
  775. errorValue = GetLastError();
  776. printf("Error %d sending PAUSE_RESUME pass through\n", errorValue);
  777. return errorValue;
  778. }
  779. // dbg(printf("PAUSE_RESUME pass through returned %d bytes\n", returned));
  780. return errorValue;
  781. }
  782. DWORD ImageDiskCommand(HANDLE device, int argc, char *argv[])
  783. /*++
  784. Routine Description:
  785. creates an image of the device by reading from sector 0 to N.
  786. Arguments:
  787. device - a file handle to send the ioctl to
  788. argc - the number of additional arguments. should be 2.
  789. argv[1] - the file to output to
  790. Return Value:
  791. STATUS_SUCCESS if successful
  792. The value of GetLastError() from the point of failure
  793. --*/
  794. {
  795. HANDLE file;
  796. PUCHAR buffer;
  797. READ_CAPACITY_DATA capacityData;
  798. ULONG dataSize;
  799. CDB cdb;
  800. ULONG sectorsPerMaxRead;
  801. ULONG currentSector;
  802. if(argc < 2) {
  803. printf("not correct number of args\n");
  804. return -1;
  805. }
  806. printf("Opening file %s\n", argv[1]);
  807. file = CreateFile(argv[1],
  808. GENERIC_WRITE,
  809. 0,
  810. NULL,
  811. CREATE_NEW,
  812. FILE_FLAG_SEQUENTIAL_SCAN,
  813. NULL);
  814. if (file == INVALID_HANDLE_VALUE) {
  815. printf("Error %d creating file %s\n", GetLastError(), argv[1]);
  816. return -2;
  817. }
  818. // read the sector size from the device
  819. RtlZeroMemory(&cdb, sizeof(CDB));
  820. RtlZeroMemory(&capacityData, sizeof(READ_CAPACITY_DATA));
  821. cdb.CDB10.OperationCode = SCSIOP_READ_CAPACITY;
  822. dataSize = sizeof(READ_CAPACITY_DATA);
  823. if (!SptSendCdbToDevice(device, &cdb, 10, (PUCHAR)&capacityData, &dataSize, TRUE)) {
  824. printf("Error %d getting capacity info\n", GetLastError());
  825. return -3;
  826. }
  827. // convert the numbers
  828. PrintBuffer(&capacityData, sizeof(READ_CAPACITY_DATA));
  829. REVERSE_LONG(&capacityData.BytesPerBlock);
  830. REVERSE_LONG(&capacityData.LogicalBlockAddress);
  831. if ( (MAX_READ_SIZE % capacityData.BytesPerBlock) != 0 ) {
  832. printf("Sector size of %x is not power of 2?!\n", capacityData.BytesPerBlock);
  833. // capacityData.BytesPerBlock = 512;
  834. return -5;
  835. }
  836. buffer = (PUCHAR)malloc(MAX_READ_SIZE);
  837. if (!buffer) {
  838. printf("Unable to alloc %x bytes\n", MAX_READ_SIZE);
  839. return -4;
  840. }
  841. sectorsPerMaxRead = MAX_READ_SIZE / capacityData.BytesPerBlock;
  842. // read the data from disk and dump to file
  843. for (currentSector = 0; currentSector <= capacityData.LogicalBlockAddress; currentSector += sectorsPerMaxRead) {
  844. ULONG sectorsThisRead = sectorsPerMaxRead;
  845. UpdatePercentageDisplay(currentSector, capacityData.LogicalBlockAddress);
  846. if (currentSector > capacityData.LogicalBlockAddress - sectorsPerMaxRead) {
  847. sectorsThisRead = capacityData.LogicalBlockAddress - currentSector;
  848. }
  849. RtlZeroMemory(&cdb, sizeof(CDB));
  850. RtlZeroMemory(buffer, MAX_READ_SIZE);
  851. cdb.CDB10.OperationCode = SCSIOP_READ;
  852. cdb.CDB10.LogicalBlockByte0 = (UCHAR)(currentSector >> (8*3));
  853. cdb.CDB10.LogicalBlockByte1 = (UCHAR)(currentSector >> (8*2));
  854. cdb.CDB10.LogicalBlockByte2 = (UCHAR)(currentSector >> (8*1));
  855. cdb.CDB10.LogicalBlockByte3 = (UCHAR)(currentSector >> (8*0));
  856. cdb.CDB10.TransferBlocksMsb = (UCHAR)(sectorsThisRead >> (8*1));
  857. cdb.CDB10.TransferBlocksLsb = (UCHAR)(sectorsThisRead >> (8*0));
  858. dataSize = sectorsThisRead * capacityData.BytesPerBlock;
  859. if (!SptSendCdbToDevice(device, &cdb, 10, buffer, &dataSize, TRUE)) {
  860. printf("Error %d reading %x sectors starting at %x\n",
  861. GetLastError(), sectorsThisRead, currentSector);
  862. free(buffer);
  863. return -6;
  864. }
  865. if (dataSize != sectorsThisRead * capacityData.BytesPerBlock) {
  866. printf("Only got %x of %x bytes reading %x sectors starting at %x\n",
  867. dataSize, sectorsThisRead * capacityData.BytesPerBlock,
  868. sectorsThisRead, currentSector);
  869. free(buffer);
  870. return -7;
  871. }
  872. dataSize = sectorsThisRead * capacityData.BytesPerBlock;
  873. if (!WriteFile(file, buffer, dataSize, &dataSize, NULL)) {
  874. printf("Error %d writing %x bytes starting at sector %x\n",
  875. GetLastError(), dataSize, currentSector);
  876. free(buffer);
  877. return -8;
  878. }
  879. if (dataSize != sectorsThisRead * capacityData.BytesPerBlock) {
  880. printf("Only wrote %x of %x bytes writing %x sectors starting at %x\n",
  881. dataSize, sectorsThisRead * capacityData.BytesPerBlock,
  882. sectorsThisRead, currentSector);
  883. free(buffer);
  884. return -9;
  885. }
  886. }
  887. UpdatePercentageDisplay(capacityData.LogicalBlockAddress,
  888. capacityData.LogicalBlockAddress
  889. );
  890. free(buffer);
  891. printf("\nSuccess!\n");
  892. return 0;
  893. }
  894. DWORD SendCommand(HANDLE device, int argc, char *argv[])
  895. /*++
  896. Routine Description:
  897. Parses a hex byte string and creates a cdb to send down.
  898. Arguments:
  899. device - a file handle to send the ioctl to
  900. argc - the number of additional arguments. should be 2 or 4
  901. argv[1] - The CDB to send in a quoted hex byte string
  902. "47 00 00 00 01 00 00 ff 00 00"
  903. argv[2] - "SET" or "GET"
  904. argv[3] - for GET commands: the number of bytes (decimal) to
  905. expect from the target
  906. for SET commands: a quoted hex byte string to send to
  907. the target
  908. NOTE:
  909. Due to the potentially damaging nature of making sending an
  910. arbitrary SCSI command to an arbitrary device, this command should
  911. not be documented outside of this source code.
  912. Return Value:
  913. STATUS_SUCCESS if successful
  914. The value of GetLastError() from the point of failure
  915. --*/
  916. {
  917. DWORD errorValue = STATUS_SUCCESS;
  918. UCHAR cdbSize;
  919. CDB cdb;
  920. DWORD setData = FALSE;
  921. PUCHAR returnedData = NULL;
  922. DWORD i;
  923. DWORD dataSize = 0;
  924. ////////////////////////////////////////////////////////////////////////////////
  925. // verify the arguments
  926. ////////////////////////////////////////////////////////////////////////////////
  927. if ( argc == 4 ) {
  928. if (strcmp(argv[2], "get") != 0 &&
  929. strcmp(argv[2], "set") != 0 &&
  930. strcmp(argv[2], "GET") != 0 &&
  931. strcmp(argv[2], "SET") != 0 ) {
  932. printf("argv2 == %s\n", argv[2]);
  933. argc = 0; // this will cause help to print
  934. }
  935. if (strcmp(argv[2], "set") == 0 ||
  936. strcmp(argv[2], "SET") == 0 ) {
  937. setData = TRUE;
  938. }
  939. }
  940. if ( argc != 2 && argc != 4 ) {
  941. printf("requires one or three args:\n"
  942. "1)\tquoted hex string for cdb\n"
  943. "2)\t(optional) GET or SET\n"
  944. "3)\t(optional) GET: number of bytes to expect\n"
  945. "\t(optional) SET: quoted hex string for cdb\n");
  946. printf("\n");
  947. printf("Example commands:\n"
  948. "Send STOP_UNIT to eject drive q:\n"
  949. "\tcdp q: send \"1b 00 00 00 02 00\"\n"
  950. "Get CDVD_CAPABILITIES_PAGE from drive q:\n"
  951. "\tcdp q: send \"5a 40 2a 00 00 00 00 00 1a 00\" get 21\n"
  952. );
  953. return 1;
  954. }
  955. if (!SptUtilLockVolumeByHandle(device, TRUE)) {
  956. printf("Failed %x\n", GetLastError());
  957. return 1;
  958. }
  959. ////////////////////////////////////////////////////////////////////////////////
  960. // parse the arguments
  961. ////////////////////////////////////////////////////////////////////////////////
  962. if (!CmdHelpValidateStringHex(argv[1])) {
  963. printf("Hex string must be two (0-9,a-f) then one space (repeated)\n");
  964. return 1;
  965. }
  966. //
  967. // Determine the length of the CDB first
  968. // sscanf returns the number of things read in (ie. cdb size)
  969. //
  970. cdbSize = (UCHAR)sscanf(argv[1],
  971. "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
  972. cdb.AsByte + 0, cdb.AsByte + 1,
  973. cdb.AsByte + 2, cdb.AsByte + 3,
  974. cdb.AsByte + 4, cdb.AsByte + 5,
  975. cdb.AsByte + 6, cdb.AsByte + 7,
  976. cdb.AsByte + 8, cdb.AsByte + 9,
  977. cdb.AsByte + 10, cdb.AsByte + 11,
  978. cdb.AsByte + 12, cdb.AsByte + 13,
  979. cdb.AsByte + 14, cdb.AsByte + 15
  980. );
  981. //
  982. // now figure out how much memory we need to allocate
  983. //
  984. if (argc == 4) {
  985. if (setData) {
  986. if (!CmdHelpValidateStringHexQuoted(argv[3])) {
  987. printf("Hex string must be two (0-9,a-f) then one space (repeated)\n");
  988. return 1;
  989. }
  990. dataSize = strlen(argv[3]);
  991. if (dataSize % 3) {
  992. dataSize /= 3;
  993. dataSize ++;
  994. } else {
  995. dataSize /= 3;
  996. }
  997. if (dataSize == 0) {
  998. printf("Cannot set zero bytes of data\n");
  999. return 1;
  1000. }
  1001. } else {
  1002. i = sscanf(argv[3], "%x", &dataSize);
  1003. if (i != 1) {
  1004. printf("Error scanning second argument\n");
  1005. return 1;
  1006. }
  1007. }
  1008. }
  1009. //
  1010. // allocate the memory we may need
  1011. //
  1012. if (dataSize != 0) {
  1013. returnedData = (PUCHAR)malloc(dataSize);
  1014. if (returnedData == NULL) {
  1015. printf("Unable to allocate %x bytes for data\n", dataSize);
  1016. return 1;
  1017. }
  1018. memset(returnedData, 0, dataSize);
  1019. }
  1020. //
  1021. // now scan in the data to set, if that's what the user wants.
  1022. // note that since it's already been validated, we can presume
  1023. // the format is (number)(number)(space) repeated
  1024. //
  1025. if (setData) {
  1026. ULONG index;
  1027. PCHAR location = argv[3];
  1028. for (index = 0; index < dataSize; index++) {
  1029. if (sscanf(location, "%x", returnedData + index) != 1) {
  1030. printf("sscanf did not return 1 for index %i\n", index);
  1031. return 1;
  1032. }
  1033. if ((*location + 0 == '\0') ||
  1034. (*location + 1 == '\0')) {
  1035. printf("string too short!\n");
  1036. return 1;
  1037. }
  1038. location += 3;
  1039. }
  1040. }
  1041. #if DBG
  1042. ////////////////////////////////////////////////////////////////////////////////
  1043. // provide some user feedback
  1044. ////////////////////////////////////////////////////////////////////////////////
  1045. //
  1046. // it is the amount of data expected back from the command
  1047. //
  1048. printf("\nSending %x byte Command:\n", cdbSize);
  1049. PrintBuffer(cdb.AsByte, cdbSize);
  1050. if (setData) {
  1051. printf("Setting Buffer:\n");
  1052. PrintBuffer(returnedData, dataSize);
  1053. } else {
  1054. printf("Expecting %#x bytes of data\n", dataSize);
  1055. }
  1056. #endif // DBG
  1057. ////////////////////////////////////////////////////////////////////////////////
  1058. // send the command
  1059. ////////////////////////////////////////////////////////////////////////////////
  1060. while (1) {
  1061. UCHAR senseSize = sizeof(SENSE_DATA);
  1062. SENSE_DATA senseData;
  1063. BOOLEAN retry = FALSE;
  1064. DWORD retryDelay = 0;
  1065. if (!SptSendCdbToDeviceEx(device,
  1066. &cdb,
  1067. cdbSize,
  1068. returnedData, &dataSize,
  1069. &senseData, senseSize,
  1070. (BOOLEAN)(setData ? FALSE : TRUE),
  1071. 360) // six minutes
  1072. ) {
  1073. errorValue = 0;
  1074. if (senseSize == 0) {
  1075. errorValue = GetLastError();
  1076. if (errorValue == ERROR_SUCCESS) {
  1077. errorValue = ERROR_IO_DEVICE;
  1078. }
  1079. } else {
  1080. printf("Sense Data: (%x bytes) Sense %x ASC %x ASCQ %x\n",
  1081. senseSize,
  1082. senseData.SenseKey & 0xf,
  1083. senseData.AdditionalSenseCode,
  1084. senseData.AdditionalSenseCodeQualifier);
  1085. PrintBuffer(&senseData, senseSize);
  1086. SptUtilInterpretSenseInfo(&senseData,
  1087. senseSize,
  1088. &errorValue,
  1089. &retry,
  1090. &retryDelay);
  1091. }
  1092. if (retry) {
  1093. printf("Command should be retried in %d.%d seconds\n",
  1094. (retryDelay / 10), (retryDelay % 10));
  1095. Sleep(retryDelay*10);
  1096. } else {
  1097. printf("Error %d sending command via pass through\n", errorValue);
  1098. break;
  1099. }
  1100. }
  1101. if (!setData) {
  1102. printf("(%x bytes returned)\n",dataSize);
  1103. PrintBuffer(returnedData, dataSize);
  1104. } else {
  1105. printf("Successfully sent the command\n");
  1106. }
  1107. break; // out of for loop
  1108. }
  1109. return errorValue;
  1110. }
  1111. DWORD TestCommand(HANDLE device, int argc, char *argv[])
  1112. /*++
  1113. Routine Description:
  1114. Tests the command "parsing"
  1115. Arguments:
  1116. device - a file handle to send the ioctl to
  1117. argc - the number of additional arguments. should be zero
  1118. argv - the additional arguments
  1119. Return Value:
  1120. STATUS_SUCCESS if successful
  1121. The value of GetLastError() from the point of failure
  1122. --*/
  1123. {
  1124. int i;
  1125. UNREFERENCED_PARAMETER(device);
  1126. printf("Test - %d additional arguments\n", argc);
  1127. for(i = 0; i < argc; i++) {
  1128. printf("arg %d: %s\n", i, argv[i]);
  1129. }
  1130. return STATUS_SUCCESS;
  1131. }
  1132. DWORD ListCommand(HANDLE device, int argc, char *argv[])
  1133. /*++
  1134. Routine Description:
  1135. Prints out the command list
  1136. Arguments:
  1137. device - unused
  1138. argc - unused
  1139. argv - unused
  1140. Return Value:
  1141. STATUS_SUCCESS
  1142. --*/
  1143. {
  1144. int i = 0;
  1145. UNREFERENCED_PARAMETER(device);
  1146. UNREFERENCED_PARAMETER(argc);
  1147. UNREFERENCED_PARAMETER(argv);
  1148. while(CommandArray[i].Name != NULL) {
  1149. if(CommandArray[i].Description != NULL) {
  1150. printf("\t%s - %s\n",
  1151. CommandArray[i].Name,
  1152. CommandArray[i].Description);
  1153. }
  1154. i++;
  1155. }
  1156. return STATUS_SUCCESS;
  1157. }
  1158. DWORD DvdReadStructure(HANDLE device, int argc, char *argv[])
  1159. /*++
  1160. Routine Description:
  1161. Sends down a startstop command.
  1162. Arguments:
  1163. device - a file handle to send the ioctl to
  1164. argc - the number of additional arguments. should be zero
  1165. argv[0] - "eject", "load", "start" or "stop"
  1166. Return Value:
  1167. STATUS_SUCCESS if successful
  1168. The value of GetLastError() from the point of failure
  1169. --*/
  1170. {
  1171. DVD_READ_STRUCTURE readStructure;
  1172. PUCHAR buffer;
  1173. PDVD_DESCRIPTOR_HEADER header;
  1174. DWORD returned;
  1175. DWORD errorValue = STATUS_SUCCESS;
  1176. printf("argument count is %d\n", argc);
  1177. if(argc <= 1) {
  1178. printf("\tValid structure types are Physical, Copyright, DiskKey, "
  1179. "BCA or Manufacturer\n");
  1180. return STATUS_SUCCESS;
  1181. }
  1182. printf("Argv[1] = %s\n", argv[1]);
  1183. buffer = malloc(sizeof(DVD_DISK_KEY_DESCRIPTOR) +
  1184. sizeof(DVD_DESCRIPTOR_HEADER));
  1185. if (buffer == NULL) {
  1186. printf("Insufficient memory\n");
  1187. return STATUS_SUCCESS;
  1188. }
  1189. header = (PDVD_DESCRIPTOR_HEADER) buffer;
  1190. if(_stricmp("physical", argv[1]) == 0) {
  1191. if(argc < 1) {
  1192. printf("reading physical descriptor requires layer number\n");
  1193. return STATUS_SUCCESS;
  1194. }
  1195. readStructure.Format = DvdPhysicalDescriptor;
  1196. readStructure.LayerNumber = (UCHAR)atoi(argv[1]);
  1197. } else if(_stricmp("copyright", argv[1]) == 0) {
  1198. readStructure.Format = DvdCopyrightDescriptor;
  1199. } else if(_stricmp("diskkey", argv[1]) == 0) {
  1200. if(argc < 1) {
  1201. printf("reading physical descriptor requires a session ID\n");
  1202. return STATUS_SUCCESS;
  1203. }
  1204. readStructure.Format = DvdPhysicalDescriptor;
  1205. readStructure.SessionId = atoi(argv[1]);
  1206. } else if(_stricmp("bca", argv[1]) == 0) {
  1207. readStructure.Format = DvdBCADescriptor;
  1208. } else if(_stricmp("manufacturer", argv[1]) == 0) {
  1209. readStructure.Format = DvdManufacturerDescriptor;
  1210. } else {
  1211. printf("\tValid structure types are Physical, Copyright, DiskKey, "
  1212. "BCA or Manufacturer\n");
  1213. return STATUS_SUCCESS;
  1214. }
  1215. returned = 0;
  1216. if(!DeviceIoControl(device,
  1217. IOCTL_DVD_READ_STRUCTURE,
  1218. &readStructure,
  1219. sizeof(DVD_READ_STRUCTURE),
  1220. buffer,
  1221. sizeof(DVD_DISK_KEY_DESCRIPTOR),
  1222. &returned,
  1223. FALSE)) {
  1224. errorValue = GetLastError();
  1225. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  1226. return errorValue;
  1227. }
  1228. printf("DvdReadStructure returned %d bytes\n", returned);
  1229. printf("Header Length is %#08lx\n", header->Length);
  1230. printf("Header @ %p\n", header);
  1231. printf("Data @ %p\n", &(header->Data[0]));
  1232. if(_stricmp("physical", argv[1]) == 0) {
  1233. PDVD_LAYER_DESCRIPTOR layer = (PDVD_LAYER_DESCRIPTOR) ((PUCHAR) &(header->Data[0]));
  1234. int i;
  1235. printf("\tBook Version: %d\n", layer->BookVersion);
  1236. printf("\tBook Type: %d\n", layer->BookType);
  1237. printf("\tMinimumRate: %d\n", layer->MinimumRate);
  1238. printf("\tDiskSize: %d\n", layer->DiskSize);
  1239. printf("\tLayerType: %d\n", layer->LayerType);
  1240. printf("\tTrackPath: %d\n", layer->TrackPath);
  1241. printf("\tNumberOfLayers: %d\n", layer->NumberOfLayers);
  1242. printf("\tTrackDensity: %d\n", layer->TrackDensity);
  1243. printf("\tLinearDensity: %d\n", layer->LinearDensity);
  1244. printf("\tStartingDataSector: %#08lx\n", layer->StartingDataSector);
  1245. printf("\tEndDataSector: %#08lx\n", layer->EndDataSector);
  1246. printf("\tEndLayerZeroSector: %#08lx\n", layer->EndLayerZeroSector);
  1247. printf("\tBCAFlag: %d\n", layer->BCAFlag);
  1248. printf("\n");
  1249. for(i = 0; i < sizeof(DVD_LAYER_DESCRIPTOR); i++) {
  1250. printf("byte %d: %#x\n", i, header->Data[i]);
  1251. }
  1252. } else if(_stricmp("copyright", argv[1]) == 0) {
  1253. } else if(_stricmp("diskkey", argv[1]) == 0) {
  1254. } else if(_stricmp("bca", argv[1]) == 0) {
  1255. } else if(_stricmp("manufacturer", argv[1]) == 0) {
  1256. }
  1257. printf("final status %d\n", errorValue);
  1258. return errorValue;
  1259. }
  1260. DWORD DiskGetPartitionInfo(HANDLE device, int argc, char *argv[])
  1261. /*++
  1262. Routine Description:
  1263. Sends down a startstop command.
  1264. Arguments:
  1265. device - a file handle to send the ioctl to
  1266. argc - the number of additional arguments. should be zero
  1267. argv[0] - "eject", "load", "start" or "stop"
  1268. Return Value:
  1269. STATUS_SUCCESS if successful
  1270. The value of GetLastError() from the point of failure
  1271. --*/
  1272. {
  1273. PARTITION_INFORMATION partitionInformation;
  1274. DWORD returned;
  1275. DWORD errorValue = STATUS_SUCCESS;
  1276. UNREFERENCED_PARAMETER(argc);
  1277. UNREFERENCED_PARAMETER(argv);
  1278. returned = 0;
  1279. if(!DeviceIoControl(device,
  1280. IOCTL_DISK_GET_PARTITION_INFO,
  1281. NULL,
  1282. 0L,
  1283. &partitionInformation,
  1284. sizeof(PARTITION_INFORMATION),
  1285. &returned,
  1286. FALSE)) {
  1287. errorValue = GetLastError();
  1288. printf("Eject - error sending IOCTL (%d)\n", errorValue);
  1289. return errorValue;
  1290. }
  1291. printf("IOCTL_DISK_GET_PARTITION_INFO returned %d bytes\n", returned);
  1292. printf("Starting Offset = %#016I64x\n", partitionInformation.StartingOffset.QuadPart);
  1293. printf("Partition Length = %#016I64x\n", partitionInformation.PartitionLength.QuadPart);
  1294. printf("Hidden Sectors = %#08lx\n", partitionInformation.HiddenSectors);
  1295. printf("PartitionNumber = %#08lx\n", partitionInformation.PartitionNumber);
  1296. printf("PartitionType = %#08lx\n", partitionInformation.PartitionType);
  1297. printf("BootIndicator = %s\n", partitionInformation.BootIndicator ? "TRUE" : "FALSE");
  1298. printf("RecognizedPartition = %s\n", partitionInformation.RecognizedPartition ? "TRUE" : "FALSE");
  1299. printf("RewritePartition = %s\n", partitionInformation.RewritePartition ? "TRUE" : "FALSE");
  1300. return errorValue;
  1301. }
  1302. DWORD IoctlCommand(HANDLE device, int argc, char *argv[])
  1303. /*++
  1304. Routine Description:
  1305. Sends down a specified ioctl.
  1306. Arguments:
  1307. device - a file handle to send the ioctl to
  1308. argc - the number of additional arguments. should be two
  1309. argv[0] - ioctl code in hexadecimal
  1310. argv[1] - quoted string, bytes to send, "" if none
  1311. argv[2] - number of bytes to get back [optional]
  1312. Return Value:
  1313. STATUS_SUCCESS if successful
  1314. The value of GetLastError() from the point of failure
  1315. --*/
  1316. {
  1317. ULONG ctlCode = 0;
  1318. ULONG returned;
  1319. ULONG inputSize = 0;
  1320. ULONG outputSize = 0;
  1321. UCHAR buffer[MAX_IOCTL_BUFFER_SIZE];
  1322. BOOLEAN get;
  1323. if (argc < 3) { // n+1 -- require two args, accept three
  1324. ctlCode = 0;
  1325. } else if (!CmdHelpValidateStringHexQuoted(argv[2])) {
  1326. printf("input hex string invalid\n");
  1327. ctlCode = 0;
  1328. } else {
  1329. //
  1330. // retrieve the ioctl
  1331. //
  1332. (void)sscanf(argv[1], "%x", &ctlCode);
  1333. }
  1334. if (argc > 3) { // n+1 -- require three args.
  1335. (void)sscanf(argv[3], "%x", &outputSize);
  1336. printf("output size: %x\n", outputSize);
  1337. } else {
  1338. outputSize = 0;
  1339. }
  1340. if (outputSize > MAX_IOCTL_OUTPUT_SIZE) {
  1341. printf("output size too large\n");
  1342. ctlCode = 0;
  1343. }
  1344. if (ctlCode == 0) {
  1345. printf("args:\n"
  1346. "1)\tioctl in hex\n"
  1347. "2)\tquoted string of bytes to send, \"\" if none\n"
  1348. "3)\tnumber of bytes to expect\n");
  1349. return -1;
  1350. }
  1351. //////////////////////////////////////////////////////////////////////////
  1352. // ioctl and args are valid.
  1353. //
  1354. RtlZeroMemory(buffer, sizeof(UCHAR)*MAX_IOCTL_BUFFER_SIZE);
  1355. if (strlen(argv[2])) {
  1356. inputSize = MAX_IOCTL_INPUT_SIZE;
  1357. if (!CmdHelpScanQuotedHexString(argv[2], buffer, &inputSize)) {
  1358. printf("Error scanning hex string\n");
  1359. return -1;
  1360. }
  1361. } else {
  1362. inputSize = 0;
  1363. }
  1364. // inputSize of zero is valid as input
  1365. printf("Sending ioctl %x to device %p\n"
  1366. "using input buffer %p of size %x\n"
  1367. "and output buffer %p of size %x\n",
  1368. ctlCode, device,
  1369. ((inputSize == 0) ? NULL : buffer),
  1370. inputSize,
  1371. ((outputSize == 0) ? NULL : buffer),
  1372. outputSize);
  1373. if (!DeviceIoControl(device,
  1374. ctlCode,
  1375. ((inputSize == 0) ? NULL : buffer),
  1376. inputSize,
  1377. ((outputSize == 0) ? NULL : buffer),
  1378. outputSize,
  1379. &returned,
  1380. FALSE)) {
  1381. printf("Failed with %d\n", GetLastError());
  1382. return GetLastError();
  1383. }
  1384. if (returned != 0) {
  1385. printf("Returned data (%x of %x bytes):\n", returned, outputSize);
  1386. PrintBuffer(buffer, returned);
  1387. } else {
  1388. printf("Command completed successfully\n");
  1389. }
  1390. return 0;
  1391. }
  1392. DWORD FormatErrorCommand(HANDLE device, int argc, char *argv[])
  1393. /*++
  1394. Routine Description:
  1395. Gets and displays the message string associated with an error code.
  1396. Arguments:
  1397. device - not used, but required :P
  1398. argc - the number of additional arguments. should be one
  1399. argv[0] - error code in hexadecimal
  1400. Return Value:
  1401. STATUS_SUCCESS if successful
  1402. The value of GetLastError() from the point of failure
  1403. --*/
  1404. {
  1405. LPVOID stringBuffer = NULL;
  1406. DWORD errorCode = 0;
  1407. DWORD numOfChars = 0;
  1408. DWORD flags;
  1409. ULONG i;
  1410. //
  1411. // verify number of args and give help.
  1412. //
  1413. if (argc != 2) { // n+1
  1414. printf("requires one argument: the error code in *hex*\n"
  1415. "Example commands:\n"
  1416. "\tcdp c: error 80030306\n"
  1417. "\t(DVD Copy Protection Error)\n"
  1418. );
  1419. return 1;
  1420. }
  1421. i = sscanf(argv[1], "%x", &errorCode);
  1422. if (i < 1) {
  1423. printf("Unable to find a valid hex number in '%s'.\n", argv[1]);
  1424. return 1;
  1425. }
  1426. printf("Formatting error code for 0x%x (%d)\n", errorCode, errorCode);
  1427. flags = 0;
  1428. flags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
  1429. flags |= FORMAT_MESSAGE_FROM_SYSTEM;
  1430. flags |= FORMAT_MESSAGE_IGNORE_INSERTS;
  1431. numOfChars = FormatMessageA(flags,
  1432. NULL,
  1433. errorCode,
  1434. 0, // language indifferent
  1435. (LPSTR)&stringBuffer, // double pointer
  1436. 0,
  1437. NULL
  1438. );
  1439. if (stringBuffer == NULL) {
  1440. printf("No buffer returned?\n");
  1441. return -1;
  1442. }
  1443. if (numOfChars == 0) {
  1444. printf("Size zero buffer returned?\n");
  1445. return -1;
  1446. }
  1447. printf("ERROR MESSAGE RETURNED:\n");
  1448. printf("%s\n", stringBuffer);
  1449. LocalFree(stringBuffer);
  1450. return 0;
  1451. }
  1452. DWORD FormatMrwCommand(HANDLE device, int argc, char *argv[])
  1453. /*++
  1454. Routine Description:
  1455. Formats an MRW-Compliant drive and shows percentage complete
  1456. Arguments:
  1457. device - drive to format media as MRW in
  1458. argc - the number of additional arguments. should be zero
  1459. Return Value:
  1460. STATUS_SUCCESS if successful
  1461. The value of GetLastError() from the point of failure
  1462. --*/
  1463. {
  1464. #define MRW_FORMAT_BUFFER_SIZE 0xc
  1465. CDB cdb;
  1466. ULONG size = MRW_FORMAT_BUFFER_SIZE;
  1467. SENSE_DATA senseData;
  1468. UCHAR formatBuffer[MRW_FORMAT_BUFFER_SIZE];
  1469. RtlZeroMemory(&cdb, sizeof(CDB));
  1470. RtlZeroMemory(formatBuffer, size);
  1471. RtlZeroMemory(&senseData, sizeof(SENSE_DATA));
  1472. cdb.CDB6FORMAT.OperationCode = SCSIOP_FORMAT_UNIT;
  1473. cdb.CDB6FORMAT.FormatControl = 0x11; // FmtData == 1, FormatCode = 1
  1474. //formatBuffer[0x0] = 0x00;
  1475. //formatBuffer[0x1] = 0x00; // (same as 0x82)
  1476. //formatBuffer[0x2] = 0x00;
  1477. formatBuffer[0x3] = 0x08;
  1478. formatBuffer[0x4] = 0xff; //---vvv
  1479. formatBuffer[0x5] = 0xff; // NumberOfBlocks must be set to 0xffffffff
  1480. formatBuffer[0x6] = 0xff; //
  1481. formatBuffer[0x7] = 0xff; //--^^^^
  1482. formatBuffer[0x8] = 0x90; // format code == 0x24 ( << 2 == 0x90 )
  1483. //formatBuffer[0x9] = 0x00;
  1484. //formatBuffer[0xa] = 0x00;
  1485. //formatBuffer[0xb] = 0x00;
  1486. if (!SptSendCdbToDeviceEx(device,
  1487. &cdb,
  1488. 6,
  1489. formatBuffer,
  1490. &size,
  1491. &senseData,
  1492. sizeof(SENSE_DATA),
  1493. FALSE,
  1494. 60)) {
  1495. printf("Unable to format, %x\n", GetLastError());
  1496. printf("Sense Buffer: %02x/%02x/%02x\n",
  1497. senseData.SenseKey,
  1498. senseData.AdditionalSenseCode,
  1499. senseData.AdditionalSenseCodeQualifier);
  1500. PrintBuffer((PUCHAR)&senseData, sizeof(SENSE_DATA));
  1501. return -1;
  1502. } else if (senseData.SenseKey != SCSI_SENSE_NO_SENSE) {
  1503. printf("Sense Buffer: %02x/%02x/%02x\n",
  1504. senseData.SenseKey,
  1505. senseData.AdditionalSenseCode,
  1506. senseData.AdditionalSenseCodeQualifier);
  1507. PrintBuffer((PUCHAR)&senseData, sizeof(SENSE_DATA));
  1508. return -1;
  1509. }
  1510. printf("format command succeeded (%02x/%02x/%02x)\n",
  1511. senseData.SenseKey,
  1512. senseData.AdditionalSenseCode,
  1513. senseData.AdditionalSenseCodeQualifier);
  1514. return ShowMrwProgressCommand(device, argc, argv);
  1515. }
  1516. DWORD ShowMrwProgressCommand(HANDLE device, int argc, char *argv[])
  1517. /*++
  1518. Routine Description:
  1519. Formats an MRW-Compliant drive and shows percentage complete
  1520. Arguments:
  1521. device - drive to format media as MRW in
  1522. argc - the number of additional arguments. should be zero
  1523. Return Value:
  1524. STATUS_SUCCESS if successful
  1525. The value of GetLastError() from the point of failure
  1526. --*/
  1527. {
  1528. CDB cdb;
  1529. SENSE_DATA sense;
  1530. ULONG size;
  1531. ULONG ignoredLoopCount;
  1532. BOOLEAN succeededOnce;
  1533. BOOLEAN senseHeaderPrinted;
  1534. //
  1535. // loop, displaying percentage done.
  1536. //
  1537. ignoredLoopCount = 0;
  1538. succeededOnce = FALSE;
  1539. senseHeaderPrinted = FALSE;
  1540. while (1) {
  1541. #if 0
  1542. RtlZeroMemory(&cdb, sizeof(CDB));
  1543. size = 0;
  1544. if (!SptSendCdbToDevice(device,
  1545. &cdb,
  1546. 6,
  1547. NULL,
  1548. &size,
  1549. TRUE)) {
  1550. printf("\nUnable to send TUR to get percentage done! %x\n",
  1551. GetLastError());
  1552. return -1;
  1553. }
  1554. Sleep(500);
  1555. #endif // 0
  1556. RtlZeroMemory(&cdb, sizeof(CDB));
  1557. RtlZeroMemory(&sense, sizeof(SENSE_DATA));
  1558. size = sizeof(SENSE_DATA);
  1559. cdb.AsByte[0] = SCSIOP_REQUEST_SENSE;
  1560. cdb.AsByte[4] = (UCHAR)(sizeof(SENSE_DATA));
  1561. if (!SptSendCdbToDevice(device,
  1562. &cdb,
  1563. 6,
  1564. (PUCHAR)&sense,
  1565. &size,
  1566. TRUE)) {
  1567. printf("\nUnable to get percentage done! %x\n", GetLastError());
  1568. return -1;
  1569. }
  1570. if (sense.AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY &&
  1571. sense.AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS &&
  1572. (sense.SenseKeySpecific[0] & 0x80)
  1573. ) {
  1574. ULONG done;
  1575. succeededOnce = TRUE;
  1576. if (senseHeaderPrinted) { printf("\n"); }
  1577. senseHeaderPrinted = FALSE;
  1578. done =
  1579. ((sense.SenseKeySpecific[0] & 0x7f) << (8*2)) |
  1580. ((sense.SenseKeySpecific[1] & 0xff) << (8*1)) |
  1581. ((sense.SenseKeySpecific[2] & 0xff) << (8*0)) ;
  1582. UpdatePercentageDisplay(done, 0x10000);
  1583. ignoredLoopCount = 0;
  1584. } else {
  1585. if (!succeededOnce) {
  1586. if (!senseHeaderPrinted) {
  1587. senseHeaderPrinted = TRUE;
  1588. printf("\nSenseData not showing format progress yet: %x/%x/%x ",
  1589. sense.SenseKey,
  1590. sense.AdditionalSenseCode,
  1591. sense.AdditionalSenseCodeQualifier
  1592. );
  1593. }
  1594. printf(".");
  1595. } else {
  1596. if (senseHeaderPrinted) { printf("\n"); }
  1597. senseHeaderPrinted = FALSE;
  1598. ignoredLoopCount++;
  1599. if (ignoredLoopCount > 50) {
  1600. printf("\nSenseData: %x/%x/%x\n",
  1601. sense.SenseKey,
  1602. sense.AdditionalSenseCode,
  1603. sense.AdditionalSenseCodeQualifier
  1604. );
  1605. printf("\nSenseData not as expected. Format has "
  1606. "probably completed.\n");
  1607. return -1;
  1608. }
  1609. }
  1610. // else let it go on
  1611. }
  1612. Sleep(1000);
  1613. } // while(1) loop
  1614. }
  1615. BOOLEAN
  1616. ModeSelect(
  1617. HANDLE Device,
  1618. PVOID ModePage,
  1619. ULONG ModePageSize
  1620. )
  1621. {
  1622. CDB cdb;
  1623. ULONG tmp;
  1624. ULONG size;
  1625. PMODE_PARAMETER_HEADER10 header;
  1626. tmp = sizeof(MODE_PARAMETER_HEADER10) + ModePageSize;
  1627. header = malloc(tmp);
  1628. if (header == NULL) {
  1629. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1630. return FALSE;
  1631. }
  1632. RtlZeroMemory(header, tmp);
  1633. tmp -= 2; // sizeof through field
  1634. header->ModeDataLength[0] = (UCHAR)(tmp >> (8*1));
  1635. header->ModeDataLength[1] = (UCHAR)(tmp >> (8*0));
  1636. tmp += 2; // still used for size...
  1637. RtlCopyMemory(header+1, // pointer math
  1638. ModePage,
  1639. ModePageSize);
  1640. RtlZeroMemory(&cdb, sizeof(CDB));
  1641. cdb.MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
  1642. cdb.MODE_SELECT10.PFBit = 1;
  1643. cdb.MODE_SELECT10.ParameterListLength[0] = (UCHAR)(tmp >> (8*1));
  1644. cdb.MODE_SELECT10.ParameterListLength[1] = (UCHAR)(tmp >> (8*0));
  1645. size = tmp;
  1646. if (!SptSendCdbToDevice(Device,
  1647. &cdb,
  1648. 10,
  1649. (PUCHAR)header,
  1650. &size,
  1651. FALSE)) {
  1652. printf("Unable to set mode page %x\n", GetLastError());
  1653. return FALSE;
  1654. }
  1655. return TRUE;
  1656. }
  1657. BOOLEAN
  1658. FillDisk(
  1659. HANDLE Device,
  1660. ULONG Signature
  1661. )
  1662. {
  1663. READ_CAPACITY_DATA capacity;
  1664. ULONG currentLba;
  1665. PULONGLONG data;
  1666. //
  1667. // do a READ_CAPACITY to find the drive's sector size
  1668. // and number of LBAs
  1669. //
  1670. {
  1671. CDB cdb;
  1672. ULONG size;
  1673. RtlZeroMemory(&cdb, sizeof(CDB));
  1674. RtlZeroMemory(&capacity, sizeof(READ_CAPACITY_DATA));
  1675. cdb.CDB10.OperationCode = SCSIOP_READ_CAPACITY;
  1676. size = sizeof(READ_CAPACITY_DATA);
  1677. if (!SptSendCdbToDevice(Device,
  1678. &cdb,
  1679. 10,
  1680. (PUCHAR)&capacity,
  1681. &size,
  1682. TRUE)) {
  1683. printf("Unable to get capacity %x\n", GetLastError());
  1684. return FALSE;
  1685. }
  1686. //
  1687. // convert the numbers
  1688. //
  1689. REVERSE_LONG(&capacity.BytesPerBlock);
  1690. REVERSE_LONG(&capacity.LogicalBlockAddress);
  1691. if ( (capacity.BytesPerBlock % 512) != 0 ) {
  1692. printf("Sector size of %x is not a multiple of 512?!\n", capacity.BytesPerBlock);
  1693. // capacity.BytesPerBlock = 512;
  1694. return FALSE;
  1695. }
  1696. }
  1697. //
  1698. // print for kicks...
  1699. //
  1700. printf(" Bytes Per Block %10d (%8x)\n"
  1701. "Number Of Sectors %10d (%8x)\n",
  1702. capacity.BytesPerBlock,
  1703. capacity.BytesPerBlock,
  1704. capacity.LogicalBlockAddress,
  1705. capacity.LogicalBlockAddress
  1706. );
  1707. //
  1708. // allocate a sector's worth of data
  1709. //
  1710. data = (PLONGLONG)malloc( capacity.BytesPerBlock );
  1711. if (data == NULL) {
  1712. printf("Not enough memory to allocate data\n");
  1713. return FALSE;
  1714. }
  1715. for (currentLba = 0x0; currentLba <= capacity.LogicalBlockAddress; currentLba++) {
  1716. CDB cdb;
  1717. PULONGLONG t = data;
  1718. ULONG size;
  1719. ULONG iterate = capacity.BytesPerBlock / sizeof(ULONGLONG);
  1720. ULONG j;
  1721. if ((currentLba % 100) == 0) {
  1722. UpdatePercentageDisplay(currentLba, capacity.LogicalBlockAddress);
  1723. }
  1724. // for the first ULONGLONG of each sector, put "Sector %08x"
  1725. // in plain text.
  1726. sprintf((PCHAR)t,
  1727. "Sector %08x",
  1728. currentLba
  1729. );
  1730. // RtlZeroMemory(data, capacity.BytesPerBlock);
  1731. for (j=1; j < iterate ; j++, t++) {
  1732. *t = ((ULONGLONG)Signature) << 32; // signature
  1733. *t += currentLba; // etc.
  1734. }
  1735. //
  1736. // prepare the "write" operation for this sector
  1737. //
  1738. RtlZeroMemory(&cdb, sizeof(CDB));
  1739. cdb.CDB10.OperationCode = SCSIOP_WRITE;
  1740. cdb.CDB10.LogicalBlockByte0 = (UCHAR)(currentLba >> (8*3));
  1741. cdb.CDB10.LogicalBlockByte1 = (UCHAR)(currentLba >> (8*2));
  1742. cdb.CDB10.LogicalBlockByte2 = (UCHAR)(currentLba >> (8*1));
  1743. cdb.CDB10.LogicalBlockByte3 = (UCHAR)(currentLba >> (8*0));
  1744. cdb.CDB10.TransferBlocksMsb = 0;
  1745. cdb.CDB10.TransferBlocksLsb = 1;
  1746. size = capacity.BytesPerBlock;
  1747. if (!SptSendCdbToDevice(Device, &cdb, 10, (PUCHAR)data, &size, FALSE)) {
  1748. printf("Error %d writing sectors at %x\n",
  1749. GetLastError(), currentLba);
  1750. free(data);
  1751. return FALSE;
  1752. }
  1753. }
  1754. UpdatePercentageDisplay(capacity.LogicalBlockAddress, capacity.LogicalBlockAddress);
  1755. free(data);
  1756. data = NULL;
  1757. return TRUE;
  1758. }
  1759. BOOLEAN WriteImageSpt(HANDLE Device, HANDLE FsHandle, ULONG SectorsToWrite)
  1760. {
  1761. ULONG currentLba;
  1762. PULONGLONG data;
  1763. //
  1764. // allocate a packet's worth of data
  1765. //
  1766. data = (PULONGLONG)malloc( CDRW_WRITE_BYTES );
  1767. if (data == NULL)
  1768. {
  1769. printf("Not enough memory to allocate data\n");
  1770. return FALSE;
  1771. }
  1772. for (currentLba = 0x0; currentLba <= SectorsToWrite; currentLba += CDRW_WRITE_SECTORS)
  1773. {
  1774. CDB cdb;
  1775. ULONG size;
  1776. ULONG sectorsThisRead;
  1777. sectorsThisRead = SectorsToWrite - currentLba;
  1778. if ( sectorsThisRead > CDRW_WRITE_SECTORS )
  1779. {
  1780. sectorsThisRead = CDRW_WRITE_SECTORS;
  1781. }
  1782. if ((currentLba % 100) == 0) {
  1783. UpdatePercentageDisplay(currentLba, SectorsToWrite);
  1784. }
  1785. // read in the next bits of data
  1786. {
  1787. ULONG bytesToRead;
  1788. ULONG bytesActuallyRead;
  1789. RtlZeroMemory(data, CDRW_WRITE_BYTES);
  1790. bytesToRead = sectorsThisRead * 2048;
  1791. bytesActuallyRead = 0;
  1792. if ( !ReadFile(FsHandle, data, bytesToRead, &bytesActuallyRead, NULL) )
  1793. {
  1794. printf("Failed to read from sector %x of %x\n",
  1795. currentLba, SectorsToWrite);
  1796. LocalFree(data);
  1797. return FALSE;
  1798. }
  1799. if ( bytesActuallyRead != bytesToRead )
  1800. {
  1801. printf("Only read %x of %x bytes reading from sector %x of %x\n",
  1802. bytesActuallyRead, bytesToRead,
  1803. currentLba, SectorsToWrite);
  1804. LocalFree(data);
  1805. return FALSE;
  1806. }
  1807. }
  1808. //
  1809. // prepare the "write" operation for this sector
  1810. //
  1811. RtlZeroMemory(&cdb, sizeof(CDB));
  1812. cdb.CDB10.OperationCode = SCSIOP_WRITE;
  1813. cdb.CDB10.LogicalBlockByte0 = (UCHAR)(currentLba >> (8*3));
  1814. cdb.CDB10.LogicalBlockByte1 = (UCHAR)(currentLba >> (8*2));
  1815. cdb.CDB10.LogicalBlockByte2 = (UCHAR)(currentLba >> (8*1));
  1816. cdb.CDB10.LogicalBlockByte3 = (UCHAR)(currentLba >> (8*0));
  1817. cdb.CDB10.TransferBlocksMsb = (UCHAR)(sectorsThisRead >> (8*1));
  1818. cdb.CDB10.TransferBlocksLsb = (UCHAR)(sectorsThisRead >> (8*0));
  1819. size = sectorsThisRead * 2048;
  1820. if (!SptSendCdbToDevice(Device, &cdb, 10, (PUCHAR)data, &size, FALSE)) {
  1821. printf("Error %d writing sectors at %x\n",
  1822. GetLastError(), currentLba);
  1823. free(data);
  1824. return FALSE;
  1825. }
  1826. }
  1827. UpdatePercentageDisplay(SectorsToWrite, SectorsToWrite);
  1828. free(data);
  1829. data = NULL;
  1830. return TRUE;
  1831. }
  1832. BOOLEAN WriteImage(HANDLE device, HANDLE fsHandle, ULONG sectorsToWrite)
  1833. {
  1834. PUCHAR buffer = NULL;
  1835. ULONG currentSector = 0;
  1836. buffer = LocalAlloc(LPTR, CDRW_WRITE_BYTES);
  1837. if (buffer == NULL)
  1838. {
  1839. return FALSE;
  1840. }
  1841. for (currentSector = 0; currentSector < sectorsToWrite; currentSector+=CDRW_WRITE_SECTORS)
  1842. {
  1843. ULONG bytesToRead = 0;
  1844. ULONG bytesActuallyRead = 0;
  1845. if (sectorsToWrite - currentSector >= CDRW_WRITE_SECTORS)
  1846. {
  1847. bytesToRead = CDRW_WRITE_BYTES;
  1848. }
  1849. else
  1850. {
  1851. bytesToRead = (sectorsToWrite - currentSector) * 2048;
  1852. RtlZeroMemory(buffer, CDRW_WRITE_BYTES);
  1853. }
  1854. if (!ReadFile(fsHandle,
  1855. buffer,
  1856. bytesToRead,
  1857. &bytesActuallyRead,
  1858. NULL)
  1859. )
  1860. {
  1861. printf("Failed to read from sector %x of %x\n",
  1862. currentSector, sectorsToWrite);
  1863. LocalFree(buffer);
  1864. return FALSE;
  1865. }
  1866. if (bytesActuallyRead != bytesToRead)
  1867. {
  1868. printf("Only read %x of %x bytes readinf from sector %x of %x\n",
  1869. bytesActuallyRead, bytesToRead,
  1870. currentSector, sectorsToWrite);
  1871. LocalFree(buffer);
  1872. return FALSE;
  1873. }
  1874. // always write 64k at a time
  1875. bytesToRead = CDRW_WRITE_BYTES;
  1876. if (!WriteFile(device,
  1877. buffer,
  1878. bytesToRead,
  1879. &bytesActuallyRead,
  1880. NULL))
  1881. {
  1882. printf("Failed to write from sector %x of %x\n",
  1883. currentSector, sectorsToWrite);
  1884. LocalFree(buffer);
  1885. return FALSE;
  1886. }
  1887. if (bytesActuallyRead != bytesToRead)
  1888. {
  1889. printf("Only wrote %x of %x bytes readinf from sector %x of %x\n",
  1890. bytesActuallyRead, bytesToRead,
  1891. currentSector, sectorsToWrite);
  1892. LocalFree(buffer);
  1893. return FALSE;
  1894. }
  1895. printf(".");
  1896. }
  1897. printf("Success!\n");
  1898. LocalFree(buffer);
  1899. return TRUE;
  1900. }
  1901. DWORD MrwInitGaaFileSystem(HANDLE device, int argc, char *argv[])
  1902. /*++
  1903. Routine Description:
  1904. Writes the GAA with the given FS image
  1905. Arguments:
  1906. device - drive to write to...
  1907. argc - the number of additional arguments. should be one
  1908. Return Value:
  1909. STATUS_SUCCESS if successful
  1910. The value of GetLastError() from the point of failure
  1911. --*/
  1912. {
  1913. MODE_MRW_PAGE savedModePage;
  1914. HANDLE fsHandle = INVALID_HANDLE_VALUE;
  1915. ULONG sectorsToWrite = 0;
  1916. // open the fs to write
  1917. {
  1918. BY_HANDLE_FILE_INFORMATION fileInfo = {0};
  1919. if (argc != 2)
  1920. {
  1921. printf("Requires an image to write\n");
  1922. return -1;
  1923. }
  1924. printf("Opening %s for FS handle\n", argv[1]);
  1925. fsHandle = CreateFile(argv[1],
  1926. GENERIC_READ,
  1927. FILE_SHARE_READ,
  1928. NULL,
  1929. OPEN_EXISTING,
  1930. FILE_ATTRIBUTE_NORMAL,
  1931. NULL);
  1932. if (fsHandle == INVALID_HANDLE_VALUE)
  1933. {
  1934. printf("Unable to open FS file (%x)\n", GetLastError());
  1935. return -1;
  1936. }
  1937. if (!GetFileInformationByHandle(fsHandle, &fileInfo))
  1938. {
  1939. printf("Unable to query file info (%x)\n", GetLastError());
  1940. return -1;
  1941. }
  1942. if (fileInfo.nFileSizeHigh != 0)
  1943. {
  1944. printf("File too large (high size not zero)\n");
  1945. return -1;
  1946. }
  1947. if (fileInfo.nFileSizeLow % 2048)
  1948. {
  1949. printf("File not multiple of 2048 bytes in size\n");
  1950. return -1;
  1951. }
  1952. if (fileInfo.nFileSizeLow > (2048 * 32 * 32))
  1953. {
  1954. printf("File size of %x won't fit in GAA (%x)\n",
  1955. fileInfo.nFileSizeLow,
  1956. 2048*32*32);
  1957. return -1;
  1958. }
  1959. printf("File passed verification\n");
  1960. sectorsToWrite = fileInfo.nFileSizeLow / 2048;
  1961. }
  1962. RtlZeroMemory(&savedModePage, sizeof(MODE_MRW_PAGE));
  1963. savedModePage.PageCode = 0x3f; // illegal value for MODE_SELECT10
  1964. //
  1965. // first use GET_CONFIGURATION to verify that we're
  1966. // actually on an MRW capable device
  1967. //
  1968. {
  1969. #define MRW_FEATURE_DATA_SIZE (sizeof(GET_CONFIGURATION_HEADER)+sizeof(FEATURE_DATA_MRW))
  1970. GET_CONFIGURATION_IOCTL_INPUT input;
  1971. PGET_CONFIGURATION_HEADER header;
  1972. PFEATURE_DATA_MRW mrwFeature;
  1973. UCHAR data[ MRW_FEATURE_DATA_SIZE ];
  1974. DWORD dataSize;
  1975. DWORD expectedSize;
  1976. DWORD feature;
  1977. ULONG size;
  1978. RtlZeroMemory(&input, sizeof(GET_CONFIGURATION_IOCTL_INPUT));
  1979. RtlZeroMemory(&data, MRW_FEATURE_DATA_SIZE);
  1980. input.Feature = FeatureMrw;
  1981. input.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE;
  1982. size = 0;
  1983. if (!DeviceIoControl(device,
  1984. IOCTL_CDROM_GET_CONFIGURATION,
  1985. &input,
  1986. sizeof(GET_CONFIGURATION_IOCTL_INPUT),
  1987. data,
  1988. MRW_FEATURE_DATA_SIZE,
  1989. &size,
  1990. FALSE)) {
  1991. DWORD errorValue = GetLastError();
  1992. printf("error requesting GET_CONFIG data for MRW feature (%d)\n", errorValue);
  1993. return errorValue;
  1994. }
  1995. header = (PGET_CONFIGURATION_HEADER)data;
  1996. mrwFeature = (PFEATURE_DATA_MRW)header->Data;
  1997. expectedSize =
  1998. MRW_FEATURE_DATA_SIZE -
  1999. RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength);
  2000. dataSize =
  2001. (header->DataLength[0] << (8 * 3)) |
  2002. (header->DataLength[1] << (8 * 2)) |
  2003. (header->DataLength[2] << (8 * 1)) |
  2004. (header->DataLength[3] << (8 * 0));
  2005. if ( dataSize < expectedSize ) {
  2006. printf("data size too small -- drive may not support MRW? (%x)\n", expectedSize);
  2007. return -1;
  2008. }
  2009. feature =
  2010. (mrwFeature->Header.FeatureCode[0] << (8 * 1)) |
  2011. (mrwFeature->Header.FeatureCode[1] << (8 * 0));
  2012. if (feature != FeatureMrw) {
  2013. printf("data size too small -- drive may not support MRW? (%x)\n", feature);
  2014. return -1;
  2015. }
  2016. if (!mrwFeature->Write) {
  2017. printf("Drive supports MRW, but as Read-Only\n");
  2018. return -1;
  2019. }
  2020. if (!mrwFeature->Header.Current) {
  2021. printf("Drive supports MRW, but not with the current medium (may need to be formatted MRW first\n");
  2022. return -1;
  2023. }
  2024. } // end verification
  2025. //
  2026. // ensure we're in the correct mode (data area vs. GAA)
  2027. //
  2028. {
  2029. #define MODE_MRW_PAGE_DATA_SIZE (sizeof(MODE_PARAMETER_HEADER10) + sizeof(MODE_MRW_PAGE))
  2030. PMODE_PARAMETER_HEADER10 header;
  2031. PMODE_MRW_PAGE page;
  2032. PUCHAR data [ MODE_MRW_PAGE_DATA_SIZE ];
  2033. CDB cdb;
  2034. ULONG size;
  2035. ULONG t1, t2;
  2036. RtlZeroMemory(&cdb, sizeof(CDB));
  2037. RtlZeroMemory(data, MODE_MRW_PAGE_DATA_SIZE);
  2038. size = MODE_MRW_PAGE_DATA_SIZE;
  2039. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  2040. cdb.MODE_SENSE10.Dbd = 1;
  2041. cdb.MODE_SENSE10.PageCode = MODE_PAGE_MRW;
  2042. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_MRW_PAGE_DATA_SIZE >> 8);
  2043. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_MRW_PAGE_DATA_SIZE & 0xff);
  2044. PrintBuffer(&cdb, 10);
  2045. if (!SptSendCdbToDevice(device,
  2046. &cdb,
  2047. 10,
  2048. (PUCHAR)&data,
  2049. &size,
  2050. TRUE)) {
  2051. printf("Unable to get MRW mode page %x\n", GetLastError());
  2052. // FAKE IT FOR NOW... BUGBUG
  2053. header = (PMODE_PARAMETER_HEADER10)data;
  2054. RtlZeroMemory(data, MODE_MRW_PAGE_DATA_SIZE);
  2055. header->ModeDataLength[0] = 0;
  2056. header->ModeDataLength[1] = 0xE;
  2057. page = (PMODE_MRW_PAGE)(header+1);
  2058. page->PageCode = MODE_PAGE_MRW;
  2059. page->PageLength = 0x6;
  2060. page->LbaSpace = 0;
  2061. }
  2062. header = (PMODE_PARAMETER_HEADER10)data;
  2063. t1 = (header->ModeDataLength[0] << (8*1)) |
  2064. (header->ModeDataLength[1] << (8*0)) ;
  2065. t2 = MODE_MRW_PAGE_DATA_SIZE -
  2066. RTL_SIZEOF_THROUGH_FIELD(MODE_PARAMETER_HEADER10, ModeDataLength);
  2067. if (t1 != t2) {
  2068. // size is wrong
  2069. printf("MRW mode page wrong size, %x != %x\n", t1, t2);
  2070. return -1;
  2071. }
  2072. if ((header->BlockDescriptorLength[0] != 0) ||
  2073. (header->BlockDescriptorLength[1] != 0) ) {
  2074. printf("MRW drive force a block descriptor %x %x\n",
  2075. header->BlockDescriptorLength[0],
  2076. header->BlockDescriptorLength[1]);
  2077. return -1;
  2078. }
  2079. page = (PMODE_MRW_PAGE)(header+1); // pointer arithmetic
  2080. if (page->PageCode != MODE_PAGE_MRW) {
  2081. printf("MRW mode page has wrong page code, %x != %x\n",
  2082. page->PageCode, MODE_PAGE_MRW);
  2083. return -1;
  2084. }
  2085. if (page->LbaSpace) {
  2086. printf("MRW mode page is set to GAA\n",
  2087. page->PageCode, MODE_PAGE_MRW);
  2088. // ModeSelect()...
  2089. //return -1;
  2090. }
  2091. RtlCopyMemory(&savedModePage, page, sizeof(MODE_MRW_PAGE));
  2092. }
  2093. savedModePage.LbaSpace = 1;
  2094. if (!ModeSelect(device, &savedModePage, sizeof(MODE_MRW_PAGE))) {
  2095. printf("Unable to set MRW mode page to use GAA (%x)\n", GetLastError());
  2096. return -1;
  2097. }
  2098. if (!WriteImageSpt(device, fsHandle, sectorsToWrite)) {
  2099. printf("Unable to fill the GAA with the FS (%x)\n", GetLastError());
  2100. }
  2101. printf("\nFinished Writing General Application Area!\n");
  2102. savedModePage.LbaSpace = 0;
  2103. if (!ModeSelect(device, &savedModePage, sizeof(MODE_MRW_PAGE))) {
  2104. printf("Unable to revert from GAA space -- disc may be unusable! (%x)\n",
  2105. GetLastError());
  2106. return -1;
  2107. }
  2108. return 0;
  2109. }
  2110. DWORD MrwInitTestPatternCommand(HANDLE device, int argc, char *argv[])
  2111. /*++
  2112. Routine Description:
  2113. Initializes a disk to contain 64-bit numbers that equate to
  2114. the sector's LBA.
  2115. Arguments:
  2116. device - drive to write to...
  2117. argc - the number of additional arguments. should be zero
  2118. Return Value:
  2119. STATUS_SUCCESS if successful
  2120. The value of GetLastError() from the point of failure
  2121. --*/
  2122. {
  2123. MODE_MRW_PAGE savedModePage;
  2124. RtlZeroMemory(&savedModePage, sizeof(MODE_MRW_PAGE));
  2125. savedModePage.PageCode = 0x3f; // illegal value for MODE_SELECT10
  2126. //
  2127. // first use GET_CONFIGURATION to verify that we're
  2128. // actually on an MRW capable device
  2129. //
  2130. {
  2131. #define MRW_FEATURE_DATA_SIZE (sizeof(GET_CONFIGURATION_HEADER)+sizeof(FEATURE_DATA_MRW))
  2132. GET_CONFIGURATION_IOCTL_INPUT input;
  2133. PGET_CONFIGURATION_HEADER header;
  2134. PFEATURE_DATA_MRW mrwFeature;
  2135. UCHAR data[ MRW_FEATURE_DATA_SIZE ];
  2136. DWORD dataSize;
  2137. DWORD expectedSize;
  2138. DWORD feature;
  2139. ULONG size;
  2140. RtlZeroMemory(&input, sizeof(GET_CONFIGURATION_IOCTL_INPUT));
  2141. RtlZeroMemory(&data, MRW_FEATURE_DATA_SIZE);
  2142. input.Feature = FeatureMrw;
  2143. input.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE;
  2144. size = 0;
  2145. if (!DeviceIoControl(device,
  2146. IOCTL_CDROM_GET_CONFIGURATION,
  2147. &input,
  2148. sizeof(GET_CONFIGURATION_IOCTL_INPUT),
  2149. data,
  2150. MRW_FEATURE_DATA_SIZE,
  2151. &size,
  2152. FALSE)) {
  2153. DWORD errorValue = GetLastError();
  2154. printf("error requesting GET_CONFIG data for MRW feature (%d)\n", errorValue);
  2155. return errorValue;
  2156. }
  2157. header = (PGET_CONFIGURATION_HEADER)data;
  2158. mrwFeature = (PFEATURE_DATA_MRW)header->Data;
  2159. expectedSize =
  2160. MRW_FEATURE_DATA_SIZE -
  2161. RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength);
  2162. dataSize =
  2163. (header->DataLength[0] << (8 * 3)) |
  2164. (header->DataLength[1] << (8 * 2)) |
  2165. (header->DataLength[2] << (8 * 1)) |
  2166. (header->DataLength[3] << (8 * 0));
  2167. if ( dataSize < expectedSize ) {
  2168. printf("data size too small -- drive may not support MRW? (%x)\n", expectedSize);
  2169. return -1;
  2170. }
  2171. feature =
  2172. (mrwFeature->Header.FeatureCode[0] << (8 * 1)) |
  2173. (mrwFeature->Header.FeatureCode[1] << (8 * 0));
  2174. if (feature != FeatureMrw) {
  2175. printf("data size too small -- drive may not support MRW? (%x)\n", feature);
  2176. return -1;
  2177. }
  2178. if (!mrwFeature->Write) {
  2179. printf("Drive supports MRW, but as Read-Only\n");
  2180. return -1;
  2181. }
  2182. if (!mrwFeature->Header.Current) {
  2183. printf("Drive supports MRW, but not with the current medium (may need to be formatted MRW first\n");
  2184. return -1;
  2185. }
  2186. } // end verification
  2187. //
  2188. // ensure we're in the correct mode (data area vs. GAA)
  2189. //
  2190. #if 0
  2191. {
  2192. #define MODE_MRW_PAGE_DATA_SIZE (sizeof(MODE_PARAMETER_HEADER10) + sizeof(MODE_MRW_PAGE))
  2193. PMODE_PARAMETER_HEADER10 header;
  2194. PMODE_MRW_PAGE page;
  2195. PUCHAR data [ MODE_MRW_PAGE_DATA_SIZE ];
  2196. CDB cdb;
  2197. ULONG size;
  2198. ULONG t1, t2;
  2199. RtlZeroMemory(&cdb, sizeof(CDB));
  2200. RtlZeroMemory(data, MODE_MRW_PAGE_DATA_SIZE);
  2201. size = MODE_MRW_PAGE_DATA_SIZE;
  2202. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  2203. cdb.MODE_SENSE10.Dbd = 1;
  2204. cdb.MODE_SENSE10.PageCode = MODE_PAGE_MRW;
  2205. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_MRW_PAGE_DATA_SIZE >> 8);
  2206. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_MRW_PAGE_DATA_SIZE & 0xff);
  2207. PrintBuffer(&cdb, 10);
  2208. if (!SptSendCdbToDevice(device,
  2209. &cdb,
  2210. 10,
  2211. (PUCHAR)&data,
  2212. &size,
  2213. TRUE)) {
  2214. printf("Unable to get MRW mode page %x\n", GetLastError());
  2215. // FAKE IT FOR NOW... BUGBUG
  2216. header = (PMODE_PARAMETER_HEADER10)data;
  2217. RtlZeroMemory(data, MODE_MRW_PAGE_DATA_SIZE);
  2218. header->ModeDataLength[0] = 0;
  2219. header->ModeDataLength[1] = 0xE;
  2220. page = (PMODE_MRW_PAGE)(header+1);
  2221. page->PageCode = MODE_PAGE_MRW;
  2222. page->PageLength = 0x6;
  2223. page->LbaSpace = 0;
  2224. }
  2225. header = (PMODE_PARAMETER_HEADER10)data;
  2226. t1 = (header->ModeDataLength[0] << (8*1)) |
  2227. (header->ModeDataLength[1] << (8*0)) ;
  2228. t2 = MODE_MRW_PAGE_DATA_SIZE -
  2229. RTL_SIZEOF_THROUGH_FIELD(MODE_PARAMETER_HEADER10, ModeDataLength);
  2230. if (t1 != t2) {
  2231. // size is wrong
  2232. printf("MRW mode page wrong size, %x != %x\n", t1, t2);
  2233. return -1;
  2234. }
  2235. if ((header->BlockDescriptorLength[0] != 0) ||
  2236. (header->BlockDescriptorLength[1] != 0) ) {
  2237. printf("MRW drive force a block descriptor %x %x\n",
  2238. header->BlockDescriptorLength[0],
  2239. header->BlockDescriptorLength[1]);
  2240. return -1;
  2241. }
  2242. page = (PMODE_MRW_PAGE)(header+1); // pointer arithmetic
  2243. if (page->PageCode != MODE_PAGE_MRW) {
  2244. printf("MRW mode page has wrong page code, %x != %x\n",
  2245. page->PageCode, MODE_PAGE_MRW);
  2246. return -1;
  2247. }
  2248. if (page->LbaSpace) {
  2249. printf("MRW mode page is set to GAA\n",
  2250. page->PageCode, MODE_PAGE_MRW);
  2251. // ModeSelect()...
  2252. return -1;
  2253. }
  2254. RtlCopyMemory(&savedModePage, page, sizeof(MODE_MRW_PAGE));
  2255. }
  2256. savedModePage.LbaSpace = 1;
  2257. if (!ModeSelect(device, &savedModePage, sizeof(MODE_MRW_PAGE))) {
  2258. printf("Unable to set MRW mode page to use GAA (%x)\n", GetLastError());
  2259. return -1;
  2260. }
  2261. if (!FillDisk(device, '\0wrm')) {
  2262. printf("Unable to fill the GAA (%x)\n", GetLastError());
  2263. }
  2264. printf("\nFinished Writing General Application Area!\n");
  2265. savedModePage.LbaSpace = 0;
  2266. if (!ModeSelect(device, &savedModePage, sizeof(MODE_MRW_PAGE))) {
  2267. printf("Unable to revert from GAA space -- disc may be unusable! (%x)\n",
  2268. GetLastError());
  2269. return -1;
  2270. }
  2271. #endif // 0
  2272. if (!FillDisk(device, '\0WRM')) {
  2273. printf("Unable to fill the disc (%x)\n", GetLastError());
  2274. return -1;
  2275. }
  2276. printf("\nFinished Writing Defect-managed Area!\n");
  2277. return 0;
  2278. }
  2279. DWORD
  2280. WaitForReadDiscInfoCommand(
  2281. HANDLE device,
  2282. int argc,
  2283. char *argv[]
  2284. )
  2285. {
  2286. CDB cdb;
  2287. DWORD size;
  2288. DISK_INFORMATION diskInfo;
  2289. DWORD i;
  2290. //
  2291. // loop using SCSIOP_READ_DISK_INFORMATION (0x51) since
  2292. // that seems to fail for *ALL* drives until the drive is ready
  2293. //
  2294. printf("Waiting for ReadDiscInfo");
  2295. for (i=0; ; i++) {
  2296. size = sizeof(DISK_INFORMATION);
  2297. RtlZeroMemory(&diskInfo, sizeof(DISK_INFORMATION));
  2298. RtlZeroMemory(&cdb, sizeof(CDB));
  2299. cdb.READ_DISK_INFORMATION.OperationCode = SCSIOP_READ_DISK_INFORMATION;
  2300. cdb.READ_DISK_INFORMATION.AllocationLength[0] = (UCHAR)(size >> 8);
  2301. cdb.READ_DISK_INFORMATION.AllocationLength[1] = (UCHAR)(size & 0xff);
  2302. if (SptSendCdbToDeviceEx(device, &cdb, 10,
  2303. (PUCHAR)&diskInfo, &size,
  2304. NULL, 0,
  2305. TRUE, 10)) {
  2306. printf("Succeeded! (%d seconds)\n", i);
  2307. return 0;
  2308. }
  2309. // should verify the errors are valid errors (AllowedReadDiscInfo[])?
  2310. // need to sleep here so we don't overload the unit!
  2311. Sleep(1000); // one second
  2312. if (i%10 == 0) {
  2313. printf(".");
  2314. }
  2315. }
  2316. return -1;
  2317. }