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.

1274 lines
30 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 2002
  3. Module Name:
  4. passthru.c
  5. Abstract:
  6. This file contains routines to handle IOCTL_ATA_PASS_THROUGH
  7. Authors:
  8. Krishnan Varadarajan (krishvar)
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. This module implements ATA passthru.
  13. Revision History:
  14. --*/
  15. #include "ideport.h"
  16. #define DataIn(ataPassThrough) \
  17. (ataPassThrough->AtaFlags & ATA_FLAGS_DATA_IN)
  18. #define DataOut(ataPassThrough) \
  19. (ataPassThrough->AtaFlags & ATA_FLAGS_DATA_OUT)
  20. NTSTATUS
  21. IdeAtaPassThroughValidateInput (
  22. IN PDEVICE_OBJECT Pdo,
  23. IN PIRP Irp,
  24. IN BOOLEAN Direct
  25. );
  26. NTSTATUS
  27. IdeAtaPassThroughSyncCompletion (
  28. PDEVICE_OBJECT DeviceObject,
  29. PIRP Irp,
  30. PVOID Context
  31. );
  32. VOID
  33. IdeAtaPassThroughMarshalResults(
  34. IN PSCSI_REQUEST_BLOCK Srb,
  35. IN PATA_PASS_THROUGH_EX AtaPassThrough,
  36. IN BOOLEAN Direct,
  37. OUT PIO_STATUS_BLOCK IoStatus
  38. );
  39. #if defined (_WIN64)
  40. VOID
  41. IdeTranslateAtaPassThrough32To64(
  42. IN PATA_PASS_THROUGH_EX32 AtaPassThrough32,
  43. IN OUT PATA_PASS_THROUGH_EX AtaPassThrough64
  44. );
  45. VOID
  46. IdeTranslateAtaPassThrough64To32(
  47. IN PATA_PASS_THROUGH_EX AtaPassThrough64,
  48. IN OUT PATA_PASS_THROUGH_EX32 AtaPassThrough32
  49. );
  50. #endif
  51. #ifdef ALLOC_PRAGMA
  52. #pragma alloc_text(PAGE, IdeHandleAtaPassThroughIoctl)
  53. #pragma alloc_text(PAGE, IdeAtaPassThroughSetPortAddress)
  54. #pragma alloc_text(PAGE, IdeAtaPassThroughGetPortAddress)
  55. #pragma alloc_text(PAGE, IdeAtaPassThroughValidateInput)
  56. #pragma alloc_text(PAGE, IdeAtaPassThroughSendSynchronous)
  57. #pragma alloc_text(PAGE, IdeAtaPassThroughMarshalResults)
  58. #if defined (_WIN64)
  59. #pragma alloc_text(PAGE, IdeTranslateAtaPassThrough32To64)
  60. #pragma alloc_text(PAGE, IdeTranslateAtaPassThrough64To32)
  61. #endif
  62. #endif
  63. NTSTATUS
  64. IdeAtaPassThroughSetPortAddress (
  65. PIRP Irp,
  66. UCHAR PathId,
  67. UCHAR TargetId,
  68. UCHAR Lun
  69. )
  70. /*++
  71. Routine Description:
  72. Sets the address fields in the ataPassThrough structure embedded in
  73. the irp.
  74. Arguments:
  75. Irp : The ata passthrough irp
  76. PathId : PathId of the pdo.
  77. TargetId : Pdo's targetId.
  78. Lun : Lun represented by the pdo.
  79. Return Valud:
  80. STATUS_SUCCESS if the operation succeeded.
  81. STATUS_INVALID_PARAMETER otherwise.
  82. --*/
  83. {
  84. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  85. NTSTATUS status;
  86. ULONG requiredSize;
  87. ULONG inputLength;
  88. PAGED_CODE();
  89. inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  90. requiredSize = sizeof(ATA_PASS_THROUGH_EX);
  91. #if defined (_WIN64)
  92. if (IoIs32bitProcess(Irp)) {
  93. requiredSize = sizeof(ATA_PASS_THROUGH_EX32);
  94. }
  95. #endif
  96. if (inputLength < requiredSize) {
  97. status = STATUS_INVALID_PARAMETER;
  98. } else {
  99. PATA_PASS_THROUGH_EX ataPassThrough;
  100. ataPassThrough = Irp->AssociatedIrp.SystemBuffer;
  101. ataPassThrough->PathId = PathId;
  102. ataPassThrough->TargetId = TargetId;
  103. ataPassThrough->Lun = Lun;
  104. status = STATUS_SUCCESS;
  105. }
  106. return status;
  107. }
  108. NTSTATUS
  109. IdeAtaPassThroughGetAddress(
  110. IN PIRP Irp,
  111. OUT PUCHAR PathId,
  112. OUT PUCHAR TargetId,
  113. OUT PUCHAR Lun
  114. )
  115. /*++
  116. Routine Description:
  117. This routine retrieves the address of the device to witch the passthrough
  118. request is to be sent.
  119. Arguments:
  120. Irp - Supplies a pointer to the IRP that contains the
  121. SCSI_PASS_THROUGH structure.
  122. PathId - Pointer to the PathId of the addressed device.
  123. TargetId - Pointer to the TargetId of the addressed device.
  124. Lun - Pointer to the logical unit number of the addressed device.
  125. Return Value:
  126. Returns a status indicating the success or failure of the operation.
  127. --*/
  128. {
  129. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  130. NTSTATUS status;
  131. ULONG requiredSize;
  132. ULONG inputLength;
  133. PAGED_CODE();
  134. inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  135. requiredSize = sizeof(ATA_PASS_THROUGH_EX);
  136. #if defined (_WIN64)
  137. if (IoIs32bitProcess(Irp)) {
  138. requiredSize = sizeof(ATA_PASS_THROUGH_EX32);
  139. }
  140. #endif
  141. if (inputLength < requiredSize) {
  142. status = STATUS_INVALID_PARAMETER;
  143. } else {
  144. PATA_PASS_THROUGH_EX ataPassThrough;
  145. ataPassThrough = Irp->AssociatedIrp.SystemBuffer;
  146. *PathId = ataPassThrough->PathId;
  147. *TargetId = ataPassThrough->TargetId;
  148. *Lun = ataPassThrough->Lun;
  149. status = STATUS_SUCCESS;
  150. }
  151. return status;
  152. }
  153. NTSTATUS
  154. IdeHandleAtaPassThroughIoctl (
  155. PFDO_EXTENSION FdoExtension,
  156. PIRP RequestIrp,
  157. BOOLEAN Direct
  158. )
  159. /*++
  160. Routine Description:
  161. This routine handles IOCTL_ATA_PASS_THROUGH and its DIRECT version.
  162. Arguments:
  163. FdoExtension :
  164. RequestIrp : The pass through ioctl request
  165. Direct : Indicates whether it is direct or not.
  166. Return Value:
  167. Status of the operation.
  168. --*/
  169. {
  170. BOOLEAN dataIn;
  171. NTSTATUS status;
  172. PATA_PASS_THROUGH_EX ataPassThrough;
  173. PUCHAR passThroughBuffer;
  174. PIO_STACK_LOCATION irpStack;
  175. PPDO_EXTENSION pdoExtension;
  176. UCHAR pathId, targetId, lun;
  177. PSCSI_REQUEST_BLOCK srb;
  178. PUCHAR buffer;
  179. ULONG bufferOffset;
  180. ULONG length;
  181. ULONG pages;
  182. PIRP irp;
  183. #if defined (_WIN64)
  184. ATA_PASS_THROUGH_EX ataPassThrough64;
  185. #endif
  186. PAGED_CODE();
  187. irp = NULL;
  188. srb = NULL;
  189. pdoExtension = NULL;
  190. //
  191. // get the device address
  192. //
  193. status = IdeAtaPassThroughGetAddress (RequestIrp,
  194. &pathId,
  195. &targetId,
  196. &lun
  197. );
  198. if (!NT_SUCCESS(status)) {
  199. goto GetOut;
  200. }
  201. //
  202. // Get a reference to the pdo
  203. //
  204. pdoExtension = RefLogicalUnitExtensionWithTag(
  205. FdoExtension,
  206. pathId,
  207. targetId,
  208. lun,
  209. FALSE,
  210. RequestIrp
  211. );
  212. if (pdoExtension == NULL) {
  213. status = STATUS_INVALID_PARAMETER;
  214. goto GetOut;
  215. }
  216. //
  217. // validate the system buffer in the request irp. This comes
  218. // from user mode. So every parameter needs to be validated.
  219. //
  220. status = IdeAtaPassThroughValidateInput (pdoExtension->DeviceObject,
  221. RequestIrp,
  222. Direct
  223. );
  224. if (!NT_SUCCESS(status)) {
  225. goto GetOut;
  226. }
  227. //
  228. // the system buffer has been validated. Get a pointer to it
  229. //
  230. ataPassThrough = RequestIrp->AssociatedIrp.SystemBuffer;
  231. //
  232. // we need to keep the pointer to the system buffer since
  233. // ataPassThrough could be modified to point to a structure
  234. // allocated on the stack (in WIN64 case)
  235. //
  236. passThroughBuffer = (PUCHAR) ataPassThrough;
  237. //
  238. // If the irp is from a 32-bit app running on a 64 bit system
  239. // then we need to take into account the size difference in the
  240. // structure. Create a new 64 bit structure and copy over the
  241. // fields.
  242. //
  243. #if defined (_WIN64)
  244. if (IoIs32bitProcess(RequestIrp)) {
  245. PATA_PASS_THROUGH_EX32 ataPassThrough32;
  246. ataPassThrough32 = RequestIrp->AssociatedIrp.SystemBuffer;
  247. IdeTranslateAtaPassThrough32To64(
  248. ataPassThrough32,
  249. &ataPassThrough64
  250. );
  251. ataPassThrough = &ataPassThrough64;
  252. }
  253. #endif
  254. //
  255. // determine the transfer length and the data buffer
  256. //
  257. if (ataPassThrough->DataTransferLength == 0) {
  258. length = 0;
  259. buffer = NULL;
  260. bufferOffset = 0;
  261. } else if (Direct == TRUE) {
  262. length = (ULONG) ataPassThrough->DataTransferLength;
  263. buffer = (PUCHAR) ataPassThrough->DataBufferOffset;
  264. bufferOffset = 0;
  265. } else {
  266. length = (ULONG) ataPassThrough->DataBufferOffset +
  267. ataPassThrough->DataTransferLength;
  268. buffer = (PUCHAR) passThroughBuffer;
  269. bufferOffset = (ULONG)ataPassThrough->DataBufferOffset;
  270. }
  271. //
  272. // Check if the request is too big for the adapter.
  273. //
  274. pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  275. buffer + bufferOffset,
  276. ataPassThrough->DataTransferLength);
  277. if ((ataPassThrough->DataTransferLength != 0) &&
  278. ((pages > FdoExtension->Capabilities.MaximumPhysicalPages) ||
  279. (ataPassThrough->DataTransferLength >
  280. FdoExtension->Capabilities.MaximumTransferLength))) {
  281. status = STATUS_INVALID_PARAMETER;
  282. goto GetOut;
  283. }
  284. //
  285. // setup the irp for ata pass through. The ioctl is method_buffered,
  286. // but the data buffer could be a user mode one if it is the direct ioctl.
  287. // determine the access mode accordingly
  288. //
  289. irp = IdeAtaPassThroughSetupIrp( pdoExtension->DeviceObject,
  290. buffer,
  291. length,
  292. (Direct ? UserMode : KernelMode),
  293. DataIn(ataPassThrough) ? TRUE : FALSE
  294. );
  295. if (irp == NULL) {
  296. status = STATUS_INSUFFICIENT_RESOURCES;
  297. goto GetOut;
  298. }
  299. //
  300. // setup the srb. Use the right data offset for the databuffer.
  301. // Note that the mdl is for the whole buffer (including the header)
  302. //
  303. srb = IdeAtaPassThroughSetupSrb (pdoExtension,
  304. (buffer+bufferOffset),
  305. ataPassThrough->DataTransferLength,
  306. ataPassThrough->TimeOutValue,
  307. ataPassThrough->AtaFlags,
  308. ataPassThrough->CurrentTaskFile,
  309. ataPassThrough->PreviousTaskFile
  310. );
  311. if (srb == NULL) {
  312. status = STATUS_INSUFFICIENT_RESOURCES;
  313. goto GetOut;
  314. }
  315. //
  316. // initialize irpstack
  317. //
  318. irpStack = IoGetNextIrpStackLocation(irp);
  319. irpStack->MajorFunction = IRP_MJ_SCSI;
  320. irpStack->Parameters.Scsi.Srb = srb;
  321. srb->OriginalRequest = irp;
  322. //
  323. // send it to our pdo synchronously
  324. //
  325. status = IdeAtaPassThroughSendSynchronous (pdoExtension->DeviceObject, irp);
  326. //
  327. // set the status
  328. //
  329. RequestIrp->IoStatus.Status = status;
  330. //
  331. // marshal the results
  332. //
  333. IdeAtaPassThroughMarshalResults (srb,
  334. ataPassThrough,
  335. Direct,
  336. &(RequestIrp->IoStatus)
  337. );
  338. //
  339. // copy back the results to the original 32 bit
  340. // structure if necessary
  341. //
  342. #if defined (_WIN64)
  343. if (IoIs32bitProcess(RequestIrp)) {
  344. PATA_PASS_THROUGH_EX32 ataPassThrough32;
  345. ataPassThrough32 = RequestIrp->AssociatedIrp.SystemBuffer;
  346. IdeTranslateAtaPassThrough64To32 (
  347. ataPassThrough,
  348. ataPassThrough32
  349. );
  350. }
  351. #endif
  352. //
  353. // return the status of the operation
  354. //
  355. status = RequestIrp->IoStatus.Status;
  356. GetOut:
  357. if (irp) {
  358. IdeAtaPassThroughFreeIrp(irp);
  359. irp = NULL;
  360. }
  361. if (srb) {
  362. IdeAtaPassThroughFreeSrb(srb);
  363. srb = NULL;
  364. }
  365. if (pdoExtension) {
  366. UnrefLogicalUnitExtensionWithTag(
  367. FdoExtension,
  368. pdoExtension,
  369. RequestIrp
  370. );
  371. pdoExtension = NULL;
  372. }
  373. return status;
  374. }
  375. NTSTATUS
  376. IdeAtaPassThroughValidateInput (
  377. IN PDEVICE_OBJECT Pdo,
  378. IN PIRP Irp,
  379. IN BOOLEAN Direct
  380. )
  381. /*++
  382. Routine Description:
  383. This routine validates the caller-supplied data and initializes the
  384. PORT_PASSTHROUGH_INFO structure.
  385. Arguments:
  386. PassThroughInfo - Supplies a pointer to a SCSI_PASSTHROUGH_INFO structure.
  387. Irp - Supplies a pointer to the IRP.
  388. Direct - Supplies a boolean that indicates whether this is a
  389. SCSI_PASS_THROUGH_DIRECT request.
  390. Return Value:
  391. Returns a status indicating the success or failure of the operation.
  392. --*/
  393. {
  394. NTSTATUS status;
  395. ULONG outputLength;
  396. ULONG inputLength;
  397. PIO_STACK_LOCATION irpStack;
  398. PATA_PASS_THROUGH_EX ataPassThroughEx;
  399. #if defined (_WIN64)
  400. ATA_PASS_THROUGH_EX ataPassThrough64;
  401. #endif
  402. PAGED_CODE();
  403. irpStack = IoGetCurrentIrpStackLocation(Irp);
  404. outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  405. inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  406. //
  407. // For WIN64, a passthrough request from a 32-bit application requires
  408. // us to perform a translation on the supplied SCSI_PASS_THROUGH structure.
  409. // This is required because the layout of the 32-bit structure does not
  410. // match that of a 64-bit structure. In this case, we translate the
  411. // supplied 32-bit structure into a stack-allocated 64-bit structure which
  412. // will be used to process the pass through request.
  413. //
  414. #if defined (_WIN64)
  415. if (IoIs32bitProcess(Irp)) {
  416. PATA_PASS_THROUGH_EX32 ataPassThrough32;
  417. //
  418. // the struct should atleast be as big as ATA_PASS_THROUGH_EX32
  419. //
  420. if (inputLength < sizeof(ATA_PASS_THROUGH_EX32)){
  421. return STATUS_INVALID_PARAMETER;
  422. }
  423. ataPassThrough32 = Irp->AssociatedIrp.SystemBuffer;
  424. //
  425. // The length field should match the size
  426. // of the structure
  427. //
  428. if (Direct == FALSE) {
  429. if (ataPassThrough32->Length !=
  430. sizeof(ATA_PASS_THROUGH_EX32)) {
  431. return STATUS_REVISION_MISMATCH;
  432. }
  433. } else {
  434. if (ataPassThrough32->Length !=
  435. sizeof(ATA_PASS_THROUGH_DIRECT32)) {
  436. return STATUS_REVISION_MISMATCH;
  437. }
  438. }
  439. //
  440. // translate the structure to the 64 bit version
  441. //
  442. IdeTranslateAtaPassThrough32To64(
  443. ataPassThrough32,
  444. &ataPassThrough64
  445. );
  446. ataPassThroughEx = &ataPassThrough64;
  447. } else {
  448. #endif
  449. //
  450. // the struct should atleast be as big as ATA_PASS_THROUGH_EX32
  451. //
  452. if (inputLength < sizeof(ATA_PASS_THROUGH_EX)){
  453. return(STATUS_INVALID_PARAMETER);
  454. }
  455. ataPassThroughEx = Irp->AssociatedIrp.SystemBuffer;
  456. //
  457. // The length field should match the size
  458. // of the structure
  459. //
  460. if (Direct == FALSE) {
  461. if (ataPassThroughEx->Length !=
  462. sizeof(ATA_PASS_THROUGH_EX)) {
  463. return STATUS_REVISION_MISMATCH;
  464. }
  465. } else {
  466. if (ataPassThroughEx->Length !=
  467. sizeof(ATA_PASS_THROUGH_DIRECT)) {
  468. return STATUS_REVISION_MISMATCH;
  469. }
  470. }
  471. #if defined (_WIN64)
  472. }
  473. #endif
  474. if (!Direct) {
  475. //
  476. // Data buffer offset should be greater than the size of the pass
  477. // through structure.
  478. //
  479. if (ataPassThroughEx->Length > ataPassThroughEx->DataBufferOffset &&
  480. ataPassThroughEx->DataTransferLength != 0) {
  481. return STATUS_INVALID_PARAMETER;
  482. }
  483. //
  484. // If this command is sending data to the device. Make sure the data
  485. // buffer lies entirely within the supplied input buffer.
  486. //
  487. if (DataOut(ataPassThroughEx)) {
  488. if ((ataPassThroughEx->DataBufferOffset > inputLength) ||
  489. ((ataPassThroughEx->DataBufferOffset +
  490. ataPassThroughEx->DataTransferLength) >
  491. inputLength)) {
  492. return STATUS_INVALID_PARAMETER;
  493. }
  494. }
  495. //
  496. // If this command is retrieving data from the device, make sure the
  497. // data buffer lies entirely within the supplied output buffer.
  498. //
  499. if (DataIn(ataPassThroughEx)) {
  500. if ((ataPassThroughEx->DataBufferOffset > outputLength) ||
  501. ((ataPassThroughEx->DataBufferOffset +
  502. ataPassThroughEx->DataTransferLength) >
  503. outputLength)) {
  504. return STATUS_INVALID_PARAMETER;
  505. }
  506. }
  507. } else {
  508. //
  509. // Make sure the databuffer is properly aligned.
  510. //
  511. if (ataPassThroughEx->DataBufferOffset &
  512. Pdo->AlignmentRequirement) {
  513. return STATUS_INVALID_PARAMETER;
  514. }
  515. }
  516. //
  517. // Validate the specified timeout value.
  518. //
  519. if (ataPassThroughEx->TimeOutValue == 0 ||
  520. ataPassThroughEx->TimeOutValue > 30 * 60 * 60) {
  521. return STATUS_INVALID_PARAMETER;
  522. }
  523. return STATUS_SUCCESS;
  524. }
  525. PSCSI_REQUEST_BLOCK
  526. IdeAtaPassThroughSetupSrb (
  527. PPDO_EXTENSION PdoExtension,
  528. PVOID DataBuffer,
  529. ULONG DataBufferLength,
  530. ULONG TimeOutValue,
  531. ULONG AtaFlags,
  532. PUCHAR CurrentTaskFile,
  533. PUCHAR PreviousTaskFile
  534. )
  535. /*++
  536. Routine Description:
  537. Builds an SRB for ATA PASS THROUGH.
  538. Arguments:
  539. PdoExtension : The pdo which the request is destined for
  540. DataBuffer : Pointer to the data buffer.
  541. DataBufferLength : The size of the data buffer
  542. TimeOutValue: The request timeout value
  543. AtaFlags : Specifies the flags for the request
  544. CurrentTaskFile : the current ata registers
  545. PreviousTaskFile: previous values for 48 bit LBA feature set
  546. Return Value:
  547. Pointer to an SRB if one was allocated successfully, NULL otherwise.
  548. --*/
  549. {
  550. PSCSI_REQUEST_BLOCK srb = NULL;
  551. PIDEREGS pIdeReg;
  552. //
  553. // allocate the srb
  554. //
  555. srb = ExAllocatePool (NonPagedPool, sizeof (SCSI_REQUEST_BLOCK));
  556. if (srb == NULL) {
  557. return NULL;
  558. }
  559. //
  560. // Fill in the srb.
  561. //
  562. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  563. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  564. srb->Function = SRB_FUNCTION_ATA_PASS_THROUGH_EX;
  565. srb->SrbStatus = SRB_STATUS_PENDING;
  566. srb->PathId = PdoExtension->PathId;
  567. srb->TargetId = PdoExtension->TargetId;
  568. srb->Lun = PdoExtension->Lun;
  569. srb->SenseInfoBufferLength = 0;
  570. srb->TimeOutValue = TimeOutValue;
  571. if (DataBufferLength != 0) {
  572. if (AtaFlags & ATA_FLAGS_DATA_IN) {
  573. srb->SrbFlags |= SRB_FLAGS_DATA_IN;
  574. }
  575. if (AtaFlags & ATA_FLAGS_DATA_OUT) {
  576. srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
  577. }
  578. }
  579. srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
  580. srb->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
  581. srb->DataTransferLength = DataBufferLength;
  582. srb->DataBuffer = DataBuffer;
  583. srb->SenseInfoBuffer = NULL;
  584. MARK_SRB_AS_PIO_CANDIDATE(srb);
  585. RtlCopyMemory(srb->Cdb,
  586. CurrentTaskFile,
  587. 8
  588. );
  589. RtlCopyMemory((PUCHAR) (&srb->Cdb[8]),
  590. PreviousTaskFile,
  591. 8
  592. );
  593. pIdeReg = (PIDEREGS) (srb->Cdb);
  594. if (AtaFlags & ATA_FLAGS_DRDY_REQUIRED) {
  595. pIdeReg->bReserved |= ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
  596. }
  597. return srb;
  598. }
  599. PIRP
  600. IdeAtaPassThroughSetupIrp (
  601. PDEVICE_OBJECT DeviceObject,
  602. PVOID DataBuffer,
  603. ULONG DataBufferLength,
  604. KPROCESSOR_MODE AccessMode,
  605. BOOLEAN DataIn
  606. )
  607. /*++
  608. Routine Description:
  609. Builds an Irp to handle ata pass through.
  610. Arguments:
  611. DeviceObject : The Pdo.
  612. DataBuffer : Pointer to the data buffer.
  613. DataBufferLength: its size
  614. Access Mode: KernelMode or UserMode
  615. DataIn: indicates the direction of transfer
  616. Return Value:
  617. PIRP if one was allocated successfully, NULL otherwise.
  618. --*/
  619. {
  620. PIRP irp = NULL;
  621. NTSTATUS status = STATUS_SUCCESS;
  622. //
  623. // allocate the irp
  624. //
  625. irp = IoAllocateIrp (
  626. (CCHAR) (DeviceObject->StackSize),
  627. FALSE
  628. );
  629. if (irp == NULL) {
  630. status = STATUS_INSUFFICIENT_RESOURCES;
  631. goto GetOut;
  632. }
  633. //
  634. // allocate the mdl if needed
  635. //
  636. if (DataBufferLength != 0) {
  637. ASSERT(irp);
  638. irp->MdlAddress = IoAllocateMdl( DataBuffer,
  639. DataBufferLength,
  640. FALSE,
  641. FALSE,
  642. (PIRP) NULL
  643. );
  644. if (irp->MdlAddress == NULL) {
  645. status = STATUS_INSUFFICIENT_RESOURCES;
  646. goto GetOut;
  647. }
  648. //
  649. // lock the pages
  650. //
  651. try {
  652. MmProbeAndLockPages( irp->MdlAddress,
  653. AccessMode,
  654. (LOCK_OPERATION) (DataIn ? IoWriteAccess : IoReadAccess)
  655. );
  656. } except(EXCEPTION_EXECUTE_HANDLER) {
  657. if (irp->MdlAddress != NULL) {
  658. IoFreeMdl( irp->MdlAddress );
  659. irp->MdlAddress = NULL;
  660. }
  661. }
  662. if (irp->MdlAddress == NULL) {
  663. status = STATUS_INSUFFICIENT_RESOURCES;
  664. goto GetOut;
  665. } else {
  666. //
  667. // Flush the data buffer for output. This will insure that
  668. // the data is written back to memory.
  669. //
  670. KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
  671. }
  672. }
  673. status = STATUS_SUCCESS;
  674. GetOut:
  675. if (!NT_SUCCESS(status)) {
  676. if (irp) {
  677. if (irp->MdlAddress) {
  678. //
  679. // if mdladdress is set then the probeandlock
  680. // succeeded. So unlock it now.
  681. //
  682. MmUnlockPages(irp->MdlAddress);
  683. IoFreeMdl( irp->MdlAddress );
  684. irp->MdlAddress = NULL;
  685. }
  686. IoFreeIrp(irp);
  687. irp = NULL;
  688. }
  689. }
  690. return irp;
  691. }
  692. VOID
  693. IdeAtaPassThroughFreeIrp (
  694. PIRP Irp
  695. )
  696. /*++
  697. Routine Description:
  698. Free the irp and mdl allocated by IdeAtaPassThroughSetupIrp
  699. Arguments:
  700. Irp: Irp to be freed.
  701. Return Value:
  702. None.
  703. --*/
  704. {
  705. ASSERT(Irp);
  706. if (Irp->MdlAddress) {
  707. MmUnlockPages(Irp->MdlAddress);
  708. IoFreeMdl(Irp->MdlAddress);
  709. }
  710. IoFreeIrp(Irp);
  711. return;
  712. }
  713. VOID
  714. IdeAtaPassThroughFreeSrb (
  715. PSCSI_REQUEST_BLOCK Srb
  716. )
  717. /*++
  718. Routine Description:
  719. Free the srb allocated by IdeAtaPassThroughSetupSrb
  720. Arguments:
  721. Srb: The srb to be freed.
  722. Return Value:
  723. None
  724. --*/
  725. {
  726. ASSERT(Srb);
  727. ExFreePool(Srb);
  728. return;
  729. }
  730. NTSTATUS
  731. IdeAtaPassThroughSyncCompletion (
  732. PDEVICE_OBJECT DeviceObject,
  733. PIRP Irp,
  734. PVOID Context
  735. )
  736. /*++
  737. Routine Description:
  738. The completion routine for IdeAtaPassThroughSendSynchronous. It
  739. just signals the event.
  740. Arguments:
  741. DeviceObject : Not used.
  742. Irp : Not Used
  743. Context : Event to be signalled
  744. Return Value:
  745. STATUS_MORE_PROCESSING_REQUIRED always.
  746. --*/
  747. {
  748. PKEVENT event = Context;
  749. KeSetEvent (event, 0, FALSE);
  750. return STATUS_MORE_PROCESSING_REQUIRED;
  751. }
  752. NTSTATUS
  753. IdeAtaPassThroughSendSynchronous (
  754. PDEVICE_OBJECT DeviceObject,
  755. PIRP Irp
  756. )
  757. /*++
  758. Routine Description:
  759. Sends the irp synchronously to the PDO
  760. Arguments:
  761. DeviceObject : The pdo
  762. Return Value:
  763. The irp's status
  764. --*/
  765. {
  766. KEVENT event;
  767. KeInitializeEvent(&event,
  768. NotificationEvent,
  769. FALSE);
  770. IoSetCompletionRoutine (Irp,
  771. IdeAtaPassThroughSyncCompletion,
  772. &event,
  773. TRUE,
  774. TRUE,
  775. TRUE
  776. );
  777. IoCallDriver(DeviceObject, Irp);
  778. KeWaitForSingleObject (&event,
  779. Executive,
  780. KernelMode,
  781. FALSE,
  782. NULL
  783. );
  784. return Irp->IoStatus.Status;
  785. }
  786. VOID
  787. IdeAtaPassThroughMarshalResults(
  788. IN PSCSI_REQUEST_BLOCK Srb,
  789. IN PATA_PASS_THROUGH_EX AtaPassThroughEx,
  790. IN BOOLEAN Direct,
  791. OUT PIO_STATUS_BLOCK IoStatus
  792. )
  793. /*++
  794. Routine Description:
  795. Fills in the IoStatus block with the appropriate status and information
  796. length. It also updates certain fields in the atapassthroughEx structure.
  797. Arguments:
  798. Srb: The pass through srb.
  799. AtaPassThroughEx : the pass through structure.
  800. Direct : True if it is a direct ioctl.
  801. IoStatus : The Io status block that needs to be filled in.
  802. Return Value:
  803. None
  804. --*/
  805. {
  806. PAGED_CODE();
  807. //
  808. // copy over the task file registers
  809. //
  810. RtlCopyMemory(AtaPassThroughEx->CurrentTaskFile,
  811. Srb->Cdb,
  812. 8
  813. );
  814. RtlCopyMemory(AtaPassThroughEx->PreviousTaskFile,
  815. (PUCHAR) (&Srb->Cdb[8]),
  816. 8
  817. );
  818. //
  819. // zero out the reserved register as it is used by the
  820. // port driver
  821. //
  822. AtaPassThroughEx->CurrentTaskFile[7] = 0;
  823. AtaPassThroughEx->PreviousTaskFile[7] = 0;
  824. //
  825. // If the srb status is buffer underrun then set the status to success.
  826. // This insures that the data will be returned to the caller.
  827. //
  828. if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  829. IoStatus->Status = STATUS_SUCCESS;
  830. }
  831. //
  832. // Set the information length
  833. //
  834. AtaPassThroughEx->DataTransferLength = Srb->DataTransferLength;
  835. if (Direct == TRUE) {
  836. //
  837. // the data is transferred directly to the supplied data buffer
  838. //
  839. IoStatus->Information = AtaPassThroughEx->Length;
  840. } else {
  841. //
  842. // actual data is returned
  843. //
  844. if (DataIn(AtaPassThroughEx) &&
  845. AtaPassThroughEx->DataBufferOffset != 0) {
  846. IoStatus->Information =
  847. AtaPassThroughEx->DataBufferOffset +
  848. AtaPassThroughEx->DataTransferLength;
  849. } else {
  850. IoStatus->Information = AtaPassThroughEx->Length;
  851. }
  852. }
  853. ASSERT((Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) == 0);
  854. return;
  855. }
  856. #if defined (_WIN64)
  857. VOID
  858. IdeTranslateAtaPassThrough32To64(
  859. IN PATA_PASS_THROUGH_EX32 AtaPassThrough32,
  860. IN OUT PATA_PASS_THROUGH_EX AtaPassThrough64
  861. )
  862. /*++
  863. Routine Description:
  864. This function performs that marshaling.
  865. Arguments:
  866. ataPassThrough32 - Supplies a pointer to a 32-bit ATA_PASS_THROUGH
  867. struct.
  868. ataPassThrough64 - Supplies a pointer to a 64-bit ATA_PASS_THROUGH
  869. structure, into which we'll copy the marshaled
  870. 32-bit data.
  871. Return Value:
  872. None.
  873. --*/
  874. {
  875. PAGED_CODE();
  876. //
  877. // Copy the first set of fields out of the 32-bit structure. These
  878. // fields all line up between the 32 & 64 bit versions.
  879. //
  880. // Note that we do NOT adjust the length in the srbControl. This is to
  881. // allow the calling routine to compare the length of the actual
  882. // control area against the offsets embedded within.
  883. //
  884. RtlCopyMemory(AtaPassThrough64,
  885. AtaPassThrough32,
  886. FIELD_OFFSET(ATA_PASS_THROUGH_EX, DataBufferOffset)
  887. );
  888. //
  889. // Copy over the Taskfile.
  890. //
  891. RtlCopyMemory(AtaPassThrough64->CurrentTaskFile,
  892. AtaPassThrough32->CurrentTaskFile,
  893. 8 * sizeof(UCHAR)
  894. );
  895. RtlCopyMemory(AtaPassThrough64->PreviousTaskFile,
  896. AtaPassThrough32->PreviousTaskFile,
  897. 8 * sizeof(UCHAR)
  898. );
  899. //
  900. // Copy the fields that follow the ULONG_PTR.
  901. //
  902. AtaPassThrough64->DataBufferOffset =
  903. (ULONG_PTR)AtaPassThrough32->DataBufferOffset;
  904. return;
  905. }
  906. VOID
  907. IdeTranslateAtaPassThrough64To32(
  908. IN PATA_PASS_THROUGH_EX AtaPassThrough64,
  909. IN OUT PATA_PASS_THROUGH_EX32 AtaPassThrough32
  910. )
  911. /*++
  912. Routine Description:
  913. This function marshals a 64-bit version of the structure back into a
  914. 32-bit version.
  915. Arguments:
  916. atapassthrough64 - Supplies a pointer to a 64-bit ATA_PASS_THROUGH
  917. struct.
  918. ataPassThrough32 - Supplies the address of a pointer to a 32-bit
  919. ATA_PASS_THROUGH structure, into which we'll copy the
  920. marshaled 64-bit data.
  921. Return Value:
  922. None.
  923. --*/
  924. {
  925. PAGED_CODE();
  926. //
  927. // Copy back the fields through the data offsets.
  928. //
  929. RtlCopyMemory(AtaPassThrough32,
  930. AtaPassThrough64,
  931. FIELD_OFFSET(ATA_PASS_THROUGH_EX, DataBufferOffset));
  932. //
  933. // copy over the task file
  934. //
  935. RtlCopyMemory(AtaPassThrough32->CurrentTaskFile,
  936. AtaPassThrough64->CurrentTaskFile,
  937. 8 * sizeof(UCHAR)
  938. );
  939. RtlCopyMemory(AtaPassThrough32->PreviousTaskFile,
  940. AtaPassThrough64->PreviousTaskFile,
  941. 8 * sizeof(UCHAR)
  942. );
  943. return;
  944. }
  945. #endif