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.

944 lines
22 KiB

  1. #include <ntddk.h>
  2. #include "mplib.h"
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include <ntddscsi.h>
  6. #include <scsi.h>
  7. typedef struct _MPLIB_COMPLETION_CONTEXT {
  8. PDEVICE_OBJECT DeviceObject;
  9. KEVENT Event;
  10. NTSTATUS Status;
  11. PSCSI_REQUEST_BLOCK Srb;
  12. PSENSE_DATA SenseBuffer;
  13. } MPLIB_COMPLETION_CONTEXT, *PMPLIB_COMPLETION_CONTEXT;
  14. #define max(a,b) (((a) > (b)) ? (a) : (b))
  15. #define min(a,b) (((a) < (b)) ? (a) : (b))
  16. ULONG DontLoad = 0;
  17. NTSTATUS
  18. MPLIBSignalCompletion(
  19. IN PDEVICE_OBJECT DeviceObject,
  20. IN PIRP Irp,
  21. IN PKEVENT Event
  22. )
  23. /*++
  24. Routine Description:
  25. This completion routine will signal the event given as context and then
  26. return STATUS_MORE_PROCESSING_REQUIRED to stop event completion. It is
  27. the responsibility of the routine waiting on the event to complete the
  28. request and free the event.
  29. Arguments:
  30. DeviceObject - a pointer to the device object
  31. Irp - a pointer to the irp
  32. Event - a pointer to the event to signal
  33. Return Value:
  34. STATUS_MORE_PROCESSING_REQUIRED
  35. --*/
  36. {
  37. if (Irp->PendingReturned) {
  38. IoMarkIrpPending(Irp);
  39. }
  40. KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
  41. return STATUS_MORE_PROCESSING_REQUIRED;
  42. }
  43. NTSTATUS
  44. MPLIBSendIrpSynchronous(
  45. IN PDEVICE_OBJECT TargetDeviceObject,
  46. IN PIRP Irp
  47. )
  48. /*++
  49. Routine Description:
  50. This routine issues an irp synchronously.
  51. Arguments:
  52. TargetDeviceObject - Recepient of the request.
  53. Irp - Irp to send.
  54. Return Value:
  55. Status of the request
  56. --*/
  57. {
  58. KEVENT event;
  59. NTSTATUS status;
  60. //
  61. // Ensure enough stack locations are available.
  62. //
  63. ASSERT(Irp->StackCount >= TargetDeviceObject->StackSize);
  64. //
  65. // Initialize the event that will be set by the completion
  66. // routine.
  67. //
  68. KeInitializeEvent(&event,
  69. SynchronizationEvent,
  70. FALSE);
  71. //
  72. // Set the completion routine - the event is the context.
  73. //
  74. IoSetCompletionRoutine(Irp,
  75. MPLIBSignalCompletion,
  76. &event,
  77. TRUE,
  78. TRUE,
  79. TRUE);
  80. //
  81. // Submit the request.
  82. //
  83. status = IoCallDriver(TargetDeviceObject, Irp);
  84. if (status == STATUS_PENDING) {
  85. KeWaitForSingleObject(&event,
  86. Executive,
  87. KernelMode,
  88. FALSE,
  89. NULL);
  90. status = Irp->IoStatus.Status;
  91. }
  92. return status;
  93. }
  94. VOID
  95. MPLIBSendDeviceIoControlSynchronous(
  96. IN ULONG IoControlCode,
  97. IN PDEVICE_OBJECT TargetDeviceObject,
  98. IN PVOID InputBuffer OPTIONAL,
  99. IN OUT PVOID OutputBuffer OPTIONAL,
  100. IN ULONG InputBufferLength,
  101. IN ULONG OutputBufferLength,
  102. IN BOOLEAN InternalDeviceIoControl,
  103. OUT PIO_STATUS_BLOCK IoStatus
  104. )
  105. /*++
  106. Routine Description:
  107. This routine builds and sends the IOCTL specified by IoControlCode to
  108. TargetDeviceObject.
  109. Arguments:
  110. IoControlCode - IOCTL to send.
  111. TargetDeviceObject - Recepient of the request.
  112. Buffer - Input/output buffer.
  113. InputBufferLength - Size, in bytes of the inputbuffer.
  114. OutputBufferLength - Size, in bytes of the output buffer.
  115. InternalDeviceIocontrol - Specifies whethers it's internal or not.
  116. IoStatus - Pointer to caller's iostatus block.
  117. Return Value:
  118. Status of the request
  119. --*/
  120. {
  121. PIRP irp = NULL;
  122. PIO_STACK_LOCATION irpStack;
  123. ASSERT((IoControlCode & 3) == METHOD_BUFFERED);
  124. ASSERT(ARGUMENT_PRESENT(IoStatus));
  125. //
  126. // Ensure that if either buffer length is set, that there is actually
  127. // a buffer.
  128. //
  129. if (InputBufferLength) {
  130. if (InputBuffer == NULL) {
  131. (*IoStatus).Status = STATUS_BUFFER_TOO_SMALL;
  132. (*IoStatus).Information = 0;
  133. return;
  134. }
  135. }
  136. if (OutputBufferLength) {
  137. if (OutputBuffer == NULL) {
  138. (*IoStatus).Status = STATUS_BUFFER_TOO_SMALL;
  139. (*IoStatus).Information = 0;
  140. return;
  141. }
  142. }
  143. //
  144. // Allocate an irp.
  145. //
  146. irp = IoAllocateIrp(TargetDeviceObject->StackSize, FALSE);
  147. if (irp == NULL) {
  148. (*IoStatus).Information = 0;
  149. (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES;
  150. return;
  151. }
  152. //
  153. // Get the recipient's irpstack location.
  154. //
  155. irpStack = IoGetNextIrpStackLocation(irp);
  156. //
  157. // Set the major function code based on the type of device I/O control
  158. // function the caller has specified.
  159. //
  160. if (InternalDeviceIoControl) {
  161. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  162. } else {
  163. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  164. }
  165. //
  166. // Fill in the ioControl parameters.
  167. //
  168. irpStack->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
  169. irpStack->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
  170. irpStack->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
  171. //
  172. // Allocate the SystemBuffer, if needed.
  173. //
  174. if (InputBufferLength || OutputBufferLength) {
  175. irp->AssociatedIrp.SystemBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
  176. max(InputBufferLength, OutputBufferLength));
  177. if (irp->AssociatedIrp.SystemBuffer == NULL) {
  178. IoFreeIrp(irp);
  179. (*IoStatus).Information = 0;
  180. (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES;
  181. return;
  182. }
  183. //
  184. // If passing info to TargetDevice, copy the caller's data
  185. // into the system buffer.
  186. //
  187. if (InputBufferLength) {
  188. RtlCopyMemory(irp->AssociatedIrp.SystemBuffer,
  189. InputBuffer,
  190. InputBufferLength);
  191. }
  192. }
  193. irp->UserBuffer = OutputBuffer;
  194. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  195. //
  196. // send the irp synchronously
  197. //
  198. MPLIBSendIrpSynchronous(TargetDeviceObject, irp);
  199. //
  200. // copy the iostatus block for the caller
  201. //
  202. *IoStatus = irp->IoStatus;
  203. //
  204. // If there's an ouputbuffer, copy the results.
  205. //
  206. if (OutputBufferLength && (IoControlCode != IOCTL_SCSI_PASS_THROUGH_DIRECT)) {
  207. RtlCopyMemory(OutputBuffer,
  208. irp->AssociatedIrp.SystemBuffer,
  209. OutputBufferLength
  210. );
  211. }
  212. //
  213. // Free the allocations.
  214. //
  215. if (InputBufferLength || OutputBufferLength) {
  216. ExFreePool(irp->AssociatedIrp.SystemBuffer);
  217. irp->AssociatedIrp.SystemBuffer = NULL;
  218. }
  219. IoFreeIrp(irp);
  220. irp = (PIRP) NULL;
  221. return;
  222. }
  223. NTSTATUS
  224. MPLIBGetDescriptor(
  225. IN PDEVICE_OBJECT DeviceObject,
  226. IN PSTORAGE_PROPERTY_ID PropertyId,
  227. OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor
  228. )
  229. /*++
  230. Routine Description:
  231. This routine will perform a query for the specified property id and will
  232. allocate a non-paged buffer to store the data in. It is the responsibility
  233. of the caller to ensure that this buffer is freed.
  234. Arguments:
  235. DeviceObject - the device to query
  236. DeviceInfo - a location to store a pointer to the buffer we allocate
  237. Return Value:
  238. status.
  239. --*/
  240. {
  241. STORAGE_PROPERTY_QUERY query;
  242. PIO_STATUS_BLOCK ioStatus;
  243. PSTORAGE_DESCRIPTOR_HEADER descriptor = NULL;
  244. ULONG length;
  245. //
  246. // Poison the passed in descriptor.
  247. //
  248. *Descriptor = NULL;
  249. //
  250. // Setup the query buffer.
  251. //
  252. query.PropertyId = *PropertyId;
  253. query.QueryType = PropertyStandardQuery;
  254. query.AdditionalParameters[0] = 0;
  255. ioStatus = ExAllocatePool(NonPagedPool, sizeof(IO_STATUS_BLOCK));
  256. ASSERT(ioStatus);
  257. ioStatus->Status = 0;
  258. ioStatus->Information = 0;
  259. //
  260. // On the first call, just need to get the length of the descriptor.
  261. //
  262. descriptor = (PVOID)&query;
  263. MPLIBSendDeviceIoControlSynchronous(IOCTL_STORAGE_QUERY_PROPERTY,
  264. DeviceObject,
  265. &query,
  266. &query,
  267. sizeof(STORAGE_PROPERTY_QUERY),
  268. sizeof(STORAGE_DESCRIPTOR_HEADER),
  269. FALSE,
  270. ioStatus);
  271. if(!NT_SUCCESS(ioStatus->Status)) {
  272. MPDebugPrint((0,
  273. "MPLIBGetDescriptor: Query failed (%x) on attempt 1\n",
  274. ioStatus->Status));
  275. return ioStatus->Status;
  276. }
  277. ASSERT(descriptor->Size);
  278. if (descriptor->Size == 0) {
  279. return STATUS_UNSUCCESSFUL;
  280. }
  281. //
  282. // This time we know how much data there is so we can
  283. // allocate a buffer of the correct size
  284. //
  285. length = descriptor->Size;
  286. descriptor = ExAllocatePoolWithTag(NonPagedPool, length, 'BLPM');
  287. if(descriptor == NULL) {
  288. MPDebugPrint((0,
  289. "MPLIBGetDescriptor: Couldn't allocate descriptor of %ld\n",
  290. length));
  291. return STATUS_INSUFFICIENT_RESOURCES;
  292. }
  293. //
  294. // setup the query again.
  295. //
  296. query.PropertyId = *PropertyId;
  297. query.QueryType = PropertyStandardQuery;
  298. query.AdditionalParameters[0] = 0;
  299. //
  300. // copy the input to the new outputbuffer
  301. //
  302. RtlCopyMemory(descriptor,
  303. &query,
  304. sizeof(STORAGE_PROPERTY_QUERY));
  305. MPLIBSendDeviceIoControlSynchronous(IOCTL_STORAGE_QUERY_PROPERTY,
  306. DeviceObject,
  307. descriptor,
  308. descriptor,
  309. sizeof(STORAGE_PROPERTY_QUERY),
  310. length,
  311. 0,
  312. ioStatus);
  313. if(!NT_SUCCESS(ioStatus->Status)) {
  314. MPDebugPrint((0,
  315. "MPLIBGetDescriptor: Query Failed (%x) on attempt 2\n",
  316. ioStatus->Status));
  317. ExFreePool(descriptor);
  318. return ioStatus->Status;
  319. }
  320. //
  321. // return the memory we've allocated to the caller
  322. //
  323. *Descriptor = descriptor;
  324. return ioStatus->Status;
  325. }
  326. NTSTATUS
  327. MPLibReleaseQueueCompletion(
  328. PDEVICE_OBJECT DeviceObject,
  329. PIRP Irp,
  330. PVOID Context
  331. )
  332. /*++
  333. Routine Description:
  334. Arguments:
  335. DeviceObject - The device object for the logical unit; however since this
  336. is the top stack location the value is NULL.
  337. Irp - Supplies a pointer to the Irp to be processed.
  338. Context - Supplies the context to be used to process this request.
  339. Return Value:
  340. None.
  341. --*/
  342. {
  343. PKEVENT event = Context;
  344. if (Irp->PendingReturned) {
  345. IoMarkIrpPending(Irp);
  346. }
  347. KeSetEvent(event, 0 , FALSE);
  348. //
  349. // Free the Irp.
  350. //
  351. IoFreeIrp(Irp);
  352. //
  353. // Indicate the I/O system should stop processing the Irp completion.
  354. //
  355. return STATUS_MORE_PROCESSING_REQUIRED;
  356. }
  357. NTSTATUS
  358. MPLibReleaseQueue(
  359. IN PDEVICE_OBJECT ChildDevice
  360. )
  361. /*++
  362. Routine Description:
  363. This routine issues a Release Queue to the port driver for Child device.
  364. Arguments:
  365. ChildDevice - Device Object for a scsiport child returned in QDR.
  366. Return Value:
  367. Status of the request
  368. --*/
  369. {
  370. PIRP irp;
  371. PIO_STACK_LOCATION irpStack;
  372. KEVENT event;
  373. NTSTATUS status;
  374. PSCSI_REQUEST_BLOCK srb;
  375. //
  376. // Set the event object to the unsignaled state.
  377. // It will be used to signal request completion
  378. //
  379. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  380. irp = IoAllocateIrp((CCHAR)(ChildDevice->StackSize),
  381. FALSE);
  382. if (irp) {
  383. srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
  384. if (srb) {
  385. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  386. //
  387. // Construct the IRP stack for the lower level driver.
  388. //
  389. irpStack = IoGetNextIrpStackLocation(irp);
  390. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  391. irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_NONE;
  392. irpStack->Parameters.Scsi.Srb = srb;
  393. IoSetCompletionRoutine(irp,
  394. MPLibReleaseQueueCompletion,
  395. &event,
  396. TRUE,
  397. TRUE,
  398. TRUE);
  399. //
  400. // Setup the SRB.
  401. //
  402. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  403. srb->Function = SRB_FUNCTION_FLUSH_QUEUE;
  404. srb->OriginalRequest = irp;
  405. } else {
  406. IoFreeIrp(irp);
  407. return STATUS_INSUFFICIENT_RESOURCES;
  408. }
  409. } else {
  410. return STATUS_INSUFFICIENT_RESOURCES;
  411. }
  412. //
  413. // Call the port driver with the request and wait for it to complete.
  414. //
  415. status = IoCallDriver(ChildDevice, irp);
  416. if (status == STATUS_PENDING) {
  417. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  418. }
  419. ExFreePool(srb);
  420. return status;
  421. }
  422. NTSTATUS
  423. MPLibTURCompletion(
  424. PDEVICE_OBJECT DeviceObject,
  425. PIRP Irp,
  426. PVOID Context
  427. )
  428. /*++
  429. Routine Description:
  430. This routine is called when an asynchronous I/O request
  431. which was issused by the dsm completes. Examples of such requests
  432. are release queue or test unit ready. This routine releases the queue if
  433. necessary. It then frees the context and the IRP.
  434. Arguments:
  435. DeviceObject - The device object for the logical unit; however since this
  436. is the top stack location the value is NULL.
  437. Irp - Supplies a pointer to the Irp to be processed.
  438. Context - Supplies the context to be used to process this request.
  439. Return Value:
  440. None.
  441. --*/
  442. {
  443. PMPLIB_COMPLETION_CONTEXT context = Context;
  444. PSCSI_REQUEST_BLOCK srb;
  445. srb = context->Srb;
  446. //
  447. // If this is an execute srb, then check the return status and make sure.
  448. // the queue is not frozen.
  449. //
  450. if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
  451. //
  452. // Check for a frozen queue.
  453. //
  454. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  455. //
  456. // Unfreeze the queue getting the device object from the context.
  457. //
  458. MPDebugPrint((2,
  459. "DsmCompletion: Queue is frozen!!!!\n"));
  460. MPLibReleaseQueue(context->DeviceObject);
  461. }
  462. }
  463. context->Status = Irp->IoStatus.Status;
  464. //
  465. // Free the Irp.
  466. //
  467. IoFreeIrp(Irp);
  468. KeSetEvent(&context->Event, 0, FALSE);
  469. //
  470. // Indicate the I/O system should stop processing the Irp completion.
  471. //
  472. return STATUS_MORE_PROCESSING_REQUIRED;
  473. }
  474. NTSTATUS
  475. InterpretSenseInfo(
  476. IN PSENSE_DATA SenseData,
  477. IN ULONG SenseLength
  478. )
  479. {
  480. UCHAR senseKey = SenseData->SenseKey & 0xF;
  481. UCHAR asc = SenseData->AdditionalSenseCode;
  482. UCHAR ascq = SenseData->AdditionalSenseCodeQualifier;
  483. switch (senseKey) {
  484. case SCSI_SENSE_NOT_READY:
  485. return STATUS_DEVICE_NOT_READY;
  486. case SCSI_SENSE_DATA_PROTECT:
  487. return STATUS_MEDIA_WRITE_PROTECTED;
  488. case SCSI_SENSE_MEDIUM_ERROR:
  489. return STATUS_DEVICE_DATA_ERROR;
  490. case SCSI_SENSE_ILLEGAL_REQUEST:
  491. return STATUS_INVALID_DEVICE_REQUEST;
  492. case SCSI_SENSE_BLANK_CHECK:
  493. return STATUS_NO_DATA_DETECTED;
  494. case SCSI_SENSE_RECOVERED_ERROR:
  495. return STATUS_SUCCESS;
  496. case SCSI_SENSE_HARDWARE_ERROR:
  497. case SCSI_SENSE_UNIT_ATTENTION:
  498. case SCSI_SENSE_NO_SENSE:
  499. case SCSI_SENSE_ABORTED_COMMAND:
  500. default:
  501. return STATUS_IO_DEVICE_ERROR;
  502. }
  503. return STATUS_IO_DEVICE_ERROR;
  504. }
  505. NTSTATUS
  506. InterpretScsiStatus(
  507. IN PUCHAR SenseBuffer,
  508. IN ULONG SenseLength,
  509. IN UCHAR ScsiStatus
  510. )
  511. {
  512. NTSTATUS status;
  513. switch (ScsiStatus) {
  514. case SCSISTAT_CHECK_CONDITION: {
  515. if (SenseBuffer && SenseLength) {
  516. status = InterpretSenseInfo((PSENSE_DATA)SenseBuffer,
  517. SenseLength);
  518. } else {
  519. status = STATUS_IO_DEVICE_ERROR;
  520. }
  521. break;
  522. }
  523. case SCSISTAT_BUSY:
  524. status = STATUS_DEVICE_NOT_READY;
  525. break;
  526. case SCSISTAT_RESERVATION_CONFLICT:
  527. status = STATUS_DEVICE_BUSY;
  528. break;
  529. default:
  530. status = STATUS_IO_DEVICE_ERROR;
  531. break;
  532. }
  533. return status;
  534. }
  535. NTSTATUS
  536. MPLibSendPassThroughDirect(
  537. IN PDEVICE_OBJECT DeviceObject,
  538. IN PSCSI_PASS_THROUGH_DIRECT ScsiPassThrough,
  539. IN ULONG InputBufferLength,
  540. IN ULONG OutputBufferLength
  541. )
  542. {
  543. IO_STATUS_BLOCK ioStatus;
  544. NTSTATUS status;
  545. UCHAR scsiStatus;
  546. MPLIBSendDeviceIoControlSynchronous(IOCTL_SCSI_PASS_THROUGH_DIRECT,
  547. DeviceObject,
  548. ScsiPassThrough,
  549. ScsiPassThrough->DataBuffer,
  550. InputBufferLength,
  551. OutputBufferLength,
  552. FALSE,
  553. &ioStatus);
  554. //
  555. // Check the iostatus. STATUS_SUCCESS really only means that the request
  556. // was sent successfully, not that it did what it was supposed to.
  557. //
  558. status = ioStatus.Status;
  559. if (NT_SUCCESS(status)) {
  560. //
  561. // Get the scsi status.
  562. //
  563. scsiStatus = ScsiPassThrough->ScsiStatus;
  564. if (scsiStatus == SCSISTAT_GOOD) {
  565. status = STATUS_SUCCESS;
  566. } else {
  567. PUCHAR senseBuffer;
  568. ULONG senseLength;
  569. senseBuffer = (PUCHAR)ScsiPassThrough;
  570. (ULONG_PTR)senseBuffer += ScsiPassThrough->SenseInfoOffset;
  571. senseLength = ScsiPassThrough->SenseInfoLength;
  572. status = InterpretScsiStatus(senseBuffer, senseLength, scsiStatus);
  573. }
  574. }
  575. return status;
  576. }
  577. NTSTATUS
  578. MPLibSendTUR(
  579. IN PDEVICE_OBJECT TargetDevice
  580. )
  581. /*++
  582. Routine Description:
  583. Arguments:
  584. Return Value:
  585. None.
  586. --*/
  587. {
  588. PIO_STACK_LOCATION irpStack;
  589. PMPLIB_COMPLETION_CONTEXT completionContext;
  590. PIRP irp;
  591. PSCSI_REQUEST_BLOCK srb;
  592. PSENSE_DATA senseData;
  593. NTSTATUS status;
  594. PCDB cdb;
  595. ULONG retry = 4;
  596. //
  597. // Allocate an srb, the sense buffer, and context block for the request.
  598. //
  599. srb = ExAllocatePool(NonPagedPool,sizeof(SCSI_REQUEST_BLOCK));
  600. senseData = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SENSE_DATA));
  601. completionContext = ExAllocatePool(NonPagedPool, sizeof(MPLIB_COMPLETION_CONTEXT));
  602. if ((srb == NULL) || (senseData == NULL) || (completionContext == NULL)) {
  603. if (srb) {
  604. ExFreePool(srb);
  605. }
  606. if (senseData) {
  607. ExFreePool(senseData);
  608. }
  609. if (completionContext) {
  610. ExFreePool(completionContext);
  611. }
  612. return STATUS_INSUFFICIENT_RESOURCES;
  613. }
  614. //
  615. // Setup the context.
  616. //
  617. completionContext->DeviceObject = TargetDevice;
  618. completionContext->Srb = srb;
  619. completionContext->SenseBuffer = senseData;
  620. retryRequest:
  621. KeInitializeEvent(&completionContext->Event, NotificationEvent, FALSE);
  622. //
  623. // Zero out srb and sense data.
  624. //
  625. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  626. RtlZeroMemory(senseData, sizeof(SENSE_DATA));
  627. //
  628. // Build the srb.
  629. //
  630. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  631. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  632. srb->TimeOutValue = 4;
  633. srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
  634. srb->SenseInfoBufferLength = sizeof(SENSE_DATA);
  635. srb->SenseInfoBuffer = senseData;
  636. //
  637. // Build the TUR CDB.
  638. //
  639. srb->CdbLength = 6;
  640. cdb = (PCDB)srb->Cdb;
  641. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  642. //
  643. // Build the asynchronous request to be sent to the port driver.
  644. // Since this routine is called from a DPC the IRP should always be
  645. // available.
  646. //
  647. irp = IoAllocateIrp(TargetDevice->StackSize + 1, FALSE);
  648. if(irp == NULL) {
  649. ExFreePool(srb);
  650. ExFreePool(senseData);
  651. ExFreePool(completionContext);
  652. return STATUS_INSUFFICIENT_RESOURCES;
  653. }
  654. irpStack = IoGetNextIrpStackLocation(irp);
  655. irpStack->MajorFunction = IRP_MJ_SCSI;
  656. srb->OriginalRequest = irp;
  657. //
  658. // Store the SRB address in next stack for port driver.
  659. //
  660. irpStack->Parameters.Scsi.Srb = srb;
  661. IoSetCompletionRoutine(irp,
  662. (PIO_COMPLETION_ROUTINE)MPLibTURCompletion,
  663. completionContext,
  664. TRUE,
  665. TRUE,
  666. TRUE);
  667. //
  668. // Call the port driver with the IRP.
  669. //
  670. status = IoCallDriver(TargetDevice, irp);
  671. if (status == STATUS_PENDING) {
  672. KeWaitForSingleObject(&completionContext->Event,
  673. Executive,
  674. KernelMode,
  675. FALSE,
  676. NULL);
  677. status = completionContext->Status;
  678. }
  679. if ((status != STATUS_SUCCESS) && retry--) {
  680. goto retryRequest;
  681. }
  682. //
  683. // Free the allocations.
  684. //
  685. ExFreePool(completionContext);
  686. ExFreePool(srb);
  687. ExFreePool(senseData);
  688. return status;
  689. }
  690. #if 1
  691. UCHAR DebugBuffer[DEBUG_BUFFER_LENGTH + 1];
  692. ULONG MPathDebug = 1;
  693. VOID
  694. MPathDebugPrint(
  695. ULONG DebugPrintLevel,
  696. PCCHAR DebugMessage,
  697. ...
  698. )
  699. /*++
  700. Routine Description:
  701. Debug print for multi-path components.
  702. Arguments:
  703. Return Value:
  704. None
  705. --*/
  706. {
  707. va_list ap;
  708. va_start(ap, DebugMessage);
  709. if (DebugPrintLevel <= MPathDebug) {
  710. _vsnprintf(DebugBuffer, DEBUG_BUFFER_LENGTH, DebugMessage, ap);
  711. DbgPrint(DebugBuffer);
  712. }
  713. va_end(ap);
  714. }
  715. #else
  716. VOID
  717. MPathDebugPrint(
  718. ULONG DebugPrintLevel,
  719. PCCHAR DebugMessage,
  720. ...
  721. )
  722. {
  723. }
  724. #endif