Esempio n. 1
0
/* Filedisk PnP ID query-response routine. */
static NTSTATUS STDCALL WvFilediskPnpQueryId_(
    IN PDEVICE_OBJECT dev_obj,
    IN PIRP irp,
    IN WVL_SP_DISK_T disk
  ) {
    static const WCHAR * hw_ids[WvlDiskMediaTypes] = {
        WVL_M_WLIT L"\\FileFloppyDisk",
        WVL_M_WLIT L"\\FileHardDisk",
        WVL_M_WLIT L"\\FileOpticalDisc"
      };
    WCHAR (*buf)[512];
    NTSTATUS status;
    WV_SP_FILEDISK_T filedisk = CONTAINING_RECORD(disk, WV_S_FILEDISK_T, disk);
    BUS_QUERY_ID_TYPE query_type;

    /* Allocate a buffer. */
    buf = wv_mallocz(sizeof *buf);
    if (!buf) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto err_buf;
      }

    /* Populate the buffer with IDs. */
    query_type = IoGetCurrentIrpStackLocation(irp)->Parameters.QueryId.IdType;
    switch (query_type) {
        case BusQueryDeviceID:
          swprintf(*buf, hw_ids[disk->Media]);
          break;

        case BusQueryInstanceID:
          /* "Location". */
          swprintf(*buf, L"Hash_%08X", filedisk->hash);
          break;

        case BusQueryHardwareIDs:
          swprintf(
              *buf + swprintf(*buf, hw_ids[disk->Media]) + 1,
              WvlDiskCompatIds[disk->Media]
            );
          break;

        case BusQueryCompatibleIDs:
          swprintf(*buf, WvlDiskCompatIds[disk->Media]);

        default:
          DBG("Unknown query type %d for %p!\n", query_type, filedisk);
          status = STATUS_INVALID_PARAMETER;
          goto err_query_type;
      }

    DBG("IRP_MN_QUERY_ID for file-backed disk %p.\n", filedisk);
    return WvlIrpComplete(irp, (ULONG_PTR) buf, STATUS_SUCCESS);

    err_query_type:

    wv_free(buf);
    err_buf:

    return WvlIrpComplete(irp, 0, status);
  }
Esempio n. 2
0
/**
 * Handle a disk IRP_MJ_DEVICE_CONTROL IRP.
 *
 * @v Disk              The disk to process with the IRP.
 * @v Irp               The IRP to process with the disk.
 * @v Code              The device control code.
 * @ret NTSTATUS        The status of the operation.
 */
WVL_M_LIB NTSTATUS STDCALL WvlDiskDevCtl(
    IN WVL_SP_DISK_T Disk,
    IN PIRP Irp,
    IN ULONG POINTER_ALIGNMENT Code
) {
    switch (Code) {
    case IOCTL_STORAGE_QUERY_PROPERTY:
        return WvlDiskDevCtlStorageQueryProp_(Disk, Irp);

    case IOCTL_DISK_GET_DRIVE_GEOMETRY:
        return WvlDiskDevCtlGetGeom_(Disk, Irp);

    case IOCTL_SCSI_GET_ADDRESS:
        return WvlDiskDevCtlScsiGetAddr_(Disk, Irp);

        /* Some cases that pop up on Windows Server 2003. */
#if 0
    case IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY:
    case IOCTL_MOUNTDEV_LINK_CREATED:
    case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
    case IOCTL_VOLUME_ONLINE:
        return WvlIrpComplete(Irp, 0, STATUS_SUCCESS);
#endif
    }

    return WvlIrpComplete(Irp, 0, STATUS_INVALID_PARAMETER);
}
Esempio n. 3
0
static NTSTATUS STDCALL AoeBusDevCtlDetach_(IN PIRP irp) {
    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    UINT32 unit_num;
    WVL_SP_BUS_NODE walker;
    AOE_SP_DISK aoe_disk = NULL;

    unit_num = *((PUINT32) irp->AssociatedIrp.SystemBuffer);
    DBG("Request to detach unit: %d\n", unit_num);

    walker = NULL;
    /* For each node on the bus... */
    WvlBusLock(&AoeBusMain);
    while (walker = WvlBusGetNextNode(&AoeBusMain, walker)) {
        aoe_disk = CONTAINING_RECORD(walker, AOE_S_DISK, BusNode[0]);
        /* If the unit number matches... */
        if (WvlBusGetNodeNum(walker) == unit_num) {
            /* If it's not a boot-time device... */
            if (aoe_disk->Boot) {
                DBG("Cannot detach a boot-time device.\n");
                /* Signal error. */
                aoe_disk = NULL;
                break;
            }
        }
    }
    WvlBusUnlock(&AoeBusMain);
    if (!aoe_disk) {
        DBG("Unit %d not found.\n", unit_num);
        return WvlIrpComplete(irp, 0, STATUS_INVALID_PARAMETER);
    }
    /* Detach the node. */
    WvlBusRemoveNode(aoe_disk->BusNode);
    DBG("Removed unit %d.\n", unit_num);
    return WvlIrpComplete(irp, 0, STATUS_SUCCESS);
}
Esempio n. 4
0
/* Dummy PnP IRP handler. */
static NTSTATUS STDCALL WvDummyPnp(
    IN WV_SP_DEV_T dev,
    IN PIRP irp,
    IN UCHAR code
  ) {
    switch (code) {
        case IRP_MN_QUERY_ID:
          /* The WV_S_DEV_T extension points to the dummy IDs. */
          return WvDummyIds(irp, dev->ext);

        case IRP_MN_QUERY_REMOVE_DEVICE:
          return WvlIrpComplete(irp, 0, STATUS_SUCCESS);

        case IRP_MN_REMOVE_DEVICE:
          /* Any error status for the removal slips away, here. */
          WvBusRemoveDev(dev);
          return WvlIrpComplete(irp, 0, STATUS_SUCCESS);

        default:
          /* Return whatever upper drivers in the stack yielded. */
          return WvlIrpComplete(
              irp,
              irp->IoStatus.Information,
              irp->IoStatus.Status
            );
      }
  }
Esempio n. 5
0
/**
 * Handle a PnP ID query with a WV_S_DUMMY_IDS object.
 *
 * @v Irp               The PnP ID query IRP to handle.
 * @v DummyIds          The object containing the IDs to respond with.
 * @ret NTSTATUS        The status of the operation.
 */
static NTSTATUS STDCALL WvDummyIds(
    IN PIRP Irp,
    IN WV_SP_DUMMY_IDS DummyIds
  ) {
    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(Irp);
    BUS_QUERY_ID_TYPE query_type = io_stack_loc->Parameters.QueryId.IdType;
    const CHAR * start;
    const WCHAR * ids;
    UINT32 len;
    NTSTATUS status;

    start = (const CHAR *) DummyIds + DummyIds->Offset;
    ids = (const WCHAR *) start;
    switch (query_type) {
        case BusQueryDeviceID:
          ids += DummyIds->DevOffset;
          len = DummyIds->DevLen;
          break;

        case BusQueryInstanceID:
          ids += DummyIds->InstanceOffset;
          len = DummyIds->InstanceLen;
          break;

        case BusQueryHardwareIDs:
          ids += DummyIds->HardwareOffset;
          len = DummyIds->HardwareLen;
          break;

        case BusQueryCompatibleIDs:
          ids += DummyIds->CompatOffset;
          len = DummyIds->CompatLen;
          break;

        default:
          return WvlIrpComplete(Irp, 0, STATUS_NOT_SUPPORTED);
      }

    /* Allocate the return buffer. */
    Irp->IoStatus.Information = (ULONG_PTR) wv_palloc(len * sizeof *ids);
    if (Irp->IoStatus.Information == 0) {
        DBG("wv_palloc failed.\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto alloc_info;
      }
    /* Copy the working buffer to the return buffer. */
    RtlCopyMemory(
        (PVOID) Irp->IoStatus.Information,
        ids,
        len * sizeof *ids
      );
    status = STATUS_SUCCESS;

    /* irp->IoStatus.Information not freed. */
    alloc_info:

    return WvlIrpComplete(Irp, Irp->IoStatus.Information, status);
  }
Esempio n. 6
0
/* Handle an IRP. */
static NTSTATUS WvFilediskIrpDispatch(
    IN PDEVICE_OBJECT dev_obj,
    IN PIRP irp
  ) {
    PIO_STACK_LOCATION io_stack_loc;
    WV_SP_FILEDISK_T filedisk;
    NTSTATUS status;

    io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    filedisk = dev_obj->DeviceExtension;
    switch (io_stack_loc->MajorFunction) {
        case IRP_MJ_SCSI:
          return WvlDiskScsi(dev_obj, irp, filedisk->disk);

        case IRP_MJ_PNP:
          status = WvlDiskPnp(dev_obj, irp, filedisk->disk);
          /* Note any state change. */
          filedisk->Dev->OldState = filedisk->disk->OldState;
          filedisk->Dev->State = filedisk->disk->State;
          if (filedisk->Dev->State == WvlDiskStateNotStarted) {
              if (!filedisk->Dev->BusNode.Linked) {
                  /* Unlinked _and_ deleted */
                  DBG("Deleting filedisk PDO: %p", dev_obj);
                  IoDeleteDevice(dev_obj);
                }
            }
          return status;

        case IRP_MJ_DEVICE_CONTROL:
          return WvlDiskDevCtl(
              filedisk->disk,
              irp,
              io_stack_loc->Parameters.DeviceIoControl.IoControlCode
            );

        case IRP_MJ_POWER:
          return WvlDiskPower(dev_obj, irp, filedisk->disk);

        case IRP_MJ_CREATE:
        case IRP_MJ_CLOSE:
          /* Always succeed with nothing to do. */
          return WvlIrpComplete(irp, 0, STATUS_SUCCESS);

        case IRP_MJ_SYSTEM_CONTROL:
          return WvlDiskSysCtl(dev_obj, irp, filedisk->disk);

        default:
          DBG("Unhandled IRP_MJ_*: %d\n", io_stack_loc->MajorFunction);
      }
    return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED);
  }
Esempio n. 7
0
/**
 * Handle a dummy IOCTL for creating a dummy PDO.
 *
 * @v Irp               An IRP with an associated buffer containing
 *                      WV_S_DUMMY_IDS data.
 * @ret NTSTATUS        The status of the operation.
 */
NTSTATUS STDCALL WvDummyIoctl(IN PIRP Irp) {
    WV_SP_DUMMY_IDS dummy_ids = Irp->AssociatedIrp.SystemBuffer;
    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(Irp);

    if (
        io_stack_loc->Parameters.DeviceIoControl.InputBufferLength <
        sizeof *dummy_ids
      ) {
        DBG("Dummy IDs too small in IRP %p.\n", Irp);
        return WvlIrpComplete(Irp, 0, STATUS_INVALID_PARAMETER);
      }

    return WvlIrpComplete(Irp, 0, WvDummyAdd_(dummy_ids, NULL));
  }
Esempio n. 8
0
static NTSTATUS STDCALL WvlDiskDevCtlScsiGetAddr_(
    IN WVL_SP_DISK_T disk,
    IN PIRP irp
) {
    PIO_STACK_LOCATION io_stack_loc= IoGetCurrentIrpStackLocation(irp);
    UINT32 copy_size;
    SCSI_ADDRESS scsi_address;

    copy_size = (
                    io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength <
                    sizeof (SCSI_ADDRESS) ?
                    io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength :
                    sizeof (SCSI_ADDRESS)
                );
    scsi_address.Length = sizeof (SCSI_ADDRESS);
    scsi_address.PortNumber = 0;
    scsi_address.PathId = 0;
    scsi_address.TargetId = WvlDiskUnitNum(disk);
    scsi_address.Lun = 0;
    RtlCopyMemory(
        irp->AssociatedIrp.SystemBuffer,
        &scsi_address,
        copy_size
    );
    return WvlIrpComplete(irp, (ULONG_PTR) copy_size, STATUS_SUCCESS);
}
Esempio n. 9
0
static NTSTATUS STDCALL WvlDiskDevCtlGetGeom_(
    IN WVL_SP_DISK_T disk,
    IN PIRP irp
) {
    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    UINT32 copy_size;
    DISK_GEOMETRY disk_geom;

    copy_size = (
                    io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength <
                    sizeof (DISK_GEOMETRY) ?
                    io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength :
                    sizeof (DISK_GEOMETRY)
                );
    disk_geom.MediaType = FixedMedia;
    disk_geom.Cylinders.QuadPart = disk->Cylinders;
    disk_geom.TracksPerCylinder = disk->Heads;
    disk_geom.SectorsPerTrack = disk->Sectors;
    disk_geom.BytesPerSector = disk->SectorSize;
    RtlCopyMemory(
        irp->AssociatedIrp.SystemBuffer,
        &disk_geom,
        copy_size
    );
    return WvlIrpComplete(irp, (ULONG_PTR) copy_size, STATUS_SUCCESS);
}
Esempio n. 10
0
NTSTATUS STDCALL WvDiskPnpQueryDevText(
    IN PDEVICE_OBJECT dev_obj,
    IN PIRP irp,
    IN WVL_SP_DISK_T disk
  ) {
    IN WV_SP_DEV_T dev = WvDevFromDevObj(dev_obj);
    WCHAR (*str)[512];
    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    NTSTATUS status;
    UINT32 str_len;

    /* Allocate a string buffer. */
    str = wv_mallocz(sizeof *str);
    if (str == NULL) {
        DBG("wv_malloc IRP_MN_QUERY_DEVICE_TEXT\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto alloc_str;
      }
    /* Determine the query type. */
    switch (io_stack_loc->Parameters.QueryDeviceText.DeviceTextType) {
        case DeviceTextDescription:
          str_len = swprintf(*str, WVL_M_WLIT L" Disk") + 1;
          irp->IoStatus.Information =
            (ULONG_PTR) wv_palloc(str_len * sizeof *str);
          if (irp->IoStatus.Information == 0) {
              DBG("wv_palloc DeviceTextDescription\n");
              status = STATUS_INSUFFICIENT_RESOURCES;
              goto alloc_info;
            }
          RtlCopyMemory(
              (PWCHAR) irp->IoStatus.Information,
              str,
              str_len * sizeof *str
            );
          status = STATUS_SUCCESS;
          goto alloc_info;

        case DeviceTextLocationInformation:
          if (disk->disk_ops.PnpQueryId) {
              io_stack_loc->MinorFunction = IRP_MN_QUERY_ID;
              io_stack_loc->Parameters.QueryId.IdType = BusQueryInstanceID;
              return disk->disk_ops.PnpQueryId(dev_obj, irp, disk);
            }
          /* Else, fall through... */

        default:
          irp->IoStatus.Information = 0;
          status = STATUS_NOT_SUPPORTED;
      }
    /* irp->IoStatus.Information not freed. */
    alloc_info:

    wv_free(str);
    alloc_str:

    return WvlIrpComplete(irp, irp->IoStatus.Information, status);
  }
Esempio n. 11
0
/* Handle an IRP. */
NTSTATUS AoeBusIrpDispatch(
    IN PDEVICE_OBJECT dev_obj,
    IN PIRP irp
) {
    PIO_STACK_LOCATION io_stack_loc;
    NTSTATUS status;
    ULONG POINTER_ALIGNMENT code;

    io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    switch (io_stack_loc->MajorFunction) {
    case IRP_MJ_PNP:
        status = WvlBusPnp(&AoeBusMain, irp);
        /* Did the bus detach? */
        if (AoeBusMain.State == WvlBusStateDeleted) {
            AoeStop();
            /* Delete. */
            IoDeleteDevice(AoeBusMain.Fdo);
            /* Disassociate. */
            AoeBusMain.Fdo = NULL;
        }
        return status;

    case IRP_MJ_DEVICE_CONTROL:
        code = io_stack_loc->Parameters.DeviceIoControl.IoControlCode;
        return AoeBusDevCtl(irp, code);

    case IRP_MJ_POWER:
        return WvlBusPower(&AoeBusMain, irp);

    case IRP_MJ_CREATE:
    case IRP_MJ_CLOSE:
        /* Always succeed with nothing to do. */
        return WvlIrpComplete(irp, 0, STATUS_SUCCESS);

    case IRP_MJ_SYSTEM_CONTROL:
        return WvlBusSysCtl(&AoeBusMain, irp);

    default:
        ;
    }
    return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED);
}
Esempio n. 12
0
NTSTATUS STDCALL AoeBusDevCtl(
    IN PIRP irp,
    IN ULONG POINTER_ALIGNMENT code
) {
    switch(code) {
    case IOCTL_AOE_SCAN:
        return AoeBusDevCtlScan(irp);

    case IOCTL_AOE_SHOW:
        return AoeBusDevCtlShow(irp);

    case IOCTL_AOE_MOUNT:
        return AoeBusDevCtlMount(irp);

    case IOCTL_AOE_UMOUNT:
        return AoeBusDevCtlDetach_(irp);

    default:
        DBG("Unsupported IOCTL\n");
        return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED);
    }
}
Esempio n. 13
0
/* Handle an IRP. */
static NTSTATUS WvDummyIrpDispatch(
    IN PDEVICE_OBJECT dev_obj,
    IN PIRP irp
  ) {
    PIO_STACK_LOCATION io_stack_loc;
    WV_SP_DEV_T dev;

    io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    dev = WvDevFromDevObj(dev_obj);
    switch (io_stack_loc->MajorFunction) {
        case IRP_MJ_PNP:
          return WvDummyPnp(
              dev,
              irp,
              io_stack_loc->MinorFunction
            );

        default:
          DBG("Unhandled IRP_MJ_*: %d\n", io_stack_loc->MajorFunction);
      }
    return WvlIrpComplete(irp, 0, STATUS_NOT_SUPPORTED);
  }
Esempio n. 14
0
/* Filedisk I/O routine. */
static NTSTATUS STDCALL WvFilediskIo_(
    IN WVL_SP_DISK_T disk_ptr,
    IN WVL_E_DISK_IO_MODE mode,
    IN LONGLONG start_sector,
    IN UINT32 sector_count,
    IN PUCHAR buffer,
    IN PIRP irp
  ) {
    WV_SP_FILEDISK_T filedisk_ptr;
    LARGE_INTEGER offset;
    NTSTATUS status;
    IO_STATUS_BLOCK io_status;

    if (sector_count < 1) {
        /* A silly request. */
        DBG("sector_count < 1; cancelling\n");
        return WvlIrpComplete(irp, 0, STATUS_CANCELLED);
      }

    /* Establish pointer to the filedisk. */
    filedisk_ptr = CONTAINING_RECORD(disk_ptr, WV_S_FILEDISK_T, disk);

    /*
     * These SCSI read/write IRPs should be completed in the thread context.
     * Check if the IRP was already marked pending.
     */
    if (!(IoGetCurrentIrpStackLocation(irp)->Control & SL_PENDING_RETURNED)) {
        /* Enqueue and signal work. */
        IoMarkIrpPending(irp);
        ExInterlockedInsertTailList(
            filedisk_ptr->Irps,
            &irp->Tail.Overlay.ListEntry,
            filedisk_ptr->IrpsLock
          );
        KeSetEvent(&filedisk_ptr->Thread->Signal, 0, FALSE);
        return STATUS_PENDING;
      }

    /* Calculate the offset. */
    offset.QuadPart = start_sector * disk_ptr->SectorSize;
    offset.QuadPart += filedisk_ptr->offset.QuadPart;

    /* Perform the read/write. */
    if (mode == WvlDiskIoModeWrite) {
        status = ZwWriteFile(
            filedisk_ptr->file,
            NULL,
            NULL,
            NULL,
            &io_status,
            buffer,
            sector_count * disk_ptr->SectorSize,
            &offset,
            NULL
          );
      } else {
        status = ZwReadFile(
            filedisk_ptr->file,
            NULL,
            NULL,
            NULL,
            &io_status,
            buffer,
            sector_count * disk_ptr->SectorSize,
            &offset,
            NULL
          );
        /* When the MBR is read, re-determine the disk geometry. */
        if (!start_sector)
          WvlDiskGuessGeometry((WVL_AP_DISK_BOOT_SECT) buffer, disk_ptr);
      }
    return WvlIrpComplete(irp, sector_count * disk_ptr->SectorSize, status);
  }
Esempio n. 15
0
static NTSTATUS STDCALL AoeBusPnpQueryDevText_(
    IN WVL_SP_BUS_T bus,
    IN PIRP irp
) {
    WCHAR (*str)[512];
    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    NTSTATUS status;
    UINT32 str_len;

    /* Allocate a string buffer. */
    str = wv_mallocz(sizeof *str);
    if (str == NULL) {
        DBG("wv_malloc IRP_MN_QUERY_DEVICE_TEXT\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto alloc_str;
    }
    /* Determine the query type. */
    switch (io_stack_loc->Parameters.QueryDeviceText.DeviceTextType) {
    case DeviceTextDescription:
        str_len = swprintf(*str, L"AoE Bus") + 1;
        irp->IoStatus.Information =
            (ULONG_PTR) wv_palloc(str_len * sizeof **str);
        if (irp->IoStatus.Information == 0) {
            DBG("wv_palloc DeviceTextDescription\n");
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto alloc_info;
        }
        RtlCopyMemory(
            (PWCHAR) irp->IoStatus.Information,
            str,
            str_len * sizeof **str
        );
        status = STATUS_SUCCESS;
        goto alloc_info;

    case DeviceTextLocationInformation:
        str_len = AoeBusPnpId_(
                      NULL,
                      BusQueryInstanceID,
                      str
                  );
        irp->IoStatus.Information =
            (ULONG_PTR) wv_palloc(str_len * sizeof **str);
        if (irp->IoStatus.Information == 0) {
            DBG("wv_palloc DeviceTextLocationInformation\n");
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto alloc_info;
        }
        RtlCopyMemory(
            (PWCHAR) irp->IoStatus.Information,
            str,
            str_len * sizeof **str
        );
        status = STATUS_SUCCESS;
        goto alloc_info;

    default:
        irp->IoStatus.Information = 0;
        status = STATUS_NOT_SUPPORTED;
    }
    /* irp->IoStatus.Information not freed. */
alloc_info:

    wv_free(str);
alloc_str:

    return WvlIrpComplete(irp, irp->IoStatus.Information, status);
}
Esempio n. 16
0
static NTSTATUS STDCALL WvlDiskDevCtlStorageQueryProp_(
    IN WVL_SP_DISK_T disk,
    IN PIRP irp
) {
    PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
    NTSTATUS status = STATUS_INVALID_PARAMETER;
    PSTORAGE_PROPERTY_QUERY storage_prop_query = irp->AssociatedIrp.SystemBuffer;
    UINT32 copy_size;
    STORAGE_ADAPTER_DESCRIPTOR storage_adapter_desc;
    STORAGE_DEVICE_DESCRIPTOR storage_dev_desc;

    if (
        storage_prop_query->PropertyId == StorageAdapterProperty &&
        storage_prop_query->QueryType == PropertyStandardQuery
    ) {
        copy_size = (
                        io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength <
                        sizeof (STORAGE_ADAPTER_DESCRIPTOR) ?
                        io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength :
                        sizeof (STORAGE_ADAPTER_DESCRIPTOR)
                    );
        storage_adapter_desc.Version = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
        storage_adapter_desc.Size = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
        storage_adapter_desc.MaximumTransferLength =
            WvlDiskMaxXferLen(disk);
#if 0
        storage_adapter_desc.MaximumTransferLength = SECTORSIZE * POOLSIZE;
#endif
        storage_adapter_desc.MaximumPhysicalPages = (UINT32) -1;
        storage_adapter_desc.AlignmentMask = 0;
        storage_adapter_desc.AdapterUsesPio = TRUE;
        storage_adapter_desc.AdapterScansDown = FALSE;
        storage_adapter_desc.CommandQueueing = FALSE;
        storage_adapter_desc.AcceleratedTransfer = FALSE;
        storage_adapter_desc.BusType = BusTypeScsi;
        RtlCopyMemory(
            irp->AssociatedIrp.SystemBuffer,
            &storage_adapter_desc,
            copy_size
        );
        status = STATUS_SUCCESS;
    }

    if (
        storage_prop_query->PropertyId == StorageDeviceProperty &&
        storage_prop_query->QueryType == PropertyStandardQuery
    ) {
        copy_size = (
                        io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength <
                        sizeof (STORAGE_DEVICE_DESCRIPTOR) ?
                        io_stack_loc->Parameters.DeviceIoControl.OutputBufferLength :
                        sizeof (STORAGE_DEVICE_DESCRIPTOR)
                    );
        storage_dev_desc.Version = sizeof (STORAGE_DEVICE_DESCRIPTOR);
        storage_dev_desc.Size = sizeof (STORAGE_DEVICE_DESCRIPTOR);
        storage_dev_desc.DeviceType = DIRECT_ACCESS_DEVICE;
        storage_dev_desc.DeviceTypeModifier = 0;
        storage_dev_desc.RemovableMedia = WvlDiskIsRemovable[disk->Media];
        storage_dev_desc.CommandQueueing = FALSE;
        storage_dev_desc.VendorIdOffset = 0;
        storage_dev_desc.ProductIdOffset = 0;
        storage_dev_desc.ProductRevisionOffset = 0;
        storage_dev_desc.SerialNumberOffset = 0;
        storage_dev_desc.BusType = BusTypeScsi;
        storage_dev_desc.RawPropertiesLength = 0;
        RtlCopyMemory(
            irp->AssociatedIrp.SystemBuffer,
            &storage_dev_desc,
            copy_size
        );
        status = STATUS_SUCCESS;
    }

    if (status == STATUS_INVALID_PARAMETER) {
        DBG(
            "!!Invalid IOCTL_STORAGE_QUERY_PROPERTY "
            "(PropertyId: %08x / QueryType: %08x)!!\n",
            storage_prop_query->PropertyId,
            storage_prop_query->QueryType
        );
        return WvlIrpComplete(irp, 0, status);
    }
    return WvlIrpComplete(irp, (ULONG_PTR) copy_size, status);
}