#include <ntddk.h>

#define RAID0_SECTOR_SIZE 512
#define RAID0_NUM_DISKS 2

typedef struct _RAID0_DEVICE_EXTENSION {
    PDEVICE_OBJECT TargetDevices[RAID0_NUM_DISKS];
} RAID0_DEVICE_EXTENSION, *PRAID0_DEVICE_EXTENSION;

NTSTATUS
Raid0CreateClose(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    UNREFERENCED_PARAMETER(DeviceObject);
    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

NTSTATUS
Raid0ReadWrite(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    PRAID0_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    ULONG diskNum = irpStack->FileObject->FsContext;
    ULONG length = irpStack->Parameters.Read.Length;
    ULONG offset = irpStack->Parameters.Read.ByteOffset.QuadPart;
    PUCHAR buffer = Irp->AssociatedIrp.SystemBuffer;
    NTSTATUS status;

    // Calculate the starting sector and offset for the read/write operation
    ULONG startSector = offset / RAID0_SECTOR_SIZE;
    ULONG startOffset = offset % RAID0_SECTOR_SIZE;

    // Calculate the number of sectors to read/write
    ULONG numSectors = (length + startOffset + RAID0_SECTOR_SIZE - 1) / RAID0_SECTOR_SIZE;

    // Allocate an MDL for the buffer
    PMDL mdl = IoAllocateMdl(buffer, length, FALSE, FALSE, NULL);
    if (!mdl) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        Irp->IoStatus.Status = status;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return status;
    }
    MmBuildMdlForNonPagedPool(mdl);

    // Create IRPs for each disk
    PIRP irps[RAID0_NUM_DISKS];
    KEVENT events[RAID0_NUM_DISKS];
    for (ULONG i = 0; i < RAID0_NUM_DISKS; i++) {
        // Allocate an IRP
        irps[i] = IoAllocateIrp(devExt->TargetDevices[i]->StackSize, FALSE);
        if (!irps[i]) {
            for (ULONG j = 0; j < i; j++) {
                IoFreeIrp(irps[j]);
            }
            IoFreeMdl(mdl);
            status = STATUS_INSUFFICIENT_RESOURCES;
            Irp->IoStatus.Status = status;
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            return status;
        }

        // Set up the IRP stack location
        PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(irps[i]);
        nextStack->MajorFunction = irpStack->MajorFunction;
        nextStack->MinorFunction = irpStack->MinorFunction;
        nextStack->FileObject = irpStack->FileObject;
        nextStack->Parameters.Read.Length = numSectors * RAID0_SECTOR_SIZE;
        nextStack->Parameters.Read.ByteOffset.QuadPart = startSector * RAID0_SECTOR_SIZE;

        // Set up the completion routine
        KeInitializeEvent(&events[i], NotificationEvent, FALSE);
        IoSetCompletionRoutine(ir

