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.

1090 lines
32 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 "spti.h"
  15. PUCHAR BusTypeStrings[] = {
  16. "Unknown",
  17. "Scsi",
  18. "Atapi",
  19. "Ata",
  20. "1394",
  21. "Ssa",
  22. "Fibre",
  23. "Usb",
  24. "RAID",
  25. "Not Defined",
  26. };
  27. #define NUMBER_OF_BUS_TYPE_STRINGS (sizeof(BusTypeStrings)/sizeof(BusTypeStrings[0]))
  28. typedef struct _SPTI_OPTIONS {
  29. PUCHAR PortName;
  30. BOOLEAN SharedRead;
  31. BOOLEAN SharedWrite;
  32. BOOLEAN LockVolume;
  33. BOOLEAN ForceLock;
  34. } SPTI_OPTIONS, *PSPTI_OPTIONS;
  35. typedef enum _RETURN_VALUE {
  36. RETURN_BAD_ARGS = -1,
  37. RETURN_NAME_TOO_LONG = -2,
  38. RETURN_UNABLE_TO_OPEN_DEVICE = -3,
  39. RETURN_UNABLE_TO_LOCK_VOLUME = -4,
  40. RETURN_UNABLE_TO_GET_ALIGNMENT_MASK = -5,
  41. } RETURN_VALUE, *PRETURN_VALUE;
  42. BOOL
  43. LockVolume(
  44. HANDLE DeviceHandle,
  45. PSPTI_OPTIONS Options
  46. )
  47. {
  48. BOOL lockSucceeded;
  49. lockSucceeded = SptUtilLockVolumeByHandle(DeviceHandle, FALSE);
  50. if (!lockSucceeded && !Options->ForceLock)
  51. {
  52. // save the error, and restore after getting user input
  53. ULONG lastError = GetLastError();
  54. int input;
  55. do {
  56. printf("This program cannot run because the volume is in use\n"
  57. "by another process. It may run if this volume is\n"
  58. "dismounted first.\n"
  59. "ALL OPENED HANDLES TO THIS VOLUME WOULD THEN BE INVALID.\n"
  60. "Would you like to force a dismount on this volume? (Y/N) "
  61. );
  62. input = _getch();
  63. input = toupper( input );
  64. } while ( (input != EOF) &&
  65. (input != 'Y') &&
  66. (input != 'N') );
  67. if (input == 'Y')
  68. {
  69. Options->ForceLock = TRUE;
  70. }
  71. // now restore the error from the IOCTL
  72. SetLastError(lastError);
  73. }
  74. if (!lockSucceeded && Options->ForceLock)
  75. {
  76. lockSucceeded = SptUtilLockVolumeByHandle(DeviceHandle, TRUE);
  77. }
  78. return lockSucceeded;
  79. }
  80. BOOL
  81. ParseArguments(
  82. int argc,
  83. char * argv[],
  84. PSPTI_OPTIONS Options
  85. )
  86. {
  87. int i;
  88. if (Options == NULL)
  89. {
  90. return FALSE;
  91. }
  92. RtlZeroMemory( Options, sizeof(SPTI_OPTIONS) );
  93. Options->ForceLock = FALSE;
  94. Options->LockVolume = FALSE;
  95. Options->PortName = NULL;
  96. Options->SharedRead = FALSE;
  97. Options->SharedWrite = FALSE;
  98. // loop through the arguments....
  99. for (i = 1; i < argc; i++)
  100. {
  101. if ( (argv[i][0] == '/') || (argv[i][0] == '-') )
  102. {
  103. // switch found. parse it.
  104. PUCHAR option = &(argv[i][1]);
  105. if (_strnicmp(option, "r", strlen("r")) == 0)
  106. {
  107. Options->SharedRead = TRUE;
  108. }
  109. else if (_strnicmp(option, "w", strlen("w")) == 0)
  110. {
  111. Options->SharedWrite = TRUE;
  112. }
  113. else if (_strnicmp(option, "lock", strlen("lock")) == 0)
  114. {
  115. Options->LockVolume = TRUE;
  116. }
  117. else if (_strnicmp(option, "forcelock", strlen("forcelock")) == 0)
  118. {
  119. Options->ForceLock = TRUE;
  120. }
  121. else
  122. {
  123. printf("Unknown option: %s\n", argv[i]);
  124. return FALSE;
  125. }
  126. }
  127. else
  128. {
  129. // previously set one?
  130. if (Options->PortName != NULL)
  131. {
  132. printf("Can only have one non-option argument.\n"
  133. "Two were supplied: '%s', '%s'\n",
  134. Options->PortName,
  135. argv[i]
  136. );
  137. return FALSE;
  138. }
  139. else
  140. {
  141. // set to this argument
  142. Options->PortName = argv[i];
  143. }
  144. }
  145. } // end argument loop
  146. // validate non-conflicting options.
  147. if (Options->ForceLock || Options->LockVolume)
  148. {
  149. // locking the volume requires shared read/write access
  150. if ( (( Options->SharedRead) && (!Options->SharedWrite)) ||
  151. ((!Options->SharedRead) && ( Options->SharedWrite)) )
  152. {
  153. printf("Locking the volume requires both read and write shared "
  154. "access\n");
  155. return FALSE;
  156. }
  157. Options->LockVolume = TRUE;
  158. }
  159. // validate a port name was supplied
  160. if ( Options->PortName == NULL )
  161. {
  162. printf("A port name is a required argument\n");
  163. return FALSE;
  164. }
  165. // if they passed neither read nor write, set both as default
  166. if ((!Options->SharedRead) && (!Options->SharedWrite))
  167. {
  168. Options->SharedRead = TRUE;
  169. Options->SharedWrite = TRUE;
  170. }
  171. return TRUE;
  172. }
  173. //
  174. // Prints the built-in help for this program
  175. //
  176. VOID
  177. PrintUsageInfo(
  178. char * programName
  179. )
  180. {
  181. printf("Usage: %s <port-name> [-r | -w | -lock | -forcelock]\n", programName );
  182. printf("Examples:\n");
  183. printf(" %s g: (open the G: drive in SHARED READ/WRITE mode)\n", programName);
  184. printf(" %s i: r (open the I: drive in SHARED READ mode)\n", programName);
  185. printf(" %s r: lock (lock the R: volume for exclusive access\n", programName);
  186. printf(" %s Tape0 w (open the tape class driver in SHARED WRITE mode)\n", programName);
  187. printf(" %s Scsi2: (open the miniport driver specified)\n", programName);
  188. }
  189. //
  190. // don't print non-printable chars
  191. //
  192. VOID PrintChar( IN UCHAR Char ) {
  193. if ( (Char >= 0x21) && (Char <= 0x7E) ) {
  194. printf("%c", Char);
  195. } else {
  196. printf("%c", '.');
  197. }
  198. }
  199. //
  200. // Prints a buffer to the screen in hex and ASCII
  201. //
  202. VOID
  203. PrintBuffer(
  204. IN PVOID InputBuffer,
  205. IN SIZE_T Size
  206. )
  207. {
  208. DWORD offset = 0;
  209. PUCHAR buffer = InputBuffer;
  210. while (Size >= 0x10) {
  211. DWORD i;
  212. printf( "%08x:"
  213. " %02x %02x %02x %02x %02x %02x %02x %02x"
  214. " %02x %02x %02x %02x %02x %02x %02x %02x"
  215. " ",
  216. offset,
  217. *(buffer + 0), *(buffer + 1), *(buffer + 2), *(buffer + 3),
  218. *(buffer + 4), *(buffer + 5), *(buffer + 6), *(buffer + 7),
  219. *(buffer + 8), *(buffer + 9), *(buffer + 10), *(buffer + 11),
  220. *(buffer + 12), *(buffer + 13), *(buffer + 14), *(buffer + 15)
  221. );
  222. for (i=0; i < 0x10; i++) {
  223. PrintChar(*(buffer+i));
  224. }
  225. printf("\n");
  226. Size -= 0x10;
  227. offset += 0x10;
  228. buffer += 0x10;
  229. }
  230. if (Size != 0) {
  231. DWORD i;
  232. printf("%08x:", offset);
  233. //
  234. // print the hex values
  235. //
  236. for (i=0; i<Size; i++) {
  237. if ((i%8)==0) {
  238. printf(" "); // extra space every eight chars
  239. }
  240. printf(" %02x", *(buffer+i));
  241. }
  242. // add an extra space for half-way mark
  243. if (Size <= 0x8)
  244. {
  245. printf(" ");
  246. }
  247. //
  248. // fill in the blanks
  249. //
  250. for (; i < 0x10; i++) {
  251. printf(" ");
  252. }
  253. printf(" ");
  254. //
  255. // print the ascii
  256. //
  257. for (i=0; i<Size; i++) {
  258. PrintChar(*(buffer+i));
  259. }
  260. printf("\n");
  261. }
  262. return;
  263. }
  264. //
  265. // Prints the formatted message for a given error code
  266. //
  267. VOID
  268. PrintError(
  269. ULONG ErrorCode
  270. )
  271. {
  272. UCHAR errorBuffer[80];
  273. ULONG count;
  274. count = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  275. NULL,
  276. ErrorCode,
  277. 0,
  278. errorBuffer,
  279. sizeof(errorBuffer),
  280. NULL
  281. );
  282. if (count != 0) {
  283. printf("%s\n", errorBuffer);
  284. } else {
  285. printf("Format message failed. Error: %d\n", GetLastError());
  286. }
  287. }
  288. //
  289. // Prints the device descriptor in a formatted manner
  290. //
  291. VOID
  292. PrintAdapterDescriptor(
  293. PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor
  294. )
  295. {
  296. ULONG trueMaximumTransferLength;
  297. PUCHAR busType;
  298. if (AdapterDescriptor->BusType <= NUMBER_OF_BUS_TYPE_STRINGS) {
  299. busType = BusTypeStrings[AdapterDescriptor->BusType];
  300. } else {
  301. busType = BusTypeStrings[NUMBER_OF_BUS_TYPE_STRINGS-1];
  302. }
  303. // subtract one page, as transfers do not always start on a page boundary
  304. if (AdapterDescriptor->MaximumPhysicalPages > 1) {
  305. trueMaximumTransferLength = AdapterDescriptor->MaximumPhysicalPages - 1;
  306. } else {
  307. trueMaximumTransferLength = 1;
  308. }
  309. // make it into a byte value
  310. trueMaximumTransferLength <<= PAGE_SHIFT;
  311. // take the minimum of the two
  312. if (trueMaximumTransferLength > AdapterDescriptor->MaximumTransferLength) {
  313. trueMaximumTransferLength = AdapterDescriptor->MaximumTransferLength;
  314. }
  315. // always allow at least a single page transfer
  316. if (trueMaximumTransferLength < PAGE_SIZE) {
  317. trueMaximumTransferLength = PAGE_SIZE;
  318. }
  319. puts("\n ***** STORAGE ADAPTER DESCRIPTOR DATA *****");
  320. printf(" Version: %08x\n"
  321. " TotalSize: %08x\n"
  322. "MaximumTransferLength: %08x (bytes)\n"
  323. " MaximumPhysicalPages: %08x\n"
  324. " TrueMaximumTransfer: %08x (bytes)\n"
  325. " AlignmentMask: %08x\n"
  326. " AdapterUsesPio: %s\n"
  327. " AdapterScansDown: %s\n"
  328. " CommandQueueing: %s\n"
  329. " AcceleratedTransfer: %s\n"
  330. " Bus Type: %s\n"
  331. " Bus Major Version: %04x\n"
  332. " Bus Minor Version: %04x\n",
  333. AdapterDescriptor->Version,
  334. AdapterDescriptor->Size,
  335. AdapterDescriptor->MaximumTransferLength,
  336. AdapterDescriptor->MaximumPhysicalPages,
  337. trueMaximumTransferLength,
  338. AdapterDescriptor->AlignmentMask,
  339. BOOLEAN_TO_STRING(AdapterDescriptor->AdapterUsesPio),
  340. BOOLEAN_TO_STRING(AdapterDescriptor->AdapterScansDown),
  341. BOOLEAN_TO_STRING(AdapterDescriptor->CommandQueueing),
  342. BOOLEAN_TO_STRING(AdapterDescriptor->AcceleratedTransfer),
  343. busType,
  344. AdapterDescriptor->BusMajorVersion,
  345. AdapterDescriptor->BusMinorVersion);
  346. printf("\n\n");
  347. }
  348. //
  349. // Prints the adapter descriptor in a formatted manner
  350. //
  351. VOID
  352. PrintDeviceDescriptor(
  353. PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor
  354. )
  355. {
  356. PUCHAR vendorId = "";
  357. PUCHAR productId = "";
  358. PUCHAR productRevision = "";
  359. PUCHAR serialNumber = "";
  360. PUCHAR busType;
  361. if (DeviceDescriptor->BusType <= NUMBER_OF_BUS_TYPE_STRINGS) {
  362. busType = BusTypeStrings[DeviceDescriptor->BusType];
  363. } else {
  364. busType = BusTypeStrings[NUMBER_OF_BUS_TYPE_STRINGS-1];
  365. }
  366. if ((DeviceDescriptor->ProductIdOffset != 0) &&
  367. (DeviceDescriptor->ProductIdOffset != -1)) {
  368. productId = (PUCHAR)(DeviceDescriptor);
  369. productId += (ULONG_PTR)DeviceDescriptor->ProductIdOffset;
  370. }
  371. if ((DeviceDescriptor->VendorIdOffset != 0) &&
  372. (DeviceDescriptor->VendorIdOffset != -1)) {
  373. vendorId = (PUCHAR)(DeviceDescriptor);
  374. vendorId += (ULONG_PTR)DeviceDescriptor->VendorIdOffset;
  375. }
  376. if ((DeviceDescriptor->ProductRevisionOffset != 0) &&
  377. (DeviceDescriptor->ProductRevisionOffset != -1)) {
  378. productRevision = (PUCHAR)(DeviceDescriptor);
  379. productRevision += (ULONG_PTR)DeviceDescriptor->ProductRevisionOffset;
  380. }
  381. if ((DeviceDescriptor->SerialNumberOffset != 0) &&
  382. (DeviceDescriptor->SerialNumberOffset != -1)) {
  383. serialNumber = (PUCHAR)(DeviceDescriptor);
  384. serialNumber += (ULONG_PTR)DeviceDescriptor->SerialNumberOffset;
  385. }
  386. puts("\n ***** STORAGE DEVICE DESCRIPTOR DATA *****");
  387. printf(" Version: %08x\n"
  388. " TotalSize: %08x\n"
  389. " DeviceType: %08x\n"
  390. " DeviceTypeModifier: %08x\n"
  391. " RemovableMedia: %s\n"
  392. " CommandQueueing: %s\n"
  393. " Vendor Id: %s\n"
  394. " Product Id: %s\n"
  395. " Product Revision: %s\n"
  396. " Serial Number: %s\n"
  397. " Bus Type: %s\n"
  398. " Raw Properties: %s\n",
  399. DeviceDescriptor->Version,
  400. DeviceDescriptor->Size,
  401. DeviceDescriptor->DeviceType,
  402. DeviceDescriptor->DeviceTypeModifier,
  403. BOOLEAN_TO_STRING(DeviceDescriptor->RemovableMedia),
  404. BOOLEAN_TO_STRING(DeviceDescriptor->CommandQueueing),
  405. vendorId,
  406. productId,
  407. productRevision,
  408. serialNumber,
  409. busType,
  410. (DeviceDescriptor->RawPropertiesLength ? "Follow" : "None"));
  411. if (DeviceDescriptor->RawPropertiesLength != 0) {
  412. PrintBuffer(DeviceDescriptor->RawDeviceProperties,
  413. DeviceDescriptor->RawPropertiesLength);
  414. }
  415. printf("\n\n");
  416. }
  417. //
  418. // Gets (and prints) the device and adapter descriptor
  419. // for a device. Returns the alignment mask (required
  420. // for allocating a properly aligned buffer).
  421. //
  422. BOOL
  423. GetAlignmentMaskForDevice(
  424. IN HANDLE DeviceHandle,
  425. OUT PULONG AlignmentMask
  426. )
  427. {
  428. PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor = NULL;
  429. PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
  430. STORAGE_DESCRIPTOR_HEADER header = {0};
  431. BOOL ok = TRUE;
  432. BOOL failed = TRUE;
  433. ULONG i;
  434. *AlignmentMask = 0; // default to no alignment
  435. // Loop twice:
  436. // First, get size required for storage adapter descriptor
  437. // Second, allocate and retrieve storage adapter descriptor
  438. // Third, get size required for storage device descriptor
  439. // Fourth, allocate and retrieve storage device descriptor
  440. for (i=0;i<4;i++) {
  441. PVOID buffer;
  442. ULONG bufferSize;
  443. ULONG returnedData;
  444. STORAGE_PROPERTY_QUERY query = {0};
  445. switch(i) {
  446. case 0: {
  447. query.QueryType = PropertyStandardQuery;
  448. query.PropertyId = StorageAdapterProperty;
  449. bufferSize = sizeof(STORAGE_DESCRIPTOR_HEADER);
  450. buffer = &header;
  451. break;
  452. }
  453. case 1: {
  454. query.QueryType = PropertyStandardQuery;
  455. query.PropertyId = StorageAdapterProperty;
  456. bufferSize = header.Size;
  457. if (bufferSize != 0) {
  458. adapterDescriptor = LocalAlloc(LPTR, bufferSize);
  459. if (adapterDescriptor == NULL) {
  460. goto Cleanup;
  461. }
  462. }
  463. buffer = adapterDescriptor;
  464. break;
  465. }
  466. case 2: {
  467. query.QueryType = PropertyStandardQuery;
  468. query.PropertyId = StorageDeviceProperty;
  469. bufferSize = sizeof(STORAGE_DESCRIPTOR_HEADER);
  470. buffer = &header;
  471. break;
  472. }
  473. case 3: {
  474. query.QueryType = PropertyStandardQuery;
  475. query.PropertyId = StorageDeviceProperty;
  476. bufferSize = header.Size;
  477. if (bufferSize != 0) {
  478. deviceDescriptor = LocalAlloc(LPTR, bufferSize);
  479. if (deviceDescriptor == NULL) {
  480. goto Cleanup;
  481. }
  482. }
  483. buffer = deviceDescriptor;
  484. break;
  485. }
  486. }
  487. // buffer can be NULL if the property queried DNE.
  488. if (buffer != NULL) {
  489. RtlZeroMemory(buffer, bufferSize);
  490. // all setup, do the ioctl
  491. ok = DeviceIoControl(DeviceHandle,
  492. IOCTL_STORAGE_QUERY_PROPERTY,
  493. &query,
  494. sizeof(STORAGE_PROPERTY_QUERY),
  495. buffer,
  496. bufferSize,
  497. &returnedData,
  498. FALSE);
  499. if (!ok) {
  500. if (GetLastError() == ERROR_MORE_DATA) {
  501. // this is ok, we'll ignore it here
  502. } else if (GetLastError() == ERROR_INVALID_FUNCTION) {
  503. // this is also ok, the property DNE
  504. } else if (GetLastError() == ERROR_NOT_SUPPORTED) {
  505. // this is also ok, the property DNE
  506. } else {
  507. // some unexpected error -- exit out
  508. goto Cleanup;
  509. }
  510. // zero it out, just in case it was partially filled in.
  511. RtlZeroMemory(buffer, bufferSize);
  512. }
  513. }
  514. } // end i loop
  515. // adapterDescriptor is now allocated and full of data.
  516. // deviceDescriptor is now allocated and full of data.
  517. if (adapterDescriptor == NULL) {
  518. printf(" ***** No adapter descriptor supported on the device *****\n");
  519. } else {
  520. PrintAdapterDescriptor(adapterDescriptor);
  521. *AlignmentMask = adapterDescriptor->AlignmentMask;
  522. }
  523. if (deviceDescriptor == NULL) {
  524. printf(" ***** No device descriptor supported on the device *****\n");
  525. } else {
  526. PrintDeviceDescriptor(deviceDescriptor);
  527. }
  528. failed = FALSE;
  529. Cleanup:
  530. if (adapterDescriptor != NULL) {
  531. LocalFree( adapterDescriptor );
  532. }
  533. if (deviceDescriptor != NULL) {
  534. LocalFree( deviceDescriptor );
  535. }
  536. return (!failed);
  537. }
  538. BOOL
  539. pAllocateAlignedBuffer(
  540. PSPT_ALIGNED_MEMORY Allocation,
  541. ULONG AlignmentMask,
  542. SIZE_T AllocationSize,
  543. PUCHAR File,
  544. ULONG Line
  545. )
  546. {
  547. SIZE_T allocSize;
  548. if (Allocation->A != NULL)
  549. {
  550. // ASSERT(FALSE);
  551. SetLastError( ERROR_INVALID_PARAMETER );
  552. return FALSE;
  553. }
  554. if (Allocation->U != NULL)
  555. {
  556. // ASSERT(FALSE);
  557. SetLastError( ERROR_INVALID_PARAMETER );
  558. return FALSE;
  559. }
  560. if (Allocation->File != NULL)
  561. {
  562. // ASSERT(FALSE);
  563. SetLastError( ERROR_INVALID_PARAMETER );
  564. return FALSE;
  565. }
  566. if (Allocation->Line != 0)
  567. {
  568. // ASSERT(FALSE);
  569. SetLastError( ERROR_INVALID_PARAMETER );
  570. return FALSE;
  571. }
  572. RtlZeroMemory(Allocation, sizeof( SPT_ALIGNED_MEMORY ));
  573. if ( AllocationSize > (((SIZE_T)-1) >> 2) )
  574. {
  575. SetLastError( ERROR_INVALID_PARAMETER );
  576. return FALSE;
  577. }
  578. if (AlignmentMask == ((ULONG)-1))
  579. {
  580. SetLastError( ERROR_INVALID_PARAMETER );
  581. return FALSE;
  582. }
  583. if (CountOfSetBits(AlignmentMask+1) != 1)
  584. {
  585. printf("Alignment mask (%x) is invalid -- all bits from the highest set "
  586. "bit must be set to one\n", AlignmentMask);
  587. SetLastError( ERROR_INVALID_PARAMETER );
  588. return FALSE;
  589. }
  590. //
  591. // Allocate a buffer large enough to guarantee that there exists
  592. // within the allocation an aligned address with sufficient length
  593. //
  594. Allocation->U = LocalAlloc( LPTR, AllocationSize + AlignmentMask );
  595. if (Allocation->U == NULL)
  596. {
  597. return FALSE;
  598. }
  599. //
  600. // Now fill in the remainder of the structure
  601. //
  602. Allocation->A = (PVOID)( ((ULONG_PTR)Allocation->U) + AlignmentMask );
  603. Allocation->A = (PVOID)( ((ULONG_PTR)Allocation->A) & (~((ULONG_PTR)AlignmentMask)) );
  604. Allocation->File = File;
  605. Allocation->Line = Line;
  606. return TRUE;
  607. }
  608. VOID
  609. FreeAlignedBuffer(
  610. PSPT_ALIGNED_MEMORY Allocation
  611. )
  612. {
  613. // ASSERT( Allocation->U != NULL );
  614. // ASSERT( Allocation->A != NULL );
  615. // ASSERT( Allocation->File != NULL );
  616. // ASSERT( Allocation->Line != 0 );
  617. if (Allocation->U != NULL)
  618. {
  619. LocalFree( Allocation->U );
  620. }
  621. RtlZeroMemory( Allocation, sizeof(SPT_ALIGNED_MEMORY) );
  622. return;
  623. }
  624. int
  625. __cdecl
  626. main(
  627. int argc,
  628. char *argv[]
  629. )
  630. {
  631. HANDLE deviceHandle;
  632. SPTI_OPTIONS options;
  633. ULONG alignmentMask;
  634. RtlZeroMemory(&options, sizeof(SPTI_OPTIONS));
  635. // first, verify we have proper arguments
  636. if (!ParseArguments(argc, argv, &options))
  637. {
  638. PrintUsageInfo(argv[0]);
  639. return RETURN_BAD_ARGS;
  640. }
  641. // open the device as requested
  642. {
  643. #define MAX_LENGTH 250
  644. UCHAR buffer[MAX_LENGTH];
  645. HRESULT hr;
  646. DWORD shareFlags;
  647. hr = StringCchPrintf(buffer,
  648. sizeof(buffer)/sizeof(buffer[0]),
  649. "\\\\.\\%s",
  650. options.PortName
  651. );
  652. if (!SUCCEEDED(hr)) {
  653. puts("Port name exceeded internal length limit");
  654. return RETURN_NAME_TOO_LONG;
  655. }
  656. shareFlags = 0;
  657. if (options.SharedRead)
  658. {
  659. SET_FLAG( shareFlags, FILE_SHARE_READ );
  660. }
  661. if (options.SharedWrite)
  662. {
  663. SET_FLAG( shareFlags, FILE_SHARE_WRITE );
  664. }
  665. deviceHandle = CreateFile(buffer,
  666. GENERIC_READ | GENERIC_WRITE,
  667. shareFlags,
  668. NULL,
  669. OPEN_EXISTING,
  670. FILE_ATTRIBUTE_NORMAL,
  671. NULL);
  672. if(deviceHandle == INVALID_HANDLE_VALUE) {
  673. printf("Error opening device %s\n", buffer);
  674. PrintError(GetLastError());
  675. return RETURN_UNABLE_TO_OPEN_DEVICE;
  676. }
  677. }
  678. // lock the volume if requested
  679. if (options.LockVolume)
  680. {
  681. if (!LockVolume(deviceHandle, &options))
  682. {
  683. puts("Error locking volume");
  684. PrintError(GetLastError());
  685. return RETURN_UNABLE_TO_LOCK_VOLUME;
  686. }
  687. }
  688. // get device information, such as the alignment mask
  689. if (!GetAlignmentMaskForDevice(deviceHandle, &alignmentMask))
  690. {
  691. puts("Unable to get alignment mask for device");
  692. PrintError(GetLastError());
  693. return RETURN_UNABLE_TO_GET_ALIGNMENT_MASK;
  694. }
  695. printf("\n"
  696. " ***** Detected Alignment Mask *****\n"
  697. " ***** was %08x *****\n\n",
  698. alignmentMask);
  699. puts("");
  700. puts(" ***** MODE SENSE10 -- return all pages *****");
  701. puts(" ***** with SenseInfo buffer *****\n");
  702. {
  703. SPT_ALIGNED_MEMORY alignedAllocation;
  704. DWORD allocationSize = MAXIMUM_BUFFER_SIZE;
  705. RtlZeroMemory( &alignedAllocation, sizeof(SPT_ALIGNED_MEMORY) );
  706. if (!AllocateAlignedBuffer(&alignedAllocation,
  707. alignmentMask,
  708. allocationSize))
  709. {
  710. puts("Unable to allocate memory for MODE_SENSE10");
  711. PrintError(GetLastError());
  712. }
  713. else
  714. {
  715. CDB cdb;
  716. SENSE_DATA sense;
  717. RtlZeroMemory( &cdb, sizeof(CDB) );
  718. RtlZeroMemory( &sense, sizeof(SENSE_DATA) );
  719. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  720. cdb.MODE_SENSE10.PageCode = MODE_SENSE_RETURN_ALL;
  721. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(allocationSize >> (8*1));
  722. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(allocationSize >> (8*0));
  723. if (!SptSendCdbToDeviceEx(deviceHandle,
  724. &cdb,
  725. sizeof( cdb.MODE_SENSE10 ),
  726. alignedAllocation.A,
  727. &allocationSize,
  728. &sense,
  729. sizeof( SENSE_DATA ),
  730. TRUE,
  731. SPT_MODE_SENSE_TIMEOUT))
  732. {
  733. puts("Unable to send command to device");
  734. if (GetLastError() == ERROR_SUCCESS)
  735. {
  736. puts("Inquiry data may be valid\n");
  737. printf("Failed %02x/%02x/%02x, full sense data:\n",
  738. sense.SenseKey,
  739. sense.AdditionalSenseCode,
  740. sense.AdditionalSenseCodeQualifier
  741. );
  742. PrintBuffer(&sense, sizeof(SENSE_DATA));
  743. }
  744. else
  745. {
  746. PrintError(GetLastError());
  747. }
  748. }
  749. else if (sense.SenseKey != SCSI_SENSE_NO_SENSE)
  750. {
  751. printf("Failed %02x/%02x/%02x, full sense data:\n",
  752. sense.SenseKey,
  753. sense.AdditionalSenseCode,
  754. sense.AdditionalSenseCodeQualifier
  755. );
  756. PrintBuffer(&sense, sizeof(SENSE_DATA));
  757. }
  758. else
  759. {
  760. printf("%x bytes returned:\n", allocationSize);
  761. PrintBuffer(alignedAllocation.A, allocationSize);
  762. }
  763. FreeAlignedBuffer( &alignedAllocation );
  764. }
  765. }
  766. puts("");
  767. puts(" ***** MODE SENSE10 -- return all pages *****");
  768. puts(" ***** without SenseInfo buffer *****\n");
  769. {
  770. SPT_ALIGNED_MEMORY alignedAllocation;
  771. DWORD allocationSize = MAXIMUM_BUFFER_SIZE;
  772. RtlZeroMemory( &alignedAllocation, sizeof(SPT_ALIGNED_MEMORY) );
  773. if (!AllocateAlignedBuffer(&alignedAllocation,
  774. alignmentMask,
  775. allocationSize))
  776. {
  777. puts("Unable to allocate memory for MODE_SENSE10");
  778. PrintError(GetLastError());
  779. }
  780. else
  781. {
  782. CDB cdb;
  783. RtlZeroMemory( &cdb, sizeof(CDB) );
  784. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  785. cdb.MODE_SENSE10.PageCode = MODE_SENSE_RETURN_ALL;
  786. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(allocationSize >> (8*1));
  787. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(allocationSize >> (8*0));
  788. if (!SptSendCdbToDeviceEx(deviceHandle,
  789. &cdb,
  790. sizeof( cdb.MODE_SENSE10 ),
  791. alignedAllocation.A,
  792. &allocationSize,
  793. NULL,
  794. 0,
  795. TRUE,
  796. SPT_MODE_SENSE_TIMEOUT))
  797. {
  798. PrintError(GetLastError());
  799. puts("Unable to send command to device");
  800. }
  801. else
  802. {
  803. printf("%x bytes returned:\n", allocationSize);
  804. PrintBuffer(alignedAllocation.A, allocationSize);
  805. }
  806. FreeAlignedBuffer( &alignedAllocation );
  807. }
  808. }
  809. puts("");
  810. puts(" ***** TEST UNIT READY *****\n");
  811. puts(" ***** DataBufferLength = 0 *****\n\n");
  812. {
  813. CDB cdb;
  814. SENSE_DATA sense;
  815. DWORD allocationSize = 0;
  816. RtlZeroMemory( &cdb, sizeof(CDB) );
  817. RtlZeroMemory( &sense, sizeof(SENSE_DATA) );
  818. cdb.CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  819. if (!SptSendCdbToDeviceEx(deviceHandle,
  820. &cdb,
  821. sizeof( cdb.CDB6GENERIC ),
  822. NULL,
  823. &allocationSize,
  824. &sense,
  825. sizeof( SENSE_DATA ),
  826. FALSE, // not sending anything to the device
  827. SPT_DEFAULT_TIMEOUT))
  828. {
  829. puts("Unable to send command to device");
  830. if (GetLastError() == ERROR_SUCCESS)
  831. {
  832. puts("Inquiry data may be valid\n");
  833. printf("Failed %02x/%02x/%02x, full sense data:\n",
  834. sense.SenseKey,
  835. sense.AdditionalSenseCode,
  836. sense.AdditionalSenseCodeQualifier
  837. );
  838. PrintBuffer(&sense, sizeof(SENSE_DATA));
  839. }
  840. else
  841. {
  842. PrintError(GetLastError());
  843. }
  844. }
  845. else if (sense.SenseKey != SCSI_SENSE_NO_SENSE)
  846. {
  847. printf("Failed %02x/%02x/%02x, full sense data:\n",
  848. sense.SenseKey,
  849. sense.AdditionalSenseCode,
  850. sense.AdditionalSenseCodeQualifier
  851. );
  852. PrintBuffer(&sense, sizeof(SENSE_DATA));
  853. }
  854. else
  855. {
  856. printf("%x bytes returned\n", allocationSize);
  857. }
  858. }
  859. puts("");
  860. puts(" ***** MODE SENSE10 -- return C/DVD *****");
  861. puts(" ***** capabalities page only *****\n");
  862. {
  863. SPT_ALIGNED_MEMORY alignedAllocation;
  864. DWORD allocationSize = MAXIMUM_BUFFER_SIZE;
  865. RtlZeroMemory( &alignedAllocation, sizeof(SPT_ALIGNED_MEMORY) );
  866. if (!AllocateAlignedBuffer(&alignedAllocation,
  867. alignmentMask,
  868. allocationSize))
  869. {
  870. puts("Unable to allocate memory for MODE_SENSE10");
  871. PrintError(GetLastError());
  872. }
  873. else
  874. {
  875. CDB cdb;
  876. SENSE_DATA sense;
  877. RtlZeroMemory( &cdb, sizeof(CDB) );
  878. RtlZeroMemory( &sense, sizeof(SENSE_DATA) );
  879. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  880. cdb.MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
  881. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(allocationSize >> (8*1));
  882. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(allocationSize >> (8*0));
  883. if (!SptSendCdbToDeviceEx(deviceHandle,
  884. &cdb,
  885. sizeof( cdb.MODE_SENSE10 ),
  886. alignedAllocation.A,
  887. &allocationSize,
  888. &sense,
  889. sizeof( SENSE_DATA ),
  890. TRUE,
  891. SPT_MODE_SENSE_TIMEOUT))
  892. {
  893. puts("Unable to send command to device");
  894. if (GetLastError() == ERROR_SUCCESS)
  895. {
  896. puts("Inquiry data may be valid\n");
  897. printf("Failed %02x/%02x/%02x, full sense data:\n",
  898. sense.SenseKey,
  899. sense.AdditionalSenseCode,
  900. sense.AdditionalSenseCodeQualifier
  901. );
  902. PrintBuffer(&sense, sizeof(SENSE_DATA));
  903. }
  904. else
  905. {
  906. PrintError(GetLastError());
  907. }
  908. }
  909. else if (sense.SenseKey != SCSI_SENSE_NO_SENSE)
  910. {
  911. printf("Failed %02x/%02x/%02x, full sense data:\n",
  912. sense.SenseKey,
  913. sense.AdditionalSenseCode,
  914. sense.AdditionalSenseCodeQualifier
  915. );
  916. PrintBuffer(&sense, sizeof(SENSE_DATA));
  917. }
  918. else
  919. {
  920. printf("%x bytes returned:\n", allocationSize);
  921. PrintBuffer(alignedAllocation.A, allocationSize);
  922. }
  923. FreeAlignedBuffer( &alignedAllocation );
  924. }
  925. }
  926. }