[SPTILIB] Introduce SPTI static library for storage drivers (#8209)

Add a SCSI and ATA passthrough support helper library for direct use
from low-level storage drivers.

Tested with: CDRoller, CloneCD, Magic ISO
NOTE: Vbox seems to lack support for CD/DVD burning; tested on real hardware.

CORE-10191 CORE-16452
CORE-14788 CORE-18241
CORE-17256 CORE-13866
This commit is contained in:
Dmitry Borisov 2025-07-14 02:49:51 +06:00 committed by GitHub
parent 5bd84f6f71
commit b558596409
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 1285 additions and 14 deletions

View file

@ -1,6 +1,9 @@
spec2def(scsiport.sys scsiport.spec ADD_IMPORTLIB)
include_directories(
${REACTOS_SOURCE_DIR}/sdk/lib/drivers/sptilib)
# Embed RTC libs
if (STACK_PROTECTOR)
target_sources(libscsiport PRIVATE $<TARGET_OBJECTS:gcc_ssp_scsiport>)
@ -27,5 +30,6 @@ add_library(scsiport MODULE
add_pch(scsiport scsiport.h "${PCH_SKIP_SOURCE}")
set_module_type(scsiport kernelmodedriver)
target_link_libraries(scsiport sptilib ${PSEH_LIB})
add_importlibs(scsiport ntoskrnl hal)
add_cd_file(TARGET scsiport DESTINATION reactos/system32/drivers NO_CAB FOR all)

View file

@ -8,6 +8,7 @@
*/
#include "scsiport.h"
#include <sptilib.h>
#define NDEBUG
#include <debug.h>
@ -276,7 +277,6 @@ PdoHandleQueryProperty(
}
default:
{
UNREACHABLE;
status = STATUS_NOT_IMPLEMENTED;
goto completeIrp;
}
@ -288,6 +288,56 @@ completeIrp:
return status;
}
static
NTSTATUS
PdoHandleScsiPassthrough(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PSCSI_PORT_LUN_EXTENSION lunExt = DeviceObject->DeviceExtension;
PSCSI_PORT_DEVICE_EXTENSION portExt;
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
ASSERT(!lunExt->Common.IsFDO);
/* Skip requests that bypassed the class driver. See also cdrom!RequestHandleScsiPassThrough */
if ((IoGetCurrentIrpStackLocation(Irp)->MinorFunction == 0) && lunExt->DeviceClaimed)
return STATUS_INVALID_DEVICE_REQUEST;
portExt = lunExt->Common.LowerDevice->DeviceExtension;
return SptiHandleScsiPassthru(DeviceObject,
Irp,
portExt->PortCapabilities.MaximumTransferLength,
portExt->PortCapabilities.MaximumPhysicalPages);
}
static
NTSTATUS
FdoHandleScsiPassthrough(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PSCSI_PORT_DEVICE_EXTENSION portExt;
PSCSI_PORT_LUN_EXTENSION lunExt;
PSCSI_PASS_THROUGH spt;
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
if (!VerifyIrpInBufferSize(Irp, RTL_SIZEOF_THROUGH_FIELD(SCSI_PASS_THROUGH, Lun)))
return STATUS_BUFFER_TOO_SMALL;
portExt = DeviceObject->DeviceExtension;
ASSERT(portExt->Common.IsFDO);
spt = Irp->AssociatedIrp.SystemBuffer;
lunExt = GetLunByPath(portExt, spt->PathId, spt->TargetId, spt->Lun);
if (!lunExt)
return STATUS_NO_SUCH_DEVICE;
return PdoHandleScsiPassthrough(lunExt->Common.DeviceObject, Irp);
}
static
NTSTATUS
FdoHandleQueryProperty(
@ -409,6 +459,7 @@ ScsiPortDeviceControl(
PSCSI_PORT_COMMON_EXTENSION comExt = DeviceObject->DeviceExtension;
PSCSI_PORT_DEVICE_EXTENSION portExt;
PSCSI_PORT_LUN_EXTENSION lunExt;
ULONG IoControlCode;
NTSTATUS status;
DPRINT("ScsiPortDeviceControl()\n");
@ -416,8 +467,9 @@ ScsiPortDeviceControl(
Irp->IoStatus.Information = 0;
Stack = IoGetCurrentIrpStackLocation(Irp);
IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
switch (IoControlCode)
{
case IOCTL_STORAGE_QUERY_PROPERTY:
{
@ -534,20 +586,27 @@ ScsiPortDeviceControl(
break;
case IOCTL_SCSI_PASS_THROUGH:
DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
status = STATUS_NOT_IMPLEMENTED;
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
{
DPRINT(" IOCTL_SCSI_PASS_THROUGH%s\n",
IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT ? "_DIRECT" : "");
if (comExt->IsFDO)
status = FdoHandleScsiPassthrough(DeviceObject, Irp);
else
status = PdoHandleScsiPassthrough(DeviceObject, Irp);
break;
}
case IOCTL_ATA_PASS_THROUGH:
case IOCTL_ATA_PASS_THROUGH_DIRECT:
/* ATA passthrough IOCTLs not supported by MS scsiport */
DPRINT1("ATA passthrough IOCTLs not supported: 0x%lX\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
DPRINT1("ATA passthrough IOCTLs not supported: 0x%lX\n", IoControlCode);
status = STATUS_NOT_SUPPORTED;
break;
default:
DPRINT1("unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
DPRINT1("unknown ioctl code: 0x%lX\n", IoControlCode);
status = STATUS_NOT_SUPPORTED;
break;
}

View file

@ -1,6 +1,9 @@
spec2def(storport.sys storport.spec ADD_IMPORTLIB)
include_directories(
${REACTOS_SOURCE_DIR}/sdk/lib/drivers/sptilib)
list(APPEND SOURCE
fdo.c
miniport.c
@ -20,5 +23,6 @@ add_library(storport MODULE
add_pch(storport precomp.h "${PCH_SKIP_SOURCE}")
set_module_type(storport kernelmodedriver)
target_link_libraries(storport sptilib ${PSEH_LIB})
add_importlibs(storport ntoskrnl hal)
add_cd_file(TARGET storport DESTINATION reactos/system32/drivers NO_CAB FOR all)

View file

@ -1,4 +1,7 @@
include_directories(
${REACTOS_SOURCE_DIR}/sdk/lib/drivers/sptilib)
list(APPEND SOURCE
descriptor.c
disk.c
@ -19,6 +22,7 @@ add_library(usbstor MODULE
usbstor.rc)
set_module_type(usbstor kernelmodedriver)
target_link_libraries(usbstor sptilib ${PSEH_LIB})
add_importlibs(usbstor ntoskrnl hal usbd)
add_pch(usbstor usbstor.h "${PCH_SKIP_SOURCE}")
add_cd_file(TARGET usbstor DESTINATION reactos/system32/drivers NO_CAB FOR all)

View file

@ -9,10 +9,13 @@
*/
#include "usbstor.h"
#include <sptilib.h>
#define NDEBUG
#include <debug.h>
// See CORE-10515 and CORE-10755
#define USBSTOR_DEFAULT_MAX_PHYS_PAGES (USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH / PAGE_SIZE + 1)
static
BOOLEAN
@ -394,7 +397,7 @@ USBSTOR_HandleQueryProperty(
.Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8),
.Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR_WIN8),
.MaximumTransferLength = USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH,
.MaximumPhysicalPages = USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH / PAGE_SIZE + 1, // See CORE-10515 and CORE-10755
.MaximumPhysicalPages = USBSTOR_DEFAULT_MAX_PHYS_PAGES,
.BusType = BusTypeUsb,
.BusMajorVersion = 2, //FIXME verify
.BusMinorVersion = 0 //FIXME
@ -429,13 +432,27 @@ USBSTOR_HandleDeviceControl(
Status = USBSTOR_HandleQueryProperty(DeviceObject, Irp);
break;
case IOCTL_SCSI_PASS_THROUGH:
DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH NOT implemented\n");
Status = STATUS_NOT_SUPPORTED;
break;
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH_DIRECT NOT implemented\n");
Status = STATUS_NOT_SUPPORTED;
{
PDODeviceExtension = DeviceObject->DeviceExtension;
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
ASSERT(PDODeviceExtension);
ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
/* Skip requests that bypassed the class driver. See also cdrom!RequestHandleScsiPassThrough */
if ((IoGetCurrentIrpStackLocation(Irp)->MinorFunction == 0) && PDODeviceExtension->Claimed)
{
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
Status = SptiHandleScsiPassthru(DeviceObject,
Irp,
USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH,
USBSTOR_DEFAULT_MAX_PHYS_PAGES);
break;
}
case IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER:
DPRINT1("USBSTOR_HandleDeviceControl IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER NOT implemented\n");
Status = STATUS_NOT_SUPPORTED;
@ -461,7 +478,7 @@ USBSTOR_HandleDeviceControl(
if (Capabilities)
{
Capabilities->MaximumTransferLength = USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH;
Capabilities->MaximumPhysicalPages = USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH / PAGE_SIZE + 1; // See CORE-10515 and CORE-10755
Capabilities->MaximumPhysicalPages = USBSTOR_DEFAULT_MAX_PHYS_PAGES;
Capabilities->SupportedAsynchronousEvents = 0;
Capabilities->AlignmentMask = 0;
Capabilities->TaggedQueuing = FALSE;

View file

@ -1886,6 +1886,27 @@ typedef union _CDB {
UCHAR Streaming:1;
UCHAR Control;
} WRITE12;
struct _ATA_PASSTHROUGH12 {
UCHAR OperationCode;
UCHAR Reserved1:1;
UCHAR Protocol:4;
UCHAR MultipleCount:3;
UCHAR TLength:2;
UCHAR ByteBlock:1;
UCHAR TDir:1;
UCHAR Reserved2:1;
UCHAR CkCond:1;
UCHAR Offline:2;
UCHAR Features;
UCHAR SectorCount;
UCHAR LbaLow;
UCHAR LbaMid;
UCHAR LbaHigh;
UCHAR Device;
UCHAR Command;
UCHAR Reserved3;
UCHAR Control;
} ATA_PASSTHROUGH12;
struct _READ16 {
UCHAR OperationCode;
UCHAR Reserved1:3;
@ -1944,6 +1965,31 @@ typedef union _CDB {
UCHAR Reserved2:7;
UCHAR Control;
} READ_CAPACITY16;
struct _ATA_PASSTHROUGH16 {
UCHAR OperationCode;
UCHAR Extend:1;
UCHAR Protocol:4;
UCHAR MultipleCount:3;
UCHAR TLength:2;
UCHAR ByteBlock:1;
UCHAR TDir:1;
UCHAR Reserved1:1;
UCHAR CkCond:1;
UCHAR Offline:2;
UCHAR Features15_8;
UCHAR Features7_0;
UCHAR SectorCount15_8;
UCHAR SectorCount7_0;
UCHAR LbaLow15_8;
UCHAR LbaLow7_0;
UCHAR LbaMid15_8;
UCHAR LbaMid7_0;
UCHAR LbaHigh15_8;
UCHAR LbaHigh7_0;
UCHAR Device;
UCHAR Command;
UCHAR Control;
} ATA_PASSTHROUGH16;
struct _TOKEN_OPERATION {
UCHAR OperationCode;
UCHAR ServiceAction:5;

View file

@ -256,6 +256,7 @@ typedef struct _SCSI_PASS_THROUGH_DIRECT32_EX
#define ATA_FLAGS_DATA_OUT (1 << 2)
#define ATA_FLAGS_48BIT_COMMAND (1 << 3)
#define ATA_FLAGS_USE_DMA (1 << 4)
#define ATA_FLAGS_NO_MULTIPLE (1 << 5)
typedef struct _SCSI_BUS_DATA {
UCHAR NumberOfLogicalUnits;

View file

@ -9,5 +9,6 @@ add_subdirectory(rdbsslib)
add_subdirectory(rtlver)
add_subdirectory(rxce)
add_subdirectory(sound)
add_subdirectory(sptilib)
add_subdirectory(virtio)
add_subdirectory(wdf)

View file

@ -0,0 +1,7 @@
list(APPEND SOURCE
sptilib.c)
add_library(sptilib ${SOURCE})
target_link_libraries(sptilib PRIVATE ${PSEH_LIB})
add_dependencies(sptilib xdk)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,85 @@
/*
* PROJECT: ReactOS Storage Stack
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Public header of the ATA and SCSI Pass Through Interface for storage drivers
* COPYRIGHT: Copyright 2025 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
/**
* ATA Protocol field definitions for the ATA passthrough commands
* (SCSIOP_ATA_PASSTHROUGH12 and SCSIOP_ATA_PASSTHROUGH16).
*/
/*@{*/
#define ATA_PASSTHROUGH_PROTOCOL_HARDWARE_RESET 0x0
#define ATA_PASSTHROUGH_PROTOCOL_SOFTWARE_RESET 0x1
#define ATA_PASSTHROUGH_PROTOCOL_NON_DATA 0x3
#define ATA_PASSTHROUGH_PROTOCOL_PIO_DATA_IN 0x4
#define ATA_PASSTHROUGH_PROTOCOL_PIO_DATA_OUT 0x5
#define ATA_PASSTHROUGH_PROTOCOL_DMA 0x6
#define ATA_PASSTHROUGH_PROTOCOL_DEVICE_DIAG 0x8
#define ATA_PASSTHROUGH_PROTOCOL_DEVICE_RESET 0x9
#define ATA_PASSTHROUGH_PROTOCOL_UDMA_DATA_IN 0xA
#define ATA_PASSTHROUGH_PROTOCOL_UDMA_DATA_OUT 0xB
#define ATA_PASSTHROUGH_PROTOCOL_NCQ 0xC
#define ATA_PASSTHROUGH_PROTOCOL_RETURN_RESPONSE 0xF
/*@}*/
/**
* Additional sense code for the successfully completed ATA passthrough commands
* with check condition enabled.
*/
#define SCSI_SENSEQ_ATA_PASS_THROUGH_INFORMATION_AVAILABLE 0x1D
/**
* @brief
* Handler for the IOCTL_ATA_PASS_THROUGH and IOCTL_ATA_PASS_THROUGH_DIRECT requests.
*
* @param[in] DeviceObject
* PDO device object.
*
* @param[in,out] Irp
* Pointer to the IOCTL request.
*
* @param[in] MaximumTransferLength
* Maximum size of data transfer for a device.
*
* @param[in] MaximumPhysicalPages
* Maximum number of physical pages per data transfer for a device.
*
* @return Status.
*/
CODE_SEG("PAGE")
NTSTATUS
SptiHandleAtaPassthru(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp,
_In_ ULONG MaximumTransferLength,
_In_ ULONG MaximumPhysicalPages);
/**
* @brief
* Handler for the IOCTL_SCSI_PASS_THROUGH and IOCTL_SCSI_PASS_THROUGH_DIRECT requests.
*
* @param[in] DeviceObject
* PDO device object.
*
* @param[in,out] Irp
* Pointer to the IOCTL request.
*
* @param[in] MaximumTransferLength
* Maximum size of data transfer for a device.
*
* @param[in] MaximumPhysicalPages
* Maximum number of physical pages per data transfer for a device.
*
* @return Status.
*/
CODE_SEG("PAGE")
NTSTATUS
SptiHandleScsiPassthru(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp,
_In_ ULONG MaximumTransferLength,
_In_ ULONG MaximumPhysicalPages);

View file

@ -0,0 +1,35 @@
/*
* PROJECT: ReactOS Storage Stack
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Private header of the ATA and SCSI Pass Through Interface for storage drivers
* COPYRIGHT: Copyright 2025 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
/**
* SPTI allocation tag.
*/
#define TAG_SPTI 'ITPS'
/**
* Timeouts to wait for a request to be completed, in seconds.
*/
/*@{*/
#define PASSTHROUGH_CMD_TIMEOUT_MIN_SEC 1
#define PASSTHROUGH_CMD_TIMEOUT_MAX_SEC (30 * 60 * 60) // 30 hours
/*@}*/
#define GET_IOCTL(IoStack) ((IoStack)->Parameters.DeviceIoControl.IoControlCode)
typedef union _PASSTHROUGH_DATA
{
PVOID Buffer;
ULONG_PTR BufferOffset;
} PASSTHROUGH_DATA, *PPASSTHROUGH_DATA;
typedef struct _PASSTHROUGH_IRP_CONTEXT
{
SCSI_REQUEST_BLOCK Srb;
PIRP Irp;
} PASSTHROUGH_IRP_CONTEXT, *PPASSTHROUGH_IRP_CONTEXT;