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.

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