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.

3594 lines
97 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1994 - 1999
  3. Module Name:
  4. scsitape.c
  5. Abstract:
  6. This is the tape class driver.
  7. Environment:
  8. kernel mode only
  9. Revision History:
  10. --*/
  11. #include "tape.h"
  12. //
  13. // Define the maximum inquiry data length.
  14. //
  15. #define MAXIMUM_TAPE_INQUIRY_DATA 252
  16. #define UNDEFINED_BLOCK_SIZE ((ULONG) -1)
  17. #define TAPE_SRB_LIST_SIZE 4
  18. NTSTATUS
  19. DriverEntry(
  20. IN PDRIVER_OBJECT DriverObject,
  21. IN PUNICODE_STRING RegistryPath
  22. );
  23. VOID
  24. TapeUnload(
  25. IN PDRIVER_OBJECT DriverObject
  26. );
  27. NTSTATUS
  28. TapeAddDevice(
  29. IN PDRIVER_OBJECT DriverObject,
  30. IN PDEVICE_OBJECT Pdo
  31. );
  32. NTSTATUS
  33. TapeStartDevice(
  34. IN PDEVICE_OBJECT Fdo
  35. );
  36. NTSTATUS
  37. CreateTapeDeviceObject(
  38. IN PDRIVER_OBJECT DriverObject,
  39. IN PDEVICE_OBJECT PhysicalDeviceObject,
  40. IN PTAPE_INIT_DATA_EX TapeInitData
  41. );
  42. VOID
  43. TapeError(
  44. IN PDEVICE_OBJECT DeviceObject,
  45. IN PSCSI_REQUEST_BLOCK Srb,
  46. IN OUT PNTSTATUS Status,
  47. IN OUT PBOOLEAN Retry
  48. );
  49. NTSTATUS
  50. TapeReadWriteVerification(
  51. IN PDEVICE_OBJECT DeviceObject,
  52. IN PIRP Irp
  53. );
  54. VOID
  55. TapeReadWrite(
  56. IN PDEVICE_OBJECT Fdo,
  57. IN PIRP Irp
  58. );
  59. VOID
  60. SplitTapeRequest(
  61. IN PDEVICE_OBJECT Fdo,
  62. IN PIRP Irp,
  63. IN ULONG MaximumBytes
  64. );
  65. NTSTATUS
  66. TapeIoCompleteAssociated(
  67. IN PDEVICE_OBJECT Fdo,
  68. IN PIRP Irp,
  69. IN PVOID Context
  70. );
  71. NTSTATUS
  72. TapeDeviceControl(
  73. IN PDEVICE_OBJECT DeviceObject,
  74. IN PIRP Irp
  75. );
  76. NTSTATUS
  77. TapeInitDevice(
  78. IN PDEVICE_OBJECT Fdo
  79. );
  80. NTSTATUS
  81. TapeRemoveDevice(
  82. IN PDEVICE_OBJECT DeviceObject,
  83. IN UCHAR Type
  84. );
  85. NTSTATUS
  86. TapeStopDevice(
  87. IN PDEVICE_OBJECT DeviceObject,
  88. IN UCHAR Type
  89. );
  90. #ifdef ALLOC_PRAGMA
  91. #pragma alloc_text(INIT, DriverEntry)
  92. #pragma alloc_text(PAGE, TapeUnload)
  93. #pragma alloc_text(PAGE, TapeClassInitialize)
  94. #pragma alloc_text(PAGE, TapeAddDevice)
  95. #pragma alloc_text(PAGE, CreateTapeDeviceObject)
  96. #pragma alloc_text(PAGE, TapeStartDevice)
  97. #pragma alloc_text(PAGE, TapeInitDevice)
  98. #pragma alloc_text(PAGE, TapeRemoveDevice)
  99. #pragma alloc_text(PAGE, TapeStopDevice)
  100. #pragma alloc_text(PAGE, TapeDeviceControl)
  101. #pragma alloc_text(PAGE, TapeReadWriteVerification)
  102. #pragma alloc_text(PAGE, TapeReadWrite)
  103. #pragma alloc_text(PAGE, SplitTapeRequest)
  104. #pragma alloc_text(PAGE, ScsiTapeFreeSrbBuffer)
  105. #pragma alloc_text(PAGE, TapeClassZeroMemory)
  106. #pragma alloc_text(PAGE, TapeClassCompareMemory)
  107. #pragma alloc_text(PAGE, TapeClassLiDiv)
  108. #pragma alloc_text(PAGE, GetTimeoutDeltaFromRegistry)
  109. #endif
  110. NTSTATUS
  111. DriverEntry(
  112. IN PDRIVER_OBJECT DriverObject,
  113. IN PUNICODE_STRING RegistryPath
  114. )
  115. /*++
  116. Routine Description:
  117. This is the entry point for this EXPORT DRIVER. It does nothing.
  118. --*/
  119. {
  120. return STATUS_SUCCESS;
  121. }
  122. ULONG
  123. TapeClassInitialize(
  124. IN PVOID Argument1,
  125. IN PVOID Argument2,
  126. IN PTAPE_INIT_DATA_EX TapeInitData
  127. )
  128. /*++
  129. Routine Description:
  130. This routine is called by a tape mini-class driver during its
  131. DriverEntry routine to initialize the driver.
  132. Arguments:
  133. Argument1 - Supplies the first argument to DriverEntry.
  134. Argument2 - Supplies the second argument to DriverEntry.
  135. TapeInitData - Supplies the tape initialization data.
  136. Return Value:
  137. A valid return code for a DriverEntry routine.
  138. --*/
  139. {
  140. PDRIVER_OBJECT driverObject = Argument1;
  141. PUNICODE_STRING registryPath = Argument2;
  142. PTAPE_INIT_DATA_EX driverExtension;
  143. NTSTATUS status;
  144. CLASS_INIT_DATA initializationData;
  145. TAPE_INIT_DATA_EX tmpInitData;
  146. PAGED_CODE();
  147. DebugPrint((1,"\n\nSCSI Tape Class Driver\n"));
  148. //
  149. // Zero InitData
  150. //
  151. RtlZeroMemory (&tmpInitData, sizeof(TAPE_INIT_DATA_EX));
  152. //
  153. // Save the tape init data passed in from the miniclass driver. When AddDevice gets called, it will be used.
  154. // First a check for 4.0 vs. later miniclass drivers.
  155. //
  156. if (TapeInitData->InitDataSize != sizeof(TAPE_INIT_DATA_EX)) {
  157. //
  158. // Earlier rev. Copy the bits around so that the EX structure is correct.
  159. //
  160. RtlCopyMemory(&tmpInitData.VerifyInquiry, TapeInitData, sizeof(TAPE_INIT_DATA));
  161. //
  162. // Mark it as an earlier rev.
  163. //
  164. tmpInitData.InitDataSize = sizeof(TAPE_INIT_DATA);
  165. } else {
  166. RtlCopyMemory(&tmpInitData, TapeInitData, sizeof(TAPE_INIT_DATA_EX));
  167. }
  168. //
  169. // Get the driverExtension
  170. status = IoAllocateDriverObjectExtension(driverObject,
  171. TapeClassInitialize,
  172. sizeof(TAPE_INIT_DATA_EX),
  173. &driverExtension);
  174. if (!NT_SUCCESS(status)) {
  175. if(status == STATUS_OBJECT_NAME_COLLISION) {
  176. //
  177. // An extension already exists for this key. Get a pointer to it
  178. //
  179. driverExtension = IoGetDriverObjectExtension(driverObject,
  180. TapeClassInitialize);
  181. if (driverExtension == NULL) {
  182. DebugPrint((1, "TapeClassInitialize : driverExtension NULL\n"));
  183. return STATUS_INSUFFICIENT_RESOURCES;
  184. }
  185. } else {
  186. //
  187. // As this failed, the tape init data won't be able to be stored.
  188. //
  189. DebugPrint((1, "TapeClassInitialize: Error %x allocating driver extension.\n",
  190. status));
  191. return status;
  192. }
  193. }
  194. RtlCopyMemory(driverExtension, &tmpInitData, sizeof(TAPE_INIT_DATA_EX));
  195. RtlZeroMemory (&initializationData, sizeof(CLASS_INIT_DATA));
  196. //
  197. // Set sizes
  198. //
  199. initializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
  200. initializationData.FdoData.DeviceExtensionSize = sizeof(FUNCTIONAL_DEVICE_EXTENSION) +
  201. sizeof(TAPE_DATA) + tmpInitData.MinitapeExtensionSize;
  202. initializationData.FdoData.DeviceType = FILE_DEVICE_TAPE;
  203. initializationData.FdoData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA |
  204. FILE_DEVICE_SECURE_OPEN;
  205. //
  206. // Set entry points
  207. //
  208. initializationData.FdoData.ClassStartDevice = TapeStartDevice;
  209. initializationData.FdoData.ClassStopDevice = TapeStopDevice;
  210. initializationData.FdoData.ClassInitDevice = TapeInitDevice;
  211. initializationData.FdoData.ClassRemoveDevice = TapeRemoveDevice;
  212. initializationData.ClassAddDevice = TapeAddDevice;
  213. initializationData.FdoData.ClassError = TapeError;
  214. initializationData.FdoData.ClassReadWriteVerification = TapeReadWriteVerification;
  215. initializationData.FdoData.ClassDeviceControl = TapeDeviceControl;
  216. initializationData.FdoData.ClassShutdownFlush = NULL;
  217. initializationData.FdoData.ClassCreateClose = NULL;
  218. //
  219. // Routines for WMI support
  220. //
  221. initializationData.FdoData.ClassWmiInfo.GuidCount = 6;
  222. initializationData.FdoData.ClassWmiInfo.GuidRegInfo = TapeWmiGuidList;
  223. initializationData.FdoData.ClassWmiInfo.ClassQueryWmiRegInfo = TapeQueryWmiRegInfo;
  224. initializationData.FdoData.ClassWmiInfo.ClassQueryWmiDataBlock = TapeQueryWmiDataBlock;
  225. initializationData.FdoData.ClassWmiInfo.ClassSetWmiDataBlock = TapeSetWmiDataBlock;
  226. initializationData.FdoData.ClassWmiInfo.ClassSetWmiDataItem = TapeSetWmiDataItem;
  227. initializationData.FdoData.ClassWmiInfo.ClassExecuteWmiMethod = TapeExecuteWmiMethod;
  228. initializationData.FdoData.ClassWmiInfo.ClassWmiFunctionControl = TapeWmiFunctionControl;
  229. initializationData.ClassUnload = TapeUnload;
  230. //
  231. // Call the class init routine last, so can cleanup if it fails
  232. //
  233. status = ClassInitialize( driverObject, registryPath, &initializationData);
  234. if (!NT_SUCCESS(status)) {
  235. DebugPrint((1, "TapeClassInitialize: Error %x from classinit\n", status));
  236. TapeUnload(driverObject);
  237. }
  238. return status;
  239. }
  240. VOID
  241. TapeUnload(
  242. IN PDRIVER_OBJECT DriverObject
  243. )
  244. {
  245. PAGED_CODE();
  246. UNREFERENCED_PARAMETER(DriverObject);
  247. return;
  248. }
  249. NTSTATUS
  250. TapeAddDevice(
  251. IN PDRIVER_OBJECT DriverObject,
  252. IN PDEVICE_OBJECT PhysicalDeviceObject
  253. )
  254. /*++
  255. Routine Description:
  256. This routine creates and initializes a new FDO for the corresponding
  257. PDO. It may perform property queries on the FDO but cannot do any
  258. media access operations.
  259. Arguments:
  260. DriverObject - Tape class driver object.
  261. Pdo - the physical device object we are being added to
  262. Return Value:
  263. status
  264. --*/
  265. {
  266. PTAPE_INIT_DATA_EX tapeInitData;
  267. NTSTATUS status;
  268. PULONG tapeCount;
  269. PAGED_CODE();
  270. //
  271. // Get the saved-off tape init data.
  272. //
  273. tapeInitData = IoGetDriverObjectExtension(DriverObject, TapeClassInitialize);
  274. ASSERT(tapeInitData);
  275. //
  276. // Get the address of the count of the number of tape devices already initialized.
  277. //
  278. tapeCount = &IoGetConfigurationInformation()->TapeCount;
  279. status = CreateTapeDeviceObject(DriverObject,
  280. PhysicalDeviceObject,
  281. tapeInitData);
  282. if(NT_SUCCESS(status)) {
  283. (*tapeCount)++;
  284. }
  285. return status;
  286. }
  287. NTSTATUS
  288. CreateTapeDeviceObject(
  289. IN PDRIVER_OBJECT DriverObject,
  290. IN PDEVICE_OBJECT PhysicalDeviceObject,
  291. IN PTAPE_INIT_DATA_EX TapeInitData
  292. )
  293. /*++
  294. Routine Description:
  295. This routine creates an object for the device.
  296. Arguments:
  297. DriverObject - Pointer to driver object created by system.
  298. PhysicalDeviceObject - DeviceObject of the attached to device.
  299. TapeInitData - Supplies the tape initialization data.
  300. Return Value:
  301. NTSTATUS
  302. --*/
  303. {
  304. UCHAR deviceNameBuffer[64];
  305. NTSTATUS status;
  306. PDEVICE_OBJECT deviceObject;
  307. PTAPE_INIT_DATA_EX tapeInitData;
  308. PDEVICE_OBJECT lowerDevice;
  309. PTAPE_DATA tapeData;
  310. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
  311. WCHAR dosNameBuffer[64];
  312. WCHAR wideNameBuffer[64];
  313. UNICODE_STRING dosUnicodeString;
  314. UNICODE_STRING deviceUnicodeString;
  315. ULONG tapeCount;
  316. PAGED_CODE();
  317. DebugPrint((3,"CreateDeviceObject: Enter routine\n"));
  318. lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
  319. //
  320. // Claim the device. Note that any errors after this
  321. // will goto the generic handler, where the device will
  322. // be released.
  323. //
  324. status = ClassClaimDevice(lowerDevice, FALSE);
  325. if(!NT_SUCCESS(status)) {
  326. //
  327. // Someone already had this device - we're in trouble
  328. //
  329. ObDereferenceObject(lowerDevice);
  330. return status;
  331. }
  332. //
  333. // Create device object for this device.
  334. //
  335. tapeCount = 0;
  336. do {
  337. sprintf(deviceNameBuffer,
  338. "\\Device\\Tape%d",
  339. tapeCount);
  340. status = ClassCreateDeviceObject(DriverObject,
  341. deviceNameBuffer,
  342. PhysicalDeviceObject,
  343. TRUE,
  344. &deviceObject);
  345. tapeCount++;
  346. } while (status == STATUS_OBJECT_NAME_COLLISION);
  347. if (!NT_SUCCESS(status)) {
  348. DebugPrint((1,"CreateTapeDeviceObjects: Can not create device %s\n",
  349. deviceNameBuffer));
  350. goto CreateTapeDeviceObjectExit;
  351. }
  352. //
  353. // Indicate that IRPs should include MDLs.
  354. //
  355. deviceObject->Flags |= DO_DIRECT_IO;
  356. fdoExtension = deviceObject->DeviceExtension;
  357. //
  358. // Back pointer to device object.
  359. //
  360. fdoExtension->CommonExtension.DeviceObject = deviceObject;
  361. //
  362. // This is the physical device.
  363. //
  364. fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;
  365. //
  366. // Initialize lock count to zero. The lock count is used to
  367. // disable the ejection mechanism when media is mounted.
  368. //
  369. fdoExtension->LockCount = 0;
  370. //
  371. // Save system tape number
  372. //
  373. fdoExtension->DeviceNumber = tapeCount - 1;
  374. //
  375. // Set the alignment requirements for the device based on the
  376. // host adapter requirements
  377. //
  378. if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
  379. deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
  380. }
  381. //
  382. // Save the device descriptors
  383. //
  384. fdoExtension->AdapterDescriptor = NULL;
  385. fdoExtension->DeviceDescriptor = NULL;
  386. //
  387. // Attach to the PDO
  388. //
  389. fdoExtension->LowerPdo = PhysicalDeviceObject;
  390. fdoExtension->CommonExtension.LowerDeviceObject =
  391. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  392. if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
  393. //
  394. // The attach failed. Cleanup and return.
  395. //
  396. status = STATUS_UNSUCCESSFUL;
  397. goto CreateTapeDeviceObjectExit;
  398. }
  399. //
  400. // Save the tape initialization data.
  401. //
  402. RtlCopyMemory(fdoExtension->CommonExtension.DriverData, TapeInitData,sizeof(TAPE_INIT_DATA_EX));
  403. //
  404. // Initialize the splitrequest spinlock.
  405. //
  406. tapeData = (PTAPE_DATA)fdoExtension->CommonExtension.DriverData;
  407. KeInitializeSpinLock(&tapeData->SplitRequestSpinLock);
  408. //
  409. // Create the dos port driver name.
  410. //
  411. swprintf(dosNameBuffer,
  412. L"\\DosDevices\\TAPE%d",
  413. fdoExtension->DeviceNumber);
  414. RtlInitUnicodeString(&dosUnicodeString, dosNameBuffer);
  415. //
  416. // Recreate the deviceName
  417. //
  418. swprintf(wideNameBuffer,
  419. L"\\Device\\Tape%d",
  420. fdoExtension->DeviceNumber);
  421. RtlInitUnicodeString(&deviceUnicodeString,
  422. wideNameBuffer);
  423. status = IoAssignArcName(&dosUnicodeString,
  424. &deviceUnicodeString);
  425. if (NT_SUCCESS(status)) {
  426. tapeData->DosNameCreated = TRUE;
  427. } else {
  428. tapeData->DosNameCreated = FALSE;
  429. }
  430. //
  431. // The device is initialized properly - mark it as such.
  432. //
  433. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  434. ObDereferenceObject(lowerDevice);
  435. return(STATUS_SUCCESS);
  436. CreateTapeDeviceObjectExit:
  437. //
  438. // Release the device since an error occured.
  439. //
  440. // ClassClaimDevice(PortDeviceObject,
  441. // LunInfo,
  442. // TRUE,
  443. // NULL);
  444. ObDereferenceObject(lowerDevice);
  445. if (deviceObject != NULL) {
  446. IoDeleteDevice(deviceObject);
  447. }
  448. return status;
  449. } // end CreateTapeDeviceObject()
  450. NTSTATUS
  451. TapeStartDevice(
  452. IN PDEVICE_OBJECT Fdo
  453. )
  454. /*++
  455. Routine Description:
  456. This routine is called after InitDevice, and creates the symbolic link,
  457. and sets up information in the registry.
  458. The routine could be called multiple times, in the event of a StopDevice.
  459. Arguments:
  460. Fdo - a pointer to the functional device object for this device
  461. Return Value:
  462. status
  463. --*/
  464. {
  465. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  466. PTAPE_DATA tapeData;
  467. PTAPE_INIT_DATA_EX tapeInitData;
  468. PINQUIRYDATA inquiryData;
  469. ULONG inquiryLength;
  470. SCSI_REQUEST_BLOCK srb;
  471. PCDB cdb;
  472. NTSTATUS status;
  473. PVOID minitapeExtension;
  474. PMODE_CAP_PAGE capPage = NULL ;
  475. PMODE_CAPABILITIES_PAGE capabilitiesPage;
  476. ULONG pageLength;
  477. PAGED_CODE();
  478. //
  479. // Build and send request to get inquiry data.
  480. //
  481. inquiryData = ExAllocatePool(NonPagedPoolCacheAligned, MAXIMUM_TAPE_INQUIRY_DATA);
  482. if (!inquiryData) {
  483. //
  484. // The buffer cannot be allocated.
  485. //
  486. return STATUS_INSUFFICIENT_RESOURCES;
  487. }
  488. //
  489. // Get the tape init data again.
  490. //
  491. tapeData = (PTAPE_DATA)(fdoExtension->CommonExtension.DriverData);
  492. tapeInitData = &tapeData->TapeInitData;
  493. RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
  494. //
  495. // Set timeout value.
  496. //
  497. srb.TimeOutValue = 2;
  498. srb.CdbLength = 6;
  499. cdb = (PCDB)srb.Cdb;
  500. //
  501. // Set CDB operation code.
  502. //
  503. cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
  504. //
  505. // Set allocation length to inquiry data buffer size.
  506. //
  507. cdb->CDB6INQUIRY.AllocationLength = MAXIMUM_TAPE_INQUIRY_DATA;
  508. status = ClassSendSrbSynchronous(Fdo,
  509. &srb,
  510. inquiryData,
  511. MAXIMUM_TAPE_INQUIRY_DATA,
  512. FALSE);
  513. if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_SUCCESS ||
  514. SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  515. srb.SrbStatus = SRB_STATUS_SUCCESS;
  516. }
  517. if (srb.SrbStatus == SRB_STATUS_SUCCESS) {
  518. inquiryLength = inquiryData->AdditionalLength + FIELD_OFFSET(INQUIRYDATA, Reserved);
  519. if (inquiryLength > srb.DataTransferLength) {
  520. inquiryLength = srb.DataTransferLength;
  521. }
  522. //
  523. // Verify that we really want this device.
  524. //
  525. if (tapeInitData->QueryModeCapabilitiesPage ) {
  526. capPage = ExAllocatePool(NonPagedPoolCacheAligned,
  527. sizeof(MODE_CAP_PAGE));
  528. }
  529. if (capPage) {
  530. pageLength = ClassModeSense(Fdo,
  531. (PCHAR) capPage,
  532. sizeof(MODE_CAP_PAGE),
  533. MODE_PAGE_CAPABILITIES);
  534. if (pageLength == 0) {
  535. pageLength = ClassModeSense(Fdo,
  536. (PCHAR) capPage,
  537. sizeof(MODE_CAP_PAGE),
  538. MODE_PAGE_CAPABILITIES);
  539. }
  540. if (pageLength < (sizeof(MODE_CAP_PAGE) - 1)) {
  541. ExFreePool(capPage);
  542. capPage = NULL;
  543. }
  544. }
  545. if (capPage) {
  546. capabilitiesPage = &(capPage->CapabilitiesPage);
  547. } else {
  548. capabilitiesPage = NULL;
  549. }
  550. //
  551. // Initialize the minitape extension.
  552. //
  553. if (tapeInitData->ExtensionInit) {
  554. minitapeExtension = tapeData + 1;
  555. tapeInitData->ExtensionInit(minitapeExtension,
  556. inquiryData,
  557. capabilitiesPage);
  558. }
  559. if (capPage) {
  560. ExFreePool(capPage);
  561. }
  562. } else {
  563. inquiryLength = 0;
  564. }
  565. //
  566. // Add tape device number to registry
  567. //
  568. ClassUpdateInformationInRegistry(Fdo,
  569. "Tape",
  570. fdoExtension->DeviceNumber,
  571. inquiryData,
  572. inquiryLength);
  573. ExFreePool(inquiryData);
  574. status = IoSetDeviceInterfaceState(&(tapeData->TapeInterfaceString),
  575. TRUE);
  576. if(!NT_SUCCESS(status)) {
  577. DebugPrint((1,
  578. "TapeStartDevice: Unable to register Tape%x interface name - %x.\n",
  579. fdoExtension->DeviceNumber,
  580. status));
  581. }
  582. return STATUS_SUCCESS;
  583. }
  584. NTSTATUS
  585. TapeInitDevice(
  586. IN PDEVICE_OBJECT Fdo
  587. )
  588. /*++
  589. Routine Description:
  590. This routine will complete the tape miniclass initialization. This includes
  591. allocating sense info buffers and srb s-lists.
  592. This routine will not clean up allocate resources if it fails - that
  593. is left for device stop/removal
  594. Arguments:
  595. Fdo - a pointer to the functional device object for this device
  596. Return Value:
  597. status
  598. --*/
  599. {
  600. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  601. PVOID senseData = NULL;
  602. PTAPE_DATA tapeData;
  603. PTAPE_INIT_DATA_EX tapeInitData;
  604. NTSTATUS status;
  605. PVOID minitapeExtension;
  606. STORAGE_PROPERTY_ID propertyId;
  607. UNICODE_STRING interfaceName;
  608. PAGED_CODE();
  609. //
  610. // Allocate request sense buffer.
  611. //
  612. senseData = ExAllocatePool(NonPagedPoolCacheAligned,
  613. SENSE_BUFFER_SIZE);
  614. if (senseData == NULL) {
  615. //
  616. // The buffer cannot be allocated.
  617. //
  618. return STATUS_INSUFFICIENT_RESOURCES;
  619. }
  620. //
  621. // Build the lookaside list for srb's for the physical disk. Should only
  622. // need a couple.
  623. //
  624. ClassInitializeSrbLookasideList(&(fdoExtension->CommonExtension),
  625. TAPE_SRB_LIST_SIZE);
  626. //
  627. // Set the sense data pointer in the device extension.
  628. //
  629. fdoExtension->SenseData = senseData;
  630. fdoExtension->DiskGeometry.BytesPerSector = UNDEFINED_BLOCK_SIZE;
  631. //
  632. // Get the tape init data again.
  633. //
  634. tapeData = (PTAPE_DATA)(fdoExtension->CommonExtension.DriverData);
  635. tapeInitData = &tapeData->TapeInitData;
  636. //
  637. // Set timeout value in seconds.
  638. //
  639. if (tapeInitData->DefaultTimeOutValue) {
  640. fdoExtension->TimeOutValue = tapeInitData->DefaultTimeOutValue;
  641. } else {
  642. fdoExtension->TimeOutValue = 180;
  643. }
  644. //
  645. // Used to keep track of the last time a drive clean
  646. // notification was sent by the driver
  647. //
  648. tapeData->LastDriveCleanRequestTime.QuadPart = 0;
  649. //
  650. // SRB Timeout delta is used to increase the timeout for certain
  651. // commands - typically, commands such as SET_POSITION, ERASE, etc.
  652. //
  653. tapeData->SrbTimeoutDelta = GetTimeoutDeltaFromRegistry(fdoExtension->LowerPdo);
  654. if ((tapeData->SrbTimeoutDelta) == 0) {
  655. tapeData->SrbTimeoutDelta = fdoExtension->TimeOutValue;
  656. }
  657. //
  658. // Call port driver to get adapter capabilities.
  659. //
  660. propertyId = StorageAdapterProperty;
  661. status = ClassGetDescriptor(fdoExtension->CommonExtension.LowerDeviceObject,
  662. &propertyId,
  663. &(fdoExtension->AdapterDescriptor));
  664. if(!NT_SUCCESS(status)) {
  665. DebugPrint((1,
  666. "TapeStartDevice: Unable to get adapter descriptor. Status %x\n",
  667. status));
  668. ExFreePool(senseData);
  669. return status;
  670. }
  671. //
  672. // Register for media change notification
  673. //
  674. ClassInitializeMediaChangeDetection(fdoExtension,
  675. "Tape");
  676. //
  677. // Register interfaces for this device.
  678. //
  679. RtlInitUnicodeString(&tapeData->TapeInterfaceString, NULL);
  680. status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
  681. (LPGUID) &TapeClassGuid,
  682. NULL,
  683. &(tapeData->TapeInterfaceString));
  684. if(!NT_SUCCESS(status)) {
  685. DebugPrint((1,
  686. "TapeInitDevice: Unable to register Tape%x interface name - %x.\n",
  687. fdoExtension->DeviceNumber,
  688. status));
  689. status = STATUS_SUCCESS;
  690. }
  691. return STATUS_SUCCESS;
  692. } // End TapeStartDevice
  693. NTSTATUS
  694. TapeRemoveDevice(
  695. IN PDEVICE_OBJECT DeviceObject,
  696. IN UCHAR Type
  697. )
  698. /*++
  699. Routine Description:
  700. This routine is responsible for releasing any resources in use by the
  701. tape driver.
  702. Arguments:
  703. DeviceObject - the device object being removed
  704. Return Value:
  705. none - this routine may not fail
  706. --*/
  707. {
  708. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  709. PTAPE_DATA tapeData = (PTAPE_DATA)fdoExtension->CommonExtension.DriverData;
  710. WCHAR dosNameBuffer[64];
  711. UNICODE_STRING dosUnicodeString;
  712. NTSTATUS status;
  713. PAGED_CODE();
  714. if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
  715. (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
  716. return STATUS_SUCCESS;
  717. }
  718. //
  719. // Free all allocated memory.
  720. //
  721. if (Type == IRP_MN_REMOVE_DEVICE){
  722. if (fdoExtension->DeviceDescriptor) {
  723. ExFreePool(fdoExtension->DeviceDescriptor);
  724. fdoExtension->DeviceDescriptor = NULL;
  725. }
  726. if (fdoExtension->AdapterDescriptor) {
  727. ExFreePool(fdoExtension->AdapterDescriptor);
  728. fdoExtension->AdapterDescriptor = NULL;
  729. }
  730. if (fdoExtension->SenseData) {
  731. ExFreePool(fdoExtension->SenseData);
  732. fdoExtension->SenseData = NULL;
  733. }
  734. ClassDeleteSrbLookasideList(&fdoExtension->CommonExtension);
  735. }
  736. if(tapeData->TapeInterfaceString.Buffer != NULL) {
  737. IoSetDeviceInterfaceState(&(tapeData->TapeInterfaceString),
  738. FALSE);
  739. RtlFreeUnicodeString(&(tapeData->TapeInterfaceString));
  740. //
  741. // Clear it.
  742. //
  743. RtlInitUnicodeString(&(tapeData->TapeInterfaceString), NULL);
  744. }
  745. if(tapeData->DosNameCreated) {
  746. //
  747. // Delete the symbolic link "tapeN".
  748. //
  749. swprintf(dosNameBuffer,
  750. L"\\DosDevices\\TAPE%d",
  751. fdoExtension->DeviceNumber);
  752. RtlInitUnicodeString(&dosUnicodeString, dosNameBuffer);
  753. IoDeleteSymbolicLink(&dosUnicodeString);
  754. tapeData->DosNameCreated = FALSE;
  755. }
  756. IoGetConfigurationInformation()->TapeCount--;
  757. return STATUS_SUCCESS;
  758. }
  759. NTSTATUS
  760. TapeStopDevice(
  761. IN PDEVICE_OBJECT DeviceObject,
  762. IN UCHAR Type
  763. )
  764. {
  765. PAGED_CODE();
  766. return STATUS_SUCCESS;
  767. }
  768. BOOLEAN
  769. ScsiTapeNtStatusToTapeStatus(
  770. IN NTSTATUS NtStatus,
  771. OUT PTAPE_STATUS TapeStatus
  772. )
  773. /*++
  774. Routine Description:
  775. This routine translates an NT status code to a TAPE status code.
  776. Arguments:
  777. NtStatus - Supplies the NT status code.
  778. TapeStatus - Returns the tape status code.
  779. Return Value:
  780. FALSE - No tranlation was possible.
  781. TRUE - Success.
  782. --*/
  783. {
  784. switch (NtStatus) {
  785. case STATUS_SUCCESS:
  786. *TapeStatus = TAPE_STATUS_SUCCESS;
  787. break;
  788. case STATUS_INSUFFICIENT_RESOURCES:
  789. *TapeStatus = TAPE_STATUS_INSUFFICIENT_RESOURCES;
  790. break;
  791. case STATUS_NOT_IMPLEMENTED:
  792. *TapeStatus = TAPE_STATUS_NOT_IMPLEMENTED;
  793. break;
  794. case STATUS_INVALID_DEVICE_REQUEST:
  795. *TapeStatus = TAPE_STATUS_INVALID_DEVICE_REQUEST;
  796. break;
  797. case STATUS_INVALID_PARAMETER:
  798. *TapeStatus = TAPE_STATUS_INVALID_PARAMETER;
  799. break;
  800. case STATUS_VERIFY_REQUIRED:
  801. case STATUS_MEDIA_CHANGED:
  802. *TapeStatus = TAPE_STATUS_MEDIA_CHANGED;
  803. break;
  804. case STATUS_BUS_RESET:
  805. *TapeStatus = TAPE_STATUS_BUS_RESET;
  806. break;
  807. case STATUS_SETMARK_DETECTED:
  808. *TapeStatus = TAPE_STATUS_SETMARK_DETECTED;
  809. break;
  810. case STATUS_FILEMARK_DETECTED:
  811. *TapeStatus = TAPE_STATUS_FILEMARK_DETECTED;
  812. break;
  813. case STATUS_BEGINNING_OF_MEDIA:
  814. *TapeStatus = TAPE_STATUS_BEGINNING_OF_MEDIA;
  815. break;
  816. case STATUS_END_OF_MEDIA:
  817. *TapeStatus = TAPE_STATUS_END_OF_MEDIA;
  818. break;
  819. case STATUS_BUFFER_OVERFLOW:
  820. *TapeStatus = TAPE_STATUS_BUFFER_OVERFLOW;
  821. break;
  822. case STATUS_NO_DATA_DETECTED:
  823. *TapeStatus = TAPE_STATUS_NO_DATA_DETECTED;
  824. break;
  825. case STATUS_EOM_OVERFLOW:
  826. *TapeStatus = TAPE_STATUS_EOM_OVERFLOW;
  827. break;
  828. case STATUS_NO_MEDIA:
  829. case STATUS_NO_MEDIA_IN_DEVICE:
  830. *TapeStatus = TAPE_STATUS_NO_MEDIA;
  831. break;
  832. case STATUS_IO_DEVICE_ERROR:
  833. case STATUS_NONEXISTENT_SECTOR:
  834. *TapeStatus = TAPE_STATUS_IO_DEVICE_ERROR;
  835. break;
  836. case STATUS_UNRECOGNIZED_MEDIA:
  837. *TapeStatus = TAPE_STATUS_UNRECOGNIZED_MEDIA;
  838. break;
  839. case STATUS_DEVICE_NOT_READY:
  840. *TapeStatus = TAPE_STATUS_DEVICE_NOT_READY;
  841. break;
  842. case STATUS_MEDIA_WRITE_PROTECTED:
  843. *TapeStatus = TAPE_STATUS_MEDIA_WRITE_PROTECTED;
  844. break;
  845. case STATUS_DEVICE_DATA_ERROR:
  846. *TapeStatus = TAPE_STATUS_DEVICE_DATA_ERROR;
  847. break;
  848. case STATUS_NO_SUCH_DEVICE:
  849. *TapeStatus = TAPE_STATUS_NO_SUCH_DEVICE;
  850. break;
  851. case STATUS_INVALID_BLOCK_LENGTH:
  852. *TapeStatus = TAPE_STATUS_INVALID_BLOCK_LENGTH;
  853. break;
  854. case STATUS_IO_TIMEOUT:
  855. *TapeStatus = TAPE_STATUS_IO_TIMEOUT;
  856. break;
  857. case STATUS_DEVICE_NOT_CONNECTED:
  858. *TapeStatus = TAPE_STATUS_DEVICE_NOT_CONNECTED;
  859. break;
  860. case STATUS_DATA_OVERRUN:
  861. *TapeStatus = TAPE_STATUS_DATA_OVERRUN;
  862. break;
  863. case STATUS_DEVICE_BUSY:
  864. *TapeStatus = TAPE_STATUS_DEVICE_BUSY;
  865. break;
  866. case STATUS_CLEANER_CARTRIDGE_INSTALLED:
  867. *TapeStatus = TAPE_STATUS_CLEANER_CARTRIDGE_INSTALLED;
  868. break;
  869. default:
  870. return FALSE;
  871. }
  872. return TRUE;
  873. }
  874. BOOLEAN
  875. ScsiTapeTapeStatusToNtStatus(
  876. IN TAPE_STATUS TapeStatus,
  877. OUT PNTSTATUS NtStatus
  878. )
  879. /*++
  880. Routine Description:
  881. This routine translates a TAPE status code to an NT status code.
  882. Arguments:
  883. TapeStatus - Supplies the tape status code.
  884. NtStatus - Returns the NT status code.
  885. Return Value:
  886. FALSE - No tranlation was possible.
  887. TRUE - Success.
  888. --*/
  889. {
  890. switch (TapeStatus) {
  891. case TAPE_STATUS_SUCCESS:
  892. *NtStatus = STATUS_SUCCESS;
  893. break;
  894. case TAPE_STATUS_INSUFFICIENT_RESOURCES:
  895. *NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  896. break;
  897. case TAPE_STATUS_NOT_IMPLEMENTED:
  898. *NtStatus = STATUS_NOT_IMPLEMENTED;
  899. break;
  900. case TAPE_STATUS_INVALID_DEVICE_REQUEST:
  901. *NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  902. break;
  903. case TAPE_STATUS_INVALID_PARAMETER:
  904. *NtStatus = STATUS_INVALID_PARAMETER;
  905. break;
  906. case TAPE_STATUS_MEDIA_CHANGED:
  907. *NtStatus = STATUS_VERIFY_REQUIRED;
  908. break;
  909. case TAPE_STATUS_BUS_RESET:
  910. *NtStatus = STATUS_BUS_RESET;
  911. break;
  912. case TAPE_STATUS_SETMARK_DETECTED:
  913. *NtStatus = STATUS_SETMARK_DETECTED;
  914. break;
  915. case TAPE_STATUS_FILEMARK_DETECTED:
  916. *NtStatus = STATUS_FILEMARK_DETECTED;
  917. break;
  918. case TAPE_STATUS_BEGINNING_OF_MEDIA:
  919. *NtStatus = STATUS_BEGINNING_OF_MEDIA;
  920. break;
  921. case TAPE_STATUS_END_OF_MEDIA:
  922. *NtStatus = STATUS_END_OF_MEDIA;
  923. break;
  924. case TAPE_STATUS_BUFFER_OVERFLOW:
  925. *NtStatus = STATUS_BUFFER_OVERFLOW;
  926. break;
  927. case TAPE_STATUS_NO_DATA_DETECTED:
  928. *NtStatus = STATUS_NO_DATA_DETECTED;
  929. break;
  930. case TAPE_STATUS_EOM_OVERFLOW:
  931. *NtStatus = STATUS_EOM_OVERFLOW;
  932. break;
  933. case TAPE_STATUS_NO_MEDIA:
  934. *NtStatus = STATUS_NO_MEDIA;
  935. break;
  936. case TAPE_STATUS_IO_DEVICE_ERROR:
  937. *NtStatus = STATUS_IO_DEVICE_ERROR;
  938. break;
  939. case TAPE_STATUS_UNRECOGNIZED_MEDIA:
  940. *NtStatus = STATUS_UNRECOGNIZED_MEDIA;
  941. break;
  942. case TAPE_STATUS_DEVICE_NOT_READY:
  943. *NtStatus = STATUS_DEVICE_NOT_READY;
  944. break;
  945. case TAPE_STATUS_MEDIA_WRITE_PROTECTED:
  946. *NtStatus = STATUS_MEDIA_WRITE_PROTECTED;
  947. break;
  948. case TAPE_STATUS_DEVICE_DATA_ERROR:
  949. *NtStatus = STATUS_DEVICE_DATA_ERROR;
  950. break;
  951. case TAPE_STATUS_NO_SUCH_DEVICE:
  952. *NtStatus = STATUS_NO_SUCH_DEVICE;
  953. break;
  954. case TAPE_STATUS_INVALID_BLOCK_LENGTH:
  955. *NtStatus = STATUS_INVALID_BLOCK_LENGTH;
  956. break;
  957. case TAPE_STATUS_IO_TIMEOUT:
  958. *NtStatus = STATUS_IO_TIMEOUT;
  959. break;
  960. case TAPE_STATUS_DEVICE_NOT_CONNECTED:
  961. *NtStatus = STATUS_DEVICE_NOT_CONNECTED;
  962. break;
  963. case TAPE_STATUS_DATA_OVERRUN:
  964. *NtStatus = STATUS_DATA_OVERRUN;
  965. break;
  966. case TAPE_STATUS_DEVICE_BUSY:
  967. *NtStatus = STATUS_DEVICE_BUSY;
  968. break;
  969. case TAPE_STATUS_REQUIRES_CLEANING:
  970. *NtStatus = STATUS_DEVICE_REQUIRES_CLEANING;
  971. break;
  972. case TAPE_STATUS_CLEANER_CARTRIDGE_INSTALLED:
  973. *NtStatus = STATUS_CLEANER_CARTRIDGE_INSTALLED;
  974. break;
  975. default:
  976. return FALSE;
  977. }
  978. return TRUE;
  979. }
  980. VOID
  981. TapeError(
  982. IN PDEVICE_OBJECT FDO,
  983. IN PSCSI_REQUEST_BLOCK Srb,
  984. IN OUT PNTSTATUS Status,
  985. IN OUT PBOOLEAN Retry
  986. )
  987. /*++
  988. Routine Description:
  989. When a request completes with error, the routine ScsiClassInterpretSenseInfo is
  990. called to determine from the sense data whether the request should be
  991. retried and what NT status to set in the IRP. Then this routine is called
  992. for tape requests to handle tape-specific errors and update the nt status
  993. and retry boolean.
  994. Arguments:
  995. DeviceObject - Supplies a pointer to the device object.
  996. Srb - Supplies a pointer to the failing Srb.
  997. Status - NT Status used to set the IRP's completion status.
  998. Retry - Indicates that this request should be retried.
  999. Return Value:
  1000. None.
  1001. --*/
  1002. {
  1003. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = FDO->DeviceExtension;
  1004. PTAPE_DATA tapeData = (PTAPE_DATA)(fdoExtension->CommonExtension.DriverData);
  1005. PTAPE_INIT_DATA_EX tapeInitData = &tapeData->TapeInitData;
  1006. PVOID minitapeExtension = (tapeData + 1);
  1007. PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
  1008. PIRP irp = Srb->OriginalRequest;
  1009. LONG residualBlocks;
  1010. LONG length;
  1011. TAPE_STATUS tapeStatus, oldTapeStatus;
  1012. TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure[2];
  1013. //
  1014. // Never retry tape requests.
  1015. //
  1016. *Retry = FALSE;
  1017. //
  1018. // Check that request sense buffer is valid.
  1019. //
  1020. if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
  1021. DebugPrint((1,
  1022. "Sense Code : %x, Ad Sense : %x, Ad Sense Qual : %x\n",
  1023. ((senseBuffer->SenseKey) & 0xf),
  1024. (senseBuffer->AdditionalSenseCode),
  1025. (senseBuffer->AdditionalSenseCodeQualifier)));
  1026. switch (senseBuffer->SenseKey & 0xf) {
  1027. case SCSI_SENSE_UNIT_ATTENTION:
  1028. switch (senseBuffer->AdditionalSenseCode) {
  1029. case SCSI_ADSENSE_MEDIUM_CHANGED:
  1030. DebugPrint((1,
  1031. "InterpretSenseInfo: Media changed\n"));
  1032. *Status = STATUS_MEDIA_CHANGED;
  1033. break;
  1034. default:
  1035. DebugPrint((1,
  1036. "InterpretSenseInfo: Bus reset\n"));
  1037. *Status = STATUS_BUS_RESET;
  1038. break;
  1039. }
  1040. break;
  1041. case SCSI_SENSE_RECOVERED_ERROR:
  1042. //
  1043. // Check other indicators
  1044. //
  1045. if (senseBuffer->FileMark) {
  1046. switch (senseBuffer->AdditionalSenseCodeQualifier) {
  1047. case SCSI_SENSEQ_SETMARK_DETECTED :
  1048. DebugPrint((1,
  1049. "InterpretSenseInfo: Setmark detected\n"));
  1050. *Status = STATUS_SETMARK_DETECTED;
  1051. break ;
  1052. case SCSI_SENSEQ_FILEMARK_DETECTED :
  1053. default:
  1054. DebugPrint((1,
  1055. "InterpretSenseInfo: Filemark detected\n"));
  1056. *Status = STATUS_FILEMARK_DETECTED;
  1057. break ;
  1058. }
  1059. } else if ( senseBuffer->EndOfMedia ) {
  1060. switch( senseBuffer->AdditionalSenseCodeQualifier ) {
  1061. case SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED :
  1062. DebugPrint((1,
  1063. "InterpretSenseInfo: Beginning of media detected\n"));
  1064. *Status = STATUS_BEGINNING_OF_MEDIA;
  1065. break ;
  1066. case SCSI_SENSEQ_END_OF_MEDIA_DETECTED :
  1067. default:
  1068. DebugPrint((1,
  1069. "InterpretSenseInfo: End of media detected\n"));
  1070. *Status = STATUS_END_OF_MEDIA;
  1071. break ;
  1072. }
  1073. }
  1074. break;
  1075. case SCSI_SENSE_NO_SENSE:
  1076. //
  1077. // Check other indicators
  1078. //
  1079. if (senseBuffer->FileMark) {
  1080. switch( senseBuffer->AdditionalSenseCodeQualifier ) {
  1081. case SCSI_SENSEQ_SETMARK_DETECTED :
  1082. DebugPrint((1,
  1083. "InterpretSenseInfo: Setmark detected\n"));
  1084. *Status = STATUS_SETMARK_DETECTED;
  1085. break ;
  1086. case SCSI_SENSEQ_FILEMARK_DETECTED :
  1087. default:
  1088. DebugPrint((1,
  1089. "InterpretSenseInfo: Filemark detected\n"));
  1090. *Status = STATUS_FILEMARK_DETECTED;
  1091. break ;
  1092. }
  1093. } else if (senseBuffer->EndOfMedia) {
  1094. switch(senseBuffer->AdditionalSenseCodeQualifier) {
  1095. case SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED :
  1096. DebugPrint((1,
  1097. "InterpretSenseInfo: Beginning of media detected\n"));
  1098. *Status = STATUS_BEGINNING_OF_MEDIA;
  1099. break ;
  1100. case SCSI_SENSEQ_END_OF_MEDIA_DETECTED :
  1101. default:
  1102. DebugPrint((1,
  1103. "InterpretSenseInfo: End of media detected\n"));
  1104. *Status = STATUS_END_OF_MEDIA;
  1105. break;
  1106. }
  1107. } else if (senseBuffer->IncorrectLength) {
  1108. //
  1109. // If we're in variable block mode then ignore
  1110. // incorrect length.
  1111. //
  1112. if (fdoExtension->DiskGeometry.BytesPerSector == 0 &&
  1113. Srb->Cdb[0] == SCSIOP_READ6) {
  1114. REVERSE_BYTES((FOUR_BYTE UNALIGNED *)&residualBlocks,
  1115. (FOUR_BYTE UNALIGNED *)(senseBuffer->Information));
  1116. if (residualBlocks >= 0) {
  1117. DebugPrint((1,"InterpretSenseInfo: In variable block mode :We read less than specified\n"));
  1118. *Status = STATUS_SUCCESS;
  1119. } else {
  1120. DebugPrint((1,"InterpretSenseInfo: In variable block mode :Data left in block\n"));
  1121. *Status = STATUS_BUFFER_OVERFLOW;
  1122. }
  1123. }
  1124. }
  1125. break;
  1126. case SCSI_SENSE_BLANK_CHECK:
  1127. DebugPrint((1,
  1128. "InterpretSenseInfo: Media blank check\n"));
  1129. *Status = STATUS_NO_DATA_DETECTED;
  1130. break;
  1131. case SCSI_SENSE_VOL_OVERFLOW:
  1132. DebugPrint((1,
  1133. "InterpretSenseInfo: End of Media Overflow\n"));
  1134. *Status = STATUS_EOM_OVERFLOW;
  1135. break;
  1136. case SCSI_SENSE_NOT_READY:
  1137. switch (senseBuffer->AdditionalSenseCode) {
  1138. case SCSI_ADSENSE_LUN_NOT_READY:
  1139. switch (senseBuffer->AdditionalSenseCodeQualifier) {
  1140. case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
  1141. *Status = STATUS_NO_MEDIA;
  1142. break;
  1143. case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
  1144. break;
  1145. case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
  1146. default:
  1147. //
  1148. // Allow retries, if the drive isn't ready.
  1149. //
  1150. *Retry = TRUE;
  1151. break;
  1152. }
  1153. break;
  1154. case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
  1155. DebugPrint((1,
  1156. "InterpretSenseInfo:"
  1157. " No Media in device.\n"));
  1158. *Status = STATUS_NO_MEDIA;
  1159. break;
  1160. }
  1161. break;
  1162. } // end switch
  1163. //
  1164. // Check if a filemark or setmark was encountered,
  1165. // or an end-of-media or no-data condition exists.
  1166. //
  1167. if ((NT_WARNING(*Status) || NT_SUCCESS( *Status)) &&
  1168. (Srb->Cdb[0] == SCSIOP_WRITE6 || Srb->Cdb[0] == SCSIOP_READ6)) {
  1169. LONG actualLength;
  1170. //
  1171. // Not all bytes were transfered. Update information field with
  1172. // number of bytes transfered from sense buffer.
  1173. //
  1174. if (senseBuffer->Valid) {
  1175. REVERSE_BYTES((FOUR_BYTE UNALIGNED *)&residualBlocks,
  1176. (FOUR_BYTE UNALIGNED *)(senseBuffer->Information));
  1177. } else {
  1178. residualBlocks = 0;
  1179. }
  1180. length = ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLenLSB;
  1181. length |= ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLen << 8;
  1182. length |= ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLenMSB << 16;
  1183. actualLength = length;
  1184. length -= residualBlocks;
  1185. if (length < 0) {
  1186. length = 0;
  1187. *Status = STATUS_IO_DEVICE_ERROR;
  1188. }
  1189. if (fdoExtension->DiskGeometry.BytesPerSector) {
  1190. actualLength *= fdoExtension->DiskGeometry.BytesPerSector;
  1191. length *= fdoExtension->DiskGeometry.BytesPerSector;
  1192. }
  1193. if (length > actualLength) {
  1194. length = actualLength;
  1195. }
  1196. irp->IoStatus.Information = length;
  1197. DebugPrint((1,"ScsiTapeError: Transfer Count: %lx\n", Srb->DataTransferLength));
  1198. DebugPrint((1," Residual Blocks: %lx\n", residualBlocks));
  1199. DebugPrint((1," Irp IoStatus Information = %lx\n", irp->IoStatus.Information));
  1200. }
  1201. } else {
  1202. DebugPrint((1, "SRB Status : %x, SCSI Status : %x\n",
  1203. SRB_STATUS(Srb->SrbStatus),
  1204. (Srb->ScsiStatus)));
  1205. }
  1206. //
  1207. // Call tape device specific error handler.
  1208. //
  1209. if (tapeInitData->TapeError &&
  1210. ScsiTapeNtStatusToTapeStatus(*Status, &tapeStatus)) {
  1211. oldTapeStatus = tapeStatus;
  1212. tapeInitData->TapeError(minitapeExtension, Srb, &tapeStatus);
  1213. if (tapeStatus != oldTapeStatus) {
  1214. ScsiTapeTapeStatusToNtStatus(tapeStatus, Status);
  1215. }
  1216. }
  1217. //
  1218. // Notify the system that this tape drive requires cleaning
  1219. //
  1220. if ((*Status) == STATUS_DEVICE_REQUIRES_CLEANING) {
  1221. LARGE_INTEGER currentTime;
  1222. LARGE_INTEGER driveCleanInterval;
  1223. KeQuerySystemTime(&currentTime);
  1224. driveCleanInterval.QuadPart = ONE_SECOND;
  1225. driveCleanInterval.QuadPart *= TAPE_DRIVE_CLEAN_NOTIFICATION_INTERVAL;
  1226. if ((currentTime.QuadPart) >
  1227. ((tapeData->LastDriveCleanRequestTime.QuadPart) +
  1228. (driveCleanInterval.QuadPart))) {
  1229. NotificationStructure[0].Event = GUID_IO_DRIVE_REQUIRES_CLEANING;
  1230. NotificationStructure[0].Version = 1;
  1231. NotificationStructure[0].Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) +
  1232. sizeof(ULONG) - sizeof(UCHAR);
  1233. NotificationStructure[0].FileObject = NULL;
  1234. NotificationStructure[0].NameBufferOffset = -1;
  1235. //
  1236. // Increasing Index for this event
  1237. //
  1238. *((PULONG) (&(NotificationStructure[0].CustomDataBuffer[0]))) = 0;
  1239. IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
  1240. &NotificationStructure[0],
  1241. NULL,
  1242. NULL);
  1243. tapeData->LastDriveCleanRequestTime.QuadPart = currentTime.QuadPart;
  1244. }
  1245. }
  1246. return;
  1247. } // end ScsiTapeError()
  1248. NTSTATUS
  1249. TapeReadWriteVerification(
  1250. IN PDEVICE_OBJECT DeviceObject,
  1251. IN PIRP Irp
  1252. )
  1253. /*++
  1254. Routine Description:
  1255. This routine builds up the given irp for a read or write request.
  1256. Arguments:
  1257. DeviceObject - Supplies the device object.
  1258. Irp - Supplies the I/O request packet.
  1259. Return Value:
  1260. None.
  1261. --*/
  1262. {
  1263. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1264. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension;
  1265. PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor = fdoExtension->CommonExtension.PartitionZeroExtension->AdapterDescriptor;
  1266. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  1267. ULONG transferPages;
  1268. ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
  1269. LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
  1270. ULONG maximumTransferLength = adapterDescriptor->MaximumTransferLength;
  1271. ULONG bytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
  1272. PAGED_CODE();
  1273. //
  1274. // Since most tape devices don't support 10-byte read/write, the entire request must be dealt with here.
  1275. // STATUS_PENDING will be returned to the classpnp driver, so that it does nothing.
  1276. //
  1277. //
  1278. // Ensure that the request is for something valid - ie. not 0.
  1279. //
  1280. if (currentIrpStack->Parameters.Read.Length == 0) {
  1281. //
  1282. // Class code will handle this.
  1283. //
  1284. return STATUS_SUCCESS;
  1285. }
  1286. //
  1287. // Check that blocksize has been established.
  1288. //
  1289. if (bytesPerSector == UNDEFINED_BLOCK_SIZE) {
  1290. DebugPrint((1,
  1291. "TapeReadWriteVerification: Invalid block size - UNDEFINED\n"));
  1292. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1293. Irp->IoStatus.Information = 0;
  1294. //
  1295. // ClassPnp will handle completing the request.
  1296. //
  1297. return STATUS_INVALID_PARAMETER;
  1298. }
  1299. if (bytesPerSector) {
  1300. if (transferByteCount % bytesPerSector) {
  1301. DebugPrint((1,
  1302. "TapeReadWriteVerification: Invalid block size\n"));
  1303. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1304. Irp->IoStatus.Information = 0;
  1305. //
  1306. // ClassPnp will handle completing the request.
  1307. //
  1308. return STATUS_INVALID_PARAMETER;
  1309. }
  1310. }
  1311. //
  1312. // Calculate number of pages in this transfer.
  1313. //
  1314. transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
  1315. currentIrpStack->Parameters.Read.Length);
  1316. //
  1317. // Check if request length is greater than the maximum number of
  1318. // bytes that the hardware can transfer.
  1319. //
  1320. //
  1321. // Calculate number of pages in this transfer.
  1322. //
  1323. if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
  1324. transferPages > adapterDescriptor->MaximumPhysicalPages) {
  1325. DebugPrint((2,
  1326. "TapeReadWriteVerification: Request greater than maximum\n"));
  1327. DebugPrint((2,
  1328. "TapeReadWriteVerification: Maximum is %lx\n",
  1329. maximumTransferLength));
  1330. DebugPrint((2,
  1331. "TapeReadWriteVerification: Byte count is %lx\n",
  1332. currentIrpStack->Parameters.Read.Length));
  1333. transferPages = adapterDescriptor->MaximumPhysicalPages - 1;
  1334. if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
  1335. maximumTransferLength = transferPages << PAGE_SHIFT;
  1336. }
  1337. //
  1338. // Check that maximum transfer size is not zero.
  1339. //
  1340. if (maximumTransferLength == 0) {
  1341. maximumTransferLength = PAGE_SIZE;
  1342. }
  1343. //
  1344. // Ensure that this is reasonable, according to the current block size.
  1345. //
  1346. if (bytesPerSector) {
  1347. if (maximumTransferLength % bytesPerSector) {
  1348. ULONG tmpLength;
  1349. tmpLength = maximumTransferLength % bytesPerSector;
  1350. maximumTransferLength = maximumTransferLength - tmpLength;
  1351. }
  1352. }
  1353. //
  1354. // Mark IRP with status pending.
  1355. //
  1356. IoMarkIrpPending(Irp);
  1357. //
  1358. // Request greater than port driver maximum.
  1359. // Break up into smaller routines.
  1360. //
  1361. SplitTapeRequest(DeviceObject, Irp, maximumTransferLength);
  1362. return STATUS_PENDING;
  1363. }
  1364. //
  1365. // Build SRB and CDB for this IRP.
  1366. //
  1367. TapeReadWrite(DeviceObject, Irp);
  1368. IoMarkIrpPending(Irp);
  1369. IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  1370. return STATUS_PENDING;
  1371. }
  1372. VOID
  1373. SplitTapeRequest(
  1374. IN PDEVICE_OBJECT Fdo,
  1375. IN PIRP Irp,
  1376. IN ULONG MaximumBytes
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. Break request into smaller requests.
  1381. Each new request will be the maximum transfer
  1382. size that the port driver can handle or if it
  1383. is the final request, it may be the residual
  1384. size.
  1385. The number of IRPs required to process this
  1386. request is written in the current stack of
  1387. the original IRP. Then as each new IRP completes
  1388. the count in the original IRP is decremented.
  1389. When the count goes to zero, the original IRP
  1390. is completed.
  1391. Arguments:
  1392. DeviceObject - Pointer to the device object
  1393. Irp - Pointer to Irp
  1394. Return Value:
  1395. None.
  1396. --*/
  1397. {
  1398. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  1399. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  1400. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  1401. ULONG irpCount;
  1402. ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
  1403. PSCSI_REQUEST_BLOCK srb;
  1404. LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
  1405. ULONG dataLength = MaximumBytes;
  1406. PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
  1407. LONG remainingIrps;
  1408. BOOLEAN completeOriginalIrp = FALSE;
  1409. NTSTATUS status;
  1410. ULONG i;
  1411. PAGED_CODE();
  1412. //
  1413. // Caluculate number of requests to break this IRP into.
  1414. //
  1415. irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
  1416. DebugPrint((2,
  1417. "SplitTapeRequest: Requires %d IRPs\n", irpCount));
  1418. DebugPrint((2,
  1419. "SplitTapeRequest: Original IRP %p\n", Irp));
  1420. //
  1421. // If all partial transfers complete successfully then
  1422. // the status is already set up.
  1423. // Failing partial transfer IRP will set status to
  1424. // error and bytes transferred to 0 during IoCompletion.
  1425. //
  1426. Irp->IoStatus.Status = STATUS_SUCCESS;
  1427. //CEP Irp->IoStatus.Information = transferByteCount;
  1428. Irp->IoStatus.Information = 0;
  1429. //
  1430. // Save number of IRPs to complete count on current stack
  1431. // of original IRP.
  1432. //
  1433. nextIrpStack->Parameters.Others.Argument1 = ULongToPtr( irpCount );
  1434. for (i = 0; i < irpCount; i++) {
  1435. PIRP newIrp;
  1436. PIO_STACK_LOCATION newIrpStack;
  1437. //
  1438. // Allocate new IRP.
  1439. //
  1440. newIrp = IoAllocateIrp(Fdo->StackSize, FALSE);
  1441. if (newIrp == NULL) {
  1442. DebugPrint((1,
  1443. "SplitTapeRequest: Can't allocate Irp\n"));
  1444. //
  1445. // Decrement count of outstanding partial requests.
  1446. //
  1447. remainingIrps = InterlockedDecrement((PLONG)&nextIrpStack->Parameters.Others.Argument1);
  1448. //
  1449. // Check if any outstanding IRPs.
  1450. //
  1451. if (remainingIrps == 0) {
  1452. completeOriginalIrp = TRUE;
  1453. }
  1454. //
  1455. // Update original IRP with failing status.
  1456. //
  1457. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1458. Irp->IoStatus.Information = 0;
  1459. //
  1460. // Keep going with this request as outstanding partials
  1461. // may be in progress.
  1462. //
  1463. goto KeepGoing;
  1464. }
  1465. DebugPrint((2,
  1466. "SplitTapeRequest: New IRP %p\n", newIrp));
  1467. //
  1468. // Write MDL address to new IRP.
  1469. // In the port driver the SRB data length
  1470. // field is used as an offset into the MDL,
  1471. // so the same MDL can be used for each partial
  1472. // transfer. This saves having to build a new
  1473. // MDL for each partial transfer.
  1474. //
  1475. newIrp->MdlAddress = Irp->MdlAddress;
  1476. //
  1477. // At this point there is no current stack.
  1478. // IoSetNextIrpStackLocation will make the
  1479. // first stack location the current stack
  1480. // so that the SRB address can be written
  1481. // there.
  1482. //
  1483. IoSetNextIrpStackLocation(newIrp);
  1484. newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
  1485. newIrpStack->MajorFunction = currentIrpStack->MajorFunction;
  1486. newIrpStack->Parameters.Read.Length = dataLength;
  1487. newIrpStack->Parameters.Read.ByteOffset = startingOffset;
  1488. newIrpStack->DeviceObject = Fdo;
  1489. //
  1490. // Build SRB and CDB.
  1491. //
  1492. TapeReadWrite(Fdo, newIrp);
  1493. //
  1494. // Adjust SRB for this partial transfer.
  1495. //
  1496. newIrpStack = IoGetNextIrpStackLocation(newIrp);
  1497. srb = newIrpStack->Parameters.Others.Argument1;
  1498. srb->DataBuffer = dataBuffer;
  1499. //
  1500. // Write original IRP address to new IRP.
  1501. //
  1502. newIrp->AssociatedIrp.MasterIrp = Irp;
  1503. //
  1504. // Set the completion routine to TapeIoCompleteAssociated.
  1505. //
  1506. IoSetCompletionRoutine(newIrp,
  1507. TapeIoCompleteAssociated,
  1508. srb,
  1509. TRUE,
  1510. TRUE,
  1511. TRUE);
  1512. //
  1513. // Call port driver with new request.
  1514. //
  1515. status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, newIrp);
  1516. if (!NT_SUCCESS(status)) {
  1517. DebugPrint((1,
  1518. "SplitTapeRequest: IoCallDriver returned error\n"));
  1519. //
  1520. // Decrement count of outstanding partial requests.
  1521. //
  1522. remainingIrps = InterlockedDecrement((PLONG)&nextIrpStack->Parameters.Others.Argument1);
  1523. //
  1524. // Check if any outstanding IRPs.
  1525. //
  1526. if (remainingIrps == 0) {
  1527. completeOriginalIrp = TRUE;
  1528. }
  1529. //
  1530. // Update original IRP with failing status.
  1531. //
  1532. Irp->IoStatus.Status = status;
  1533. Irp->IoStatus.Information = 0;
  1534. //
  1535. // Deallocate this partial IRP.
  1536. //
  1537. IoFreeIrp(newIrp);
  1538. }
  1539. KeepGoing:
  1540. //
  1541. // Set up for next request.
  1542. //
  1543. dataBuffer = (PCHAR)dataBuffer + MaximumBytes;
  1544. transferByteCount -= MaximumBytes;
  1545. if (transferByteCount > MaximumBytes) {
  1546. dataLength = MaximumBytes;
  1547. } else {
  1548. dataLength = transferByteCount;
  1549. }
  1550. //
  1551. // Adjust disk byte offset.
  1552. //
  1553. startingOffset.QuadPart += MaximumBytes;
  1554. }
  1555. //
  1556. // Check if original IRP should be completed.
  1557. //
  1558. if (completeOriginalIrp) {
  1559. ClassReleaseRemoveLock(Fdo, Irp);
  1560. ClassCompleteRequest(Fdo, Irp, 0);
  1561. }
  1562. return;
  1563. } // end SplitTapeRequest()
  1564. VOID
  1565. TapeReadWrite(
  1566. IN PDEVICE_OBJECT Fdo,
  1567. IN PIRP Irp
  1568. )
  1569. /*++
  1570. Routine Description:
  1571. This routine builds up the given irp for a read or write request.
  1572. Arguments:
  1573. DeviceObject - Supplies the device object.
  1574. Irp - Supplies the I/O request packet.
  1575. Return Value:
  1576. None.
  1577. --*/
  1578. {
  1579. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  1580. PTAPE_DATA tapeData = (PTAPE_DATA)(fdoExtension->CommonExtension.DriverData);
  1581. PTAPE_INIT_DATA_EX tapeInitData = &tapeData->TapeInitData;
  1582. PVOID minitapeExtension = (tapeData + 1);
  1583. PIO_STACK_LOCATION irpSp, nextSp;
  1584. PSCSI_REQUEST_BLOCK srb;
  1585. PCDB cdb;
  1586. ULONG transferBlocks;
  1587. PAGED_CODE();
  1588. //
  1589. // Allocate an Srb.
  1590. //
  1591. srb = ExAllocateFromNPagedLookasideList(&(fdoExtension->CommonExtension.SrbLookasideList));
  1592. srb->SrbFlags = 0;
  1593. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1594. if (irpSp->MajorFunction == IRP_MJ_READ) {
  1595. srb->SrbFlags |= SRB_FLAGS_DATA_IN;
  1596. } else {
  1597. srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
  1598. }
  1599. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  1600. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  1601. srb->SrbStatus = 0;
  1602. srb->ScsiStatus = 0;
  1603. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  1604. srb->SrbFlags |= fdoExtension->SrbFlags;
  1605. srb->DataTransferLength = irpSp->Parameters.Read.Length;
  1606. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1607. srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
  1608. srb->SenseInfoBuffer = fdoExtension->SenseData;
  1609. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  1610. srb->NextSrb = NULL;
  1611. srb->OriginalRequest = Irp;
  1612. srb->SrbExtension = NULL;
  1613. srb->QueueSortKey = 0;
  1614. //
  1615. // Indicate that 6-byte CDB's will be used.
  1616. //
  1617. srb->CdbLength = CDB6GENERIC_LENGTH;
  1618. //
  1619. // Fill in CDB fields.
  1620. //
  1621. cdb = (PCDB)srb->Cdb;
  1622. //
  1623. // Zero CDB in SRB.
  1624. //
  1625. RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);
  1626. if (fdoExtension->DiskGeometry.BytesPerSector) {
  1627. //
  1628. // Since we are writing fixed block mode, normalize transfer count
  1629. // to number of blocks.
  1630. //
  1631. transferBlocks = irpSp->Parameters.Read.Length / fdoExtension->DiskGeometry.BytesPerSector;
  1632. //
  1633. // Tell the device that we are in fixed block mode.
  1634. //
  1635. cdb->CDB6READWRITETAPE.VendorSpecific = 1;
  1636. } else {
  1637. //
  1638. // Variable block mode transfer.
  1639. //
  1640. transferBlocks = irpSp->Parameters.Read.Length;
  1641. cdb->CDB6READWRITETAPE.VendorSpecific = 0;
  1642. }
  1643. //
  1644. // Set up transfer length
  1645. //
  1646. cdb->CDB6READWRITETAPE.TransferLenMSB = (UCHAR)((transferBlocks >> 16) & 0xff);
  1647. cdb->CDB6READWRITETAPE.TransferLen = (UCHAR)((transferBlocks >> 8) & 0xff);
  1648. cdb->CDB6READWRITETAPE.TransferLenLSB = (UCHAR)(transferBlocks & 0xff);
  1649. //
  1650. // Set transfer direction.
  1651. //
  1652. if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
  1653. DebugPrint((3,
  1654. "TapeReadWrite: Read Command\n"));
  1655. cdb->CDB6READWRITETAPE.OperationCode = SCSIOP_READ6;
  1656. } else {
  1657. DebugPrint((3,
  1658. "TapeReadWrite: Write Command\n"));
  1659. cdb->CDB6READWRITETAPE.OperationCode = SCSIOP_WRITE6;
  1660. }
  1661. nextSp = IoGetNextIrpStackLocation(Irp);
  1662. nextSp->MajorFunction = IRP_MJ_SCSI;
  1663. nextSp->Parameters.Scsi.Srb = srb;
  1664. irpSp->Parameters.Others.Argument4 = (PVOID) MAXIMUM_RETRIES;
  1665. IoSetCompletionRoutine(Irp,
  1666. ClassIoComplete,
  1667. srb,
  1668. TRUE,
  1669. TRUE,
  1670. FALSE);
  1671. if (tapeInitData->PreProcessReadWrite) {
  1672. //
  1673. // If the routine exists, call it. The miniclass driver will
  1674. // do whatever it needs to.
  1675. //
  1676. tapeInitData->PreProcessReadWrite(minitapeExtension,
  1677. NULL,
  1678. NULL,
  1679. srb,
  1680. 0,
  1681. 0,
  1682. NULL);
  1683. }
  1684. }
  1685. NTSTATUS
  1686. TapeIoCompleteAssociated(
  1687. IN PDEVICE_OBJECT Fdo,
  1688. IN PIRP Irp,
  1689. IN PVOID Context
  1690. )
  1691. /*++
  1692. Routine Description:
  1693. This routine executes when the port driver has completed a request.
  1694. It looks at the SRB status in the completing SRB and if not success
  1695. it checks for valid request sense buffer information. If valid, the
  1696. info is used to update status with more precise message of type of
  1697. error. This routine deallocates the SRB. This routine is used for
  1698. requests which were build by split request. After it has processed
  1699. the request it decrements the Irp count in the master Irp. If the
  1700. count goes to zero then the master Irp is completed.
  1701. Arguments:
  1702. DeviceObject - Supplies the device object which represents the logical
  1703. unit.
  1704. Irp - Supplies the Irp which has completed.
  1705. Context - Supplies a pointer to the SRB.
  1706. Return Value:
  1707. NT status
  1708. --*/
  1709. {
  1710. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1711. PSCSI_REQUEST_BLOCK srb = Context;
  1712. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  1713. PTAPE_DATA tapeData = (PTAPE_DATA)(fdoExtension->CommonExtension.DriverData);
  1714. LONG irpCount;
  1715. PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
  1716. NTSTATUS status;
  1717. //
  1718. // Check SRB status for success of completing request.
  1719. //
  1720. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  1721. DebugPrint((2,
  1722. "TapeIoCompleteAssociated: IRP %p, SRB %p", Irp, srb));
  1723. //
  1724. // Release the queue if it is frozen.
  1725. //
  1726. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  1727. ClassReleaseQueue(Fdo);
  1728. }
  1729. ClassInterpretSenseInfo(Fdo,
  1730. srb,
  1731. irpStack->MajorFunction,
  1732. irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ?
  1733. irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
  1734. MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
  1735. &status,
  1736. NULL);
  1737. //
  1738. // Return the highest error that occurs. This way warning take precedence
  1739. // over success and errors take precedence over warnings.
  1740. //
  1741. if ((ULONG) status > (ULONG) originalIrp->IoStatus.Status) {
  1742. //
  1743. // Ignore any requests which were flushed.
  1744. //
  1745. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_REQUEST_FLUSHED) {
  1746. originalIrp->IoStatus.Status = status;
  1747. }
  1748. }
  1749. } // end if (SRB_STATUS(srb->SrbStatus) ...
  1750. ExInterlockedAddUlong((PULONG)&originalIrp->IoStatus.Information,
  1751. (ULONG)Irp->IoStatus.Information,
  1752. &tapeData->SplitRequestSpinLock );
  1753. //
  1754. // Return SRB to the slist
  1755. //
  1756. ExFreeToNPagedLookasideList((&fdoExtension->CommonExtension.SrbLookasideList), srb);
  1757. DebugPrint((2,
  1758. "TapeIoCompleteAssociated: Partial xfer IRP %p\n", Irp));
  1759. //
  1760. // Get next stack location. This original request is unused
  1761. // except to keep track of the completing partial IRPs so the
  1762. // stack location is valid.
  1763. //
  1764. irpStack = IoGetNextIrpStackLocation(originalIrp);
  1765. //
  1766. //
  1767. // If any of the asynchronous partial transfer IRPs fail with an error
  1768. // with an error then the original IRP will return 0 bytes transfered.
  1769. // This is an optimization for successful transfers.
  1770. //
  1771. if (NT_ERROR(originalIrp->IoStatus.Status)) {
  1772. originalIrp->IoStatus.Information = 0;
  1773. //
  1774. // Set the hard error if necessary.
  1775. //
  1776. if (IoIsErrorUserInduced(originalIrp->IoStatus.Status)) {
  1777. //
  1778. // Store DeviceObject for filesystem.
  1779. //
  1780. IoSetHardErrorOrVerifyDevice(originalIrp, Fdo);
  1781. }
  1782. }
  1783. //
  1784. // Decrement and get the count of remaining IRPs.
  1785. //
  1786. irpCount = InterlockedDecrement((PLONG)&irpStack->Parameters.Others.Argument1);
  1787. DebugPrint((2,
  1788. "TapeIoCompleteAssociated: Partial IRPs left %d\n",
  1789. irpCount));
  1790. if (irpCount == 0) {
  1791. #if DBG
  1792. irpStack = IoGetCurrentIrpStackLocation(originalIrp);
  1793. if (originalIrp->IoStatus.Information != irpStack->Parameters.Read.Length) {
  1794. DebugPrint((1,
  1795. "TapeIoCompleteAssociated: Short transfer. Request length: %lx, Return length: %lx, Status: %lx\n",
  1796. irpStack->Parameters.Read.Length,
  1797. originalIrp->IoStatus.Information,
  1798. originalIrp->IoStatus.Status));
  1799. }
  1800. #endif
  1801. //
  1802. // All partial IRPs have completed.
  1803. //
  1804. DebugPrint((2,
  1805. "TapeIoCompleteAssociated: All partial IRPs complete %p\n",
  1806. originalIrp));
  1807. //
  1808. // Release the lock and complete the original request.
  1809. //
  1810. ClassReleaseRemoveLock(Fdo, originalIrp);
  1811. ClassCompleteRequest(Fdo,originalIrp, IO_DISK_INCREMENT);
  1812. }
  1813. //
  1814. // Deallocate IRP and indicate the I/O system should not attempt any more
  1815. // processing.
  1816. //
  1817. IoFreeIrp(Irp);
  1818. return STATUS_MORE_PROCESSING_REQUIRED;
  1819. } // end TapeIoCompleteAssociated()
  1820. VOID
  1821. ScsiTapeFreeSrbBuffer(
  1822. IN OUT PSCSI_REQUEST_BLOCK Srb
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. This routine frees an SRB buffer that was previously allocated with
  1827. 'TapeClassAllocateSrbBuffer'.
  1828. Arguments:
  1829. Srb - Supplies the SCSI request block.
  1830. Return Value:
  1831. None.
  1832. --*/
  1833. {
  1834. PAGED_CODE();
  1835. if (Srb->DataBuffer) {
  1836. ExFreePool(Srb->DataBuffer);
  1837. Srb->DataBuffer = NULL;
  1838. }
  1839. Srb->DataTransferLength = 0;
  1840. }
  1841. #define IOCTL_TAPE_OLD_SET_MEDIA_PARAMS CTL_CODE(IOCTL_TAPE_BASE, 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
  1842. NTSTATUS
  1843. TapeDeviceControl(
  1844. IN PDEVICE_OBJECT DeviceObject,
  1845. IN PIRP Irp
  1846. )
  1847. /*++
  1848. Routine Description:
  1849. This routine is the dispatcher for device control requests. It
  1850. looks at the IOCTL code and calls the appropriate tape device
  1851. routine.
  1852. Arguments:
  1853. DeviceObject
  1854. Irp - Request packet
  1855. Return Value:
  1856. --*/
  1857. {
  1858. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1859. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1860. PTAPE_DATA tapeData= (PTAPE_DATA) (fdoExtension->CommonExtension.DriverData);
  1861. PTAPE_INIT_DATA_EX tapeInitData = &tapeData->TapeInitData;
  1862. PVOID minitapeExtension = tapeData + 1;
  1863. NTSTATUS status = STATUS_SUCCESS;
  1864. TAPE_PROCESS_COMMAND_ROUTINE commandRoutine;
  1865. ULONG i;
  1866. PVOID commandExtension;
  1867. SCSI_REQUEST_BLOCK srb;
  1868. BOOLEAN writeToDevice;
  1869. TAPE_STATUS tStatus;
  1870. TAPE_STATUS LastError ;
  1871. ULONG retryFlags, numRetries;
  1872. TAPE_WMI_OPERATIONS WMIOperations;
  1873. TAPE_DRIVE_PROBLEM_TYPE DriveProblemType;
  1874. PVOID commandParameters;
  1875. ULONG ioControlCode;
  1876. PWMI_TAPE_PROBLEM_WARNING TapeDriveProblem = NULL;
  1877. ULONG timeoutDelta = 0;
  1878. ULONG dataTransferLength = 0;
  1879. PAGED_CODE();
  1880. DebugPrint((3,"ScsiTapeDeviceControl: Enter routine\n"));
  1881. Irp->IoStatus.Information = 0;
  1882. ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  1883. switch (ioControlCode) {
  1884. case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
  1885. ULONG tmpSize;
  1886. //
  1887. // Validate version. Don't send this to a 4.0 miniclass driver.
  1888. //
  1889. if (tapeInitData->InitDataSize == sizeof(TAPE_INIT_DATA_EX)) {
  1890. //
  1891. // Validate buffer length.
  1892. //
  1893. tmpSize = (tapeInitData->MediaTypesSupported - 1) * sizeof(DEVICE_MEDIA_INFO);
  1894. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1895. sizeof(GET_MEDIA_TYPES) + tmpSize) {
  1896. status = STATUS_INFO_LENGTH_MISMATCH;
  1897. break;
  1898. }
  1899. //
  1900. // Validate that the buffer is large enough for all media types.
  1901. //
  1902. commandRoutine = tapeInitData->TapeGetMediaTypes;
  1903. } else {
  1904. status = STATUS_NOT_IMPLEMENTED;
  1905. }
  1906. break;
  1907. }
  1908. case IOCTL_TAPE_GET_DRIVE_PARAMS:
  1909. //
  1910. // Validate buffer length.
  1911. //
  1912. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1913. sizeof(TAPE_GET_DRIVE_PARAMETERS)) {
  1914. status = STATUS_INFO_LENGTH_MISMATCH;
  1915. break;
  1916. }
  1917. commandRoutine = tapeInitData->GetDriveParameters;
  1918. Irp->IoStatus.Information = sizeof(TAPE_GET_DRIVE_PARAMETERS);
  1919. break;
  1920. case IOCTL_TAPE_SET_DRIVE_PARAMS:
  1921. //
  1922. // Validate buffer length.
  1923. //
  1924. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1925. sizeof(TAPE_SET_DRIVE_PARAMETERS)) {
  1926. status = STATUS_INFO_LENGTH_MISMATCH;
  1927. break;
  1928. }
  1929. commandRoutine = tapeInitData->SetDriveParameters;
  1930. break;
  1931. case IOCTL_TAPE_GET_MEDIA_PARAMS:
  1932. //
  1933. // Validate buffer length.
  1934. //
  1935. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1936. sizeof(TAPE_GET_MEDIA_PARAMETERS)) {
  1937. status = STATUS_INFO_LENGTH_MISMATCH;
  1938. break;
  1939. }
  1940. commandRoutine = tapeInitData->GetMediaParameters;
  1941. Irp->IoStatus.Information = sizeof(TAPE_GET_MEDIA_PARAMETERS);
  1942. break;
  1943. //
  1944. // OLD_SET_XXX is here for legacy apps (defined READ/WRITE)
  1945. //
  1946. case IOCTL_TAPE_OLD_SET_MEDIA_PARAMS:
  1947. case IOCTL_TAPE_SET_MEDIA_PARAMS: {
  1948. PTAPE_SET_MEDIA_PARAMETERS tapeSetMediaParams = Irp->AssociatedIrp.SystemBuffer;
  1949. ULONG maxBytes1,maxBytes2,maxSize;
  1950. //
  1951. // Validate buffer length.
  1952. //
  1953. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1954. sizeof(TAPE_SET_MEDIA_PARAMETERS)) {
  1955. status = STATUS_INFO_LENGTH_MISMATCH;
  1956. break;
  1957. }
  1958. //
  1959. // Ensure that Max. block size is less than the miniports
  1960. // reported MaximumTransferLength.
  1961. //
  1962. maxBytes1 = PAGE_SIZE * (fdoExtension->AdapterDescriptor->MaximumPhysicalPages - 1);
  1963. maxBytes2 = fdoExtension->AdapterDescriptor->MaximumTransferLength;
  1964. maxSize = (maxBytes1 > maxBytes2) ? maxBytes2 : maxBytes1;
  1965. if (tapeSetMediaParams->BlockSize > maxSize) {
  1966. DebugPrint((1,
  1967. "ScsiTapeDeviceControl: Attempted to set blocksize greater than miniport capabilities\n"));
  1968. DebugPrint((1,"BlockSize %x, Miniport Maximum %x\n",
  1969. tapeSetMediaParams->BlockSize,
  1970. maxSize));
  1971. status = STATUS_INVALID_PARAMETER;
  1972. break;
  1973. }
  1974. commandRoutine = tapeInitData->SetMediaParameters;
  1975. break;
  1976. }
  1977. case IOCTL_TAPE_CREATE_PARTITION:
  1978. //
  1979. // Validate buffer length.
  1980. //
  1981. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1982. sizeof(TAPE_CREATE_PARTITION)) {
  1983. status = STATUS_INFO_LENGTH_MISMATCH;
  1984. break;
  1985. }
  1986. commandRoutine = tapeInitData->CreatePartition;
  1987. timeoutDelta = tapeData->SrbTimeoutDelta;
  1988. break;
  1989. case IOCTL_TAPE_ERASE:
  1990. //
  1991. // Validate buffer length.
  1992. //
  1993. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1994. sizeof(TAPE_ERASE)) {
  1995. status = STATUS_INFO_LENGTH_MISMATCH;
  1996. break;
  1997. }
  1998. commandRoutine = tapeInitData->Erase;
  1999. timeoutDelta = tapeData->SrbTimeoutDelta;
  2000. break;
  2001. case IOCTL_TAPE_PREPARE:
  2002. //
  2003. // Validate buffer length.
  2004. //
  2005. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  2006. sizeof(TAPE_PREPARE)) {
  2007. status = STATUS_INFO_LENGTH_MISMATCH;
  2008. break;
  2009. }
  2010. commandRoutine = tapeInitData->Prepare;
  2011. timeoutDelta = tapeData->SrbTimeoutDelta;
  2012. break;
  2013. case IOCTL_TAPE_WRITE_MARKS:
  2014. //
  2015. // Validate buffer length.
  2016. //
  2017. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  2018. sizeof(TAPE_WRITE_MARKS)) {
  2019. status = STATUS_INFO_LENGTH_MISMATCH;
  2020. break;
  2021. }
  2022. commandRoutine = tapeInitData->WriteMarks;
  2023. timeoutDelta = tapeData->SrbTimeoutDelta;
  2024. break;
  2025. case IOCTL_TAPE_GET_POSITION:
  2026. //
  2027. // Validate buffer length.
  2028. //
  2029. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  2030. sizeof(TAPE_GET_POSITION)) {
  2031. status = STATUS_INFO_LENGTH_MISMATCH;
  2032. break;
  2033. }
  2034. commandRoutine = tapeInitData->GetPosition;
  2035. Irp->IoStatus.Information = sizeof(TAPE_GET_POSITION);
  2036. break;
  2037. case IOCTL_TAPE_SET_POSITION:
  2038. //
  2039. // Validate buffer length.
  2040. //
  2041. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  2042. sizeof(TAPE_SET_POSITION)) {
  2043. status = STATUS_INFO_LENGTH_MISMATCH;
  2044. break;
  2045. }
  2046. commandRoutine = tapeInitData->SetPosition;
  2047. timeoutDelta = tapeData->SrbTimeoutDelta;
  2048. break;
  2049. case IOCTL_TAPE_GET_STATUS:
  2050. commandRoutine = tapeInitData->GetStatus;
  2051. break;
  2052. case IOCTL_STORAGE_PREDICT_FAILURE : {
  2053. //
  2054. // This IOCTL is for checking the tape drive
  2055. // to see if the device is having any problem.
  2056. //
  2057. PSTORAGE_PREDICT_FAILURE checkFailure;
  2058. checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer;
  2059. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  2060. sizeof(STORAGE_PREDICT_FAILURE)) {
  2061. status = STATUS_BUFFER_TOO_SMALL;
  2062. break;
  2063. }
  2064. //
  2065. // WMI routine to check for drive problems.
  2066. //
  2067. commandRoutine = tapeInitData->TapeWMIOperations;
  2068. if (commandRoutine == NULL) {
  2069. //
  2070. // WMI not supported by minidriver.
  2071. //
  2072. status = STATUS_WMI_NOT_SUPPORTED;
  2073. break;
  2074. }
  2075. TapeDriveProblem = ExAllocatePool(NonPagedPool,
  2076. sizeof(WMI_TAPE_PROBLEM_WARNING));
  2077. if (TapeDriveProblem == NULL) {
  2078. status = STATUS_NO_MEMORY;
  2079. break;
  2080. }
  2081. //
  2082. // Call the WMI method to check for drive problem.
  2083. //
  2084. RtlZeroMemory(TapeDriveProblem, sizeof(WMI_TAPE_PROBLEM_WARNING));
  2085. TapeDriveProblem->DriveProblemType = TapeDriveProblemNone;
  2086. WMIOperations.Method = TAPE_CHECK_FOR_DRIVE_PROBLEM;
  2087. WMIOperations.DataBufferSize = sizeof(WMI_TAPE_PROBLEM_WARNING);
  2088. WMIOperations.DataBuffer = (PVOID)TapeDriveProblem;
  2089. break;
  2090. }
  2091. default:
  2092. //
  2093. // Pass the request to the common device control routine.
  2094. //
  2095. return ClassDeviceControl(DeviceObject, Irp);
  2096. } // end switch()
  2097. if (!NT_SUCCESS(status)) {
  2098. Irp->IoStatus.Information = 0;
  2099. Irp->IoStatus.Status = status;
  2100. ClassReleaseRemoveLock(DeviceObject, Irp);
  2101. ClassCompleteRequest(DeviceObject,Irp, IO_NO_INCREMENT);
  2102. return status;
  2103. }
  2104. if (tapeInitData->CommandExtensionSize) {
  2105. commandExtension = ExAllocatePool(NonPagedPool,
  2106. tapeInitData->CommandExtensionSize);
  2107. if (commandExtension == NULL) {
  2108. Irp->IoStatus.Information = 0;
  2109. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2110. ClassReleaseRemoveLock(DeviceObject, Irp);
  2111. ClassCompleteRequest(DeviceObject,Irp, IO_NO_INCREMENT);
  2112. return STATUS_INSUFFICIENT_RESOURCES;
  2113. }
  2114. } else {
  2115. commandExtension = NULL;
  2116. }
  2117. if (ioControlCode == IOCTL_STORAGE_PREDICT_FAILURE) {
  2118. commandParameters = (PVOID)&WMIOperations;
  2119. } else {
  2120. commandParameters = Irp->AssociatedIrp.SystemBuffer;
  2121. }
  2122. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  2123. LastError = TAPE_STATUS_SUCCESS ;
  2124. for (i = 0; ; i++) {
  2125. srb.TimeOutValue = fdoExtension->TimeOutValue;
  2126. srb.SrbFlags = 0;
  2127. retryFlags = 0;
  2128. tStatus = commandRoutine(minitapeExtension, commandExtension,
  2129. commandParameters, &srb, i,
  2130. LastError, &retryFlags);
  2131. if (srb.TimeOutValue == 0) {
  2132. srb.TimeOutValue = fdoExtension->TimeOutValue;
  2133. }
  2134. //
  2135. // Add Srb Timeout delta to the current timeout value
  2136. // set in the SRB.
  2137. //
  2138. srb.TimeOutValue += timeoutDelta;
  2139. LastError = TAPE_STATUS_SUCCESS ;
  2140. numRetries = retryFlags&TAPE_RETRY_MASK;
  2141. if (tStatus == TAPE_STATUS_CHECK_TEST_UNIT_READY) {
  2142. PCDB cdb = (PCDB)srb.Cdb;
  2143. //
  2144. // Prepare SCSI command (CDB)
  2145. //
  2146. TapeClassZeroMemory(srb.Cdb, MAXIMUM_CDB_SIZE);
  2147. srb.CdbLength = CDB6GENERIC_LENGTH;
  2148. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  2149. srb.DataTransferLength = 0 ;
  2150. DebugPrint((3,"Test Unit Ready\n"));
  2151. } else if (tStatus == TAPE_STATUS_CALLBACK) {
  2152. LastError = TAPE_STATUS_CALLBACK ;
  2153. continue;
  2154. } else if (tStatus != TAPE_STATUS_SEND_SRB_AND_CALLBACK) {
  2155. break;
  2156. }
  2157. if (srb.DataBuffer && !srb.DataTransferLength) {
  2158. ScsiTapeFreeSrbBuffer(&srb);
  2159. }
  2160. if (srb.DataBuffer && (srb.SrbFlags&SRB_FLAGS_DATA_OUT)) {
  2161. writeToDevice = TRUE;
  2162. } else {
  2163. writeToDevice = FALSE;
  2164. }
  2165. dataTransferLength = srb.DataTransferLength;
  2166. for (;;) {
  2167. status = ClassSendSrbSynchronous(DeviceObject, &srb,
  2168. srb.DataBuffer,
  2169. srb.DataTransferLength,
  2170. writeToDevice);
  2171. if (NT_SUCCESS(status) ||
  2172. (status == STATUS_DATA_OVERRUN)) {
  2173. if (status == STATUS_DATA_OVERRUN) {
  2174. if ((srb.DataTransferLength) <= dataTransferLength) {
  2175. DebugPrint((1, "DataUnderRun reported as overrun\n"));
  2176. status = STATUS_SUCCESS;
  2177. break;
  2178. }
  2179. } else {
  2180. break;
  2181. }
  2182. }
  2183. if ((status == STATUS_BUS_RESET) ||
  2184. (status == STATUS_IO_TIMEOUT)) {
  2185. //
  2186. // Timeout value for the command probably wasn't sufficient.
  2187. // Update timeout delta from the registry
  2188. //
  2189. tapeData->SrbTimeoutDelta = GetTimeoutDeltaFromRegistry(fdoExtension->LowerPdo);
  2190. if ((tapeData->SrbTimeoutDelta) == 0) {
  2191. tapeData->SrbTimeoutDelta = fdoExtension->TimeOutValue;
  2192. timeoutDelta = tapeData->SrbTimeoutDelta;
  2193. srb.TimeOutValue += timeoutDelta;
  2194. }
  2195. }
  2196. if (numRetries == 0) {
  2197. if (retryFlags&RETURN_ERRORS) {
  2198. ScsiTapeNtStatusToTapeStatus(status, &LastError) ;
  2199. break ;
  2200. }
  2201. if (retryFlags&IGNORE_ERRORS) {
  2202. break;
  2203. }
  2204. if (commandExtension) {
  2205. ExFreePool(commandExtension);
  2206. }
  2207. ScsiTapeFreeSrbBuffer(&srb);
  2208. if (TapeDriveProblem) {
  2209. ExFreePool(TapeDriveProblem);
  2210. }
  2211. Irp->IoStatus.Information = 0;
  2212. Irp->IoStatus.Status = status;
  2213. ClassReleaseRemoveLock(DeviceObject, Irp);
  2214. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  2215. return status;
  2216. }
  2217. numRetries--;
  2218. }
  2219. }
  2220. ScsiTapeFreeSrbBuffer(&srb);
  2221. if (commandExtension) {
  2222. ExFreePool(commandExtension);
  2223. }
  2224. if (!ScsiTapeTapeStatusToNtStatus(tStatus, &status)) {
  2225. status = STATUS_IO_DEVICE_ERROR;
  2226. }
  2227. if (NT_SUCCESS(status)) {
  2228. PTAPE_GET_MEDIA_PARAMETERS tapeGetMediaParams;
  2229. PTAPE_SET_MEDIA_PARAMETERS tapeSetMediaParams;
  2230. PTAPE_GET_DRIVE_PARAMETERS tapeGetDriveParams;
  2231. PGET_MEDIA_TYPES tapeGetMediaTypes;
  2232. ULONG maxBytes1,maxBytes2,maxSize;
  2233. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  2234. case IOCTL_STORAGE_GET_MEDIA_TYPES_EX:
  2235. tapeGetMediaTypes = Irp->AssociatedIrp.SystemBuffer;
  2236. //
  2237. // Set information field based on the returned number of mediaTypes
  2238. //
  2239. Irp->IoStatus.Information = sizeof(GET_MEDIA_TYPES);
  2240. Irp->IoStatus.Information += ((tapeGetMediaTypes->MediaInfoCount - 1) * sizeof(DEVICE_MEDIA_INFO));
  2241. DebugPrint((1,"Tape: GET_MEDIA_TYPES - Information %x\n", Irp->IoStatus.Information));
  2242. break;
  2243. case IOCTL_TAPE_GET_MEDIA_PARAMS:
  2244. tapeGetMediaParams = Irp->AssociatedIrp.SystemBuffer;
  2245. //
  2246. // Check if block size has been initialized.
  2247. //
  2248. if (fdoExtension->DiskGeometry.BytesPerSector ==
  2249. UNDEFINED_BLOCK_SIZE) {
  2250. //
  2251. // Set the block size in the device object.
  2252. //
  2253. fdoExtension->DiskGeometry.BytesPerSector =
  2254. tapeGetMediaParams->BlockSize;
  2255. }
  2256. break;
  2257. case IOCTL_TAPE_OLD_SET_MEDIA_PARAMS:
  2258. case IOCTL_TAPE_SET_MEDIA_PARAMS:
  2259. tapeSetMediaParams = Irp->AssociatedIrp.SystemBuffer;
  2260. //
  2261. // Set the block size in the device object.
  2262. //
  2263. fdoExtension->DiskGeometry.BytesPerSector =
  2264. tapeSetMediaParams->BlockSize;
  2265. break;
  2266. case IOCTL_TAPE_GET_DRIVE_PARAMS: {
  2267. ULONG oldMinBlockSize;
  2268. ULONG oldMaxBlockSize;
  2269. ULONG oldDefBlockSize;
  2270. tapeGetDriveParams = Irp->AssociatedIrp.SystemBuffer;
  2271. //
  2272. // Ensure that Max. block size is less than the miniports
  2273. // reported MaximumTransferLength.
  2274. //
  2275. maxBytes1 = PAGE_SIZE * (fdoExtension->AdapterDescriptor->MaximumPhysicalPages - 1);
  2276. maxBytes2 = fdoExtension->AdapterDescriptor->MaximumTransferLength;
  2277. maxSize = (maxBytes1 > maxBytes2) ? maxBytes2 : maxBytes1;
  2278. if (tapeGetDriveParams->MaximumBlockSize > maxSize) {
  2279. tapeGetDriveParams->MaximumBlockSize = maxSize;
  2280. DebugPrint((1,
  2281. "ScsiTapeDeviceControl: Resetting max. tape block size to %x\n",
  2282. tapeGetDriveParams->MaximumBlockSize));
  2283. }
  2284. //
  2285. // Ensure that the default block size is less than or equal
  2286. // to maximum block size.
  2287. //
  2288. if ((tapeGetDriveParams->DefaultBlockSize) >
  2289. (tapeGetDriveParams->MaximumBlockSize)) {
  2290. tapeGetDriveParams->DefaultBlockSize =
  2291. tapeGetDriveParams->MaximumBlockSize;
  2292. }
  2293. oldMinBlockSize = tapeGetDriveParams->MinimumBlockSize;
  2294. oldMaxBlockSize = tapeGetDriveParams->MaximumBlockSize;
  2295. oldDefBlockSize = tapeGetDriveParams->DefaultBlockSize;
  2296. //
  2297. // Ensure the blocksize we return are power of 2
  2298. //
  2299. UPDATE_BLOCK_SIZE(tapeGetDriveParams->DefaultBlockSize, FALSE);
  2300. UPDATE_BLOCK_SIZE(tapeGetDriveParams->MaximumBlockSize, FALSE);
  2301. UPDATE_BLOCK_SIZE(tapeGetDriveParams->MinimumBlockSize, TRUE);
  2302. if (tapeGetDriveParams->MinimumBlockSize >
  2303. tapeGetDriveParams->MaximumBlockSize ) {
  2304. //
  2305. // After converting the blocksizes to power of 2
  2306. // Min blocksize is bigger than max blocksize.
  2307. // Revert everything to the value returned by the device
  2308. //
  2309. tapeGetDriveParams->MinimumBlockSize = oldMinBlockSize;
  2310. tapeGetDriveParams->MaximumBlockSize = oldMaxBlockSize;
  2311. tapeGetDriveParams->DefaultBlockSize = oldDefBlockSize;
  2312. }
  2313. break;
  2314. }
  2315. case IOCTL_STORAGE_PREDICT_FAILURE: {
  2316. PSTORAGE_PREDICT_FAILURE checkFailure;
  2317. WMI_TAPE_PROBLEM_WARNING TapeProblemWarning;
  2318. GUID TapeProblemWarningGuid = WMI_TAPE_PROBLEM_WARNING_GUID;
  2319. checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer;
  2320. //
  2321. // We don't want classpnp to notify WMI if the drive is having
  2322. // problems or not. We'll handle that here. So, set
  2323. // PredictFailure to 0. Then, classpnp will not process
  2324. // it further.
  2325. //
  2326. checkFailure->PredictFailure = 0;
  2327. //
  2328. // If the drive is reporting problem, we'll notify WMI
  2329. //
  2330. if (TapeDriveProblem->DriveProblemType !=
  2331. TapeDriveProblemNone) {
  2332. DebugPrint((1,
  2333. "IOCTL_STORAGE_PREDICT_FAILURE : Tape drive %p",
  2334. " is experiencing problem %d\n",
  2335. DeviceObject,
  2336. TapeDriveProblem->DriveProblemType));
  2337. ClassWmiFireEvent(DeviceObject,
  2338. &TapeProblemWarningGuid,
  2339. 0,
  2340. sizeof(WMI_TAPE_PROBLEM_WARNING),
  2341. (PUCHAR)TapeDriveProblem);
  2342. //
  2343. // ISSUE 02/28/2000 - nramas : We should decide whether
  2344. // or not we need to log an event in addition to
  2345. // firing a WMI event.
  2346. //
  2347. }
  2348. Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE);
  2349. //
  2350. // Free the buffer allocated for tape problem
  2351. // warning data
  2352. //
  2353. ExFreePool(TapeDriveProblem);
  2354. break;
  2355. }
  2356. case IOCTL_TAPE_ERASE: {
  2357. //
  2358. // Notify that the media has been successfully erased
  2359. //
  2360. TARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure[2];
  2361. NotificationStructure[0].Event = GUID_IO_TAPE_ERASE;
  2362. NotificationStructure[0].Version = 1;
  2363. NotificationStructure[0].Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) +
  2364. sizeof(ULONG) - sizeof(UCHAR);
  2365. NotificationStructure[0].FileObject = NULL;
  2366. NotificationStructure[0].NameBufferOffset = -1;
  2367. //
  2368. // Increasing Index for this event
  2369. //
  2370. *((PULONG) (&(NotificationStructure[0].CustomDataBuffer[0]))) = 0;
  2371. IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
  2372. &NotificationStructure[0],
  2373. NULL,
  2374. NULL);
  2375. break;
  2376. }
  2377. }
  2378. } else {
  2379. Irp->IoStatus.Information = 0;
  2380. if (TapeDriveProblem) {
  2381. ExFreePool(TapeDriveProblem);
  2382. }
  2383. }
  2384. Irp->IoStatus.Status = status;
  2385. ClassReleaseRemoveLock(DeviceObject, Irp);
  2386. ClassCompleteRequest(DeviceObject,Irp, 2);
  2387. return status;
  2388. } // end ScsiScsiTapeDeviceControl()
  2389. BOOLEAN
  2390. TapeClassAllocateSrbBuffer(
  2391. IN OUT PSCSI_REQUEST_BLOCK Srb,
  2392. IN ULONG SrbBufferSize
  2393. )
  2394. /*++
  2395. Routine Description:
  2396. This routine allocates a 'DataBuffer' for the given SRB of the given
  2397. size.
  2398. Arguments:
  2399. Srb - Supplies the SCSI request block.
  2400. SrbBufferSize - Supplies the desired 'DataBuffer' size.
  2401. Return Value:
  2402. FALSE - The allocation failed.
  2403. TRUE - The allocation succeeded.
  2404. --*/
  2405. {
  2406. PVOID p;
  2407. PAGED_CODE();
  2408. if (Srb->DataBuffer) {
  2409. ExFreePool(Srb->DataBuffer);
  2410. }
  2411. p = ExAllocatePool(NonPagedPoolCacheAligned, SrbBufferSize);
  2412. if (!p) {
  2413. Srb->DataBuffer = NULL;
  2414. Srb->DataTransferLength = 0;
  2415. return FALSE;
  2416. }
  2417. Srb->DataBuffer = p;
  2418. Srb->DataTransferLength = SrbBufferSize;
  2419. RtlZeroMemory(p, SrbBufferSize);
  2420. return TRUE;
  2421. }
  2422. VOID
  2423. TapeClassZeroMemory(
  2424. IN OUT PVOID Buffer,
  2425. IN ULONG BufferSize
  2426. )
  2427. /*++
  2428. Routine Description:
  2429. This routine zeroes the given memory.
  2430. Arguments:
  2431. Buffer - Supplies the buffer.
  2432. BufferSize - Supplies the buffer size.
  2433. Return Value:
  2434. None.
  2435. --*/
  2436. {
  2437. PAGED_CODE();
  2438. RtlZeroMemory(Buffer, BufferSize);
  2439. }
  2440. ULONG
  2441. TapeClassCompareMemory(
  2442. IN OUT PVOID Source1,
  2443. IN OUT PVOID Source2,
  2444. IN ULONG Length
  2445. )
  2446. /*++
  2447. Routine Description:
  2448. This routine compares the two memory buffers and returns the number
  2449. of bytes that are equivalent.
  2450. Arguments:
  2451. Source1 - Supplies the first memory buffer.
  2452. Source2 - Supplies the second memory buffer.
  2453. Length - Supplies the number of bytes to be compared.
  2454. Return Value:
  2455. The number of bytes that compared as equal.
  2456. --*/
  2457. {
  2458. PAGED_CODE();
  2459. return (ULONG)RtlCompareMemory(Source1, Source2, Length);
  2460. }
  2461. LARGE_INTEGER
  2462. TapeClassLiDiv(
  2463. IN LARGE_INTEGER Dividend,
  2464. IN LARGE_INTEGER Divisor
  2465. )
  2466. {
  2467. LARGE_INTEGER li;
  2468. PAGED_CODE();
  2469. li.QuadPart = Dividend.QuadPart / Divisor.QuadPart;
  2470. return li;
  2471. }
  2472. ULONG
  2473. GetTimeoutDeltaFromRegistry(
  2474. IN PDEVICE_OBJECT LowerPdo
  2475. )
  2476. {
  2477. ULONG srbTimeoutDelta = 0;
  2478. HANDLE deviceKey;
  2479. NTSTATUS status;
  2480. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  2481. OBJECT_ATTRIBUTES objectAttributes;
  2482. PAGED_CODE();
  2483. #define SRB_TIMEOUT_DELTA (L"SrbTimeoutDelta")
  2484. ASSERT(LowerPdo != NULL);
  2485. //
  2486. // Open a handle to the device node
  2487. //
  2488. status = IoOpenDeviceRegistryKey(LowerPdo,
  2489. PLUGPLAY_REGKEY_DEVICE,
  2490. KEY_QUERY_VALUE,
  2491. &deviceKey);
  2492. if (!NT_SUCCESS(status)) {
  2493. DebugPrint((1,
  2494. "IoOpenDeviceRegistryKey Failed in GetTimeoutDeltaFromRegistry : %x\n",
  2495. status));
  2496. return 0;
  2497. }
  2498. RtlZeroMemory(&queryTable[0], sizeof(queryTable));
  2499. queryTable[0].Name = SRB_TIMEOUT_DELTA;
  2500. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  2501. queryTable[0].EntryContext = &srbTimeoutDelta;
  2502. queryTable[0].DefaultType = REG_DWORD;
  2503. queryTable[0].DefaultData = NULL;
  2504. queryTable[0].DefaultLength = 0;
  2505. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  2506. (PWSTR)deviceKey,
  2507. queryTable,
  2508. NULL,
  2509. NULL);
  2510. if (!NT_SUCCESS(status)) {
  2511. DebugPrint((1,
  2512. "RtlQueryRegistryValue failed for SrbTimeoutDelta : %x\n",
  2513. status));
  2514. srbTimeoutDelta = 0;
  2515. }
  2516. ZwClose(deviceKey);
  2517. DebugPrint((3, "SrbTimeoutDelta read from registry %x\n",
  2518. srbTimeoutDelta));
  2519. return srbTimeoutDelta;
  2520. }
  2521. #if DBG
  2522. #define TAPE_DEBUG_PRINT_BUFF_LEN 127
  2523. ULONG TapeClassDebug = 0;
  2524. UCHAR TapeClassBuffer[TAPE_DEBUG_PRINT_BUFF_LEN + 1];
  2525. VOID
  2526. TapeDebugPrint(
  2527. ULONG DebugPrintLevel,
  2528. PCCHAR DebugMessage,
  2529. ...
  2530. )
  2531. /*++
  2532. Routine Description:
  2533. Debug print for all Tape minidrivers
  2534. Arguments:
  2535. Debug print level between 0 and 3, with 3 being the most verbose.
  2536. Return Value:
  2537. None
  2538. --*/
  2539. {
  2540. va_list ap;
  2541. va_start(ap, DebugMessage);
  2542. if ((DebugPrintLevel <= (TapeClassDebug & 0x0000ffff)) ||
  2543. ((1 << (DebugPrintLevel + 15)) & TapeClassDebug)) {
  2544. _vsnprintf(TapeClassBuffer, TAPE_DEBUG_PRINT_BUFF_LEN,
  2545. DebugMessage, ap);
  2546. TapeClassBuffer[TAPE_DEBUG_PRINT_BUFF_LEN] = '\0';
  2547. DbgPrintEx(DPFLTR_TAPE_ID, DPFLTR_INFO_LEVEL, TapeClassBuffer);
  2548. }
  2549. va_end(ap);
  2550. } // end TapeDebugPrint()
  2551. #else
  2552. //
  2553. // TapeDebugPrint stub
  2554. //
  2555. VOID
  2556. TapeDebugPrint(
  2557. ULONG DebugPrintLevel,
  2558. PCCHAR DebugMessage,
  2559. ...
  2560. )
  2561. {
  2562. }
  2563. #endif