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

1101 lines
27 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: ioctl.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "cdchgr.h"
  11. BOOLEAN
  12. InvalidElement(
  13. IN PDEVICE_EXTENSION DeviceExtension,
  14. IN CHANGER_ELEMENT Element
  15. );
  16. BOOLEAN
  17. ChgrIoctl(
  18. IN ULONG Code
  19. )
  20. {
  21. ULONG baseCode;
  22. baseCode = Code >> 16;
  23. if (baseCode == IOCTL_CHANGER_BASE) {
  24. DebugPrint((3,
  25. "ChngrIoctl returning TRUE for Base %x, Code %x\n",
  26. baseCode,
  27. Code));
  28. return TRUE;
  29. } else {
  30. DebugPrint((3,
  31. "ChngrIoctl returning FALSE for Base %x, Code %x\n",
  32. baseCode,
  33. Code));
  34. return FALSE;
  35. }
  36. }
  37. NTSTATUS
  38. ChgrGetStatus(
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN PIRP Irp
  41. )
  42. {
  43. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  44. PPASS_THROUGH_REQUEST passThrough;
  45. PSCSI_PASS_THROUGH srb;
  46. NTSTATUS status;
  47. ULONG length;
  48. PCDB cdb;
  49. //
  50. // Allocate a request block.
  51. //
  52. passThrough = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(PASS_THROUGH_REQUEST));
  53. if (!passThrough) {
  54. return STATUS_INSUFFICIENT_RESOURCES;
  55. }
  56. srb = &passThrough->Srb;
  57. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  58. cdb = (PCDB)srb->Cdb;
  59. srb->CdbLength = CDB6GENERIC_LENGTH;
  60. //
  61. // Build TUR.
  62. //
  63. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  64. srb->TimeOutValue = 20;
  65. srb->DataTransferLength = 0;
  66. if (deviceExtension->DeviceType == TORISAN) {
  67. DebugPrint((1,
  68. "GetStatus: Using CurrentPlatter %x\n",
  69. deviceExtension->CurrentPlatter));
  70. srb->Cdb[7] = (UCHAR)deviceExtension->CurrentPlatter;
  71. srb->CdbLength = 10;
  72. }
  73. //
  74. // Send the request.
  75. //
  76. status = SendPassThrough(DeviceObject,
  77. passThrough);
  78. //
  79. // Check out the status. As this is fake (taking to the cdrom drive, not to a robotic target),
  80. // will probably have to make up some stuff.
  81. //
  82. if (status == STATUS_NO_MEDIA_IN_DEVICE) {
  83. status = STATUS_SUCCESS;
  84. }
  85. ExFreePool(passThrough);
  86. if (NT_SUCCESS(status)) {
  87. if (deviceExtension->DeviceType == ATAPI_25) {
  88. //
  89. // Issue mech. status to see if any changed bits are set for those
  90. // drives that actually support this.
  91. //
  92. length = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
  93. length += (deviceExtension->NumberOfSlots) * sizeof(SLOT_TABLE_INFORMATION);
  94. passThrough = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(PASS_THROUGH_REQUEST) + length);
  95. if (!passThrough) {
  96. return STATUS_INSUFFICIENT_RESOURCES;
  97. }
  98. srb = &passThrough->Srb;
  99. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST) + length);
  100. cdb = (PCDB)srb->Cdb;
  101. srb->CdbLength = CDB12GENERIC_LENGTH;
  102. srb->DataTransferLength = length;
  103. srb->TimeOutValue = 200;
  104. cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS;
  105. cdb->MECH_STATUS.AllocationLength[0] = (UCHAR)(length >> 8);
  106. cdb->MECH_STATUS.AllocationLength[1] = (UCHAR)(length & 0xFF);
  107. //
  108. // Send SCSI command (CDB) to device
  109. //
  110. status = SendPassThrough(DeviceObject,
  111. passThrough);
  112. if (NT_SUCCESS(status)) {
  113. //
  114. // Run through slot info, looking for a set changed bit.
  115. //
  116. PSLOT_TABLE_INFORMATION slotInfo;
  117. PMECHANICAL_STATUS_INFORMATION_HEADER statusHeader;
  118. ULONG slotCount;
  119. ULONG currentSlot;
  120. (ULONG_PTR)statusHeader = (ULONG_PTR)passThrough->DataBuffer;
  121. (ULONG_PTR)slotInfo = (ULONG_PTR)statusHeader;
  122. (ULONG_PTR)slotInfo += sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
  123. slotCount = statusHeader->SlotTableLength[1];
  124. slotCount |= (statusHeader->SlotTableLength[0] << 8);
  125. //
  126. // Total slot information entries.
  127. //
  128. slotCount /= sizeof(SLOT_TABLE_INFORMATION);
  129. //
  130. // Move the slotInfo pointer to the correct entry.
  131. //
  132. for (currentSlot = 0; currentSlot < slotCount; currentSlot++) {
  133. if (slotInfo->DiscChanged) {
  134. status = STATUS_MEDIA_CHANGED;
  135. break;
  136. }
  137. //
  138. // Advance to next slot.
  139. //
  140. slotInfo += 1;
  141. }
  142. }
  143. ExFreePool(passThrough);
  144. }
  145. }
  146. return status;
  147. }
  148. NTSTATUS
  149. ChgrGetParameters(
  150. IN PDEVICE_OBJECT DeviceObject,
  151. IN PIRP Irp
  152. )
  153. {
  154. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  155. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  156. PGET_CHANGER_PARAMETERS changerParameters;
  157. changerParameters = Irp->AssociatedIrp.SystemBuffer;
  158. RtlZeroMemory(changerParameters, sizeof(GET_CHANGER_PARAMETERS));
  159. changerParameters->Size = sizeof(GET_CHANGER_PARAMETERS);
  160. changerParameters->NumberTransportElements = 1;
  161. changerParameters->NumberStorageElements = (USHORT)deviceExtension->NumberOfSlots;
  162. changerParameters->NumberIEElements = 0;
  163. changerParameters->NumberDataTransferElements = 1;
  164. changerParameters->NumberOfDoors = 0;
  165. changerParameters->NumberCleanerSlots = 0;
  166. changerParameters->FirstSlotNumber = 1;
  167. changerParameters->FirstDriveNumber = 0;
  168. changerParameters->FirstTransportNumber = 0;
  169. changerParameters->FirstIEPortNumber = 0;
  170. if (deviceExtension->MechType == 1) {
  171. //
  172. // For example, ALPS, Panasonic, Torisan.
  173. //
  174. changerParameters->MagazineSize = (USHORT)deviceExtension->NumberOfSlots;
  175. changerParameters->Features0 = (CHANGER_CARTRIDGE_MAGAZINE |
  176. CHANGER_STORAGE_SLOT |
  177. CHANGER_LOCK_UNLOCK);
  178. } else {
  179. //
  180. // For the NEC.
  181. //
  182. changerParameters->MagazineSize = 0;
  183. changerParameters->Features0 = (CHANGER_STORAGE_SLOT |
  184. CHANGER_LOCK_UNLOCK);
  185. }
  186. changerParameters->DriveCleanTimeout = 0;
  187. //
  188. // Features based on manual, nothing programatic.
  189. //
  190. changerParameters->MoveFromSlot = CHANGER_TO_DRIVE | CHANGER_TO_TRANSPORT;
  191. Irp->IoStatus.Information = sizeof(GET_CHANGER_PARAMETERS);
  192. return STATUS_SUCCESS;
  193. }
  194. NTSTATUS
  195. ChgrGetProductData(
  196. IN PDEVICE_OBJECT DeviceObject,
  197. IN PIRP Irp
  198. )
  199. {
  200. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  201. PCHANGER_PRODUCT_DATA productData = Irp->AssociatedIrp.SystemBuffer;
  202. RtlZeroMemory(productData, sizeof(CHANGER_PRODUCT_DATA));
  203. //
  204. // Copy cached inquiry data fields into the system buffer.
  205. //
  206. RtlMoveMemory(productData->VendorId, deviceExtension->InquiryData.VendorId, VENDOR_ID_LENGTH);
  207. RtlMoveMemory(productData->ProductId, deviceExtension->InquiryData.ProductId, PRODUCT_ID_LENGTH);
  208. RtlMoveMemory(productData->Revision, deviceExtension->InquiryData.ProductRevisionLevel, REVISION_LENGTH);
  209. RtlMoveMemory(productData->SerialNumber, deviceExtension->InquiryData.VendorSpecific, SERIAL_NUMBER_LENGTH);
  210. productData->DeviceType = MEDIUM_CHANGER;
  211. Irp->IoStatus.Information = sizeof(CHANGER_PRODUCT_DATA);
  212. return STATUS_SUCCESS;
  213. }
  214. NTSTATUS
  215. ChgrSetAccess(
  216. IN PDEVICE_OBJECT DeviceObject,
  217. IN PIRP Irp
  218. )
  219. {
  220. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  221. PCHANGER_SET_ACCESS setAccess = Irp->AssociatedIrp.SystemBuffer;
  222. ULONG controlOperation = setAccess->Control;
  223. PPASS_THROUGH_REQUEST passThrough;
  224. PSCSI_PASS_THROUGH srb;
  225. NTSTATUS status;
  226. PCDB cdb;
  227. if (setAccess->Element.ElementType != ChangerDoor) {
  228. //
  229. // No IEPORTs on these devices.
  230. //
  231. return STATUS_INVALID_PARAMETER;
  232. }
  233. //
  234. // Allocate a request block.
  235. //
  236. passThrough = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(PASS_THROUGH_REQUEST));
  237. if (!passThrough) {
  238. return STATUS_INSUFFICIENT_RESOURCES;
  239. }
  240. srb = &passThrough->Srb;
  241. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  242. cdb = (PCDB)srb->Cdb;
  243. srb->CdbLength = CDB6GENERIC_LENGTH;
  244. cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
  245. srb->DataTransferLength = 0;
  246. srb->TimeOutValue = 10;
  247. status = STATUS_SUCCESS;
  248. if (controlOperation == LOCK_ELEMENT) {
  249. //
  250. // Issue prevent media removal command to lock the magazine.
  251. //
  252. cdb->MEDIA_REMOVAL.Prevent = 1;
  253. } else if (controlOperation == UNLOCK_ELEMENT) {
  254. //
  255. // Issue allow media removal.
  256. //
  257. cdb->MEDIA_REMOVAL.Prevent = 0;
  258. } else {
  259. status = STATUS_INVALID_PARAMETER;
  260. }
  261. if (NT_SUCCESS(status)) {
  262. //
  263. // Send the request.
  264. //
  265. status = SendPassThrough(DeviceObject,
  266. passThrough);
  267. }
  268. ExFreePool(passThrough);
  269. if (NT_SUCCESS(status)) {
  270. Irp->IoStatus.Information = sizeof(CHANGER_SET_ACCESS);
  271. }
  272. return status;
  273. }
  274. NTSTATUS
  275. ChgrGetElementStatus(
  276. IN PDEVICE_OBJECT DeviceObject,
  277. IN PIRP Irp
  278. )
  279. {
  280. return STATUS_INVALID_DEVICE_REQUEST;
  281. }
  282. NTSTATUS
  283. ChgrInitializeElementStatus(
  284. IN PDEVICE_OBJECT DeviceObject,
  285. IN PIRP Irp
  286. )
  287. {
  288. return STATUS_INVALID_DEVICE_REQUEST;
  289. }
  290. NTSTATUS
  291. ChgrSetPosition(
  292. IN PDEVICE_OBJECT DeviceObject,
  293. IN PIRP Irp
  294. )
  295. {
  296. //
  297. // These device don't support this.
  298. //
  299. return STATUS_INVALID_DEVICE_REQUEST;
  300. }
  301. NTSTATUS
  302. ChgrExchangeMedium(
  303. IN PDEVICE_OBJECT DeviceObject,
  304. IN PIRP Irp
  305. )
  306. {
  307. //
  308. // These device don't support this.
  309. //
  310. return STATUS_INVALID_DEVICE_REQUEST;
  311. }
  312. NTSTATUS
  313. ChgrReinitializeUnit(
  314. IN PDEVICE_OBJECT DeviceObject,
  315. IN PIRP Irp
  316. )
  317. {
  318. //
  319. // These device don't support this.
  320. //
  321. return STATUS_INVALID_DEVICE_REQUEST;
  322. }
  323. NTSTATUS
  324. ChgrQueryVolumeTags(
  325. IN PDEVICE_OBJECT DeviceObject,
  326. IN PIRP Irp
  327. )
  328. {
  329. //
  330. // These device don't support this.
  331. //
  332. return STATUS_INVALID_DEVICE_REQUEST;
  333. }
  334. NTSTATUS
  335. ChgrMoveMedium(
  336. IN PDEVICE_OBJECT DeviceObject,
  337. IN PIRP Irp
  338. )
  339. {
  340. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  341. PCHANGER_MOVE_MEDIUM moveMedium = Irp->AssociatedIrp.SystemBuffer;
  342. USHORT transport;
  343. USHORT source;
  344. USHORT destination;
  345. PPASS_THROUGH_REQUEST passThrough;
  346. PSCSI_PASS_THROUGH srb;
  347. PCDB cdb;
  348. NTSTATUS status;
  349. //
  350. // Verify transport, source, and dest. are within range.
  351. //
  352. if (InvalidElement(deviceExtension,moveMedium->Transport)) {
  353. DebugPrint((1,
  354. "ChangerMoveMedium: Transport element out of range.\n"));
  355. return STATUS_ILLEGAL_ELEMENT_ADDRESS;
  356. }
  357. if (InvalidElement(deviceExtension, moveMedium->Source)) {
  358. DebugPrint((1,
  359. "ChangerMoveMedium: Source element out of range.\n"));
  360. return STATUS_ILLEGAL_ELEMENT_ADDRESS;
  361. }
  362. if (InvalidElement(deviceExtension,moveMedium->Destination)) {
  363. DebugPrint((1,
  364. "ChangerMoveMedium: Destination element out of range.\n"));
  365. return STATUS_ILLEGAL_ELEMENT_ADDRESS;
  366. }
  367. //
  368. // Build srb and cdb.
  369. //
  370. passThrough = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(PASS_THROUGH_REQUEST));
  371. if (!passThrough) {
  372. return STATUS_INSUFFICIENT_RESOURCES;
  373. }
  374. //
  375. // The torisan units don't really move medium, rather the active disc is changed.
  376. // To change slots, they've overloaded TUR.
  377. //
  378. if (deviceExtension->DeviceType == TORISAN) {
  379. if (moveMedium->Destination.ElementType == ChangerDrive) {
  380. srb = &passThrough->Srb;
  381. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  382. cdb = (PCDB)srb->Cdb;
  383. srb->CdbLength = CDB10GENERIC_LENGTH;
  384. //
  385. // Build TUR.
  386. //
  387. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  388. srb->Cdb[7] = (UCHAR)moveMedium->Source.ElementAddress;
  389. srb->TimeOutValue = 20;
  390. srb->DataTransferLength = 0;
  391. //
  392. // Send the request.
  393. //
  394. status = SendPassThrough(DeviceObject,
  395. passThrough);
  396. if (status == STATUS_DEVICE_NOT_READY) {
  397. // TODO send a TUR to verify this.
  398. DebugPrint((1,
  399. "MoveMedium - Claiming success\n"));
  400. status = STATUS_SUCCESS;
  401. } else if (status == STATUS_NO_MEDIA_IN_DEVICE) {
  402. status = STATUS_SOURCE_ELEMENT_EMPTY;
  403. }
  404. if (NT_SUCCESS(status)) {
  405. //
  406. // Update the current disc indicator.
  407. //
  408. deviceExtension->CurrentPlatter = moveMedium->Source.ElementAddress;
  409. DebugPrint((1,
  410. "MoveMedium: Set currentPlatter to %x\n",
  411. deviceExtension->CurrentPlatter));
  412. ExFreePool(passThrough);
  413. return STATUS_SUCCESS;
  414. } else {
  415. DebugPrint((1,
  416. "MoveMedium - Status on move %lx\n",
  417. status));
  418. ExFreePool(passThrough);
  419. return status;
  420. }
  421. } else {
  422. //
  423. // Claim that is happened.
  424. //
  425. ExFreePool(passThrough);
  426. return STATUS_SUCCESS;
  427. }
  428. }
  429. //
  430. // If destination is the drive, determine if media is already present.
  431. // The alps always claims media is there, so don't check.
  432. //
  433. #if 0
  434. if (((moveMedium->Destination.ElementType) == ChangerDrive) &&
  435. (deviceExtension->DeviceType != ALPS_25)) {
  436. srb = &passThrough->Srb;
  437. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  438. cdb = (PCDB)srb->Cdb;
  439. srb->CdbLength = CDB6GENERIC_LENGTH;
  440. //
  441. // Build TUR.
  442. //
  443. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  444. srb->TimeOutValue = 20;
  445. srb->DataTransferLength = 0;
  446. //
  447. // Send the request.
  448. //
  449. status = SendPassThrough(DeviceObject,
  450. passThrough);
  451. if (status != STATUS_NO_MEDIA_IN_DEVICE) {
  452. //
  453. // Drive has media. Though the device will allow this,
  454. // error it, as the expected medium changer behaviour is
  455. // to return element full in this case.
  456. //
  457. DebugPrint((1,
  458. "ChgrMoveMedium: Drive already has media. TUR Status %lx\n",
  459. status));
  460. ExFreePool(passThrough);
  461. return STATUS_DESTINATION_ELEMENT_FULL;
  462. }
  463. }
  464. #endif
  465. srb = &passThrough->Srb;
  466. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  467. cdb = (PCDB)srb->Cdb;
  468. srb->CdbLength = CDB12GENERIC_LENGTH;
  469. srb->TimeOutValue = CDCHGR_TIMEOUT;
  470. srb->DataTransferLength = 0;
  471. //
  472. // LOAD_UNLOAD will move a disc from slot to drive,
  473. // or from drive to slot.
  474. //
  475. cdb->LOAD_UNLOAD.OperationCode = SCSIOP_LOAD_UNLOAD_SLOT;
  476. if (moveMedium->Source.ElementType == ChangerDrive) {
  477. cdb->LOAD_UNLOAD.Slot = (UCHAR)moveMedium->Destination.ElementAddress;
  478. cdb->LOAD_UNLOAD.Start = 0;
  479. cdb->LOAD_UNLOAD.LoadEject = 1;
  480. } else if (moveMedium->Source.ElementType == ChangerSlot) {
  481. cdb->LOAD_UNLOAD.Slot = (UCHAR)moveMedium->Source.ElementAddress;
  482. cdb->LOAD_UNLOAD.Start = 1;
  483. cdb->LOAD_UNLOAD.LoadEject = 1;
  484. }
  485. //
  486. // Send SCSI command (CDB) to device
  487. //
  488. status = SendPassThrough(DeviceObject,
  489. passThrough);
  490. if (NT_SUCCESS(status)) {
  491. //
  492. // These devices don't seem to ever generate
  493. // a unit attention, for media changed, so fake it.
  494. //
  495. if (deviceExtension->CdromTargetDeviceObject->Vpb->Flags & VPB_MOUNTED) {
  496. DebugPrint((1,
  497. "Faking DO_VERIFY_VOLUME\n"));
  498. deviceExtension->CdromTargetDeviceObject->Flags |= DO_VERIFY_VOLUME;
  499. }
  500. } else if (status == STATUS_NO_MEDIA_IN_DEVICE) {
  501. status = STATUS_SOURCE_ELEMENT_EMPTY;
  502. }
  503. ExFreePool(passThrough);
  504. return status;
  505. }
  506. BOOLEAN
  507. InvalidElement(
  508. IN PDEVICE_EXTENSION DeviceExtension,
  509. IN CHANGER_ELEMENT Element
  510. )
  511. {
  512. if (Element.ElementType == ChangerSlot) {
  513. if (Element.ElementAddress >= DeviceExtension->NumberOfSlots) {
  514. DebugPrint((1,
  515. "Cdchgr: InvalidElement - type %x, address %x\n",
  516. Element.ElementType,
  517. Element.ElementAddress));
  518. return TRUE;
  519. }
  520. } else if (Element.ElementType == ChangerDrive) {
  521. if (Element.ElementAddress != 0) {
  522. DebugPrint((1,
  523. "Cdchgr: InvalidElement - type %x, address %x\n",
  524. Element.ElementType,
  525. Element.ElementAddress));
  526. return TRUE;
  527. }
  528. } else if (Element.ElementType == ChangerTransport) {
  529. if (Element.ElementAddress != 0) {
  530. DebugPrint((1,
  531. "Cdchgr: InvalidElement - type %x, address %x\n",
  532. Element.ElementType,
  533. Element.ElementAddress));
  534. return TRUE;
  535. }
  536. } else {
  537. DebugPrint((1,
  538. "Cdchgr: InvalidElement - type %x, address %x\n",
  539. Element.ElementType,
  540. Element.ElementAddress));
  541. return TRUE;
  542. }
  543. //
  544. // Acceptable element/address.
  545. //
  546. return FALSE;
  547. }
  548. NTSTATUS
  549. MapSenseInfo(
  550. IN PSENSE_DATA SenseBuffer
  551. )
  552. {
  553. NTSTATUS status = STATUS_SUCCESS;
  554. UCHAR senseCode = SenseBuffer->SenseKey;
  555. UCHAR additionalSenseCode = SenseBuffer->AdditionalSenseCode;
  556. UCHAR additionalSenseCodeQualifier = SenseBuffer->AdditionalSenseCodeQualifier;
  557. switch (senseCode) {
  558. case SCSI_SENSE_NO_SENSE:
  559. if (SenseBuffer->IncorrectLength) {
  560. status = STATUS_INVALID_BLOCK_LENGTH;
  561. } else {
  562. status = STATUS_IO_DEVICE_ERROR;
  563. }
  564. break;
  565. case SCSI_SENSE_RECOVERED_ERROR:
  566. status = STATUS_SUCCESS;
  567. break;
  568. case SCSI_SENSE_NOT_READY:
  569. status = STATUS_DEVICE_NOT_READY;
  570. switch (additionalSenseCode) {
  571. case SCSI_ADSENSE_LUN_NOT_READY:
  572. switch (additionalSenseCodeQualifier) {
  573. case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
  574. status = STATUS_NO_MEDIA_IN_DEVICE;
  575. break;
  576. case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
  577. case SCSI_SENSEQ_BECOMING_READY:
  578. //
  579. // Fall through.
  580. //
  581. default:
  582. status = STATUS_DEVICE_NOT_READY;
  583. }
  584. break;
  585. case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
  586. status = STATUS_NO_MEDIA_IN_DEVICE;
  587. break;
  588. default:
  589. status = STATUS_DEVICE_NOT_READY;
  590. }
  591. break;
  592. case SCSI_SENSE_MEDIUM_ERROR:
  593. status = STATUS_DEVICE_DATA_ERROR;
  594. break;
  595. case SCSI_SENSE_ILLEGAL_REQUEST:
  596. switch (additionalSenseCode) {
  597. case SCSI_ADSENSE_ILLEGAL_BLOCK:
  598. status = STATUS_NONEXISTENT_SECTOR;
  599. break;
  600. case SCSI_ADSENSE_INVALID_LUN:
  601. status = STATUS_NO_SUCH_DEVICE;
  602. break;
  603. case SCSI_ADSENSE_MUSIC_AREA:
  604. case SCSI_ADSENSE_DATA_AREA:
  605. case SCSI_ADSENSE_VOLUME_OVERFLOW:
  606. case SCSI_ADSENSE_ILLEGAL_COMMAND:
  607. case SCSI_ADSENSE_INVALID_CDB:
  608. default:
  609. status = STATUS_INVALID_DEVICE_REQUEST;
  610. break;
  611. }
  612. break;
  613. case SCSI_SENSE_UNIT_ATTENTION:
  614. // TODO - check on this.
  615. DebugPrint((1,
  616. "MapSenseInfo: UnitAttention \n"));
  617. status = STATUS_VERIFY_REQUIRED;
  618. break;
  619. case SCSI_SENSE_DATA_PROTECT:
  620. status = STATUS_MEDIA_WRITE_PROTECTED;
  621. break;
  622. case SCSI_SENSE_HARDWARE_ERROR:
  623. case SCSI_SENSE_ABORTED_COMMAND:
  624. //
  625. // Fall through.
  626. //
  627. default:
  628. status = STATUS_IO_DEVICE_ERROR;
  629. break;
  630. }
  631. DebugPrint((1,
  632. "CdChgr: MapSenseInfo - SK %x, ASC %x, ASCQ %x, Status %lx\n",
  633. senseCode,
  634. additionalSenseCode,
  635. additionalSenseCodeQualifier,
  636. status));
  637. return status;
  638. }
  639. NTSTATUS
  640. SendTorisanCheckVerify(
  641. PDEVICE_OBJECT DeviceObject,
  642. PIRP Irp
  643. )
  644. /*++
  645. Routine Description:
  646. This routine handles only the check verify commands for the Sanyo changers.
  647. Arguments:
  648. DeviceObject
  649. Irp
  650. Return Value:
  651. Status is returned.
  652. --*/
  653. {
  654. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  655. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  656. PPASS_THROUGH_REQUEST passThrough;
  657. PSCSI_PASS_THROUGH srb;
  658. NTSTATUS status;
  659. ULONG length;
  660. PCDB cdb;
  661. //
  662. // Allocate a request block.
  663. //
  664. passThrough = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(PASS_THROUGH_REQUEST));
  665. if (!passThrough) {
  666. return STATUS_INSUFFICIENT_RESOURCES;
  667. }
  668. srb = &passThrough->Srb;
  669. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  670. cdb = (PCDB)srb->Cdb;
  671. srb->CdbLength = CDB10GENERIC_LENGTH;
  672. //
  673. // Build TUR.
  674. //
  675. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  676. srb->TimeOutValue = 20;
  677. DebugPrint((1,
  678. "SendTorisanCheckVerify: Using CurrentPlatter of %x\n",
  679. deviceExtension->CurrentPlatter));
  680. srb->Cdb[7] = (UCHAR)deviceExtension->CurrentPlatter;
  681. srb->DataTransferLength = 0;
  682. //
  683. // Send the request.
  684. //
  685. status = SendPassThrough(DeviceObject,
  686. passThrough);
  687. ExFreePool(passThrough);
  688. return status;
  689. }
  690. NTSTATUS
  691. SendPassThrough(
  692. IN PDEVICE_OBJECT DeviceObject,
  693. IN PPASS_THROUGH_REQUEST ScsiPassThrough
  694. )
  695. /*++
  696. Routine Description:
  697. This routine fills in most SPT fields, then sends the given SRB synchronously
  698. to the CDROM class driver.
  699. DataTransferLength, TimeoutValue are the responsibility of the caller.
  700. Arguments:
  701. Extension - Supplies the device extension.
  702. Srb - Supplies the SRB.
  703. Buffer - Supplies the return buffer.
  704. BufferLength - Supplies the buffer length.
  705. Return Value:
  706. NTSTATUS
  707. --*/
  708. //typedef struct _PASS_THROUGH_REQUEST {
  709. // SCSI_PASS_THROUGH Srb;
  710. // SENSE_DATA SenseInfoBuffer;
  711. // CHAR DataBuffer[0];
  712. //} PASS_THROUGH_REQUEST, *PPASS_THROUGH_REQUEST;
  713. //typedef struct _SCSI_PASS_THROUGH {
  714. // USHORT Length;
  715. // UCHAR ScsiStatus;
  716. // UCHAR PathId;
  717. // UCHAR TargetId;
  718. // UCHAR Lun;
  719. // UCHAR CdbLength;
  720. // UCHAR SenseInfoLength;
  721. // UCHAR DataIn;
  722. // ULONG DataTransferLength;
  723. // ULONG TimeOutValue;
  724. // ULONG DataBufferOffset;
  725. // ULONG SenseInfoOffset;
  726. // UCHAR Cdb[16];
  727. //}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
  728. {
  729. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  730. PSCSI_PASS_THROUGH srb = &ScsiPassThrough->Srb;
  731. KEVENT event;
  732. PIRP irp;
  733. IO_STATUS_BLOCK ioStatus;
  734. NTSTATUS status;
  735. srb->Length = sizeof(SCSI_PASS_THROUGH);
  736. srb->SenseInfoLength = sizeof(SENSE_DATA);
  737. srb->SenseInfoOffset = FIELD_OFFSET(PASS_THROUGH_REQUEST, SenseInfoBuffer);
  738. if (srb->DataTransferLength) {
  739. srb->DataBufferOffset = FIELD_OFFSET(PASS_THROUGH_REQUEST, DataBuffer);
  740. srb->DataIn = SCSI_IOCTL_DATA_IN;
  741. } else {
  742. srb->DataIn = SCSI_IOCTL_DATA_OUT;
  743. srb->DataBufferOffset = 0;
  744. }
  745. KeInitializeEvent(&event,
  746. NotificationEvent,
  747. FALSE);
  748. irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_PASS_THROUGH,
  749. deviceExtension->CdromTargetDeviceObject,
  750. ScsiPassThrough,
  751. sizeof(PASS_THROUGH_REQUEST) + srb->DataTransferLength,
  752. ScsiPassThrough,
  753. sizeof(PASS_THROUGH_REQUEST) + srb->DataTransferLength,
  754. FALSE,
  755. &event,
  756. &ioStatus);
  757. if (!irp) {
  758. DebugPrint((1,
  759. "Cdchgr: SendPassThrough NULL irp\n"));
  760. return STATUS_INSUFFICIENT_RESOURCES;
  761. }
  762. status = IoCallDriver(deviceExtension->CdromTargetDeviceObject,
  763. irp);
  764. if (status == STATUS_PENDING) {
  765. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  766. status = ioStatus.Status;
  767. }
  768. //
  769. // Check status and map appropriately.
  770. //
  771. if (srb->ScsiStatus != SCSISTAT_GOOD) {
  772. if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION) {
  773. status = MapSenseInfo(&ScsiPassThrough->SenseInfoBuffer);
  774. if (status == STATUS_VERIFY_REQUIRED) {
  775. if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
  776. DeviceObject->Flags |= DO_VERIFY_VOLUME;
  777. }
  778. }
  779. } else {
  780. DebugPrint((1,
  781. "Cdchgr: Unhandled scsi status %lx\n",
  782. srb->ScsiStatus));
  783. status = STATUS_IO_DEVICE_ERROR;
  784. }
  785. }
  786. DebugPrint((1,
  787. "Cdchgr: SendSrbPassThrough Status %lx\n",
  788. status));
  789. return status;
  790. }