ReactOS 0.4.16-dev-1558-g67e4713
sptilib.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: ATA and SCSI Pass Through Interface for storage drivers
5 * COPYRIGHT: Copyright 2025 Dmitry Borisov <di.sean@protonmail.com>
6 */
7
8/*
9 * This library provides helper code for handling ATA and SCSI Pass Through IOCTLs.
10 * Typically, these IRPs come from user-mode applications.
11 * The handler will translate the IOCTL into an SRB and send it to the PDO.
12 */
13
14/* INCLUDES *******************************************************************/
15
16#include <ntddk.h>
17#include <ntintsafe.h>
18#include <pseh/pseh2.h>
19#include <scsi.h>
20#include <ntddscsi.h>
21
22#define NDEBUG
23#include <debug.h>
24
25#include "sptilib.h"
26#include "sptilibp.h"
27
28/* PRIVATE FUNCTIONS **********************************************************/
29
30_At_(IrpContext->Srb.SenseInfoBuffer, __drv_freesMem(Mem))
31static
32CODE_SEG("PAGE")
33VOID
34SptiFreeIrpContext(
36{
37 PIRP Irp;
38
39 PAGED_CODE();
40
41 ASSERT(IrpContext);
42
43 Irp = IrpContext->Irp;
44 if (Irp)
45 {
46 if (Irp->MdlAddress)
47 {
48 MmUnlockPages(Irp->MdlAddress);
49 IoFreeMdl(Irp->MdlAddress);
50 }
51 Irp->MdlAddress = NULL;
53 }
54
55 if (IrpContext->Srb.SenseInfoBuffer)
56 ExFreePoolWithTag(IrpContext->Srb.SenseInfoBuffer, TAG_SPTI);
57
58 ExFreePoolWithTag(IrpContext, TAG_SPTI);
59}
60
61static IO_COMPLETION_ROUTINE SptiCompletionRoutine;
62static
68 _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
69{
71
72 if (Irp->PendingReturned)
74
76}
77
79static
80CODE_SEG("PAGE")
82SptiCreateIrpContext(
85 _In_ PVOID DataBuffer,
87 _In_ BOOLEAN IsDirectMemoryAccess,
88 _In_ BOOLEAN IsBufferReadAccess)
89{
90 PPASSTHROUGH_IRP_CONTEXT IrpContext;
91 PIRP Irp;
92 PIO_STACK_LOCATION IoStack;
93
94 PAGED_CODE();
95
96 IrpContext = ExAllocatePoolZero(NonPagedPool, sizeof(*IrpContext), TAG_SPTI);
97 if (!IrpContext)
98 return NULL;
99
100 IrpContext->Irp = Irp = IoAllocateIrp(DeviceObject->StackSize, 0);
101 if (!Irp)
102 goto Cleanup;
103
104 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
105
106 if (DataBuffer)
107 {
108 if (!IoAllocateMdl(DataBuffer, DataBufferLength, FALSE, FALSE, Irp))
109 goto Cleanup;
110 ASSERT(Irp->MdlAddress);
111
113 {
114 MmProbeAndLockPages(Irp->MdlAddress,
115 IsDirectMemoryAccess ? OriginalIrp->RequestorMode : KernelMode,
116 IsBufferReadAccess ? IoReadAccess : IoWriteAccess);
117 }
119 {
120 _SEH2_YIELD(goto Cleanup);
121 }
122 _SEH2_END;
123 }
124
127 IrpContext->Srb.OriginalRequest = Irp;
128 IrpContext->Srb.DataBuffer = DataBuffer;
131
134 IoStack->MajorFunction = IRP_MJ_SCSI;
135 IoStack->Parameters.Scsi.Srb = &IrpContext->Srb;
136
137 return IrpContext;
138
139Cleanup:
140 DPRINT1("Failed to create IRP\n");
141 SptiFreeIrpContext(IrpContext);
142 return NULL;
143}
144
145static
146CODE_SEG("PAGE")
147VOID
149 _In_ PIRP Irp)
150{
152 ULONG OutputBufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
153 ULONG InputBufferLength = IoStack->Parameters.DeviceIoControl.InputBufferLength;
154
155 PAGED_CODE();
156
158 {
159 ULONG_PTR BufferStart = (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer + InputBufferLength;
161 }
162}
163
164static
165CODE_SEG("PAGE")
170{
171 PIRP Irp = IrpContext->Irp;
174
175 PAGED_CODE();
176
178
179 // TODO: Send the IRP in an asynchronous way (do not block the user app thread)
181
184 &Event,
185 TRUE,
186 TRUE,
187 TRUE);
188
190 if (Status == STATUS_PENDING)
191 {
193 Status = Irp->IoStatus.Status;
194 }
195
196 return Status;
197}
198
200static
201CODE_SEG("PAGE")
203SptiSrbAppendSenseBuffer(
206{
207 PAGED_CODE();
208
209 if (BufferSize == 0)
210 {
212 return STATUS_SUCCESS;
213 }
214
217 TAG_SPTI);
220
222
224}
225
226static
227CODE_SEG("PAGE")
228VOID
230 _Out_ CDB* __restrict Cdb,
231 _In_ UCHAR* __restrict TaskFile,
232 _In_ USHORT AtaFlags)
233{
235
236 PAGED_CODE();
237
239
240 Cdb->ATA_PASSTHROUGH16.Features7_0 = TaskFile[8 + 0];
241 Cdb->ATA_PASSTHROUGH16.SectorCount7_0 = TaskFile[8 + 1];
242 Cdb->ATA_PASSTHROUGH16.LbaLow7_0 = TaskFile[8 + 2];
243 Cdb->ATA_PASSTHROUGH16.LbaMid7_0 = TaskFile[8 + 3];
244 Cdb->ATA_PASSTHROUGH16.LbaHigh7_0 = TaskFile[8 + 4];
245 Cdb->ATA_PASSTHROUGH16.Device = TaskFile[8 + 5];
246 Cdb->ATA_PASSTHROUGH16.Command = TaskFile[8 + 6];
247
248 if (AtaFlags & ATA_FLAGS_48BIT_COMMAND)
249 {
250 Cdb->ATA_PASSTHROUGH16.Features15_8 = TaskFile[0];
251 Cdb->ATA_PASSTHROUGH16.SectorCount15_8 = TaskFile[1];
252 Cdb->ATA_PASSTHROUGH16.LbaLow15_8 = TaskFile[2];
253 Cdb->ATA_PASSTHROUGH16.LbaMid15_8 = TaskFile[3];
254 Cdb->ATA_PASSTHROUGH16.LbaHigh15_8 = TaskFile[4];
255
256 Cdb->ATA_PASSTHROUGH16.Extend = 1;
257 }
258
259 /* Enable the check condition to get ATA fields from the device */
260 Cdb->ATA_PASSTHROUGH16.CkCond = 1;
261
262 if (AtaFlags & (ATA_FLAGS_DATA_IN | ATA_FLAGS_DATA_OUT))
263 {
264 Cdb->ATA_PASSTHROUGH16.TLength = 3;
265
266 if (AtaFlags & ATA_FLAGS_DATA_IN)
267 Cdb->ATA_PASSTHROUGH16.TDir = 1;
268 }
269
270 if (AtaFlags & ATA_FLAGS_USE_DMA)
271 {
273 }
274 else
275 {
276 if (AtaFlags & (ATA_FLAGS_DATA_IN | ATA_FLAGS_DATA_OUT))
277 {
278 if (AtaFlags & ATA_FLAGS_DATA_IN)
280 else
282 }
283 else
284 {
286 }
287 }
288 Cdb->ATA_PASSTHROUGH16.Protocol = Protocol;
289}
290
291static
292CODE_SEG("PAGE")
295 _In_ SCSI_REQUEST_BLOCK* __restrict Srb,
296 _In_ DESCRIPTOR_SENSE_DATA* __restrict SenseData,
297 _Out_ UCHAR* __restrict TaskFile)
298{
299 BOOLEAN WasCheckCondition = FALSE;
300
301 PAGED_CODE();
302
304 return WasCheckCondition;
305
306 if (SenseData->ErrorCode == SCSI_SENSE_ERRORCODE_DESCRIPTOR_CURRENT)
307 {
309
310 Descriptor = (PSCSI_SENSE_DESCRIPTOR_ATA_STATUS_RETURN)&SenseData->DescriptorBuffer[0];
311
313 {
314 TaskFile[8 + 0] = Descriptor->Error;
315 TaskFile[8 + 1] = Descriptor->SectorCount7_0;
316 TaskFile[8 + 2] = Descriptor->LbaLow7_0;
317 TaskFile[8 + 3] = Descriptor->LbaMid7_0;
318 TaskFile[8 + 4] = Descriptor->LbaHigh7_0;
319 TaskFile[8 + 5] = Descriptor->Device;
320 TaskFile[8 + 6] = Descriptor->Status;
321
322 if (Descriptor->Extend)
323 {
324 TaskFile[1] = Descriptor->SectorCount15_8;
325 TaskFile[2] = Descriptor->LbaLow15_8;
326 TaskFile[3] = Descriptor->LbaMid15_8;
327 TaskFile[4] = Descriptor->LbaHigh15_8;
328 }
329 }
330 }
331
332 /*
333 * The check condition bit will cause the APT command to return an error upon completion.
334 * We should determine if there was a real error or not.
335 */
337 (SenseData->SenseKey == SCSI_SENSE_RECOVERED_ERROR) &&
338 (SenseData->AdditionalSenseCode == SCSI_ADSENSE_NO_SENSE) &&
339 (SenseData->AdditionalSenseCodeQualifier ==
341 {
342 WasCheckCondition = TRUE;
343 }
344
345 return WasCheckCondition;
346}
347
348static
349CODE_SEG("PAGE")
352 _Out_ SCSI_REQUEST_BLOCK* __restrict Srb,
353 _In_ ATA_PASS_THROUGH_EX* __restrict Apt,
354 _In_ PUCHAR TaskFile)
355{
357
358 PAGED_CODE();
359
360 Status = SptiSrbAppendSenseBuffer(Srb,
363 if (!NT_SUCCESS(Status))
364 return Status;
365
366 Srb->CdbLength = RTL_FIELD_SIZE(CDB, ATA_PASSTHROUGH16);
367 Srb->TimeOutValue = Apt->TimeOutValue;
368
369 Srb->PathId = Apt->PathId;
370 Srb->TargetId = Apt->TargetId;
371 Srb->Lun = Apt->Lun;
372
373 if (Apt->AtaFlags & ATA_FLAGS_DATA_IN)
375 if (Apt->AtaFlags & ATA_FLAGS_DATA_OUT)
377
378 SptiTranslateTaskFileToCdb((PCDB)Srb->Cdb, TaskFile, Apt->AtaFlags);
379 return STATUS_SUCCESS;
380}
381
382static
383CODE_SEG("PAGE")
387 _In_ PIRP Irp,
388 _In_ PIO_STACK_LOCATION IoStack,
389 _In_ BOOLEAN IsDirectMemoryAccess,
391 _In_ ULONG MaximumPhysicalPages,
393 _Out_ PPASSTHROUGH_DATA AptData,
394 _Out_ PUCHAR* TaskFile,
395 _Out_ PVOID* DataBuffer)
396{
397 ULONG StructSize;
398 BOOLEAN IsNativeStructSize;
399
400 PAGED_CODE();
401
402#if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
403 if (IoIs32bitProcess(Irp))
404 {
405 StructSize = sizeof(ATA_PASS_THROUGH_EX32);
406 *TaskFile = (PVOID)((ULONG_PTR)Apt + FIELD_OFFSET(ATA_PASS_THROUGH_EX32, PreviousTaskFile));
407 IsNativeStructSize = FALSE;
408 }
409 else
410#endif
411 {
412 StructSize = sizeof(ATA_PASS_THROUGH_EX);
413 *TaskFile = (PVOID)((ULONG_PTR)Apt + FIELD_OFFSET(ATA_PASS_THROUGH_EX, PreviousTaskFile));
414 IsNativeStructSize = TRUE;
415 }
416
417 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < StructSize)
418 {
419 DPRINT1("Buffer too small %lu/%lu\n",
420 IoStack->Parameters.DeviceIoControl.InputBufferLength, StructSize);
422 }
423
424 if (Apt->Length != StructSize)
425 {
426 DPRINT1("Unknown structure size %lu\n", StructSize);
428 }
429
430 if (Apt->DataTransferLength > MaximumTransferLength)
431 {
432 DPRINT1("Too large transfer %lu/%lu\n", Apt->DataTransferLength, MaximumTransferLength);
434 }
435
436 if (BYTES_TO_PAGES(Apt->DataTransferLength) > MaximumPhysicalPages)
437 {
438 DPRINT1("Too large transfer %lu/%lu pages\n",
439 BYTES_TO_PAGES(Apt->DataTransferLength), MaximumPhysicalPages);
441 }
442
443 /* Retrieve the data buffer or the data buffer offset */
444#if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
445 AptData->Buffer = NULL;
446 RtlCopyMemory(AptData,
447 (PVOID)((ULONG_PTR)Apt + FIELD_OFFSET(ATA_PASS_THROUGH_EX, DataBufferOffset)),
448 IsNativeStructSize ? sizeof(PVOID) : sizeof(ULONG32));
449#else
450 DBG_UNREFERENCED_LOCAL_VARIABLE(IsNativeStructSize);
451
452 AptData->BufferOffset = Apt->DataBufferOffset;
453#endif
454
455 if (Apt->DataTransferLength != 0)
456 {
457 if (IsDirectMemoryAccess)
458 *DataBuffer = AptData->Buffer;
459 else
460 *DataBuffer = (PVOID)((ULONG_PTR)Apt + AptData->BufferOffset);
461 }
462 else
463 {
464 *DataBuffer = NULL;
465 }
466
467 // FIXME: Validate the command opcode
468
469 if (*(PULONG_PTR)DataBuffer & DeviceObject->AlignmentRequirement)
470 {
471 DPRINT1("Unaligned data buffer %p:%lx\n",
472 (PVOID)*(PULONG_PTR)DataBuffer, DeviceObject->AlignmentRequirement);
474 }
475
476 if (Apt->DataTransferLength & DeviceObject->AlignmentRequirement)
477 {
478 DPRINT1("Unaligned data transfer length %lx:%lx\n",
479 Apt->DataTransferLength, DeviceObject->AlignmentRequirement);
481 }
482
483 if ((Apt->AtaFlags & (ATA_FLAGS_DATA_IN | ATA_FLAGS_DATA_OUT)) &&
484 (Apt->DataTransferLength == 0))
485 {
486 DPRINT1("Data buffer too small\n");
488 }
489
490 if (Apt->TimeOutValue < PASSTHROUGH_CMD_TIMEOUT_MIN_SEC ||
491 Apt->TimeOutValue > PASSTHROUGH_CMD_TIMEOUT_MAX_SEC)
492 {
493 DPRINT1("Invalid timeout value %lu\n", Apt->TimeOutValue);
495 }
496
497 if (!IsDirectMemoryAccess)
498 {
499 ULONG_PTR DataBufferEnd;
501
502 Status = RtlULongPtrAdd(AptData->BufferOffset, Apt->DataTransferLength, &DataBufferEnd);
503 if (!NT_SUCCESS(Status))
504 {
505 DPRINT1("Invalid data buffer offset\n");
506 return Status;
507 }
508
509 if ((Apt->Length > AptData->BufferOffset) && (Apt->DataTransferLength != 0))
510 {
511 DPRINT1("Data buffer overlaps APT\n");
513 }
514
515 if ((Apt->AtaFlags & ATA_FLAGS_DATA_IN) &&
516 (DataBufferEnd > IoStack->Parameters.DeviceIoControl.OutputBufferLength))
517 {
518 DPRINT1("Data buffer outside of available space\n");
520 }
521
522 if ((Apt->AtaFlags & ATA_FLAGS_DATA_OUT) &&
523 (DataBufferEnd > IoStack->Parameters.DeviceIoControl.InputBufferLength))
524 {
525 DPRINT1("Data buffer outside of available space\n");
527 }
528 }
529
530 return STATUS_SUCCESS;
531}
532
533static
534CODE_SEG("PAGE")
537 _Out_ SCSI_REQUEST_BLOCK* __restrict Srb,
538 _In_ SCSI_PASS_THROUGH* __restrict Spt,
540{
542
543 PAGED_CODE();
544
545 Status = SptiSrbAppendSenseBuffer(Srb, Spt->SenseInfoLength);
546 if (!NT_SUCCESS(Status))
547 return Status;
548
549 Srb->CdbLength = Spt->CdbLength;
550 Srb->TimeOutValue = Spt->TimeOutValue;
551
552 Srb->PathId = Spt->PathId;
553 Srb->TargetId = Spt->TargetId;
554 Srb->Lun = Spt->Lun;
555
556 if (Spt->DataTransferLength != 0)
557 {
558 switch (Spt->DataIn)
559 {
562 break;
565 break;
566 default: // SCSI_IOCTL_DATA_UNSPECIFIED
568 break;
569 }
570 }
571
573
574 return STATUS_SUCCESS;
575}
576
577static
578CODE_SEG("PAGE")
582 _In_ PIRP Irp,
583 _In_ PIO_STACK_LOCATION IoStack,
584 _In_ BOOLEAN IsDirectMemoryAccess,
586 _In_ ULONG MaximumPhysicalPages,
588 _Out_ PPASSTHROUGH_DATA SptData,
589 _Out_ PULONG SenseInfoOffset,
591 _Out_ PVOID* DataBuffer)
592{
593 ULONG StructSize;
594 BOOLEAN IsNativeStructSize;
595 PULONG SenseInfoOffsetPtr;
596
597 PAGED_CODE();
598
599#if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
600 if (IoIs32bitProcess(Irp))
601 {
602 StructSize = sizeof(SCSI_PASS_THROUGH32);
603 SenseInfoOffsetPtr = (PVOID)((ULONG_PTR)Spt +
604 FIELD_OFFSET(SCSI_PASS_THROUGH32, SenseInfoOffset));
605 *Cdb = (PVOID)((ULONG_PTR)Spt + FIELD_OFFSET(SCSI_PASS_THROUGH32, Cdb));
606 IsNativeStructSize = FALSE;
607 }
608 else
609#endif
610 {
611 StructSize = sizeof(SCSI_PASS_THROUGH);
612 SenseInfoOffsetPtr = (PVOID)((ULONG_PTR)Spt +
613 FIELD_OFFSET(SCSI_PASS_THROUGH, SenseInfoOffset));
615 IsNativeStructSize = TRUE;
616 }
617
618 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < StructSize)
619 {
620 DPRINT1("Buffer too small %lu/%lu\n",
621 IoStack->Parameters.DeviceIoControl.InputBufferLength, StructSize);
623 }
624
625 if (Spt->Length != StructSize)
626 {
627 DPRINT1("Unknown structure size %lu\n", StructSize);
629 }
630
631 if (Spt->DataTransferLength > MaximumTransferLength)
632 {
633 DPRINT1("Too large transfer %lu/%lu\n", Spt->DataTransferLength, MaximumTransferLength);
635 }
636
637 if (BYTES_TO_PAGES(Spt->DataTransferLength) > MaximumPhysicalPages)
638 {
639 DPRINT1("Too large transfer %lu/%lu pages\n",
640 BYTES_TO_PAGES(Spt->DataTransferLength), MaximumPhysicalPages);
642 }
643
644 /* Retrieve the data buffer or the data buffer offset */
645#if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
646 SptData->Buffer = NULL;
647 RtlCopyMemory(SptData,
648 (PVOID)((ULONG_PTR)Spt + FIELD_OFFSET(SCSI_PASS_THROUGH, DataBufferOffset)),
649 IsNativeStructSize ? sizeof(PVOID) : sizeof(ULONG32));
650#else
651 DBG_UNREFERENCED_LOCAL_VARIABLE(IsNativeStructSize);
652
653 SptData->BufferOffset = Spt->DataBufferOffset;
654#endif
655 *SenseInfoOffset = *SenseInfoOffsetPtr;
656
657 if (Spt->DataTransferLength != 0)
658 {
659 if (IsDirectMemoryAccess)
660 *DataBuffer = SptData->Buffer;
661 else
662 *DataBuffer = (PVOID)((ULONG_PTR)Spt + SptData->BufferOffset);
663 }
664 else
665 {
666 *DataBuffer = NULL;
667 }
668
669 // FIXME: Validate the command opcode
670
671 if (*(PULONG_PTR)DataBuffer & DeviceObject->AlignmentRequirement)
672 {
673 DPRINT1("Unaligned data buffer %p:%lx\n",
674 (PVOID)*(PULONG_PTR)DataBuffer, DeviceObject->AlignmentRequirement);
676 }
677
678 if (Spt->DataTransferLength & DeviceObject->AlignmentRequirement)
679 {
680 DPRINT1("Unaligned data transfer length %lx:%lx\n",
681 Spt->DataTransferLength, DeviceObject->AlignmentRequirement);
683 }
684
685 if (Spt->TimeOutValue < PASSTHROUGH_CMD_TIMEOUT_MIN_SEC ||
686 Spt->TimeOutValue > PASSTHROUGH_CMD_TIMEOUT_MAX_SEC)
687 {
688 DPRINT1("Invalid timeout value %lu\n", Spt->TimeOutValue);
690 }
691
692 if (Spt->CdbLength > RTL_FIELD_SIZE(SCSI_REQUEST_BLOCK, Cdb))
693 {
694 DPRINT1("Invalid CDB size %u\n", Spt->CdbLength);
696 }
697
698 if (Spt->DataIn > SCSI_IOCTL_DATA_UNSPECIFIED)
699 {
700 DPRINT1("Unknown DataIn value %u\n", Spt->DataIn);
702 }
703
704 if (Spt->SenseInfoLength != 0)
705 {
706 ULONG SenseBufferEnd;
708
709 Status = RtlULongAdd(*SenseInfoOffset, Spt->SenseInfoLength, &SenseBufferEnd);
710 if (!NT_SUCCESS(Status))
711 {
712 DPRINT1("Invalid sense buffer offset\n");
713 return Status;
714 }
715
716 if (Spt->Length > *SenseInfoOffset)
717 {
718 DPRINT1("Sense buffer overlaps SPT\n");
720 }
721
722 if (!IsDirectMemoryAccess)
723 {
724 if ((SenseBufferEnd > SptData->BufferOffset) && (Spt->DataTransferLength != 0))
725 {
726 DPRINT1("Sense buffer overlaps data buffer\n");
728 }
729
730 if (SenseBufferEnd > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
731 {
732 DPRINT1("Sense buffer outside of available space\n");
734 }
735 }
736 }
737
738 if (!IsDirectMemoryAccess)
739 {
740 ULONG_PTR DataBufferEnd;
742
743 Status = RtlULongPtrAdd(SptData->BufferOffset, Spt->DataTransferLength, &DataBufferEnd);
744 if (!NT_SUCCESS(Status))
745 {
746 DPRINT1("Invalid data buffer offset\n");
747 return Status;
748 }
749
750 if ((Spt->Length > SptData->BufferOffset) && (Spt->DataTransferLength != 0))
751 {
752 DPRINT1("Data buffer inside of structure bounds\n");
754 }
755
756 if (Spt->DataIn == SCSI_IOCTL_DATA_IN || Spt->DataIn == SCSI_IOCTL_DATA_UNSPECIFIED)
757 {
758 if (DataBufferEnd > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
759 {
760 DPRINT1("Data buffer outside of available space\n");
762 }
763 }
764
765 if (Spt->DataIn == SCSI_IOCTL_DATA_OUT || Spt->DataIn == SCSI_IOCTL_DATA_UNSPECIFIED)
766 {
767 if (DataBufferEnd > IoStack->Parameters.DeviceIoControl.InputBufferLength)
768 {
769 DPRINT1("Data buffer outside of available space\n");
771 }
772 }
773 }
774
775 return STATUS_SUCCESS;
776}
777
778/* PUBLIC FUNCTIONS ***********************************************************/
779
780CODE_SEG("PAGE")
786 _In_ ULONG MaximumPhysicalPages)
787{
788 PATA_PASS_THROUGH_EX Apt = Irp->AssociatedIrp.SystemBuffer;
789 PIO_STACK_LOCATION IoStack;
790 BOOLEAN IsDirectMemoryAccess;
791 PASSTHROUGH_DATA AptData;
792 PUCHAR TaskFile;
794 PVOID DataBuffer;
795 PPASSTHROUGH_IRP_CONTEXT IrpContext;
797
798 PAGED_CODE();
799
801
804
805 IsDirectMemoryAccess = (GET_IOCTL(IoStack) == IOCTL_ATA_PASS_THROUGH_DIRECT);
806
808 Irp,
809 IoStack,
810 IsDirectMemoryAccess,
812 MaximumPhysicalPages,
813 Apt,
814 &AptData,
815 &TaskFile,
816 &DataBuffer);
817 if (!NT_SUCCESS(Status))
818 return Status;
819
820 DPRINT("APT: Flags %x DTL %lu\n", Apt->AtaFlags, Apt->DataTransferLength);
821 DPRINT("APT: Curr %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
822 TaskFile[8 + 0], TaskFile[8 + 1], TaskFile[8 + 2], TaskFile[8 + 3],
823 TaskFile[8 + 4], TaskFile[8 + 5], TaskFile[8 + 6],
824 Apt->AtaFlags,
825 Apt->DataTransferLength);
827 {
828 DPRINT("APT: Prev %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
829 TaskFile[0], TaskFile[1], TaskFile[2], TaskFile[3],
830 TaskFile[4], TaskFile[5], TaskFile[6]);
831 }
832
833 IrpContext = SptiCreateIrpContext(DeviceObject,
834 Irp,
835 DataBuffer,
837 IsDirectMemoryAccess,
838 !!(Apt->AtaFlags & ATA_FLAGS_DATA_OUT));
839 if (!IrpContext)
841
842 Status = SptiTranslateAptToSrb(&IrpContext->Srb, Apt, TaskFile);
843 if (!NT_SUCCESS(Status))
844 goto Cleanup;
845
846 Status = SptiCallDriver(DeviceObject, IrpContext);
847
848 Srb = &IrpContext->Srb;
849
852
853 /* Update the output buffer size */
855 if (IsDirectMemoryAccess)
856 {
857 Irp->IoStatus.Information = Apt->Length;
858 }
859 else
860 {
861 if ((Apt->AtaFlags & ATA_FLAGS_DATA_IN) && (AptData.BufferOffset != 0))
862 Irp->IoStatus.Information = AptData.BufferOffset + Apt->DataTransferLength;
863 else
864 Irp->IoStatus.Information = Apt->Length;
865 }
866
867 DPRINT("APT: Return %lx, DTL %lu, %lu bytes\n",
868 Status,
870 (ULONG)Irp->IoStatus.Information);
871 DPRINT("APT: Return curr %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
872 TaskFile[8 + 0], TaskFile[8 + 1], TaskFile[8 + 2], TaskFile[8 + 3],
873 TaskFile[8 + 4], TaskFile[8 + 5], TaskFile[8 + 6]);
875 {
876 DPRINT("APT: Return prev %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
877 TaskFile[0], TaskFile[1], TaskFile[2], TaskFile[3],
878 TaskFile[4], TaskFile[5], TaskFile[6]);
879 }
880
881Cleanup:
882 SptiFreeIrpContext(IrpContext);
883 return Status;
884}
885
886CODE_SEG("PAGE")
892 _In_ ULONG MaximumPhysicalPages)
893{
894 PSCSI_PASS_THROUGH Spt = Irp->AssociatedIrp.SystemBuffer;
895 PIO_STACK_LOCATION IoStack;
896 BOOLEAN IsDirectMemoryAccess;
897 PASSTHROUGH_DATA SptData;
898 ULONG SenseInfoOffset;
899 PUCHAR Cdb;
901 PVOID DataBuffer;
902 PPASSTHROUGH_IRP_CONTEXT IrpContext;
904
905 PAGED_CODE();
906
908
911
912 IsDirectMemoryAccess = (GET_IOCTL(IoStack) == IOCTL_SCSI_PASS_THROUGH_DIRECT);
913
915 Irp,
916 IoStack,
917 IsDirectMemoryAccess,
919 MaximumPhysicalPages,
920 Spt,
921 &SptData,
922 &SenseInfoOffset,
923 &Cdb,
924 &DataBuffer);
925 if (!NT_SUCCESS(Status))
926 return Status;
927
928 DPRINT("SPT: Flags %u, DTL %lu, sense len %u\n",
929 Spt->DataIn,
931 Spt->SenseInfoLength);
932 DPRINT("SPT: CDB %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
933 Cdb[0], Cdb[1], Cdb[2], Cdb[3], Cdb[4], Cdb[5], Cdb[6], Cdb[7], Cdb[8], Cdb[9]);
934
935 IrpContext = SptiCreateIrpContext(DeviceObject,
936 Irp,
937 DataBuffer,
939 IsDirectMemoryAccess,
940 !!(Spt->DataIn == SCSI_IOCTL_DATA_OUT));
941 if (!IrpContext)
943
944 Status = SptiTranslateSptToSrb(&IrpContext->Srb, Spt, Cdb);
945 if (!NT_SUCCESS(Status))
946 goto Cleanup;
947
948 Status = SptiCallDriver(DeviceObject, IrpContext);
949
950 Srb = &IrpContext->Srb;
951
952 /*
953 * Low-level storage drivers map SRB_STATUS_DATA_OVERRUN to STATUS_BUFFER_OVERFLOW.
954 * This SRB status is usually set on an underrun and means success in that case.
955 */
958
960 {
962
964
965 /* Copy the sense buffer back */
966 RtlCopyMemory((PVOID)((ULONG_PTR)Spt + SenseInfoOffset),
969 }
970 else
971 {
972 Spt->SenseInfoLength = 0;
973 }
974
975 Spt->ScsiStatus = Srb->ScsiStatus;
976
977 /* Update the output buffer size */
979 if (IsDirectMemoryAccess)
980 {
981 if (Spt->SenseInfoLength != 0)
982 Irp->IoStatus.Information = SenseInfoOffset + Spt->SenseInfoLength;
983 else
984 Irp->IoStatus.Information = Spt->Length;
985 }
986 else
987 {
988 if ((Srb->SrbFlags & SRB_FLAGS_DATA_IN) && (SptData.BufferOffset != 0))
989 Irp->IoStatus.Information = SptData.BufferOffset + Spt->DataTransferLength;
990 else if (Spt->SenseInfoLength != 0)
991 Irp->IoStatus.Information = SenseInfoOffset + Spt->SenseInfoLength;
992 else
993 Irp->IoStatus.Information = Spt->Length;
994 }
995
996 DPRINT("SPT: Return %lx, DTL %lu, "
997 "Srb status %02x, SCSI status %02x, sense len %u, %lu bytes\n",
998 Status,
1000 Srb->SrbStatus,
1001 Spt->ScsiStatus,
1002 Spt->SenseInfoLength,
1003 (ULONG)Irp->IoStatus.Information);
1004
1005Cleanup:
1006 SptiFreeIrpContext(IrpContext);
1007 return Status;
1008}
#define ExAllocatePoolUninitialized
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
#define PAGED_CODE()
#define CODE_SEG(...)
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG32
Definition: basetsd.h:123
_In_ PSCSI_REQUEST_BLOCK Srb
Definition: cdrom.h:989
#define SCSISTAT_CHECK_CONDITION
Definition: cdrw_hw.h:1079
#define SCSI_ADSENSE_NO_SENSE
Definition: cdrw_hw.h:1207
#define SCSI_SENSE_RECOVERED_ERROR
Definition: cdrw_hw.h:1188
_In_ PTRANSFER_PACKET _In_ ULONG _In_ PIRP OriginalIrp
Definition: classp.h:1757
_In_ PIRP Irp
Definition: csq.h:116
#define STATUS_PENDING
Definition: d3dkmdt.h:43
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
static const WCHAR Cleanup[]
Definition: register.c:80
#define ULONG_PTR
Definition: config.h:101
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: srb.h:315
#define SRB_STATUS_DATA_OVERRUN
Definition: srb.h:357
#define SRB_FLAGS_DATA_OUT
Definition: srb.h:401
#define SRB_STATUS_AUTOSENSE_VALID
Definition: srb.h:387
#define SRB_FLAGS_DISABLE_AUTOSENSE
Definition: srb.h:399
#define SRB_FLAGS_DATA_IN
Definition: srb.h:400
#define SRB_FLAGS_UNSPECIFIED_DIRECTION
Definition: srb.h:403
#define SRB_STATUS(Status)
Definition: srb.h:389
#define SRB_FLAGS_NO_QUEUE_FREEZE
Definition: srb.h:404
#define __drv_freesMem(kind)
Definition: driverspecs.h:272
#define __drv_allocatesMem(kind)
Definition: driverspecs.h:257
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define NonPagedPoolCacheAligned
Definition: env_spec_w32.h:310
#define NonPagedPool
Definition: env_spec_w32.h:307
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ ULONG _In_opt_ GUID _In_ USHORT DataBufferLength
Definition: fltkernel.h:1270
#define IoFreeMdl
Definition: fxmdl.h:89
#define IoAllocateMdl
Definition: fxmdl.h:88
Status
Definition: gdiplustypes.h:25
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
#define RTL_FIELD_SIZE(type, field)
Definition: kdb_expr.c:86
if(dx< 0)
Definition: linetemp.h:194
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:931
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1435
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
FORCEINLINE PVOID ExAllocatePoolZero(ULONG PoolType, SIZE_T NumberOfBytes, ULONG Tag)
Definition: precomp.h:45
#define KernelMode
Definition: asm.h:38
#define _Inout_
Definition: no_sal2.h:162
#define _At_(t, a)
Definition: no_sal2.h:40
#define _Out_
Definition: no_sal2.h:160
#define _In_reads_opt_(s)
Definition: no_sal2.h:222
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define DBG_UNREFERENCED_LOCAL_VARIABLE(L)
Definition: ntbasedef.h:331
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
@ NotificationEvent
PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota)
Definition: irp.c:615
#define IoCallDriver
Definition: irp.c:1225
VOID NTAPI IoFreeIrp(IN PIRP Irp)
Definition: irp.c:1666
#define STATUS_REVISION_MISMATCH
Definition: ntstatus.h:325
unsigned short USHORT
Definition: pedump.c:61
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:82
#define _SEH2_END
Definition: pseh2_64.h:171
#define _SEH2_TRY
Definition: pseh2_64.h:71
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:184
_In_opt_ WDFREQUEST _In_ ULONG _In_ BOOLEAN _In_ PCDB Cdb
Definition: scratch.h:159
_In_opt_ WDFREQUEST _In_ ULONG MaximumTransferLength
Definition: scratch.h:54
#define IOCTL_SCSI_PASS_THROUGH
Definition: scsi_port.h:47
#define IOCTL_SCSI_PASS_THROUGH_DIRECT
Definition: scsi_port.h:51
#define SCSI_IOCTL_DATA_UNSPECIFIED
Definition: scsi_port.h:173
#define SCSI_IOCTL_DATA_IN
Definition: scsi_port.h:172
#define SCSI_IOCTL_DATA_OUT
Definition: scsi_port.h:171
struct _SCSI_PASS_THROUGH SCSI_PASS_THROUGH
struct _SCSI_SENSE_DESCRIPTOR_ATA_STATUS_RETURN * PSCSI_SENSE_DESCRIPTOR_ATA_STATUS_RETURN
#define SCSI_SENSE_ERRORCODE_DESCRIPTOR_CURRENT
Definition: scsi.h:625
#define SCSIOP_ATA_PASSTHROUGH16
Definition: scsi.h:344
#define SCSI_SENSE_DESCRIPTOR_TYPE_ATA_STATUS_RETURN
Definition: scsi.h:639
_In_ UCHAR _Outptr_result_bytebuffer_ DescriptorBufferLength PVOID * DescriptorBuffer
Definition: scsi.h:3930
#define IOCTL_ATA_PASS_THROUGH_DIRECT
Definition: ntddscsi.h:41
#define IOCTL_ATA_PASS_THROUGH
Definition: ntddscsi.h:40
struct _ATA_PASS_THROUGH_EX ATA_PASS_THROUGH_EX
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define DPRINT
Definition: sndvol32.h:73
NTSTATUS SptiHandleAtaPassthru(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _In_ ULONG MaximumTransferLength, _In_ ULONG MaximumPhysicalPages)
Handler for the IOCTL_ATA_PASS_THROUGH and IOCTL_ATA_PASS_THROUGH_DIRECT requests.
Definition: sptilib.c:782
static VOID SptiTranslateTaskFileToCdb(_Out_ CDB *__restrict Cdb, _In_ UCHAR *__restrict TaskFile, _In_ USHORT AtaFlags)
Definition: sptilib.c:229
static NTSTATUS SptiTranslateAptToSrb(_Out_ SCSI_REQUEST_BLOCK *__restrict Srb, _In_ ATA_PASS_THROUGH_EX *__restrict Apt, _In_ PUCHAR TaskFile)
Definition: sptilib.c:351
_In_ ULONG BufferSize
Definition: sptilib.c:206
static NTSTATUS SptiCallDriver(_In_ PDEVICE_OBJECT DeviceObject, _In_ PPASSTHROUGH_IRP_CONTEXT IrpContext)
Definition: sptilib.c:167
static VOID SptiInitializeOutputBuffer(_In_ PIRP Irp)
Definition: sptilib.c:148
static NTSTATUS SptiInitializeSpt(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PIO_STACK_LOCATION IoStack, _In_ BOOLEAN IsDirectMemoryAccess, _In_ ULONG MaximumTransferLength, _In_ ULONG MaximumPhysicalPages, _In_ PSCSI_PASS_THROUGH Spt, _Out_ PPASSTHROUGH_DATA SptData, _Out_ PULONG SenseInfoOffset, _Out_ PUCHAR *Cdb, _Out_ PVOID *DataBuffer)
Definition: sptilib.c:580
return STATUS_SUCCESS
Definition: sptilib.c:223
static NTSTATUS SptiTranslateSptToSrb(_Out_ SCSI_REQUEST_BLOCK *__restrict Srb, _In_ SCSI_PASS_THROUGH *__restrict Spt, _In_ PUCHAR Cdb)
Definition: sptilib.c:536
NTSTATUS SptiHandleScsiPassthru(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _In_ ULONG MaximumTransferLength, _In_ ULONG MaximumPhysicalPages)
Handler for the IOCTL_SCSI_PASS_THROUGH and IOCTL_SCSI_PASS_THROUGH_DIRECT requests.
Definition: sptilib.c:888
static BOOLEAN SptiTranslateAtaStatusReturnToTaskFile(_In_ SCSI_REQUEST_BLOCK *__restrict Srb, _In_ DESCRIPTOR_SENSE_DATA *__restrict SenseData, _Out_ UCHAR *__restrict TaskFile)
Definition: sptilib.c:294
static NTSTATUS SptiInitializeApt(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PIO_STACK_LOCATION IoStack, _In_ BOOLEAN IsDirectMemoryAccess, _In_ ULONG MaximumTransferLength, _In_ ULONG MaximumPhysicalPages, _In_ PATA_PASS_THROUGH_EX Apt, _Out_ PPASSTHROUGH_DATA AptData, _Out_ PUCHAR *TaskFile, _Out_ PVOID *DataBuffer)
Definition: sptilib.c:385
static IO_COMPLETION_ROUTINE SptiCompletionRoutine
Definition: sptilib.c:61
#define ATA_PASSTHROUGH_PROTOCOL_PIO_DATA_IN
Definition: sptilib.h:18
#define ATA_PASSTHROUGH_PROTOCOL_NON_DATA
Definition: sptilib.h:17
#define ATA_PASSTHROUGH_PROTOCOL_PIO_DATA_OUT
Definition: sptilib.h:19
#define ATA_PASSTHROUGH_PROTOCOL_DMA
Definition: sptilib.h:20
#define SCSI_SENSEQ_ATA_PASS_THROUGH_INFORMATION_AVAILABLE
Definition: sptilib.h:33
#define GET_IOCTL(IoStack)
Definition: sptilibp.h:23
#define PASSTHROUGH_CMD_TIMEOUT_MIN_SEC
Definition: sptilibp.h:19
#define PASSTHROUGH_CMD_TIMEOUT_MAX_SEC
Definition: sptilibp.h:20
#define TAG_SPTI
Definition: sptilibp.h:13
ULONG DataTransferLength
Definition: ntddscsi.h:198
struct _IO_STACK_LOCATION::@4235::@4257 Scsi
struct _IO_STACK_LOCATION::@1701::@1702 DeviceIoControl
union _IO_STACK_LOCATION::@1701 Parameters
SCSI_REQUEST_BLOCK Srb
Definition: sptilibp.h:33
UCHAR SenseInfoLength
Definition: scsi_port.h:65
ULONG DataTransferLength
Definition: scsi_port.h:67
ULONG TimeOutValue
Definition: srb.h:262
UCHAR TargetId
Definition: srb.h:254
PVOID OriginalRequest
Definition: srb.h:266
UCHAR SenseInfoBufferLength
Definition: srb.h:259
PVOID DataBuffer
Definition: srb.h:263
UCHAR PathId
Definition: srb.h:253
UCHAR CdbLength
Definition: srb.h:258
UCHAR Cdb[16]
Definition: srb.h:279
PVOID SenseInfoBuffer
Definition: srb.h:264
UCHAR Function
Definition: srb.h:250
UCHAR ScsiStatus
Definition: srb.h:252
ULONG DataTransferLength
Definition: srb.h:261
ULONG SrbFlags
Definition: srb.h:260
USHORT Length
Definition: srb.h:249
UCHAR SrbStatus
Definition: srb.h:251
uint32_t * PULONG_PTR
Definition: typedefs.h:65
uint32_t * PULONG
Definition: typedefs.h:59
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define ATA_FLAGS_USE_DMA
Definition: uata_ctl.h:226
#define ATA_FLAGS_DATA_OUT
Definition: uata_ctl.h:221
#define ATA_FLAGS_DATA_IN
Definition: uata_ctl.h:222
#define ATA_FLAGS_48BIT_COMMAND
Definition: uata_ctl.h:223
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
Definition: cdrw_hw.h:28
struct _CDB::_ATA_PASSTHROUGH16 ATA_PASSTHROUGH16
ULONG_PTR BufferOffset
Definition: sptilibp.h:28
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_In_ WDFREQUEST _In_ size_t OutputBufferLength
Definition: wdfio.h:320
_In_ WDFREQUEST _In_ size_t _In_ size_t InputBufferLength
Definition: wdfio.h:322
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
_Must_inspect_result_ _In_ WDFIORESLIST _In_ PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: wdfresource.h:342
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2695
#define IRP_MJ_SCSI
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#define IRP_MN_SCSI_CLASS
@ Executive
Definition: ketypes.h:415
@ IoReadAccess
Definition: ketypes.h:863
@ IoWriteAccess
Definition: ketypes.h:864
#define BYTES_TO_PAGES(Size)
unsigned char UCHAR
Definition: xmlstorage.h:181