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.

1164 lines
31 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1999
  3. Module Name:
  4. passthru.c
  5. Abstract:
  6. This is the storage port driver library. This file contains code that
  7. implements SCSI passthrough.
  8. Authors:
  9. John Strange (JohnStra)
  10. Environment:
  11. kernel mode only
  12. Notes:
  13. This module implements SCSI passthru for storage port drivers.
  14. Revision History:
  15. --*/
  16. #include "precomp.h"
  17. //
  18. // Constants and macros to enforce good use of Ex[Allocate|Free]PoolWithTag.
  19. // Remeber that all pool tags will display in the debugger in reverse order
  20. //
  21. #if USE_EXFREEPOOLWITHTAG_ONLY
  22. #define TAG(x) (x | 0x80000000)
  23. #else
  24. #define TAG(x) (x)
  25. #endif
  26. #define PORT_TAG_SENSE_BUFFER TAG('iPlP') // Sense info
  27. #define PORT_IS_COPY(Srb) \
  28. ((Srb)->Cdb[0] == SCSIOP_COPY)
  29. #define PORT_IS_COMPARE(Srb) \
  30. ((Srb)->Cdb[0] == SCSIOP_COMPARE)
  31. #define PORT_IS_COPY_COMPARE(Srb) \
  32. ((Srb)->Cdb[0] == SCSIOP_COPY_COMPARE)
  33. #define PORT_IS_ILLEGAL_PASSTHROUGH_COMMAND(Srb) \
  34. (PORT_IS_COPY((Srb)) || \
  35. PORT_IS_COMPARE((Srb)) || \
  36. PORT_IS_COPY_COMPARE((Srb)))
  37. #if defined (_WIN64)
  38. NTSTATUS
  39. PortpTranslatePassThrough32To64(
  40. IN PSCSI_PASS_THROUGH32 SrbControl32,
  41. IN OUT PSCSI_PASS_THROUGH SrbControl64
  42. );
  43. VOID
  44. PortpTranslatePassThrough64To32(
  45. IN PSCSI_PASS_THROUGH SrbControl64,
  46. IN OUT PSCSI_PASS_THROUGH32 SrbControl32
  47. );
  48. #endif
  49. NTSTATUS
  50. PortpSendValidPassThrough(
  51. IN PPORT_PASSTHROUGH_INFO PassThroughInfo,
  52. IN PIRP RequestIrp,
  53. IN ULONG SrbFlags,
  54. IN BOOLEAN Direct
  55. );
  56. #ifdef ALLOC_PRAGMA
  57. #pragma alloc_text(PAGE, PortGetPassThrough)
  58. #pragma alloc_text(PAGE, PortPassThroughInitialize)
  59. #pragma alloc_text(PAGE, PortPassThroughInitializeSrb)
  60. #pragma alloc_text(PAGE, PortSendPassThrough)
  61. #pragma alloc_text(PAGE, PortpSendValidPassThrough)
  62. #pragma alloc_text(PAGE, PortPassThroughCleanup)
  63. #pragma alloc_text(PAGE, PortGetPassThroughAddress)
  64. #pragma alloc_text(PAGE, PortSetPassThroughAddress)
  65. #pragma alloc_text(PAGE, PortPassThroughMarshalResults)
  66. #if defined (_WIN64)
  67. #pragma alloc_text(PAGE, PortpTranslatePassThrough32To64)
  68. #pragma alloc_text(PAGE, PortpTranslatePassThrough64To32)
  69. #endif
  70. #endif
  71. NTSTATUS
  72. PortGetPassThroughAddress(
  73. IN PIRP Irp,
  74. OUT PUCHAR PathId,
  75. OUT PUCHAR TargetId,
  76. OUT PUCHAR Lun
  77. )
  78. /*++
  79. Routine Description:
  80. This routine retrieves the address of the device to witch the passthrough
  81. request is to be sent.
  82. Arguments:
  83. Irp - Supplies a pointer to the IRP that contains the
  84. SCSI_PASS_THROUGH structure.
  85. PathId - Pointer to the PathId of the addressed device.
  86. TargetId - Pointer to the TargetId of the addressed device.
  87. Lun - Pointer to the logical unit number of the addressed device.
  88. Return Value:
  89. Returns a status indicating the success or failure of the operation.
  90. --*/
  91. {
  92. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  93. PSCSI_PASS_THROUGH srbControl = Irp->AssociatedIrp.SystemBuffer;
  94. ULONG requiredSize;
  95. NTSTATUS status;
  96. PAGED_CODE();
  97. #if defined(_WIN64)
  98. if (IoIs32bitProcess(Irp)) {
  99. requiredSize = sizeof(SCSI_PASS_THROUGH32);
  100. } else {
  101. requiredSize = sizeof(SCSI_PASS_THROUGH);
  102. }
  103. #else
  104. requiredSize = sizeof(SCSI_PASS_THROUGH);
  105. #endif
  106. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  107. requiredSize) {
  108. status = STATUS_BUFFER_TOO_SMALL;
  109. } else {
  110. *PathId = srbControl->PathId;
  111. *TargetId = srbControl->TargetId;
  112. *Lun = srbControl->Lun;
  113. status = STATUS_SUCCESS;
  114. }
  115. return status;
  116. }
  117. NTSTATUS
  118. PortSetPassThroughAddress(
  119. IN PIRP Irp,
  120. IN UCHAR PathId,
  121. IN UCHAR TargetId,
  122. IN UCHAR Lun
  123. )
  124. /*++
  125. Routine Description:
  126. This routine initializes the address of the SCSI_PASS_THROUGH structure
  127. embedded in the supplied IRP.
  128. Arguments:
  129. Irp - Supplies a pointer to the IRP that contains the
  130. SCSI_PASS_THROUGH structure.
  131. PathId - The PathId of the addressed device.
  132. TargetId - The TargetId of the addressed device.
  133. Lun - The logical unit number of the addressed device.
  134. Return Value:
  135. Returns a status indicating the success or failure of the operation.
  136. --*/
  137. {
  138. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  139. PSCSI_PASS_THROUGH srbControl = Irp->AssociatedIrp.SystemBuffer;
  140. ULONG requiredSize;
  141. NTSTATUS status;
  142. PAGED_CODE();
  143. #if defined(_WIN64)
  144. if (IoIs32bitProcess(Irp)) {
  145. requiredSize = sizeof(SCSI_PASS_THROUGH32);
  146. } else {
  147. requiredSize = sizeof(SCSI_PASS_THROUGH);
  148. }
  149. #else
  150. requiredSize = sizeof(SCSI_PASS_THROUGH);
  151. #endif
  152. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  153. requiredSize) {
  154. status = STATUS_BUFFER_TOO_SMALL;
  155. } else {
  156. srbControl->PathId = PathId;
  157. srbControl->TargetId = TargetId;
  158. srbControl->Lun = Lun;
  159. status = STATUS_SUCCESS;
  160. }
  161. return status;
  162. }
  163. NTSTATUS
  164. PortSendPassThrough (
  165. IN PDEVICE_OBJECT Pdo,
  166. IN PIRP RequestIrp,
  167. IN BOOLEAN Direct,
  168. IN ULONG SrbFlags,
  169. IN PIO_SCSI_CAPABILITIES Capabilities
  170. )
  171. /*++
  172. Routine Description:
  173. This function sends a user specified SCSI CDB to the device identified in
  174. the supplied SCSI_PASS_THROUGH structure. It creates an srb which is
  175. processed normally by the port driver. This call is synchornous.
  176. Arguments:
  177. Pdo - Supplies a pointer to the PDO to which the passthrough
  178. command will be dispatched.
  179. RequestIrp - Supplies a pointer to the IRP that made the original
  180. request.
  181. Direct - Boolean indicating whether this is a direct passthrough.
  182. SrbFlags - The flags to copy into the SRB used for this command.
  183. Capabilities - Supplies a pointer to the IO_SCSI_CAPABILITIES structure
  184. describing the storage adapter.
  185. Return Value:
  186. Returns a status indicating the success or failure of the operation.
  187. --*/
  188. {
  189. NTSTATUS status;
  190. PORT_PASSTHROUGH_INFO passThroughInfo;
  191. PAGED_CODE();
  192. RtlZeroMemory(&passThroughInfo, sizeof(PORT_PASSTHROUGH_INFO));
  193. //
  194. // Try to init a pointer to the passthrough structure in the IRP.
  195. //
  196. status = PortGetPassThrough(
  197. &passThroughInfo,
  198. RequestIrp,
  199. Direct
  200. );
  201. if (status == STATUS_SUCCESS) {
  202. //
  203. // Perform parameter checking and to setup the PORT_PASSTHROUGH_INFO
  204. // structure.
  205. //
  206. status = PortPassThroughInitialize(
  207. &passThroughInfo,
  208. RequestIrp,
  209. Capabilities,
  210. Pdo,
  211. Direct
  212. );
  213. if (status == STATUS_SUCCESS) {
  214. //
  215. // Call helper routine to finish processing the passthrough request.
  216. //
  217. status = PortpSendValidPassThrough(
  218. &passThroughInfo,
  219. RequestIrp,
  220. SrbFlags,
  221. Direct
  222. );
  223. }
  224. PortPassThroughCleanup(&passThroughInfo);
  225. }
  226. return status;
  227. }
  228. NTSTATUS
  229. PortGetPassThrough(
  230. IN OUT PPORT_PASSTHROUGH_INFO PassThroughInfo,
  231. IN PIRP Irp,
  232. IN BOOLEAN Direct
  233. )
  234. /*++
  235. Routine Description:
  236. This routine returns a pointer to the user supplied SCSI_PASS_THROUGH
  237. structure.
  238. Arguments:
  239. PassThroughInfo - Supplies a pointer to a SCSI_PASSTHROUGH_INFO structure.
  240. Irp - Supplies a pointer to the IRP.
  241. Direct - Supplies a boolean that indicates whether this is a
  242. SCSI_PASS_THROUGH_DIRECT request.
  243. Return Value:
  244. Returns a status indicating the success or failure of the operation.
  245. --*/
  246. {
  247. NTSTATUS status;
  248. PIO_STACK_LOCATION irpStack;
  249. ULONG inputLength;
  250. PAGED_CODE();
  251. //
  252. // Get a pointer to the pass through structure.
  253. //
  254. irpStack = IoGetCurrentIrpStackLocation(Irp);
  255. PassThroughInfo->SrbControl = Irp->AssociatedIrp.SystemBuffer;
  256. //
  257. // BUGBUG: Why do we need to save this pointer to the beginning of
  258. // the SCSI_PASS_THROUGH structure.
  259. //
  260. PassThroughInfo->SrbBuffer = (PVOID) PassThroughInfo->SrbControl;
  261. //
  262. // Initialize a stack variable to hold the size of the input buffer.
  263. //
  264. inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  265. //
  266. // For WIN64, a passthrough request from a 32-bit application requires
  267. // us to perform a translation on the supplied SCSI_PASS_THROUGH structure.
  268. // This is required because the layout of the 32-bit structure does not
  269. // match that of a 64-bit structure. In this case, we translate the
  270. // supplied 32-bit structure into a stack-allocated 64-bit structure which
  271. // will be used to process the pass through request.
  272. //
  273. #if defined (_WIN64)
  274. if (IoIs32bitProcess(Irp)) {
  275. if (inputLength < sizeof(SCSI_PASS_THROUGH32)){
  276. return STATUS_INVALID_PARAMETER;
  277. }
  278. PassThroughInfo->SrbControl32 =
  279. (PSCSI_PASS_THROUGH32)(Irp->AssociatedIrp.SystemBuffer);
  280. if (Direct == FALSE) {
  281. if (PassThroughInfo->SrbControl32->Length !=
  282. sizeof(SCSI_PASS_THROUGH32)) {
  283. return STATUS_REVISION_MISMATCH;
  284. }
  285. } else {
  286. if (PassThroughInfo->SrbControl32->Length !=
  287. sizeof(SCSI_PASS_THROUGH_DIRECT32)) {
  288. return STATUS_REVISION_MISMATCH;
  289. }
  290. }
  291. status = PortpTranslatePassThrough32To64(
  292. PassThroughInfo->SrbControl32,
  293. &PassThroughInfo->SrbControl64);
  294. if (!NT_SUCCESS(status)) {
  295. return status;
  296. }
  297. PassThroughInfo->SrbControl = &PassThroughInfo->SrbControl64;
  298. } else {
  299. #endif
  300. if (inputLength < sizeof(SCSI_PASS_THROUGH)){
  301. return(STATUS_INVALID_PARAMETER);
  302. }
  303. if (Direct == FALSE) {
  304. if (PassThroughInfo->SrbControl->Length !=
  305. sizeof(SCSI_PASS_THROUGH)) {
  306. return STATUS_REVISION_MISMATCH;
  307. }
  308. } else {
  309. if (PassThroughInfo->SrbControl->Length !=
  310. sizeof(SCSI_PASS_THROUGH_DIRECT)) {
  311. return STATUS_REVISION_MISMATCH;
  312. }
  313. }
  314. #if defined (_WIN64)
  315. }
  316. #endif
  317. return STATUS_SUCCESS;
  318. }
  319. NTSTATUS
  320. PortPassThroughInitialize(
  321. IN OUT PPORT_PASSTHROUGH_INFO PassThroughInfo,
  322. IN PIRP Irp,
  323. IN PIO_SCSI_CAPABILITIES Capabilities,
  324. IN PDEVICE_OBJECT Pdo,
  325. IN BOOLEAN Direct
  326. )
  327. /*++
  328. Routine Description:
  329. This routine validates the caller-supplied data and initializes the
  330. PORT_PASSTHROUGH_INFO structure.
  331. Arguments:
  332. PassThroughInfo - Supplies a pointer to a SCSI_PASSTHROUGH_INFO structure.
  333. Irp - Supplies a pointer to the IRP.
  334. Direct - Supplies a boolean that indicates whether this is a
  335. SCSI_PASS_THROUGH_DIRECT request.
  336. Return Value:
  337. Returns a status indicating the success or failure of the operation.
  338. --*/
  339. {
  340. NTSTATUS status;
  341. ULONG outputLength;
  342. ULONG inputLength;
  343. PIO_STACK_LOCATION irpStack;
  344. PSCSI_PASS_THROUGH srbControl;
  345. ULONG dataTransferLength;
  346. ULONG pages;
  347. PAGED_CODE();
  348. irpStack = IoGetCurrentIrpStackLocation(Irp);
  349. srbControl = PassThroughInfo->SrbControl;
  350. outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  351. inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  352. PassThroughInfo->Pdo = Pdo;
  353. //
  354. // Verify that the CDB is no greater than 16 bytes.
  355. //
  356. if (srbControl->CdbLength > 16) {
  357. return STATUS_INVALID_PARAMETER;
  358. }
  359. //
  360. // If there's a sense buffer then its offset cannot be shorter than the
  361. // length of the srbControl block, nor can it be located after the data
  362. // buffer (if any).
  363. //
  364. if (srbControl->SenseInfoLength != 0) {
  365. //
  366. // Sense info offset should not be smaller than the size of the
  367. // pass through structure.
  368. //
  369. if (srbControl->Length > srbControl->SenseInfoOffset) {
  370. return STATUS_INVALID_PARAMETER;
  371. }
  372. if (!Direct) {
  373. //
  374. // Sense info buffer should precede the data buffer offset.
  375. //
  376. if ((srbControl->SenseInfoOffset >= srbControl->DataBufferOffset) ||
  377. ((srbControl->SenseInfoOffset + srbControl->SenseInfoLength) >
  378. srbControl->DataBufferOffset)) {
  379. return STATUS_INVALID_PARAMETER;
  380. }
  381. //
  382. // Sense info buffer should be within the output buffer.
  383. //
  384. if ((srbControl->SenseInfoOffset > outputLength) ||
  385. (srbControl->SenseInfoOffset + srbControl->SenseInfoLength >
  386. outputLength)) {
  387. return STATUS_INVALID_PARAMETER;
  388. }
  389. } else {
  390. //
  391. // Sense info buffer should be within the output buffer.
  392. //
  393. if ((srbControl->SenseInfoOffset > outputLength) ||
  394. (srbControl->SenseInfoOffset + srbControl->SenseInfoLength >
  395. outputLength)) {
  396. return STATUS_INVALID_PARAMETER;
  397. }
  398. }
  399. }
  400. if (!Direct) {
  401. //
  402. // Data buffer offset should be greater than the size of the pass
  403. // through structure.
  404. //
  405. if (srbControl->Length > srbControl->DataBufferOffset &&
  406. srbControl->DataTransferLength != 0) {
  407. return STATUS_INVALID_PARAMETER;
  408. }
  409. //
  410. // If this command is sending data to the device. Make sure the data
  411. // buffer lies entirely within the supplied input buffer.
  412. //
  413. if (srbControl->DataIn != SCSI_IOCTL_DATA_IN) {
  414. if ((srbControl->DataBufferOffset > inputLength) ||
  415. ((srbControl->DataBufferOffset +
  416. srbControl->DataTransferLength) >
  417. inputLength)) {
  418. return STATUS_INVALID_PARAMETER;
  419. }
  420. }
  421. //
  422. // If this command is retrieving data from the device, make sure the
  423. // data buffer lies entirely within the supplied output buffer.
  424. //
  425. if (srbControl->DataIn) {
  426. if ((srbControl->DataBufferOffset > outputLength) ||
  427. ((srbControl->DataBufferOffset +
  428. srbControl->DataTransferLength) >
  429. outputLength)) {
  430. return STATUS_INVALID_PARAMETER;
  431. }
  432. }
  433. }
  434. //
  435. // Validate the specified timeout value.
  436. //
  437. if (srbControl->TimeOutValue == 0 ||
  438. srbControl->TimeOutValue > 30 * 60 * 60) {
  439. return STATUS_INVALID_PARAMETER;
  440. }
  441. //
  442. // Check for illegal command codes.
  443. //
  444. if (PORT_IS_ILLEGAL_PASSTHROUGH_COMMAND(srbControl)) {
  445. return STATUS_INVALID_DEVICE_REQUEST;
  446. }
  447. if (srbControl->DataTransferLength == 0) {
  448. PassThroughInfo->Length = 0;
  449. PassThroughInfo->Buffer = NULL;
  450. PassThroughInfo->BufferOffset = 0;
  451. PassThroughInfo->MajorCode = IRP_MJ_FLUSH_BUFFERS;
  452. } else if (Direct == TRUE) {
  453. PassThroughInfo->Length = (ULONG) srbControl->DataTransferLength;
  454. PassThroughInfo->Buffer = (PUCHAR) srbControl->DataBufferOffset;
  455. PassThroughInfo->BufferOffset = 0;
  456. PassThroughInfo->MajorCode = !srbControl->DataIn ? IRP_MJ_WRITE :
  457. IRP_MJ_READ;
  458. } else {
  459. PassThroughInfo->Length = (ULONG) srbControl->DataBufferOffset +
  460. srbControl->DataTransferLength;
  461. PassThroughInfo->Buffer = (PUCHAR) PassThroughInfo->SrbBuffer;
  462. PassThroughInfo->BufferOffset = (ULONG)srbControl->DataBufferOffset;
  463. PassThroughInfo->MajorCode = !srbControl->DataIn ? IRP_MJ_WRITE :
  464. IRP_MJ_READ;
  465. }
  466. //
  467. // Make sure the buffer is properly aligned.
  468. //
  469. if (Direct == TRUE) {
  470. //
  471. // Make sure the user buffer is valid. IoBuildSynchronouseFsdRequest
  472. // calls MmProbeAndLock with AccessMode == KernelMode. This check is
  473. // the extra stuff that MM would do if it were called with
  474. // AccessMode == UserMode.
  475. //
  476. // ISSUE: We should probably do an MmProbeAndLock here.
  477. //
  478. if (Irp->RequestorMode != KernelMode) {
  479. PVOID endByte;
  480. if (PassThroughInfo->Length) {
  481. endByte = (PVOID)((PCHAR)PassThroughInfo->Buffer +
  482. PassThroughInfo->Length - 1);
  483. if ((endByte > (PVOID)MM_HIGHEST_USER_ADDRESS) ||
  484. (PassThroughInfo->Buffer >= endByte)) {
  485. return STATUS_INVALID_USER_BUFFER;
  486. }
  487. }
  488. }
  489. if (srbControl->DataBufferOffset &
  490. PassThroughInfo->Pdo->AlignmentRequirement) {
  491. return STATUS_INVALID_PARAMETER;
  492. }
  493. }
  494. //
  495. // Check if the request is too big for the adapter.
  496. //
  497. dataTransferLength = PassThroughInfo->SrbControl->DataTransferLength;
  498. pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  499. (PUCHAR)PassThroughInfo->Buffer + PassThroughInfo->BufferOffset,
  500. dataTransferLength);
  501. if ((dataTransferLength != 0) &&
  502. (pages > Capabilities->MaximumPhysicalPages ||
  503. dataTransferLength > Capabilities->MaximumTransferLength)) {
  504. return STATUS_INVALID_PARAMETER;
  505. }
  506. return STATUS_SUCCESS;
  507. }
  508. VOID
  509. PortPassThroughCleanup(
  510. IN PPORT_PASSTHROUGH_INFO PassThroughInfo
  511. )
  512. /*++
  513. Routine Description:
  514. This routine performs any cleanup required after processing a SCSI
  515. passthrough request.
  516. Arguments:
  517. PassThroughInfo - Supplies a pointer to a SCSI_PASSTHROUGH_INFO structure.
  518. Return Value:
  519. VOID
  520. --*/
  521. {
  522. PAGED_CODE();
  523. #if defined (_WIN64)
  524. if (PassThroughInfo->SrbControl32 != NULL) {
  525. PortpTranslatePassThrough64To32(
  526. PassThroughInfo->SrbControl,
  527. PassThroughInfo->SrbControl32);
  528. }
  529. #endif
  530. }
  531. NTSTATUS
  532. PortPassThroughInitializeSrb(
  533. IN PPORT_PASSTHROUGH_INFO PassThroughInfo,
  534. IN PSCSI_REQUEST_BLOCK Srb,
  535. IN PIRP Irp,
  536. IN ULONG SrbFlags,
  537. IN PVOID SenseBuffer
  538. )
  539. /*++
  540. Routine Description:
  541. This routine initializes the supplied SRB to send a passthrough request.
  542. Arguments:
  543. PassThroughInfo - Supplies a pointer to a SCSI_PASSTHROUGH_INFO structure.
  544. Srb - Supplies a pointer to the SRB to initialize.
  545. Irp - Supplies a pointer to the IRP.
  546. SrbFlags - Supplies the appropriate SRB flags for the request.
  547. SenseBuffer - Supplies a pointer to request sense buffer to put in
  548. the SRB.
  549. Return Value:
  550. Returns a status indicating the success or failure of the operation.
  551. --*/
  552. {
  553. PSCSI_PASS_THROUGH srbControl;
  554. NTSTATUS status;
  555. PAGED_CODE();
  556. //
  557. // Zero out the srb.
  558. //
  559. RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
  560. //
  561. // Fill in the srb.
  562. //
  563. srbControl = PassThroughInfo->SrbControl;
  564. Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  565. Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  566. Srb->SrbStatus = SRB_STATUS_PENDING;
  567. Srb->PathId = srbControl->PathId;
  568. Srb->TargetId = srbControl->TargetId;
  569. Srb->Lun = srbControl->Lun;
  570. Srb->CdbLength = srbControl->CdbLength;
  571. Srb->SenseInfoBufferLength = srbControl->SenseInfoLength;
  572. switch (srbControl->DataIn) {
  573. case SCSI_IOCTL_DATA_OUT:
  574. if (srbControl->DataTransferLength) {
  575. Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
  576. }
  577. break;
  578. case SCSI_IOCTL_DATA_IN:
  579. if (srbControl->DataTransferLength) {
  580. Srb->SrbFlags = SRB_FLAGS_DATA_IN;
  581. }
  582. break;
  583. default:
  584. Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT;
  585. break;
  586. }
  587. if (srbControl->DataTransferLength == 0) {
  588. Srb->SrbFlags = 0;
  589. } else {
  590. //
  591. // Flush the data buffer for output. This will insure that the data is
  592. // written back to memory.
  593. //
  594. if (Irp != NULL) {
  595. KeFlushIoBuffers(Irp->MdlAddress, FALSE, TRUE);
  596. }
  597. }
  598. Srb->SrbFlags |= (SrbFlags | SRB_FLAGS_NO_QUEUE_FREEZE);
  599. Srb->DataTransferLength = srbControl->DataTransferLength;
  600. Srb->TimeOutValue = srbControl->TimeOutValue;
  601. Srb->DataBuffer = (PCHAR) PassThroughInfo->Buffer +
  602. PassThroughInfo->BufferOffset;
  603. Srb->SenseInfoBuffer = SenseBuffer;
  604. Srb->OriginalRequest = Irp;
  605. RtlCopyMemory(Srb->Cdb, srbControl->Cdb, srbControl->CdbLength);
  606. //
  607. // Disable autosense if there's no sense buffer to put the data in.
  608. //
  609. if (SenseBuffer == NULL) {
  610. Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
  611. }
  612. return STATUS_SUCCESS;
  613. }
  614. #if defined (_WIN64)
  615. NTSTATUS
  616. PortpTranslatePassThrough32To64(
  617. IN PSCSI_PASS_THROUGH32 SrbControl32,
  618. IN OUT PSCSI_PASS_THROUGH SrbControl64
  619. )
  620. /*++
  621. Routine Description:
  622. On WIN64, a SCSI_PASS_THROUGH structure sent down by a 32-bit application
  623. must be marshaled into a 64-bit version of the structure. This function
  624. performs that marshaling.
  625. Arguments:
  626. SrbControl32 - Supplies a pointer to a 32-bit SCSI_PASS_THROUGH struct.
  627. SrbControl64 - Supplies the address of a pointer to a 64-bit
  628. SCSI_PASS_THROUGH structure, into which we'll copy the
  629. marshaled 32-bit data.
  630. Return Value:
  631. Returns a status indicating the success or failure of the operation.
  632. --*/
  633. {
  634. PAGED_CODE();
  635. //
  636. // Copy the first set of fields out of the 32-bit structure. These
  637. // fields all line up between the 32 & 64 bit versions.
  638. //
  639. // Note that we do NOT adjust the length in the srbControl. This is to
  640. // allow the calling routine to compare the length of the actual
  641. // control area against the offsets embedded within. If we adjusted the
  642. // length then requests with the sense area backed against the control
  643. // area would be rejected because the 64-bit control area is 4 bytes
  644. // longer.
  645. //
  646. RtlCopyMemory(SrbControl64,
  647. SrbControl32,
  648. FIELD_OFFSET(SCSI_PASS_THROUGH, DataBufferOffset)
  649. );
  650. //
  651. // Copy over the CDB.
  652. //
  653. RtlCopyMemory(SrbControl64->Cdb,
  654. SrbControl32->Cdb,
  655. 16 * sizeof(UCHAR)
  656. );
  657. //
  658. // Copy the fields that follow the ULONG_PTR.
  659. //
  660. SrbControl64->DataBufferOffset = (ULONG_PTR)SrbControl32->DataBufferOffset;
  661. SrbControl64->SenseInfoOffset = SrbControl32->SenseInfoOffset;
  662. return STATUS_SUCCESS;
  663. }
  664. VOID
  665. PortpTranslatePassThrough64To32(
  666. IN PSCSI_PASS_THROUGH SrbControl64,
  667. IN OUT PSCSI_PASS_THROUGH32 SrbControl32
  668. )
  669. /*++
  670. Routine Description:
  671. On WIN64, a SCSI_PASS_THROUGH structure sent down by a 32-bit application
  672. must be marshaled into a 64-bit version of the structure. This function
  673. marshals a 64-bit version of the structure back into a 32-bit version.
  674. Arguments:
  675. SrbControl64 - Supplies a pointer to a 64-bit SCSI_PASS_THROUGH struct.
  676. SrbControl32 - Supplies the address of a pointer to a 32-bit
  677. SCSI_PASS_THROUGH structure, into which we'll copy the
  678. marshaled 64-bit data.
  679. Return Value:
  680. Returns a status indicating the success or failure of the operation.
  681. --*/
  682. {
  683. PAGED_CODE();
  684. //
  685. // Copy back the fields through the data offsets.
  686. //
  687. RtlCopyMemory(SrbControl32,
  688. SrbControl64,
  689. FIELD_OFFSET(SCSI_PASS_THROUGH, DataBufferOffset));
  690. return;
  691. }
  692. #endif
  693. NTSTATUS
  694. PortpSendValidPassThrough(
  695. IN PPORT_PASSTHROUGH_INFO PassThroughInfo,
  696. IN PIRP RequestIrp,
  697. IN ULONG SrbFlags,
  698. IN BOOLEAN Direct
  699. )
  700. /*++
  701. Routine Description:
  702. This routine sends the SCSI passthrough request described by the supplied
  703. PORT_PASSTHROUGH_INFO.
  704. Arguments:
  705. PassThroughInfo - Supplies a pointer to a SCSI_PASSTHROUGH_INFO structure.
  706. RequestIrp - Supplies a pointer to the IRP.
  707. SrbFlags - Supplies the appropriate SRB flags for the request.
  708. Direct - Indicates whether this is a SCSO_PASS_THROUGH_DIRECT.
  709. Return Value:
  710. Returns a status indicating the success or failure of the operation.
  711. --*/
  712. {
  713. PIO_STACK_LOCATION irpStack;
  714. NTSTATUS status;
  715. PIRP irp;
  716. PVOID senseBuffer;
  717. KEVENT event;
  718. LARGE_INTEGER startingOffset;
  719. IO_STATUS_BLOCK ioStatusBlock;
  720. SCSI_REQUEST_BLOCK srb;
  721. PAGED_CODE();
  722. //
  723. // Allocate an aligned sense buffer if one is required.
  724. //
  725. if (PassThroughInfo->SrbControl->SenseInfoLength != 0) {
  726. senseBuffer = ExAllocatePoolWithTag(
  727. NonPagedPoolCacheAligned,
  728. PassThroughInfo->SrbControl->SenseInfoLength,
  729. PORT_TAG_SENSE_BUFFER
  730. );
  731. if (senseBuffer == NULL) {
  732. return STATUS_INSUFFICIENT_RESOURCES;
  733. }
  734. } else {
  735. senseBuffer = NULL;
  736. }
  737. //
  738. // Must be at PASSIVE_LEVEL to use synchronous FSD.
  739. //
  740. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  741. //
  742. // Initialize the notification event.
  743. //
  744. KeInitializeEvent(&event, NotificationEvent, FALSE);
  745. //
  746. // Build IRP for this request.
  747. // Note we do this synchronously for two reasons. If it was done
  748. // asynchonously then the completion code would have to make a special
  749. // check to deallocate the buffer. Second if a completion routine were
  750. // used then an addation stack locate would be needed.
  751. //
  752. startingOffset.QuadPart = (LONGLONG) 1;
  753. irp = IoBuildSynchronousFsdRequest(
  754. PassThroughInfo->MajorCode,
  755. PassThroughInfo->Pdo,
  756. PassThroughInfo->Buffer,
  757. PassThroughInfo->Length,
  758. &startingOffset,
  759. &event,
  760. &ioStatusBlock);
  761. if (irp == NULL) {
  762. if (senseBuffer != NULL) {
  763. ExFreePool(senseBuffer);
  764. }
  765. return STATUS_INSUFFICIENT_RESOURCES;
  766. }
  767. //
  768. // Set major code.
  769. //
  770. irpStack = IoGetNextIrpStackLocation(irp);
  771. irpStack->MajorFunction = IRP_MJ_SCSI;
  772. irpStack->MinorFunction = 1;
  773. //
  774. // Initialize the IRP stack location to point to the SRB.
  775. //
  776. irpStack->Parameters.Others.Argument1 = &srb;
  777. //
  778. // Have the port library initialize the SRB for us.
  779. //
  780. status = PortPassThroughInitializeSrb(
  781. PassThroughInfo,
  782. &srb,
  783. irp,
  784. SrbFlags,
  785. senseBuffer);
  786. //
  787. // Call port driver to handle this request and wait for the request to
  788. // complete.
  789. //
  790. status = IoCallDriver(PassThroughInfo->Pdo, irp);
  791. if (status == STATUS_PENDING) {
  792. KeWaitForSingleObject(&event,
  793. Executive,
  794. KernelMode,
  795. FALSE,
  796. NULL);
  797. } else {
  798. ioStatusBlock.Status = status;
  799. }
  800. PortPassThroughMarshalResults(PassThroughInfo,
  801. &srb,
  802. RequestIrp,
  803. &ioStatusBlock,
  804. Direct);
  805. //
  806. // Free the sense buffer.
  807. //
  808. if (senseBuffer != NULL) {
  809. ExFreePool(senseBuffer);
  810. }
  811. return ioStatusBlock.Status;
  812. }
  813. VOID
  814. PortPassThroughMarshalResults(
  815. IN PPORT_PASSTHROUGH_INFO PassThroughInfo,
  816. IN PSCSI_REQUEST_BLOCK Srb,
  817. IN PIRP RequestIrp,
  818. IN PIO_STATUS_BLOCK IoStatusBlock,
  819. IN BOOLEAN Direct
  820. )
  821. {
  822. PAGED_CODE();
  823. //
  824. // Copy the returned values from the srb to the control structure.
  825. //
  826. PassThroughInfo->SrbControl->ScsiStatus = Srb->ScsiStatus;
  827. if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
  828. //
  829. // Set the status to success so that the data is returned.
  830. //
  831. IoStatusBlock->Status = STATUS_SUCCESS;
  832. PassThroughInfo->SrbControl->SenseInfoLength =
  833. Srb->SenseInfoBufferLength;
  834. //
  835. // Copy the sense data to the system buffer.
  836. //
  837. RtlCopyMemory(
  838. (PUCHAR)PassThroughInfo->SrbBuffer +
  839. PassThroughInfo->SrbControl->SenseInfoOffset,
  840. Srb->SenseInfoBuffer,
  841. Srb->SenseInfoBufferLength);
  842. } else {
  843. PassThroughInfo->SrbControl->SenseInfoLength = 0;
  844. }
  845. //
  846. // If the srb status is buffer underrun then set the status to success.
  847. // This insures that the data will be returned to the caller.
  848. //
  849. if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  850. IoStatusBlock->Status = STATUS_SUCCESS;
  851. }
  852. //
  853. // Set the information length
  854. //
  855. PassThroughInfo->SrbControl->DataTransferLength = Srb->DataTransferLength;
  856. if (Direct == TRUE) {
  857. RequestIrp->IoStatus.Information =
  858. PassThroughInfo->SrbControl->SenseInfoOffset +
  859. PassThroughInfo->SrbControl->SenseInfoLength;
  860. } else {
  861. if (!PassThroughInfo->SrbControl->DataIn ||
  862. PassThroughInfo->BufferOffset == 0) {
  863. RequestIrp->IoStatus.Information =
  864. PassThroughInfo->SrbControl->SenseInfoOffset +
  865. PassThroughInfo->SrbControl->SenseInfoLength;
  866. } else {
  867. RequestIrp->IoStatus.Information =
  868. PassThroughInfo->SrbControl->DataBufferOffset +
  869. PassThroughInfo->SrbControl->DataTransferLength;
  870. }
  871. }
  872. ASSERT((Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) == 0);
  873. RequestIrp->IoStatus.Status = IoStatusBlock->Status;
  874. return;
  875. }