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.

1101 lines
28 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. productData->DeviceType = MEDIUM_CHANGER;
  210. Irp->IoStatus.Information = sizeof(CHANGER_PRODUCT_DATA);
  211. return STATUS_SUCCESS;
  212. }
  213. NTSTATUS
  214. ChgrSetAccess(
  215. IN PDEVICE_OBJECT DeviceObject,
  216. IN PIRP Irp
  217. )
  218. {
  219. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  220. PCHANGER_SET_ACCESS setAccess = Irp->AssociatedIrp.SystemBuffer;
  221. ULONG controlOperation = setAccess->Control;
  222. PPASS_THROUGH_REQUEST passThrough;
  223. PSCSI_PASS_THROUGH srb;
  224. NTSTATUS status;
  225. PCDB cdb;
  226. if (setAccess->Element.ElementType != ChangerDoor) {
  227. //
  228. // No IEPORTs on these devices.
  229. //
  230. return STATUS_INVALID_PARAMETER;
  231. }
  232. //
  233. // Allocate a request block.
  234. //
  235. passThrough = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(PASS_THROUGH_REQUEST));
  236. if (!passThrough) {
  237. return STATUS_INSUFFICIENT_RESOURCES;
  238. }
  239. srb = &passThrough->Srb;
  240. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  241. cdb = (PCDB)srb->Cdb;
  242. srb->CdbLength = CDB6GENERIC_LENGTH;
  243. cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
  244. srb->DataTransferLength = 0;
  245. srb->TimeOutValue = 10;
  246. status = STATUS_SUCCESS;
  247. if (controlOperation == LOCK_ELEMENT) {
  248. //
  249. // Issue prevent media removal command to lock the magazine.
  250. //
  251. cdb->MEDIA_REMOVAL.Prevent = 1;
  252. } else if (controlOperation == UNLOCK_ELEMENT) {
  253. //
  254. // Issue allow media removal.
  255. //
  256. cdb->MEDIA_REMOVAL.Prevent = 0;
  257. } else {
  258. status = STATUS_INVALID_PARAMETER;
  259. }
  260. if (NT_SUCCESS(status)) {
  261. //
  262. // Send the request.
  263. //
  264. status = SendPassThrough(DeviceObject,
  265. passThrough);
  266. }
  267. ExFreePool(passThrough);
  268. if (NT_SUCCESS(status)) {
  269. Irp->IoStatus.Information = sizeof(CHANGER_SET_ACCESS);
  270. }
  271. return status;
  272. }
  273. NTSTATUS
  274. ChgrGetElementStatus(
  275. IN PDEVICE_OBJECT DeviceObject,
  276. IN PIRP Irp
  277. )
  278. {
  279. return STATUS_INVALID_DEVICE_REQUEST;
  280. }
  281. NTSTATUS
  282. ChgrInitializeElementStatus(
  283. IN PDEVICE_OBJECT DeviceObject,
  284. IN PIRP Irp
  285. )
  286. {
  287. return STATUS_INVALID_DEVICE_REQUEST;
  288. }
  289. NTSTATUS
  290. ChgrSetPosition(
  291. IN PDEVICE_OBJECT DeviceObject,
  292. IN PIRP Irp
  293. )
  294. {
  295. //
  296. // These device don't support this.
  297. //
  298. return STATUS_INVALID_DEVICE_REQUEST;
  299. }
  300. NTSTATUS
  301. ChgrExchangeMedium(
  302. IN PDEVICE_OBJECT DeviceObject,
  303. IN PIRP Irp
  304. )
  305. {
  306. //
  307. // These device don't support this.
  308. //
  309. return STATUS_INVALID_DEVICE_REQUEST;
  310. }
  311. NTSTATUS
  312. ChgrReinitializeUnit(
  313. IN PDEVICE_OBJECT DeviceObject,
  314. IN PIRP Irp
  315. )
  316. {
  317. //
  318. // These device don't support this.
  319. //
  320. return STATUS_INVALID_DEVICE_REQUEST;
  321. }
  322. NTSTATUS
  323. ChgrQueryVolumeTags(
  324. IN PDEVICE_OBJECT DeviceObject,
  325. IN PIRP Irp
  326. )
  327. {
  328. //
  329. // These device don't support this.
  330. //
  331. return STATUS_INVALID_DEVICE_REQUEST;
  332. }
  333. NTSTATUS
  334. ChgrMoveMedium(
  335. IN PDEVICE_OBJECT DeviceObject,
  336. IN PIRP Irp
  337. )
  338. {
  339. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  340. PCHANGER_MOVE_MEDIUM moveMedium = Irp->AssociatedIrp.SystemBuffer;
  341. USHORT transport;
  342. USHORT source;
  343. USHORT destination;
  344. PPASS_THROUGH_REQUEST passThrough;
  345. PSCSI_PASS_THROUGH srb;
  346. PCDB cdb;
  347. NTSTATUS status;
  348. //
  349. // Verify transport, source, and dest. are within range.
  350. //
  351. if (InvalidElement(deviceExtension,moveMedium->Transport)) {
  352. DebugPrint((1,
  353. "ChangerMoveMedium: Transport element out of range.\n"));
  354. return STATUS_ILLEGAL_ELEMENT_ADDRESS;
  355. }
  356. if (InvalidElement(deviceExtension, moveMedium->Source)) {
  357. DebugPrint((1,
  358. "ChangerMoveMedium: Source element out of range.\n"));
  359. return STATUS_ILLEGAL_ELEMENT_ADDRESS;
  360. }
  361. if (InvalidElement(deviceExtension,moveMedium->Destination)) {
  362. DebugPrint((1,
  363. "ChangerMoveMedium: Destination element out of range.\n"));
  364. return STATUS_ILLEGAL_ELEMENT_ADDRESS;
  365. }
  366. //
  367. // Build srb and cdb.
  368. //
  369. passThrough = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(PASS_THROUGH_REQUEST));
  370. if (!passThrough) {
  371. return STATUS_INSUFFICIENT_RESOURCES;
  372. }
  373. //
  374. // The torisan units don't really move medium, rather the active disc is changed.
  375. // To change slots, they've overloaded TUR.
  376. //
  377. if (deviceExtension->DeviceType == TORISAN) {
  378. if (moveMedium->Destination.ElementType == ChangerDrive) {
  379. srb = &passThrough->Srb;
  380. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  381. cdb = (PCDB)srb->Cdb;
  382. srb->CdbLength = CDB10GENERIC_LENGTH;
  383. //
  384. // Build TUR.
  385. //
  386. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  387. srb->Cdb[7] = (UCHAR)moveMedium->Source.ElementAddress;
  388. srb->TimeOutValue = 20;
  389. srb->DataTransferLength = 0;
  390. //
  391. // Send the request.
  392. //
  393. status = SendPassThrough(DeviceObject,
  394. passThrough);
  395. if (status == STATUS_DEVICE_NOT_READY) {
  396. // TODO send a TUR to verify this.
  397. DebugPrint((1,
  398. "MoveMedium - Claiming success\n"));
  399. status = STATUS_SUCCESS;
  400. } else if (status == STATUS_NO_MEDIA_IN_DEVICE) {
  401. status = STATUS_SOURCE_ELEMENT_EMPTY;
  402. }
  403. if (NT_SUCCESS(status)) {
  404. //
  405. // Update the current disc indicator.
  406. //
  407. deviceExtension->CurrentPlatter = moveMedium->Source.ElementAddress;
  408. DebugPrint((1,
  409. "MoveMedium: Set currentPlatter to %x\n",
  410. deviceExtension->CurrentPlatter));
  411. ExFreePool(passThrough);
  412. return STATUS_SUCCESS;
  413. } else {
  414. DebugPrint((1,
  415. "MoveMedium - Status on move %lx\n",
  416. status));
  417. ExFreePool(passThrough);
  418. return status;
  419. }
  420. } else {
  421. //
  422. // Claim that is happened.
  423. //
  424. ExFreePool(passThrough);
  425. return STATUS_SUCCESS;
  426. }
  427. }
  428. //
  429. // If destination is the drive, determine if media is already present.
  430. // The alps always claims media is there, so don't check.
  431. //
  432. #if 0
  433. if (((moveMedium->Destination.ElementType) == ChangerDrive) &&
  434. (deviceExtension->DeviceType != ALPS_25)) {
  435. srb = &passThrough->Srb;
  436. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  437. cdb = (PCDB)srb->Cdb;
  438. srb->CdbLength = CDB6GENERIC_LENGTH;
  439. //
  440. // Build TUR.
  441. //
  442. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  443. srb->TimeOutValue = 20;
  444. srb->DataTransferLength = 0;
  445. //
  446. // Send the request.
  447. //
  448. status = SendPassThrough(DeviceObject,
  449. passThrough);
  450. if (status != STATUS_NO_MEDIA_IN_DEVICE) {
  451. //
  452. // Drive has media. Though the device will allow this,
  453. // error it, as the expected medium changer behaviour is
  454. // to return element full in this case.
  455. //
  456. DebugPrint((1,
  457. "ChgrMoveMedium: Drive already has media. TUR Status %lx\n",
  458. status));
  459. ExFreePool(passThrough);
  460. return STATUS_DESTINATION_ELEMENT_FULL;
  461. }
  462. }
  463. #endif
  464. srb = &passThrough->Srb;
  465. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  466. cdb = (PCDB)srb->Cdb;
  467. srb->CdbLength = CDB12GENERIC_LENGTH;
  468. srb->TimeOutValue = CDCHGR_TIMEOUT;
  469. srb->DataTransferLength = 0;
  470. //
  471. // LOAD_UNLOAD will move a disc from slot to drive,
  472. // or from drive to slot.
  473. //
  474. cdb->LOAD_UNLOAD.OperationCode = SCSIOP_LOAD_UNLOAD_SLOT;
  475. if (moveMedium->Source.ElementType == ChangerDrive) {
  476. cdb->LOAD_UNLOAD.Slot = (UCHAR)moveMedium->Destination.ElementAddress;
  477. cdb->LOAD_UNLOAD.Start = 0;
  478. cdb->LOAD_UNLOAD.LoadEject = 1;
  479. } else if (moveMedium->Source.ElementType == ChangerSlot) {
  480. cdb->LOAD_UNLOAD.Slot = (UCHAR)moveMedium->Source.ElementAddress;
  481. cdb->LOAD_UNLOAD.Start = 1;
  482. cdb->LOAD_UNLOAD.LoadEject = 1;
  483. }
  484. //
  485. // Send SCSI command (CDB) to device
  486. //
  487. status = SendPassThrough(DeviceObject,
  488. passThrough);
  489. if (NT_SUCCESS(status)) {
  490. //
  491. // These devices don't seem to ever generate
  492. // a unit attention, for media changed, so fake it.
  493. //
  494. if (deviceExtension->CdromTargetDeviceObject->Vpb->Flags & VPB_MOUNTED) {
  495. DebugPrint((1,
  496. "Faking DO_VERIFY_VOLUME\n"));
  497. deviceExtension->CdromTargetDeviceObject->Flags |= DO_VERIFY_VOLUME;
  498. }
  499. } else if (status == STATUS_NO_MEDIA_IN_DEVICE) {
  500. status = STATUS_SOURCE_ELEMENT_EMPTY;
  501. }
  502. ExFreePool(passThrough);
  503. return status;
  504. }
  505. BOOLEAN
  506. InvalidElement(
  507. IN PDEVICE_EXTENSION DeviceExtension,
  508. IN CHANGER_ELEMENT Element
  509. )
  510. {
  511. if (Element.ElementType == ChangerSlot) {
  512. if (Element.ElementAddress >= DeviceExtension->NumberOfSlots) {
  513. DebugPrint((1,
  514. "Cdchgr: InvalidElement - type %x, address %x\n",
  515. Element.ElementType,
  516. Element.ElementAddress));
  517. return TRUE;
  518. }
  519. } else if (Element.ElementType == ChangerDrive) {
  520. if (Element.ElementAddress != 0) {
  521. DebugPrint((1,
  522. "Cdchgr: InvalidElement - type %x, address %x\n",
  523. Element.ElementType,
  524. Element.ElementAddress));
  525. return TRUE;
  526. }
  527. } else if (Element.ElementType == ChangerTransport) {
  528. if (Element.ElementAddress != 0) {
  529. DebugPrint((1,
  530. "Cdchgr: InvalidElement - type %x, address %x\n",
  531. Element.ElementType,
  532. Element.ElementAddress));
  533. return TRUE;
  534. }
  535. } else {
  536. DebugPrint((1,
  537. "Cdchgr: InvalidElement - type %x, address %x\n",
  538. Element.ElementType,
  539. Element.ElementAddress));
  540. return TRUE;
  541. }
  542. //
  543. // Acceptable element/address.
  544. //
  545. return FALSE;
  546. }
  547. NTSTATUS
  548. MapSenseInfo(
  549. IN PSENSE_DATA SenseBuffer
  550. )
  551. {
  552. NTSTATUS status = STATUS_SUCCESS;
  553. UCHAR senseCode = SenseBuffer->SenseKey;
  554. UCHAR additionalSenseCode = SenseBuffer->AdditionalSenseCode;
  555. UCHAR additionalSenseCodeQualifier = SenseBuffer->AdditionalSenseCodeQualifier;
  556. switch (senseCode) {
  557. case SCSI_SENSE_NO_SENSE:
  558. if (SenseBuffer->IncorrectLength) {
  559. status = STATUS_INVALID_BLOCK_LENGTH;
  560. } else {
  561. status = STATUS_IO_DEVICE_ERROR;
  562. }
  563. break;
  564. case SCSI_SENSE_RECOVERED_ERROR:
  565. status = STATUS_SUCCESS;
  566. break;
  567. case SCSI_SENSE_NOT_READY:
  568. status = STATUS_DEVICE_NOT_READY;
  569. switch (additionalSenseCode) {
  570. case SCSI_ADSENSE_LUN_NOT_READY:
  571. switch (additionalSenseCodeQualifier) {
  572. case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
  573. status = STATUS_NO_MEDIA_IN_DEVICE;
  574. break;
  575. case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
  576. case SCSI_SENSEQ_BECOMING_READY:
  577. //
  578. // Fall through.
  579. //
  580. default:
  581. status = STATUS_DEVICE_NOT_READY;
  582. }
  583. break;
  584. case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
  585. status = STATUS_NO_MEDIA_IN_DEVICE;
  586. break;
  587. default:
  588. status = STATUS_DEVICE_NOT_READY;
  589. }
  590. break;
  591. case SCSI_SENSE_MEDIUM_ERROR:
  592. status = STATUS_DEVICE_DATA_ERROR;
  593. break;
  594. case SCSI_SENSE_ILLEGAL_REQUEST:
  595. switch (additionalSenseCode) {
  596. case SCSI_ADSENSE_ILLEGAL_BLOCK:
  597. status = STATUS_NONEXISTENT_SECTOR;
  598. break;
  599. case SCSI_ADSENSE_INVALID_LUN:
  600. status = STATUS_NO_SUCH_DEVICE;
  601. break;
  602. case SCSI_ADSENSE_MUSIC_AREA:
  603. case SCSI_ADSENSE_DATA_AREA:
  604. case SCSI_ADSENSE_VOLUME_OVERFLOW:
  605. case SCSI_ADSENSE_ILLEGAL_COMMAND:
  606. case SCSI_ADSENSE_INVALID_CDB:
  607. default:
  608. status = STATUS_INVALID_DEVICE_REQUEST;
  609. break;
  610. }
  611. break;
  612. case SCSI_SENSE_UNIT_ATTENTION:
  613. // TODO - check on this.
  614. DebugPrint((1,
  615. "MapSenseInfo: UnitAttention \n"));
  616. status = STATUS_VERIFY_REQUIRED;
  617. break;
  618. case SCSI_SENSE_DATA_PROTECT:
  619. status = STATUS_MEDIA_WRITE_PROTECTED;
  620. break;
  621. case SCSI_SENSE_HARDWARE_ERROR:
  622. case SCSI_SENSE_ABORTED_COMMAND:
  623. //
  624. // Fall through.
  625. //
  626. default:
  627. status = STATUS_IO_DEVICE_ERROR;
  628. break;
  629. }
  630. DebugPrint((1,
  631. "CdChgr: MapSenseInfo - SK %x, ASC %x, ASCQ %x, Status %lx\n",
  632. senseCode,
  633. additionalSenseCode,
  634. additionalSenseCodeQualifier,
  635. status));
  636. return status;
  637. }
  638. NTSTATUS
  639. SendTorisanCheckVerify(
  640. PDEVICE_OBJECT DeviceObject,
  641. PIRP Irp
  642. )
  643. /*++
  644. Routine Description:
  645. This routine handles only the check verify commands for the Sanyo changers.
  646. Arguments:
  647. DeviceObject
  648. Irp
  649. Return Value:
  650. Status is returned.
  651. --*/
  652. {
  653. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  654. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  655. PPASS_THROUGH_REQUEST passThrough;
  656. PSCSI_PASS_THROUGH srb;
  657. NTSTATUS status;
  658. ULONG length;
  659. PCDB cdb;
  660. //
  661. // Allocate a request block.
  662. //
  663. passThrough = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(PASS_THROUGH_REQUEST));
  664. if (!passThrough) {
  665. return STATUS_INSUFFICIENT_RESOURCES;
  666. }
  667. srb = &passThrough->Srb;
  668. RtlZeroMemory(passThrough, sizeof(PASS_THROUGH_REQUEST));
  669. cdb = (PCDB)srb->Cdb;
  670. srb->CdbLength = CDB10GENERIC_LENGTH;
  671. //
  672. // Build TUR.
  673. //
  674. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  675. srb->TimeOutValue = 20;
  676. DebugPrint((1,
  677. "SendTorisanCheckVerify: Using CurrentPlatter of %x\n",
  678. deviceExtension->CurrentPlatter));
  679. srb->Cdb[7] = (UCHAR)deviceExtension->CurrentPlatter;
  680. srb->DataTransferLength = 0;
  681. //
  682. // Send the request.
  683. //
  684. status = SendPassThrough(DeviceObject,
  685. passThrough);
  686. ExFreePool(passThrough);
  687. return status;
  688. }
  689. NTSTATUS
  690. SendPassThrough(
  691. IN PDEVICE_OBJECT DeviceObject,
  692. IN PPASS_THROUGH_REQUEST ScsiPassThrough
  693. )
  694. /*++
  695. Routine Description:
  696. This routine fills in most SPT fields, then sends the given SRB synchronously
  697. to the CDROM class driver.
  698. DataTransferLength, TimeoutValue are the responsibility of the caller.
  699. Arguments:
  700. Extension - Supplies the device extension.
  701. Srb - Supplies the SRB.
  702. Buffer - Supplies the return buffer.
  703. BufferLength - Supplies the buffer length.
  704. Return Value:
  705. NTSTATUS
  706. --*/
  707. //typedef struct _PASS_THROUGH_REQUEST {
  708. // SCSI_PASS_THROUGH Srb;
  709. // SENSE_DATA SenseInfoBuffer;
  710. // CHAR DataBuffer[0];
  711. //} PASS_THROUGH_REQUEST, *PPASS_THROUGH_REQUEST;
  712. //typedef struct _SCSI_PASS_THROUGH {
  713. // USHORT Length;
  714. // UCHAR ScsiStatus;
  715. // UCHAR PathId;
  716. // UCHAR TargetId;
  717. // UCHAR Lun;
  718. // UCHAR CdbLength;
  719. // UCHAR SenseInfoLength;
  720. // UCHAR DataIn;
  721. // ULONG DataTransferLength;
  722. // ULONG TimeOutValue;
  723. // ULONG DataBufferOffset;
  724. // ULONG SenseInfoOffset;
  725. // UCHAR Cdb[16];
  726. //}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
  727. {
  728. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  729. PSCSI_PASS_THROUGH srb = &ScsiPassThrough->Srb;
  730. KEVENT event;
  731. PIRP irp;
  732. IO_STATUS_BLOCK ioStatus;
  733. NTSTATUS status;
  734. srb->Length = sizeof(SCSI_PASS_THROUGH);
  735. srb->SenseInfoLength = sizeof(SENSE_DATA);
  736. srb->SenseInfoOffset = FIELD_OFFSET(PASS_THROUGH_REQUEST, SenseInfoBuffer);
  737. if (srb->DataTransferLength) {
  738. srb->DataBufferOffset = FIELD_OFFSET(PASS_THROUGH_REQUEST, DataBuffer);
  739. srb->DataIn = SCSI_IOCTL_DATA_IN;
  740. } else {
  741. srb->DataIn = SCSI_IOCTL_DATA_OUT;
  742. srb->DataBufferOffset = 0;
  743. }
  744. KeInitializeEvent(&event,
  745. NotificationEvent,
  746. FALSE);
  747. irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_PASS_THROUGH,
  748. deviceExtension->CdromTargetDeviceObject,
  749. ScsiPassThrough,
  750. sizeof(PASS_THROUGH_REQUEST) + srb->DataTransferLength,
  751. ScsiPassThrough,
  752. sizeof(PASS_THROUGH_REQUEST) + srb->DataTransferLength,
  753. FALSE,
  754. &event,
  755. &ioStatus);
  756. if (!irp) {
  757. DebugPrint((1,
  758. "Cdchgr: SendPassThrough NULL irp\n"));
  759. return STATUS_INSUFFICIENT_RESOURCES;
  760. }
  761. status = IoCallDriver(deviceExtension->CdromTargetDeviceObject,
  762. irp);
  763. if (status == STATUS_PENDING) {
  764. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  765. status = ioStatus.Status;
  766. }
  767. //
  768. // Check status and map appropriately.
  769. //
  770. if (srb->ScsiStatus != SCSISTAT_GOOD) {
  771. if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION) {
  772. status = MapSenseInfo(&ScsiPassThrough->SenseInfoBuffer);
  773. if (status == STATUS_VERIFY_REQUIRED) {
  774. if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
  775. DeviceObject->Flags |= DO_VERIFY_VOLUME;
  776. }
  777. }
  778. } else {
  779. DebugPrint((1,
  780. "Cdchgr: Unhandled scsi status %lx\n",
  781. srb->ScsiStatus));
  782. status = STATUS_IO_DEVICE_ERROR;
  783. }
  784. }
  785. DebugPrint((1,
  786. "Cdchgr: SendSrbPassThrough Status %lx\n",
  787. status));
  788. return status;
  789. }