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

868 lines
25 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1999
  3. Module Name:
  4. tapewmi.c
  5. Abstract:
  6. This is the tape class driver - WMI support routines.
  7. Environment:
  8. kernel mode only
  9. Revision History:
  10. --*/
  11. #include "tape.h"
  12. //
  13. // List guids supported by Tape driver
  14. //
  15. GUIDREGINFO TapeWmiGuidList[] =
  16. {
  17. {
  18. WMI_TAPE_DRIVE_PARAMETERS_GUID,
  19. 1,
  20. 0
  21. },
  22. {
  23. WMI_TAPE_MEDIA_PARAMETERS_GUID,
  24. 1,
  25. 0
  26. },
  27. {
  28. WMI_TAPE_PROBLEM_WARNING_GUID,
  29. 1,
  30. WMIREG_FLAG_EVENT_ONLY_GUID
  31. },
  32. {
  33. WMI_TAPE_PROBLEM_IO_ERROR_GUID,
  34. 1,
  35. WMIREG_FLAG_EXPENSIVE
  36. },
  37. {
  38. WMI_TAPE_PROBLEM_DEVICE_ERROR_GUID,
  39. 1,
  40. WMIREG_FLAG_EXPENSIVE
  41. },
  42. {
  43. WMI_TAPE_SYMBOLIC_NAME_GUID,
  44. 1,
  45. 0
  46. }
  47. };
  48. GUID TapeDriveProblemEventGuid = WMI_TAPE_PROBLEM_WARNING_GUID;
  49. //
  50. // GUID index. It should match the guid list
  51. // defined above
  52. //
  53. #define TapeDriveParametersGuid 0
  54. #define TapeMediaCapacityGuid 1
  55. #define TapeDriveProblemWarningGuid 2
  56. #define TapeDriveProblemIoErrorGuid 3
  57. #define TapeDriveProblemDevErrorGuid 4
  58. #define TapeSymbolicNameGuid 5
  59. #ifdef ALLOC_PRAGMA
  60. #pragma alloc_text(PAGE, TapeWMIControl)
  61. #pragma alloc_text(PAGE, TapeQueryWmiRegInfo)
  62. #pragma alloc_text(PAGE, TapeQueryWmiDataBlock)
  63. #pragma alloc_text(PAGE, TapeExecuteWmiMethod)
  64. #pragma alloc_text(PAGE, TapeWmiFunctionControl)
  65. #pragma alloc_text(PAGE, TapeSetWmiDataBlock)
  66. #pragma alloc_text(PAGE, TapeSetWmiDataItem)
  67. #pragma alloc_text(PAGE, TapeEnableDisableDrivePolling)
  68. #endif
  69. NTSTATUS
  70. TapeQueryWmiRegInfo(
  71. IN PDEVICE_OBJECT DeviceObject,
  72. OUT ULONG *RegFlags,
  73. OUT PUNICODE_STRING InstanceName
  74. )
  75. /*++
  76. Routine Description:
  77. This routine is a callback into the driver to retrieve the list of
  78. guids or data blocks that the driver wants to register with WMI. This
  79. routine may not pend or block. Driver should NOT call
  80. ClassWmiCompleteRequest.
  81. Arguments:
  82. DeviceObject is the device whose data block is being queried
  83. *RegFlags returns with a set of flags that describe the guids being
  84. registered for this device. If the device wants enable and disable
  85. collection callbacks before receiving queries for the registered
  86. guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
  87. returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
  88. the instance name is determined from the PDO associated with the
  89. device object. Note that the PDO must have an associated devnode. If
  90. WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
  91. name for the device.
  92. InstanceName returns with the instance name for the guids if
  93. WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
  94. caller will call ExFreePool with the buffer returned.
  95. Return Value:
  96. status
  97. --*/
  98. {
  99. PAGED_CODE();
  100. //
  101. // Use devnode for FDOs
  102. //
  103. *RegFlags = WMIREG_FLAG_INSTANCE_PDO;
  104. return STATUS_SUCCESS;
  105. }
  106. NTSTATUS
  107. TapeQueryWmiDataBlock(
  108. IN PDEVICE_OBJECT DeviceObject,
  109. IN PIRP Irp,
  110. IN ULONG GuidIndex,
  111. IN ULONG BufferAvail,
  112. OUT PUCHAR Buffer
  113. )
  114. /*++
  115. Routine Description:
  116. This routine is a callback into the driver to query for the contents of
  117. a data block. When the driver has finished filling the data block it
  118. must call ClassWmiCompleteRequest to complete the irp. The driver can
  119. return STATUS_PENDING if the irp cannot be completed immediately.
  120. Arguments:
  121. DeviceObject is the device whose data block is being queried
  122. Irp is the Irp that makes this request
  123. GuidIndex is the index into the list of guids provided when the
  124. device registered
  125. BufferAvail on has the maximum size available to write the data
  126. block.
  127. Buffer on return is filled with the returned data block
  128. Return Value:
  129. status
  130. --*/
  131. {
  132. NTSTATUS status = STATUS_SUCCESS;
  133. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  134. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  135. PTAPE_INIT_DATA_EX tapeInitData;
  136. PVPB Vpb;
  137. ULONG sizeNeeded;
  138. ULONG wmiMethod;
  139. TAPE_WMI_OPERATIONS wmiWorkItem;
  140. TAPE_PROCESS_COMMAND_ROUTINE commandRoutine;
  141. PAGED_CODE();
  142. DebugPrint((3,
  143. "TapeQueryWmiDataBlock : Device %p, Irp %p, GuidIndex %d",
  144. " BufferAvail %lx Buffer %lx\n",
  145. DeviceObject, Irp, GuidIndex, BufferAvail, Buffer));
  146. Vpb = ClassGetVpb(DeviceObject);
  147. if ((Vpb) && ((Vpb->Flags) & VPB_MOUNTED)) {
  148. //
  149. // Tape drive is in use. Return busy status
  150. //
  151. status = ClassWmiCompleteRequest(DeviceObject,
  152. Irp,
  153. STATUS_DEVICE_BUSY,
  154. 0,
  155. IO_NO_INCREMENT);
  156. return status;
  157. }
  158. tapeInitData = (PTAPE_INIT_DATA_EX) (fdoExtension->CommonExtension.DriverData);
  159. switch (GuidIndex) {
  160. case TapeDriveParametersGuid: {
  161. TAPE_GET_DRIVE_PARAMETERS dataBuffer;
  162. PWMI_TAPE_DRIVE_PARAMETERS outBuffer;
  163. sizeNeeded = sizeof(WMI_TAPE_DRIVE_PARAMETERS);
  164. if (BufferAvail < sizeNeeded) {
  165. status = STATUS_BUFFER_TOO_SMALL;
  166. break;
  167. }
  168. RtlZeroMemory(&dataBuffer, sizeof(TAPE_GET_DRIVE_PARAMETERS));
  169. commandRoutine = tapeInitData->GetDriveParameters;
  170. status = TapeWMIControl(DeviceObject, commandRoutine,
  171. (PUCHAR)&dataBuffer);
  172. if (NT_SUCCESS(status)) {
  173. outBuffer = (PWMI_TAPE_DRIVE_PARAMETERS)Buffer;
  174. outBuffer->MaximumBlockSize = dataBuffer.MaximumBlockSize;
  175. outBuffer->MinimumBlockSize = dataBuffer.MinimumBlockSize;
  176. outBuffer->DefaultBlockSize = dataBuffer.DefaultBlockSize;
  177. outBuffer->MaximumPartitionCount = dataBuffer.MaximumPartitionCount;
  178. if ((dataBuffer.FeaturesLow) & TAPE_DRIVE_COMPRESSION) {
  179. outBuffer->CompressionCapable = TRUE;
  180. } else {
  181. outBuffer->CompressionCapable = FALSE;
  182. }
  183. outBuffer->CompressionEnabled = dataBuffer.Compression;
  184. outBuffer->HardwareErrorCorrection = dataBuffer.ECC;
  185. outBuffer->ReportSetmarks = dataBuffer.ReportSetmarks;
  186. }
  187. break;
  188. }
  189. case TapeMediaCapacityGuid: {
  190. TAPE_GET_MEDIA_PARAMETERS dataBuffer;
  191. PWMI_TAPE_MEDIA_PARAMETERS outBuffer;
  192. sizeNeeded = sizeof(WMI_TAPE_MEDIA_PARAMETERS);
  193. if (BufferAvail < sizeNeeded) {
  194. status = STATUS_BUFFER_TOO_SMALL;
  195. break;
  196. }
  197. RtlZeroMemory(&dataBuffer, sizeof(TAPE_GET_MEDIA_PARAMETERS));
  198. commandRoutine = tapeInitData->GetMediaParameters;
  199. status = TapeWMIControl(DeviceObject, commandRoutine,
  200. (PUCHAR)&dataBuffer);
  201. if (NT_SUCCESS(status)) {
  202. outBuffer = (PWMI_TAPE_MEDIA_PARAMETERS)Buffer;
  203. outBuffer->AvailableCapacity = dataBuffer.Remaining.QuadPart;
  204. outBuffer->MaximumCapacity = dataBuffer.Capacity.QuadPart;
  205. outBuffer->BlockSize = dataBuffer.BlockSize;
  206. outBuffer->PartitionCount = dataBuffer.PartitionCount;
  207. outBuffer->MediaWriteProtected = dataBuffer.WriteProtected;
  208. }
  209. break;
  210. }
  211. case TapeSymbolicNameGuid: {
  212. //
  213. // We need buffer large enough to put the string TapeN
  214. // where N is an integer. We'll take 32 wide chars
  215. //
  216. sizeNeeded = sizeof(WCHAR) * 32;
  217. if (BufferAvail < sizeNeeded) {
  218. status = STATUS_BUFFER_TOO_SMALL;
  219. break;
  220. }
  221. RtlZeroMemory(Buffer, sizeof(WCHAR) * 32);
  222. swprintf((PWCHAR)(Buffer + sizeof(USHORT)), L"Tape%d",
  223. fdoExtension->DeviceNumber);
  224. *((PUSHORT)Buffer) = wcslen((PWCHAR)(Buffer + sizeof(USHORT))) * sizeof(WCHAR);
  225. status = STATUS_SUCCESS;
  226. break;
  227. }
  228. case TapeDriveProblemIoErrorGuid: {
  229. sizeNeeded = sizeof(WMI_TAPE_PROBLEM_WARNING);
  230. if (BufferAvail < sizeNeeded) {
  231. status = STATUS_BUFFER_TOO_SMALL;
  232. break;
  233. }
  234. commandRoutine = tapeInitData->TapeWMIOperations;
  235. wmiWorkItem.Method = TAPE_QUERY_IO_ERROR_DATA;
  236. wmiWorkItem.DataBufferSize = BufferAvail;
  237. wmiWorkItem.DataBuffer = Buffer;
  238. status = TapeWMIControl(DeviceObject, commandRoutine,
  239. (PUCHAR)&wmiWorkItem);
  240. break;
  241. }
  242. case TapeDriveProblemDevErrorGuid: {
  243. sizeNeeded = sizeof(WMI_TAPE_PROBLEM_WARNING);
  244. if (BufferAvail < sizeNeeded) {
  245. status = STATUS_BUFFER_TOO_SMALL;
  246. break;
  247. }
  248. commandRoutine = tapeInitData->TapeWMIOperations;
  249. wmiWorkItem.Method = TAPE_QUERY_DEVICE_ERROR_DATA;
  250. wmiWorkItem.DataBufferSize = BufferAvail;
  251. wmiWorkItem.DataBuffer = Buffer;
  252. status = TapeWMIControl(DeviceObject, commandRoutine,
  253. (PUCHAR)&wmiWorkItem);
  254. break;
  255. }
  256. default:{
  257. sizeNeeded = 0;
  258. status = STATUS_WMI_GUID_NOT_FOUND;
  259. break;
  260. }
  261. } // switch (GuidIndex)
  262. DebugPrint((3, "TapeQueryWmiData : Device %p, Irp %p, ",
  263. "GuidIndex %d, status %x\n",
  264. DeviceObject, Irp, GuidIndex, status));
  265. status = ClassWmiCompleteRequest(DeviceObject,
  266. Irp,
  267. status,
  268. sizeNeeded,
  269. IO_NO_INCREMENT);
  270. return status;
  271. }
  272. NTSTATUS
  273. TapeExecuteWmiMethod(
  274. IN PDEVICE_OBJECT DeviceObject,
  275. IN PIRP Irp,
  276. IN ULONG GuidIndex,
  277. IN ULONG MethodId,
  278. IN ULONG InBufferSize,
  279. IN ULONG OutBufferSize,
  280. IN PUCHAR Buffer
  281. )
  282. /*++
  283. Routine Description:
  284. This routine is a callback into the driver to execute a method. When the
  285. driver has finished filling the data block it must call
  286. ClassWmiCompleteRequest to complete the irp. The driver can
  287. return STATUS_PENDING if the irp cannot be completed immediately.
  288. Arguments:
  289. DeviceObject is the device whose data block is being queried
  290. Irp is the Irp that makes this request
  291. GuidIndex is the index into the list of guids provided when the
  292. device registered
  293. MethodId has the id of the method being called
  294. InBufferSize has the size of the data block passed in as the input to
  295. the method.
  296. OutBufferSize on entry has the maximum size available to write the
  297. returned data block.
  298. Buffer is filled with the returned data block
  299. Return Value:
  300. status
  301. --*/
  302. {
  303. NTSTATUS status = STATUS_SUCCESS;
  304. PAGED_CODE();
  305. status = ClassWmiCompleteRequest(DeviceObject,
  306. Irp,
  307. status,
  308. 0,
  309. IO_NO_INCREMENT);
  310. return status;
  311. }
  312. NTSTATUS
  313. TapeWmiFunctionControl(
  314. IN PDEVICE_OBJECT DeviceObject,
  315. IN PIRP Irp,
  316. IN ULONG GuidIndex,
  317. IN CLASSENABLEDISABLEFUNCTION Function,
  318. IN BOOLEAN Enable
  319. )
  320. /*++
  321. Routine Description:
  322. This routine is a callback into the driver to enabled or disable event
  323. generation or data block collection. A device should only expect a
  324. single enable when the first event or data consumer enables events or
  325. data collection and a single disable when the last event or data
  326. consumer disables events or data collection. Data blocks will only
  327. receive collection enable/disable if they were registered as requiring
  328. it.
  329. This function can be used to enable\disable event generation. The event
  330. mentioned here is Tape Drive Problem Warning event. This event is disabled
  331. by default. If any application is interested in being notified of drive
  332. problems, it can enable this event generation.
  333. Arguments:
  334. DeviceObject is the device whose data block is being queried
  335. GuidIndex is the index into the list of guids provided when the
  336. device registered
  337. Function specifies which functionality is being enabled or disabled
  338. Enable is TRUE then the function is being enabled else disabled
  339. Return Value:
  340. status
  341. --*/
  342. {
  343. NTSTATUS status = STATUS_SUCCESS;
  344. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  345. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  346. PAGED_CODE();
  347. //
  348. // We handle only enable\disable tape drive problem warning events,
  349. // query data blocks.
  350. //
  351. if ((Function == EventGeneration) &&
  352. (GuidIndex == TapeDriveProblemWarningGuid)) {
  353. DebugPrint((3,
  354. "TapeWmiFunctionControl : DeviceObject %p, Irp %p, ",
  355. "GuidIndex %d. Event Generation %s\n",
  356. DeviceObject, Irp, GuidIndex,
  357. Enable ? "Enabled" : "Disabled"));
  358. status = TapeEnableDisableDrivePolling(fdoExtension,
  359. Enable,
  360. TAPE_DRIVE_POLLING_PERIOD);
  361. } else if (Function == DataBlockCollection) {
  362. DebugPrint((3,
  363. "TapeWmiFunctionControl : Irp %p - %s DataBlockCollection",
  364. " for Device %p.\n",
  365. Irp, Enable ? "Enable " : "Disable ", DeviceObject));
  366. status = STATUS_SUCCESS;
  367. } else {
  368. DebugPrint((3,
  369. "TapeWmiFunctionControl : Unknown function %d for ",
  370. "Device %p, Irp %p\n",
  371. Function, DeviceObject, Irp));
  372. status = STATUS_INVALID_DEVICE_REQUEST;
  373. }
  374. status = ClassWmiCompleteRequest(DeviceObject,
  375. Irp,
  376. status,
  377. 0,
  378. IO_NO_INCREMENT);
  379. return status;
  380. }
  381. NTSTATUS
  382. TapeSetWmiDataBlock(
  383. IN PDEVICE_OBJECT DeviceObject,
  384. IN PIRP Irp,
  385. IN ULONG GuidIndex,
  386. IN ULONG BufferSize,
  387. IN PUCHAR Buffer
  388. )
  389. /*+
  390. Routine Description :
  391. This routine is called to set the contents of a datablock.
  392. When the driver is finished setting the buffer, it must call
  393. ClassWmiCompleteRequest to complete the irp. The driver can
  394. return STATUS_PENDING if the irp cannot be completed immediately.
  395. Arguments :
  396. Device object of the device being referred.
  397. Irp is the WMI Irp
  398. GuidIndex is the index of the guid for which the data is being set
  399. BufferSize is the size of the data block
  400. Buffer is the pointer to the data block
  401. Return valus :
  402. NTSTATUS returned by ClassWmiCompleteRequest
  403. STATUS_WMI_READ_ONLY if the datablock cannot be modified.
  404. STATUS_WMI_GUID_NOT_FOUND if an invalid guid index is passed
  405. -*/
  406. {
  407. NTSTATUS status = STATUS_WMI_READ_ONLY;
  408. PAGED_CODE();
  409. DebugPrint((3,
  410. "TapeWmiSetBlock : Device %p, Irp %p, GuidIndex %d\n",
  411. DeviceObject, Irp, GuidIndex));
  412. if (GuidIndex > TapeDriveProblemDevErrorGuid) {
  413. status = STATUS_WMI_GUID_NOT_FOUND;
  414. }
  415. status = ClassWmiCompleteRequest(DeviceObject,
  416. Irp,
  417. status,
  418. 0,
  419. IO_NO_INCREMENT);
  420. DebugPrint((3, "TapeSetWmiDataBlock : Device %p, Irp %p returns %lx\n",
  421. DeviceObject, Irp, status));
  422. return status;
  423. }
  424. NTSTATUS
  425. TapeSetWmiDataItem(
  426. IN PDEVICE_OBJECT DeviceObject,
  427. IN PIRP Irp,
  428. IN ULONG GuidIndex,
  429. IN ULONG DataItemId,
  430. IN ULONG BufferSize,
  431. IN PUCHAR Buffer
  432. )
  433. /*++
  434. Routine Description:
  435. This routine is a callback into the driver to query for the contents of
  436. a data block. When the driver has finished filling the data block it
  437. must call ClassWmiCompleteRequest to complete the irp. The driver can
  438. return STATUS_PENDING if the irp cannot be completed immediately.
  439. Arguments:
  440. DeviceObject is the device whose data block is being queried
  441. Irp is the Irp that makes this request
  442. GuidIndex is the index into the list of guids provided when the
  443. device registered
  444. DataItemId has the id of the data item being set
  445. BufferSize has the size of the data item passed
  446. Buffer has the new values for the data item
  447. Return Value:
  448. NTSTATUS returned by ClassWmiCompleteRequest
  449. STATUS_WMI_READ_ONLY if the datablock cannot be modified.
  450. STATUS_WMI_GUID_NOT_FOUND if an invalid guid index is passed
  451. -*/
  452. {
  453. NTSTATUS status = STATUS_WMI_READ_ONLY;
  454. PAGED_CODE();
  455. DebugPrint((3,
  456. "TapeSetWmiDataItem, Device %p, Irp %p, GuiIndex %d",
  457. " BufferSize %#x Buffer %p\n",
  458. DeviceObject, Irp,
  459. GuidIndex, DataItemId,
  460. BufferSize, Buffer));
  461. if (GuidIndex > TapeDriveProblemDevErrorGuid) {
  462. status = STATUS_WMI_GUID_NOT_FOUND;
  463. }
  464. status = ClassWmiCompleteRequest(DeviceObject,
  465. Irp,
  466. status,
  467. 0,
  468. IO_NO_INCREMENT);
  469. DebugPrint((3, "TapeSetWmiDataItem Device %p, Irp %p returns %lx\n",
  470. DeviceObject, Irp, status));
  471. return status;
  472. }
  473. NTSTATUS
  474. TapeEnableDisableDrivePolling(
  475. IN PFUNCTIONAL_DEVICE_EXTENSION fdoExtension,
  476. IN BOOLEAN Enable,
  477. IN ULONG PollingTimeInSeconds
  478. )
  479. /*++
  480. Routine Description:
  481. Enable or disable polling to check for drive problems.
  482. Arguments:
  483. FdoExtension Device extension
  484. Enable TRUE if polling is to be enabled. FALSE otherwise.
  485. PollTimeInSeconds - if 0 then no change to current polling timer
  486. Return Value:
  487. NT Status
  488. --*/
  489. {
  490. NTSTATUS status;
  491. FAILURE_PREDICTION_METHOD failurePredictionMethod;
  492. PAGED_CODE();
  493. //
  494. // Failure prediction is done through IOCTL_STORAGE_PREDICT_FAILURE
  495. //
  496. if (Enable) {
  497. failurePredictionMethod = FailurePredictionIoctl;
  498. } else {
  499. failurePredictionMethod = FailurePredictionNone;
  500. }
  501. status = ClassSetFailurePredictionPoll(fdoExtension,
  502. failurePredictionMethod,
  503. PollingTimeInSeconds);
  504. return status;
  505. }
  506. NTSTATUS
  507. TapeWMIControl(
  508. IN PDEVICE_OBJECT DeviceObject,
  509. IN TAPE_PROCESS_COMMAND_ROUTINE commandRoutine,
  510. OUT PUCHAR Buffer
  511. )
  512. /*++
  513. Routine Description:
  514. This is the class routine to handle WMI requests. It handles all query
  515. requests.
  516. Arguments:
  517. DeviceObject The device object
  518. commandRoutine minidriver routine to call.
  519. Buffer Pointer to the buffer
  520. Return Value:
  521. NT Status
  522. --*/
  523. {
  524. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  525. PTAPE_DATA tapeData= (PTAPE_DATA) (fdoExtension->CommonExtension.DriverData);
  526. PTAPE_INIT_DATA_EX tapeInitData = &tapeData->TapeInitData;
  527. PVOID minitapeExtension = tapeData + 1;
  528. NTSTATUS status = STATUS_SUCCESS;
  529. TAPE_STATUS lastError;
  530. TAPE_STATUS tapeStatus;
  531. ULONG callNumber;
  532. PVOID commandExtension;
  533. ULONG retryFlags;
  534. ULONG numRetries;
  535. SCSI_REQUEST_BLOCK srb;
  536. BOOLEAN writeToDevice;
  537. PAGED_CODE();
  538. //
  539. // Verify if the minidriver supports WMI operations
  540. //
  541. if (commandRoutine == NULL) {
  542. DebugPrint((1,
  543. "TapeWMIControl : DeviceObject %d does not support WMI\n"));
  544. return STATUS_WMI_NOT_SUPPORTED;
  545. }
  546. if (tapeInitData->CommandExtensionSize) {
  547. commandExtension = ExAllocatePool(NonPagedPool,
  548. tapeInitData->CommandExtensionSize);
  549. } else {
  550. commandExtension = NULL;
  551. }
  552. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  553. lastError = TAPE_STATUS_SUCCESS ;
  554. for (callNumber = 0; ;callNumber++) {
  555. srb.TimeOutValue = fdoExtension->TimeOutValue;
  556. srb.SrbFlags = 0;
  557. retryFlags = 0;
  558. tapeStatus = commandRoutine(minitapeExtension,
  559. commandExtension,
  560. Buffer,
  561. &srb,
  562. callNumber,
  563. lastError,
  564. &retryFlags);
  565. lastError = TAPE_STATUS_SUCCESS ;
  566. numRetries = retryFlags & TAPE_RETRY_MASK;
  567. if (tapeStatus == TAPE_STATUS_CHECK_TEST_UNIT_READY) {
  568. PCDB cdb = (PCDB)srb.Cdb;
  569. //
  570. // Prepare SCSI command (CDB)
  571. //
  572. TapeClassZeroMemory(srb.Cdb, MAXIMUM_CDB_SIZE);
  573. srb.CdbLength = CDB6GENERIC_LENGTH;
  574. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  575. srb.DataTransferLength = 0 ;
  576. DebugPrint((3,"Test Unit Ready\n"));
  577. } else if (tapeStatus == TAPE_STATUS_CALLBACK) {
  578. lastError = TAPE_STATUS_CALLBACK ;
  579. continue;
  580. } else if (tapeStatus != TAPE_STATUS_SEND_SRB_AND_CALLBACK) {
  581. break;
  582. }
  583. if (srb.DataBuffer && !srb.DataTransferLength) {
  584. ScsiTapeFreeSrbBuffer(&srb);
  585. }
  586. if (srb.DataBuffer && (srb.SrbFlags & SRB_FLAGS_DATA_OUT)) {
  587. writeToDevice = TRUE;
  588. } else {
  589. writeToDevice = FALSE;
  590. }
  591. for (;;) {
  592. status = ClassSendSrbSynchronous(DeviceObject,
  593. &srb,
  594. srb.DataBuffer,
  595. srb.DataTransferLength,
  596. writeToDevice);
  597. if (NT_SUCCESS(status) ||
  598. (status == STATUS_DATA_OVERRUN)) {
  599. if (status == STATUS_DATA_OVERRUN) {
  600. ULONG allocLen;
  601. PCDB Cdb;
  602. //
  603. // ISSUE: 03/31/2000: nramas
  604. // We use either LOG SENSE or REQUEST SENSE CDB
  605. // in minidrivers. For LogSense, AllocationLength
  606. // is 2 bytes. It is 10 byte CDB.
  607. //
  608. // Currently, if DataOverrun occurs on request sense,
  609. // we don't handle that.
  610. //
  611. if ((srb.CdbLength) == CDB10GENERIC_LENGTH) {
  612. Cdb = (PCDB)(srb.Cdb);
  613. allocLen = Cdb->LOGSENSE.AllocationLength[0];
  614. allocLen <<= 8;
  615. allocLen |= Cdb->LOGSENSE.AllocationLength[1];
  616. DebugPrint((3, "DataXferLen %x, AllocLen %x\n",
  617. srb.DataTransferLength,
  618. allocLen));
  619. if ((srb.DataTransferLength) <= allocLen) {
  620. status = STATUS_SUCCESS;
  621. break;
  622. } else {
  623. DebugPrint((1,
  624. "DataOverrun in TapeWMI routine. Srb %p\n",
  625. &srb));
  626. }
  627. }
  628. } else {
  629. break;
  630. }
  631. }
  632. if (numRetries == 0) {
  633. if (retryFlags & RETURN_ERRORS) {
  634. ScsiTapeNtStatusToTapeStatus(status, &lastError) ;
  635. break ;
  636. }
  637. if (retryFlags & IGNORE_ERRORS) {
  638. break;
  639. }
  640. if (commandExtension) {
  641. ExFreePool(commandExtension);
  642. }
  643. ScsiTapeFreeSrbBuffer(&srb);
  644. return status;
  645. }
  646. numRetries--;
  647. }
  648. }
  649. ScsiTapeFreeSrbBuffer(&srb);
  650. if (commandExtension) {
  651. ExFreePool(commandExtension);
  652. }
  653. if (!ScsiTapeTapeStatusToNtStatus(tapeStatus, &status)) {
  654. status = STATUS_IO_DEVICE_ERROR;
  655. }
  656. return status;
  657. } // end TapeWMIControl