scsi(windows): fix StorageAdapterDescriptor.BusType width (u8 -> u32)

STORAGE_ADAPTER_DESCRIPTOR.BusType is STORAGE_BUS_TYPE, an int-sized
(4-byte) enum, but the repr(C) struct declared it as u8. The total
size stayed 32 bytes by coincidence of alignment padding, and the two
fields actually read today (MaximumTransferLength at offset 8 and
AlignmentMask at offset 16) sit ahead of BusType, so there was no
runtime impact. But BusMajorVersion and BusMinorVersion landed at
offsets 26 and 28 instead of the SDK's 28 and 30, so any future reader
of those fields would have gotten wrong values.

Widen BusType to u32 so BusMajorVersion/BusMinorVersion fall at the
correct offsets, and add a layout regression test asserting every
field offset and the 32-byte total against the winioctl.h layout.
This commit is contained in:
Matthew Jackson
2026-06-23 03:45:34 -07:00
parent 8e6d494e54
commit 4a76deadeb
+42 -1
View File
@@ -109,7 +109,13 @@ struct StorageAdapterDescriptor {
AdapterScansDown: u8, AdapterScansDown: u8,
CommandQueueing: u8, CommandQueueing: u8,
AcceleratedTransfer: u8, AcceleratedTransfer: u8,
BusType: u8, // STORAGE_BUS_TYPE is an `int`-sized enum (4 bytes), not a byte. With the
// four preceding `BOOLEAN`s filling offsets 20..24, `BusType` sits at
// offset 24 and the two `USHORT` version fields follow at 28 and 30 —
// matching winioctl.h. (Declaring this `u8` total-sized to 32 by luck but
// pushed BusMajor/BusMinorVersion to offsets 26/28, so any reader of those
// fields got garbage.)
BusType: u32,
BusMajorVersion: u16, BusMajorVersion: u16,
BusMinorVersion: u16, BusMinorVersion: u16,
} }
@@ -615,4 +621,39 @@ mod tests {
assert_ne!(IOCTL_STORAGE_RESET_DEVICE, 0x002D_1004); assert_ne!(IOCTL_STORAGE_RESET_DEVICE, 0x002D_1004);
assert_ne!(IOCTL_STORAGE_RESET_DEVICE, 0x002D_D000); assert_ne!(IOCTL_STORAGE_RESET_DEVICE, 0x002D_D000);
} }
/// Regression guard for the `StorageAdapterDescriptor` layout. It must
/// match `STORAGE_ADAPTER_DESCRIPTOR` (winioctl.h) field-for-field so a
/// driver-filled buffer is interpreted at the correct offsets. `BusType`
/// is `STORAGE_BUS_TYPE`, an `int`-sized (4-byte) enum, NOT a byte; a
/// previous `u8` declaration kept the total size at 32 by coincidence but
/// shifted `BusMajorVersion`/`BusMinorVersion` to offsets 26/28 (vs the
/// SDK's 28/30), so any reader of those fields got wrong values.
#[test]
fn storage_adapter_descriptor_matches_sdk_layout() {
use std::mem::{offset_of, size_of};
assert_eq!(offset_of!(StorageAdapterDescriptor, Version), 0);
assert_eq!(offset_of!(StorageAdapterDescriptor, Size), 4);
assert_eq!(
offset_of!(StorageAdapterDescriptor, MaximumTransferLength),
8
);
assert_eq!(
offset_of!(StorageAdapterDescriptor, MaximumPhysicalPages),
12
);
assert_eq!(offset_of!(StorageAdapterDescriptor, AlignmentMask), 16);
assert_eq!(offset_of!(StorageAdapterDescriptor, AdapterUsesPio), 20);
assert_eq!(offset_of!(StorageAdapterDescriptor, AdapterScansDown), 21);
assert_eq!(offset_of!(StorageAdapterDescriptor, CommandQueueing), 22);
assert_eq!(
offset_of!(StorageAdapterDescriptor, AcceleratedTransfer),
23
);
// The fields that were misplaced by the old `u8` BusType.
assert_eq!(offset_of!(StorageAdapterDescriptor, BusType), 24);
assert_eq!(offset_of!(StorageAdapterDescriptor, BusMajorVersion), 28);
assert_eq!(offset_of!(StorageAdapterDescriptor, BusMinorVersion), 30);
assert_eq!(size_of::<StorageAdapterDescriptor>(), 32);
}
} }