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.

1582 lines
38 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. mcd.c
  5. Abstract:
  6. Environment:
  7. Kernel mode
  8. Revision History :
  9. --*/
  10. #include "mchgr.h"
  11. #ifdef ALLOC_PRAGMA
  12. #pragma alloc_text(INIT, DriverEntry)
  13. #pragma alloc_text(PAGE, ChangerUnload)
  14. #pragma alloc_text(PAGE, CreateChangerDeviceObject)
  15. #pragma alloc_text(PAGE, ChangerClassCreateClose)
  16. #pragma alloc_text(PAGE, ChangerClassDeviceControl)
  17. #pragma alloc_text(PAGE, ChangerAddDevice)
  18. #pragma alloc_text(PAGE, ChangerStartDevice)
  19. #pragma alloc_text(PAGE, ChangerInitDevice)
  20. #pragma alloc_text(PAGE, ChangerRemoveDevice)
  21. #pragma alloc_text(PAGE, ChangerStopDevice)
  22. #pragma alloc_text(PAGE, ChangerReadWriteVerification)
  23. #endif
  24. NTSTATUS
  25. ChangerClassCreateClose (
  26. IN PDEVICE_OBJECT DeviceObject,
  27. IN PIRP Irp
  28. )
  29. /*++
  30. Routine Description:
  31. This routine handles CREATE/CLOSE requests.
  32. As these are exclusive devices, don't allow multiple opens.
  33. Arguments:
  34. DeviceObject
  35. Irp
  36. Return Value:
  37. NT Status
  38. --*/
  39. {
  40. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  41. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  42. PMCD_CLASS_DATA mcdClassData;
  43. PMCD_INIT_DATA mcdInitData;
  44. ULONG miniclassExtSize;
  45. NTSTATUS status = STATUS_SUCCESS;
  46. PAGED_CODE();
  47. mcdClassData = (PMCD_CLASS_DATA)(fdoExtension->CommonExtension.DriverData);
  48. mcdInitData = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  49. ChangerClassInitialize);
  50. if (mcdInitData == NULL) {
  51. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  52. ClassReleaseRemoveLock(DeviceObject, Irp);
  53. ClassCompleteRequest(DeviceObject,Irp, IO_NO_INCREMENT);
  54. return STATUS_NO_SUCH_DEVICE;
  55. }
  56. miniclassExtSize = mcdInitData->ChangerAdditionalExtensionSize();
  57. //
  58. // The class library's private data is after the miniclass's.
  59. //
  60. (ULONG_PTR)mcdClassData += miniclassExtSize;
  61. if (irpStack->MajorFunction == IRP_MJ_CLOSE) {
  62. DebugPrint((3,
  63. "ChangerClassCreateClose - IRP_MJ_CLOSE\n"));
  64. //
  65. // Indicate that the device is available for others.
  66. //
  67. mcdClassData->DeviceOpen = 0;
  68. status = STATUS_SUCCESS;
  69. } else if (irpStack->MajorFunction == IRP_MJ_CREATE) {
  70. DebugPrint((3,
  71. "ChangerClassCreateClose - IRP_MJ_CREATE\n"));
  72. //
  73. // If already opened, return busy.
  74. //
  75. if (mcdClassData->DeviceOpen) {
  76. DebugPrint((1,
  77. "ChangerClassCreateClose - returning DEVICE_BUSY. DeviceOpen - %x\n",
  78. mcdClassData->DeviceOpen));
  79. status = STATUS_DEVICE_BUSY;
  80. } else {
  81. //
  82. // Indicate that the device is busy.
  83. //
  84. InterlockedIncrement(&mcdClassData->DeviceOpen);
  85. status = STATUS_SUCCESS;
  86. }
  87. }
  88. Irp->IoStatus.Status = status;
  89. ClassReleaseRemoveLock(DeviceObject, Irp);
  90. ClassCompleteRequest(DeviceObject,Irp, IO_NO_INCREMENT);
  91. return status;
  92. } // end ChangerCreate()
  93. NTSTATUS
  94. ChangerClassDeviceControl (
  95. IN PDEVICE_OBJECT DeviceObject,
  96. IN PIRP Irp
  97. )
  98. {
  99. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  100. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  101. PMCD_INIT_DATA mcdInitData;
  102. NTSTATUS status;
  103. PAGED_CODE();
  104. mcdInitData = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  105. ChangerClassInitialize);
  106. if (mcdInitData == NULL) {
  107. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  108. ClassReleaseRemoveLock(DeviceObject, Irp);
  109. ClassCompleteRequest(DeviceObject,Irp, IO_NO_INCREMENT);
  110. return STATUS_NO_SUCH_DEVICE;
  111. }
  112. //
  113. // Disable media change detection before processing current IOCTL
  114. //
  115. ClassDisableMediaChangeDetection(fdoExtension);
  116. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  117. case IOCTL_CHANGER_GET_PARAMETERS:
  118. DebugPrint((3,
  119. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_GET_PARAMETERS\n"));
  120. //
  121. // Validate buffer length.
  122. //
  123. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  124. sizeof(GET_CHANGER_PARAMETERS)) {
  125. status = STATUS_INFO_LENGTH_MISMATCH;
  126. } else {
  127. status = mcdInitData->ChangerGetParameters(DeviceObject, Irp);
  128. }
  129. break;
  130. case IOCTL_CHANGER_GET_STATUS:
  131. DebugPrint((3,
  132. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_GET_STATUS\n"));
  133. status = mcdInitData->ChangerGetStatus(DeviceObject, Irp);
  134. break;
  135. case IOCTL_CHANGER_GET_PRODUCT_DATA:
  136. DebugPrint((3,
  137. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_GET_PRODUCT_DATA\n"));
  138. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  139. sizeof(CHANGER_PRODUCT_DATA)) {
  140. status = STATUS_INFO_LENGTH_MISMATCH;
  141. } else {
  142. status = mcdInitData->ChangerGetProductData(DeviceObject, Irp);
  143. }
  144. break;
  145. case IOCTL_CHANGER_SET_ACCESS:
  146. DebugPrint((3,
  147. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_SET_ACCESS\n"));
  148. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  149. sizeof(CHANGER_SET_ACCESS)) {
  150. status = STATUS_INFO_LENGTH_MISMATCH;
  151. } else {
  152. status = mcdInitData->ChangerSetAccess(DeviceObject, Irp);
  153. }
  154. break;
  155. case IOCTL_CHANGER_GET_ELEMENT_STATUS:
  156. DebugPrint((3,
  157. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_GET_ELEMENT_STATUS\n"));
  158. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  159. sizeof(CHANGER_READ_ELEMENT_STATUS)) {
  160. status = STATUS_INFO_LENGTH_MISMATCH;
  161. } else {
  162. PCHANGER_READ_ELEMENT_STATUS readElementStatus = Irp->AssociatedIrp.SystemBuffer;
  163. ULONG length = readElementStatus->ElementList.NumberOfElements * sizeof(CHANGER_ELEMENT_STATUS);
  164. ULONG lengthEx = readElementStatus->ElementList.NumberOfElements * sizeof(CHANGER_ELEMENT_STATUS_EX);
  165. ULONG outputBuffLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  166. //
  167. // Further validate parameters.
  168. //
  169. status = STATUS_SUCCESS;
  170. if ((outputBuffLen < lengthEx) &&
  171. (outputBuffLen < length)) {
  172. status = STATUS_BUFFER_TOO_SMALL;
  173. } else if ((length == 0) ||
  174. (lengthEx == 0)) {
  175. status = STATUS_INVALID_PARAMETER;
  176. }
  177. if (NT_SUCCESS(status)) {
  178. status = mcdInitData->ChangerGetElementStatus(DeviceObject, Irp);
  179. }
  180. }
  181. break;
  182. case IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS:
  183. DebugPrint((3,
  184. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS\n"));
  185. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  186. sizeof(CHANGER_INITIALIZE_ELEMENT_STATUS)) {
  187. status = STATUS_INFO_LENGTH_MISMATCH;
  188. } else {
  189. status = mcdInitData->ChangerInitializeElementStatus(DeviceObject, Irp);
  190. }
  191. break;
  192. case IOCTL_CHANGER_SET_POSITION:
  193. DebugPrint((3,
  194. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_SET_POSITION\n"));
  195. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  196. sizeof(CHANGER_SET_POSITION)) {
  197. status = STATUS_INFO_LENGTH_MISMATCH;
  198. } else {
  199. status = mcdInitData->ChangerSetPosition(DeviceObject, Irp);
  200. }
  201. break;
  202. case IOCTL_CHANGER_EXCHANGE_MEDIUM:
  203. DebugPrint((3,
  204. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_EXCHANGE_MEDIUM\n"));
  205. status = mcdInitData->ChangerExchangeMedium(DeviceObject, Irp);
  206. break;
  207. case IOCTL_CHANGER_MOVE_MEDIUM:
  208. DebugPrint((3,
  209. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_MOVE_MEDIUM\n"));
  210. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  211. sizeof(CHANGER_MOVE_MEDIUM)) {
  212. status = STATUS_INFO_LENGTH_MISMATCH;
  213. } else {
  214. status = mcdInitData->ChangerMoveMedium(DeviceObject, Irp);
  215. }
  216. break;
  217. case IOCTL_CHANGER_REINITIALIZE_TRANSPORT:
  218. DebugPrint((3,
  219. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_REINITIALIZE_TRANSPORT\n"));
  220. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  221. sizeof(CHANGER_ELEMENT)) {
  222. status = STATUS_INFO_LENGTH_MISMATCH;
  223. } else {
  224. status = mcdInitData->ChangerReinitializeUnit(DeviceObject, Irp);
  225. }
  226. break;
  227. case IOCTL_CHANGER_QUERY_VOLUME_TAGS:
  228. DebugPrint((3,
  229. "Mcd.ChangerDeviceControl: IOCTL_CHANGER_QUERY_VOLUME_TAGS\n"));
  230. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  231. sizeof(CHANGER_SEND_VOLUME_TAG_INFORMATION)) {
  232. status = STATUS_INFO_LENGTH_MISMATCH;
  233. } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  234. sizeof(READ_ELEMENT_ADDRESS_INFO)) {
  235. status = STATUS_INFO_LENGTH_MISMATCH;
  236. } else {
  237. status = mcdInitData->ChangerQueryVolumeTags(DeviceObject, Irp);
  238. }
  239. break;
  240. default:
  241. DebugPrint((1,
  242. "Mcd.ChangerDeviceControl: Unhandled IOCTL\n"));
  243. //
  244. // Pass the request to the common device control routine.
  245. //
  246. status = ClassDeviceControl(DeviceObject, Irp);
  247. //
  248. // Re-enable media change detection
  249. //
  250. ClassEnableMediaChangeDetection(fdoExtension);
  251. return status;
  252. }
  253. Irp->IoStatus.Status = status;
  254. //
  255. // Re-enable media change detection
  256. //
  257. ClassEnableMediaChangeDetection(fdoExtension);
  258. if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
  259. DebugPrint((1,
  260. "Mcd.ChangerDeviceControl: IOCTL %x, status %x\n",
  261. irpStack->Parameters.DeviceIoControl.IoControlCode,
  262. status));
  263. IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
  264. }
  265. ClassReleaseRemoveLock(DeviceObject, Irp);
  266. ClassCompleteRequest(DeviceObject,Irp, IO_NO_INCREMENT);
  267. return status;
  268. }
  269. VOID
  270. ChangerClassError(
  271. PDEVICE_OBJECT DeviceObject,
  272. PSCSI_REQUEST_BLOCK Srb,
  273. NTSTATUS *Status,
  274. BOOLEAN *Retry
  275. )
  276. /*++
  277. Routine Description:
  278. Arguments:
  279. DeviceObject
  280. Irp
  281. Return Value:
  282. Final Nt status indicating the results of the operation.
  283. Notes:
  284. --*/
  285. {
  286. PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
  287. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  288. PMCD_INIT_DATA mcdInitData;
  289. mcdInitData = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  290. ChangerClassInitialize);
  291. if (mcdInitData == NULL) {
  292. return;
  293. }
  294. if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
  295. switch (senseBuffer->SenseKey & 0xf) {
  296. case SCSI_SENSE_MEDIUM_ERROR: {
  297. *Retry = FALSE;
  298. if (((senseBuffer->AdditionalSenseCode) == SCSI_ADSENSE_INVALID_MEDIA) &&
  299. ((senseBuffer->AdditionalSenseCodeQualifier) == SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED)) {
  300. //
  301. // This indicates a cleaner cartridge is present in the changer
  302. //
  303. *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED;
  304. }
  305. break;
  306. }
  307. case SCSI_SENSE_ILLEGAL_REQUEST: {
  308. switch (senseBuffer->AdditionalSenseCode) {
  309. case SCSI_ADSENSE_ILLEGAL_BLOCK:
  310. if (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_ILLEGAL_ELEMENT_ADDR ) {
  311. DebugPrint((1,
  312. "MediumChanger: An operation was attempted on an invalid element\n"));
  313. //
  314. // Attemped operation to an invalid element.
  315. //
  316. *Retry = FALSE;
  317. *Status = STATUS_ILLEGAL_ELEMENT_ADDRESS;
  318. }
  319. break;
  320. case SCSI_ADSENSE_POSITION_ERROR:
  321. if (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_SOURCE_EMPTY) {
  322. DebugPrint((1,
  323. "MediumChanger: The specified source element has no media\n"));
  324. //
  325. // The indicated source address has no media.
  326. //
  327. *Retry = FALSE;
  328. *Status = STATUS_SOURCE_ELEMENT_EMPTY;
  329. } else if (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_DESTINATION_FULL) {
  330. DebugPrint((1,
  331. "MediumChanger: The specified destination element already has media.\n"));
  332. //
  333. // The indicated destination already contains media.
  334. //
  335. *Retry = FALSE;
  336. *Status = STATUS_DESTINATION_ELEMENT_FULL;
  337. }
  338. break;
  339. default:
  340. break;
  341. } // switch (senseBuffer->AdditionalSenseCode)
  342. break;
  343. }
  344. case SCSI_SENSE_UNIT_ATTENTION: {
  345. if ((senseBuffer->AdditionalSenseCode) ==
  346. SCSI_ADSENSE_MEDIUM_CHANGED) {
  347. //
  348. // Need to notify applications of possible media change in
  349. // the library. First, set the current media state to
  350. // NotPresent and then set the state to present. We need to
  351. // do this because, changer devices do not report MediaNotPresent
  352. // state. They only convey MediumChanged condition. In order for
  353. // classpnp to notify applications of media change, we need to
  354. // simulate media notpresent to present state transition
  355. //
  356. ClassSetMediaChangeState(fdoExtension, MediaNotPresent, FALSE);
  357. ClassSetMediaChangeState(fdoExtension, MediaPresent, FALSE);
  358. }
  359. break;
  360. }
  361. default:
  362. break;
  363. } // end switch (senseBuffer->SenseKey & 0xf)
  364. } // if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
  365. //
  366. // Call Changer MiniDriver error routine only if we
  367. // are running at or below APC_LEVEL
  368. //
  369. if (KeGetCurrentIrql() > APC_LEVEL) {
  370. return;
  371. }
  372. if (mcdInitData->ChangerError) {
  373. //
  374. // Allow device-specific module to update this.
  375. //
  376. mcdInitData->ChangerError(DeviceObject, Srb, Status, Retry);
  377. }
  378. return;
  379. }
  380. NTSTATUS
  381. ChangerAddDevice(
  382. IN PDRIVER_OBJECT DriverObject,
  383. IN PDEVICE_OBJECT PhysicalDeviceObject
  384. )
  385. /*++
  386. Routine Description:
  387. This routine creates and initializes a new FDO for the corresponding
  388. PDO. It may perform property queries on the FDO but cannot do any
  389. media access operations.
  390. Arguments:
  391. DriverObject - MC class driver object.
  392. Pdo - the physical device object we are being added to
  393. Return Value:
  394. status
  395. --*/
  396. {
  397. PULONG devicesFound = NULL;
  398. NTSTATUS status;
  399. PAGED_CODE();
  400. //
  401. // Get the address of the count of the number of tape devices already initialized.
  402. //
  403. devicesFound = &IoGetConfigurationInformation()->MediumChangerCount;
  404. status = CreateChangerDeviceObject(DriverObject,
  405. PhysicalDeviceObject);
  406. if(NT_SUCCESS(status)) {
  407. (*devicesFound)++;
  408. }
  409. return status;
  410. }
  411. NTSTATUS
  412. ChangerStartDevice(
  413. IN PDEVICE_OBJECT Fdo
  414. )
  415. /*++
  416. Routine Description:
  417. This routine is called after InitDevice, and creates the symbolic link,
  418. and sets up information in the registry.
  419. The routine could be called multiple times, in the event of a StopDevice.
  420. Arguments:
  421. Fdo - a pointer to the functional device object for this device
  422. Return Value:
  423. status
  424. --*/
  425. {
  426. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  427. PINQUIRYDATA inquiryData = NULL;
  428. ULONG pageLength;
  429. ULONG inquiryLength;
  430. SCSI_REQUEST_BLOCK srb;
  431. PCDB cdb;
  432. NTSTATUS status;
  433. PMCD_CLASS_DATA mcdClassData = (PMCD_CLASS_DATA)fdoExtension->CommonExtension.DriverData;
  434. PMCD_INIT_DATA mcdInitData;
  435. ULONG miniClassExtSize;
  436. PAGED_CODE();
  437. mcdInitData = IoGetDriverObjectExtension(Fdo->DriverObject,
  438. ChangerClassInitialize);
  439. if (mcdInitData == NULL) {
  440. return STATUS_NO_SUCH_DEVICE;
  441. }
  442. miniClassExtSize = mcdInitData->ChangerAdditionalExtensionSize();
  443. //
  444. // Build and send request to get inquiry data.
  445. //
  446. inquiryData = ExAllocatePool(NonPagedPoolCacheAligned, MAXIMUM_CHANGER_INQUIRY_DATA);
  447. if (!inquiryData) {
  448. //
  449. // The buffer cannot be allocated.
  450. //
  451. return STATUS_INSUFFICIENT_RESOURCES;
  452. }
  453. RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
  454. //
  455. // Set timeout value.
  456. //
  457. srb.TimeOutValue = 2;
  458. srb.CdbLength = 6;
  459. cdb = (PCDB)srb.Cdb;
  460. //
  461. // Set CDB operation code.
  462. //
  463. cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
  464. //
  465. // Set allocation length to inquiry data buffer size.
  466. //
  467. cdb->CDB6INQUIRY.AllocationLength = MAXIMUM_CHANGER_INQUIRY_DATA;
  468. status = ClassSendSrbSynchronous(Fdo,
  469. &srb,
  470. inquiryData,
  471. MAXIMUM_CHANGER_INQUIRY_DATA,
  472. FALSE);
  473. if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_SUCCESS ||
  474. SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  475. srb.SrbStatus = SRB_STATUS_SUCCESS;
  476. }
  477. if (srb.SrbStatus == SRB_STATUS_SUCCESS) {
  478. inquiryLength = inquiryData->AdditionalLength + FIELD_OFFSET(INQUIRYDATA, Reserved);
  479. if (inquiryLength > srb.DataTransferLength) {
  480. inquiryLength = srb.DataTransferLength;
  481. }
  482. } else {
  483. //
  484. // The class function will only write inquiryLength of inquiryData
  485. // to the reg. key.
  486. //
  487. inquiryLength = 0;
  488. }
  489. //
  490. // Add changer device info to registry
  491. //
  492. ClassUpdateInformationInRegistry(Fdo,
  493. "Changer",
  494. fdoExtension->DeviceNumber,
  495. inquiryData,
  496. inquiryLength);
  497. ExFreePool(inquiryData);
  498. return STATUS_SUCCESS;
  499. }
  500. NTSTATUS
  501. ChangerStopDevice(
  502. IN PDEVICE_OBJECT DeviceObject,
  503. IN UCHAR Type
  504. )
  505. {
  506. return STATUS_SUCCESS;
  507. }
  508. #define CHANGER_SRB_LIST_SIZE 2
  509. NTSTATUS
  510. ChangerInitDevice(
  511. IN PDEVICE_OBJECT Fdo
  512. )
  513. /*++
  514. Routine Description:
  515. This routine will complete the changer initialization. This includes
  516. allocating sense info buffers and srb s-lists. Additionally, the miniclass
  517. driver's init entry points are called.
  518. This routine will not clean up allocate resources if it fails - that
  519. is left for device stop/removal
  520. Arguments:
  521. Fdo - a pointer to the functional device object for this device
  522. Return Value:
  523. NTSTATUS
  524. --*/
  525. {
  526. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  527. PVOID senseData = NULL;
  528. NTSTATUS status;
  529. PVOID minitapeExtension;
  530. PMCD_INIT_DATA mcdInitData;
  531. STORAGE_PROPERTY_ID propertyId;
  532. UNICODE_STRING interfaceName;
  533. PMCD_CLASS_DATA mcdClassData;
  534. PAGED_CODE();
  535. mcdInitData = IoGetDriverObjectExtension(Fdo->DriverObject,
  536. ChangerClassInitialize);
  537. if (mcdInitData == NULL) {
  538. return STATUS_NO_SUCH_DEVICE;
  539. }
  540. //
  541. // Allocate request sense buffer.
  542. //
  543. senseData = ExAllocatePool(NonPagedPoolCacheAligned,
  544. SENSE_BUFFER_SIZE);
  545. if (senseData == NULL) {
  546. //
  547. // The buffer cannot be allocated.
  548. //
  549. status = STATUS_INSUFFICIENT_RESOURCES;
  550. goto ChangerInitDeviceExit;
  551. }
  552. //
  553. // Build the lookaside list for srb's for the device. Should only
  554. // need a couple.
  555. //
  556. ClassInitializeSrbLookasideList(&(fdoExtension->CommonExtension), CHANGER_SRB_LIST_SIZE);
  557. //
  558. // Set the sense data pointer in the device extension.
  559. //
  560. fdoExtension->SenseData = senseData;
  561. fdoExtension->TimeOutValue = 600;
  562. //
  563. // Call port driver to get adapter capabilities.
  564. //
  565. propertyId = StorageAdapterProperty;
  566. status = ClassGetDescriptor(fdoExtension->CommonExtension.LowerDeviceObject,
  567. &propertyId,
  568. &(fdoExtension->AdapterDescriptor));
  569. if(!NT_SUCCESS(status)) {
  570. DebugPrint((1,
  571. "ChangerStartDevice: Unable to get adapter descriptor. Status %x\n",
  572. status));
  573. goto ChangerInitDeviceExit;
  574. }
  575. //
  576. // Invoke the device-specific initialization function.
  577. //
  578. status = mcdInitData->ChangerInitialize(Fdo);
  579. //
  580. // Register for media change notification
  581. //
  582. ClassInitializeMediaChangeDetection(fdoExtension,
  583. "Changer");
  584. //
  585. // Register interfaces for this device.
  586. //
  587. RtlInitUnicodeString(&interfaceName, NULL);
  588. status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
  589. (LPGUID) &MediumChangerClassGuid,
  590. NULL,
  591. &interfaceName);
  592. if(NT_SUCCESS(status)) {
  593. mcdClassData = (PMCD_CLASS_DATA)(fdoExtension->CommonExtension.DriverData);
  594. //
  595. // The class library's private data is after the miniclass's.
  596. //
  597. (ULONG_PTR)mcdClassData += mcdInitData->ChangerAdditionalExtensionSize();
  598. mcdClassData->MediumChangerInterfaceString = interfaceName;
  599. status = IoSetDeviceInterfaceState(
  600. &interfaceName,
  601. TRUE);
  602. if(!NT_SUCCESS(status)) {
  603. DebugPrint((1,
  604. "ChangerInitDevice: Unable to register Changer%x interface name - %x.\n",
  605. fdoExtension->DeviceNumber,
  606. status));
  607. status = STATUS_SUCCESS;
  608. }
  609. }
  610. return status;
  611. //
  612. // Fall through and return whatever status the miniclass driver returned.
  613. //
  614. ChangerInitDeviceExit:
  615. if (senseData) {
  616. ExFreePool(senseData);
  617. }
  618. return status;
  619. } // End ChangerStartDevice
  620. NTSTATUS
  621. ChangerRemoveDevice(
  622. IN PDEVICE_OBJECT DeviceObject,
  623. IN UCHAR Type
  624. )
  625. /*++
  626. Routine Description:
  627. This routine is responsible for releasing any resources in use by the
  628. tape driver.
  629. Arguments:
  630. DeviceObject - the device object being removed
  631. Return Value:
  632. none - this routine may not fail
  633. --*/
  634. {
  635. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  636. PMCD_CLASS_DATA mcdClassData = (PMCD_CLASS_DATA)fdoExtension->CommonExtension.DriverData;
  637. PMCD_INIT_DATA mcdInitData;
  638. ULONG miniClassExtSize;
  639. WCHAR dosNameBuffer[64];
  640. UNICODE_STRING dosUnicodeString;
  641. NTSTATUS status;
  642. PAGED_CODE();
  643. if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
  644. (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
  645. return STATUS_SUCCESS;
  646. }
  647. mcdInitData = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  648. ChangerClassInitialize);
  649. if (mcdInitData == NULL) {
  650. return STATUS_NO_SUCH_DEVICE;
  651. }
  652. miniClassExtSize = mcdInitData->ChangerAdditionalExtensionSize();
  653. //
  654. // Free all allocated memory.
  655. //
  656. if (fdoExtension->DeviceDescriptor) {
  657. ExFreePool(fdoExtension->DeviceDescriptor);
  658. fdoExtension->DeviceDescriptor = NULL;
  659. }
  660. if (fdoExtension->AdapterDescriptor) {
  661. ExFreePool(fdoExtension->AdapterDescriptor);
  662. fdoExtension->AdapterDescriptor = NULL;
  663. }
  664. if (fdoExtension->SenseData) {
  665. ExFreePool(fdoExtension->SenseData);
  666. fdoExtension->SenseData = NULL;
  667. }
  668. //
  669. // Remove the lookaside list.
  670. //
  671. ClassDeleteSrbLookasideList(&fdoExtension->CommonExtension);
  672. (ULONG_PTR)mcdClassData += miniClassExtSize;
  673. if(mcdClassData->MediumChangerInterfaceString.Buffer != NULL) {
  674. IoSetDeviceInterfaceState(&(mcdClassData->MediumChangerInterfaceString),
  675. FALSE);
  676. RtlFreeUnicodeString(&(mcdClassData->MediumChangerInterfaceString));
  677. //
  678. // Clear it.
  679. //
  680. RtlInitUnicodeString(&(mcdClassData->MediumChangerInterfaceString), NULL);
  681. }
  682. //
  683. // Delete the symbolic link "changerN".
  684. //
  685. if(mcdClassData->DosNameCreated) {
  686. swprintf(dosNameBuffer,
  687. L"\\DosDevices\\Changer%d",
  688. fdoExtension->DeviceNumber);
  689. RtlInitUnicodeString(&dosUnicodeString, dosNameBuffer);
  690. IoDeleteSymbolicLink(&dosUnicodeString);
  691. mcdClassData->DosNameCreated = FALSE;
  692. }
  693. //
  694. // Remove registry bits.
  695. //
  696. if(Type == IRP_MN_REMOVE_DEVICE) {
  697. IoGetConfigurationInformation()->MediumChangerCount--;
  698. }
  699. return STATUS_SUCCESS;
  700. }
  701. NTSTATUS
  702. ChangerReadWriteVerification(
  703. IN PDEVICE_OBJECT DeviceObject,
  704. IN PIRP Irp
  705. )
  706. /*++
  707. Routine Description:
  708. This routine is a stub that returns invalid device request.
  709. Arguments:
  710. DeviceObject - Supplies the device object.
  711. Irp - Supplies the I/O request packet.
  712. Return Value:
  713. STATUS_INVALID_DEVICE_REQUEST
  714. --*/
  715. {
  716. return STATUS_INVALID_DEVICE_REQUEST;
  717. }
  718. NTSTATUS
  719. DriverEntry(
  720. IN PDRIVER_OBJECT DriverObject,
  721. IN PUNICODE_STRING RegistryPath
  722. )
  723. /*++
  724. Routine Description:
  725. This is the entry point for this EXPORT DRIVER. It does nothing.
  726. --*/
  727. {
  728. return STATUS_SUCCESS;
  729. }
  730. NTSTATUS
  731. ChangerClassInitialize(
  732. IN PDRIVER_OBJECT DriverObject,
  733. IN PUNICODE_STRING RegistryPath,
  734. IN PMCD_INIT_DATA MCDInitData
  735. )
  736. /*++
  737. Routine Description:
  738. This routine is called by a changer mini-class driver during its
  739. DriverEntry routine to initialize the driver.
  740. Arguments:
  741. DriverObject - Supplies the driver object.
  742. RegistryPath - Supplies the registry path for this driver.
  743. MCDInitData - Changer Minidriver Init Data
  744. Return Value:
  745. Status value returned by ClassInitialize
  746. --*/
  747. {
  748. PMCD_INIT_DATA driverExtension;
  749. CLASS_INIT_DATA InitializationData;
  750. NTSTATUS status;
  751. //
  752. // Get the driver extension
  753. //
  754. status = IoAllocateDriverObjectExtension(
  755. DriverObject,
  756. ChangerClassInitialize,
  757. sizeof(MCD_INIT_DATA),
  758. &driverExtension);
  759. if (!NT_SUCCESS(status)) {
  760. if(status == STATUS_OBJECT_NAME_COLLISION) {
  761. //
  762. // An extension already exists for this key. Get a pointer to it
  763. //
  764. driverExtension = IoGetDriverObjectExtension(DriverObject,
  765. ChangerClassInitialize);
  766. if (driverExtension == NULL) {
  767. DebugPrint((1,
  768. "ChangerClassInitialize : driverExtension NULL\n"));
  769. return STATUS_INSUFFICIENT_RESOURCES;
  770. }
  771. } else {
  772. //
  773. // As this failed, the changer init data won't be able to be stored.
  774. //
  775. DebugPrint((1,
  776. "ChangerClassInitialize: Error %x allocating driver extension\n",
  777. status));
  778. return status;
  779. }
  780. }
  781. RtlCopyMemory(driverExtension, MCDInitData, sizeof(MCD_INIT_DATA));
  782. //
  783. // Zero InitData
  784. //
  785. RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
  786. //
  787. // Set sizes
  788. //
  789. InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
  790. InitializationData.FdoData.DeviceExtensionSize =
  791. sizeof(FUNCTIONAL_DEVICE_EXTENSION) +
  792. MCDInitData->ChangerAdditionalExtensionSize() +
  793. sizeof(MCD_CLASS_DATA);
  794. InitializationData.FdoData.DeviceType = FILE_DEVICE_CHANGER;
  795. InitializationData.FdoData.DeviceCharacteristics = 0;
  796. //
  797. // Set entry points
  798. //
  799. InitializationData.FdoData.ClassStartDevice = ChangerStartDevice;
  800. InitializationData.FdoData.ClassInitDevice = ChangerInitDevice;
  801. InitializationData.FdoData.ClassStopDevice = ChangerStopDevice;
  802. InitializationData.FdoData.ClassRemoveDevice = ChangerRemoveDevice;
  803. InitializationData.ClassAddDevice = ChangerAddDevice;
  804. InitializationData.FdoData.ClassReadWriteVerification = NULL;
  805. InitializationData.FdoData.ClassDeviceControl = ChangerClassDeviceControl;
  806. InitializationData.FdoData.ClassError = ChangerClassError;
  807. InitializationData.FdoData.ClassShutdownFlush = NULL;
  808. InitializationData.FdoData.ClassCreateClose = ChangerClassCreateClose;
  809. //
  810. // Stub routine to make the class driver happy.
  811. //
  812. InitializationData.FdoData.ClassReadWriteVerification = ChangerReadWriteVerification;
  813. InitializationData.ClassUnload = ChangerUnload;
  814. //
  815. // Routines for WMI support
  816. //
  817. InitializationData.FdoData.ClassWmiInfo.GuidCount = 3;
  818. InitializationData.FdoData.ClassWmiInfo.GuidRegInfo = ChangerWmiFdoGuidList;
  819. InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiRegInfo = ChangerFdoQueryWmiRegInfo;
  820. InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiDataBlock = ChangerFdoQueryWmiDataBlock;
  821. InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataBlock = ChangerFdoSetWmiDataBlock;
  822. InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataItem = ChangerFdoSetWmiDataItem;
  823. InitializationData.FdoData.ClassWmiInfo.ClassExecuteWmiMethod = ChangerFdoExecuteWmiMethod;
  824. InitializationData.FdoData.ClassWmiInfo.ClassWmiFunctionControl = ChangerWmiFunctionControl;
  825. //
  826. // Call the class init routine
  827. //
  828. return ClassInitialize( DriverObject, RegistryPath, &InitializationData);
  829. }
  830. VOID
  831. ChangerUnload(
  832. IN PDRIVER_OBJECT DriverObject
  833. )
  834. {
  835. PAGED_CODE();
  836. UNREFERENCED_PARAMETER(DriverObject);
  837. return;
  838. }
  839. NTSTATUS
  840. CreateChangerDeviceObject(
  841. IN PDRIVER_OBJECT DriverObject,
  842. IN PDEVICE_OBJECT PhysicalDeviceObject
  843. )
  844. /*++
  845. Routine Description:
  846. This routine creates an object for the device and then searches
  847. the device for partitions and creates an object for each partition.
  848. Arguments:
  849. DriverObject - Pointer to driver object created by system.
  850. PhysicalDeviceObject - DeviceObject of the attached to device.
  851. Return Value:
  852. NTSTATUS
  853. --*/
  854. {
  855. PDEVICE_OBJECT lowerDevice;
  856. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
  857. CCHAR deviceNameBuffer[64];
  858. NTSTATUS status;
  859. PDEVICE_OBJECT deviceObject;
  860. ULONG requiredStackSize;
  861. PVOID senseData;
  862. WCHAR dosNameBuffer[64];
  863. WCHAR wideNameBuffer[64];
  864. UNICODE_STRING dosUnicodeString;
  865. UNICODE_STRING deviceUnicodeString;
  866. PMCD_CLASS_DATA mcdClassData;
  867. PMCD_INIT_DATA mcdInitData;
  868. ULONG mcdCount;
  869. PAGED_CODE();
  870. DebugPrint((3,"CreateChangerDeviceObject: Enter routine\n"));
  871. //
  872. // Get the saved MCD Init Data
  873. //
  874. mcdInitData = IoGetDriverObjectExtension(DriverObject,
  875. ChangerClassInitialize);
  876. if (mcdInitData == NULL) {
  877. return STATUS_NO_SUCH_DEVICE;
  878. }
  879. ASSERT(mcdInitData);
  880. lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
  881. //
  882. // Claim the device. Note that any errors after this
  883. // will goto the generic handler, where the device will
  884. // be released.
  885. //
  886. status = ClassClaimDevice(lowerDevice, FALSE);
  887. if(!NT_SUCCESS(status)) {
  888. //
  889. // Someone already had this device.
  890. //
  891. ObDereferenceObject(lowerDevice);
  892. return status;
  893. }
  894. //
  895. // Create device object for this device.
  896. //
  897. mcdCount = 0;
  898. do {
  899. sprintf(deviceNameBuffer,
  900. "\\Device\\Changer%d",
  901. mcdCount);
  902. status = ClassCreateDeviceObject(DriverObject,
  903. deviceNameBuffer,
  904. PhysicalDeviceObject,
  905. TRUE,
  906. &deviceObject);
  907. mcdCount++;
  908. } while (status == STATUS_OBJECT_NAME_COLLISION);
  909. if (!NT_SUCCESS(status)) {
  910. DebugPrint((1,"CreateChangerDeviceObjects: Can not create device %s\n",
  911. deviceNameBuffer));
  912. goto CreateChangerDeviceObjectExit;
  913. }
  914. //
  915. // Indicate that IRPs should include MDLs.
  916. //
  917. deviceObject->Flags |= DO_DIRECT_IO;
  918. fdoExtension = deviceObject->DeviceExtension;
  919. //
  920. // Back pointer to device object.
  921. //
  922. fdoExtension->CommonExtension.DeviceObject = deviceObject;
  923. //
  924. // This is the physical device.
  925. //
  926. fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;
  927. //
  928. // Initialize lock count to zero. The lock count is used to
  929. // disable the ejection mechanism when media is mounted.
  930. //
  931. fdoExtension->LockCount = 0;
  932. //
  933. // Save system tape number
  934. //
  935. fdoExtension->DeviceNumber = mcdCount - 1;
  936. //
  937. // Set the alignment requirements for the device based on the
  938. // host adapter requirements
  939. //
  940. if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
  941. deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
  942. }
  943. //
  944. // Save the device descriptors
  945. //
  946. fdoExtension->AdapterDescriptor = NULL;
  947. fdoExtension->DeviceDescriptor = NULL;
  948. //
  949. // Clear the SrbFlags and disable synchronous transfers
  950. //
  951. fdoExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  952. //
  953. // Attach to the PDO
  954. //
  955. fdoExtension->LowerPdo = PhysicalDeviceObject;
  956. fdoExtension->CommonExtension.LowerDeviceObject =
  957. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  958. if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
  959. //
  960. // The attach failed. Cleanup and return.
  961. //
  962. status = STATUS_UNSUCCESSFUL;
  963. goto CreateChangerDeviceObjectExit;
  964. }
  965. //
  966. // Create the dos port driver name.
  967. //
  968. swprintf(dosNameBuffer,
  969. L"\\DosDevices\\Changer%d",
  970. fdoExtension->DeviceNumber);
  971. RtlInitUnicodeString(&dosUnicodeString, dosNameBuffer);
  972. //
  973. // Recreate the deviceName
  974. //
  975. swprintf(wideNameBuffer,
  976. L"\\Device\\Changer%d",
  977. fdoExtension->DeviceNumber);
  978. RtlInitUnicodeString(&deviceUnicodeString,
  979. wideNameBuffer);
  980. mcdClassData = (PMCD_CLASS_DATA)(fdoExtension->CommonExtension.DriverData);
  981. (ULONG_PTR)mcdClassData += mcdInitData->ChangerAdditionalExtensionSize();
  982. if (NT_SUCCESS(IoAssignArcName(&dosUnicodeString, &deviceUnicodeString))) {
  983. mcdClassData->DosNameCreated = TRUE;
  984. } else {
  985. mcdClassData->DosNameCreated = FALSE;
  986. }
  987. //
  988. // The device is initialized properly - mark it as such.
  989. //
  990. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  991. ObDereferenceObject(lowerDevice);
  992. return(STATUS_SUCCESS);
  993. CreateChangerDeviceObjectExit:
  994. //
  995. // Release the device since an error occured.
  996. //
  997. // ClassClaimDevice(PortDeviceObject,
  998. // LunInfo,
  999. // TRUE,
  1000. // NULL);
  1001. ObDereferenceObject(lowerDevice);
  1002. if (deviceObject != NULL) {
  1003. IoDeleteDevice(deviceObject);
  1004. }
  1005. return status;
  1006. } // end CreateChangerDeviceObject()
  1007. NTSTATUS
  1008. ChangerClassSendSrbSynchronous(
  1009. IN PDEVICE_OBJECT DeviceObject,
  1010. IN PSCSI_REQUEST_BLOCK Srb,
  1011. IN PVOID Buffer,
  1012. IN ULONG BufferSize,
  1013. IN BOOLEAN WriteToDevice
  1014. )
  1015. {
  1016. return ClassSendSrbSynchronous(DeviceObject, Srb,
  1017. Buffer, BufferSize,
  1018. WriteToDevice);
  1019. }
  1020. PVOID
  1021. ChangerClassAllocatePool(
  1022. IN POOL_TYPE PoolType,
  1023. IN ULONG NumberOfBytes
  1024. )
  1025. {
  1026. return ExAllocatePoolWithTag(PoolType, NumberOfBytes, 'CMcS');
  1027. }
  1028. VOID
  1029. ChangerClassFreePool(
  1030. IN PVOID PoolToFree
  1031. )
  1032. {
  1033. ExFreePool(PoolToFree);
  1034. }
  1035. #if DBG
  1036. #define MCHGR_DEBUG_PRINT_BUFF_LEN 128
  1037. ULONG MCDebug = 0;
  1038. UCHAR DebugBuffer[MCHGR_DEBUG_PRINT_BUFF_LEN];
  1039. #endif
  1040. #if DBG
  1041. VOID
  1042. ChangerClassDebugPrint(
  1043. ULONG DebugPrintLevel,
  1044. PCCHAR DebugMessage,
  1045. ...
  1046. )
  1047. /*++
  1048. Routine Description:
  1049. Debug print for all medium changer drivers
  1050. Arguments:
  1051. Debug print level between 0 and 3, with 3 being the most verbose.
  1052. Return Value:
  1053. None
  1054. --*/
  1055. {
  1056. va_list ap;
  1057. va_start(ap, DebugMessage);
  1058. if (DebugPrintLevel <= MCDebug) {
  1059. _vsnprintf(DebugBuffer, MCHGR_DEBUG_PRINT_BUFF_LEN,
  1060. DebugMessage, ap);
  1061. DbgPrintEx(DPFLTR_MCHGR_ID, DPFLTR_INFO_LEVEL, DebugBuffer);
  1062. }
  1063. va_end(ap);
  1064. } // end MCDebugPrint()
  1065. #else
  1066. //
  1067. // DebugPrint stub
  1068. //
  1069. VOID
  1070. ChangerClassDebugPrint(
  1071. ULONG DebugPrintLevel,
  1072. PCCHAR DebugMessage,
  1073. ...
  1074. )
  1075. {
  1076. }
  1077. #endif