//! The block-device wire protocol — what a filesystem (the FAT server) says to a
//! block driver (usb-storage) over its well-known `.block` endpoint. A protocol
//! module like vfs-protocol / usb-transfer-protocol: extern-struct messages, an
//! `Operation` tag, everything in one IPC message.
//!
//! Data path: read and write move whole blocks to or from a **caller-owned DMA
//! buffer**, named by its physical address — the same physical-address handoff
//! usb-storage already uses toward the controller, one layer up. So a 512-byte
//! sector never has to cross the 256-byte IPC boundary; only the small request /
//! reply headers do. (Safe while the IOMMU is unenforced; see docs/driver-model.md.)

pub const Operation = enum(u32) {
    /// geometry() -> { block_size, block_count }
    geometry = 0,
    /// read(lba, count, physical): read `count` blocks from `lba` into the buffer
    read = 1,
    /// write(lba, count, physical): write `count` blocks at `lba` from the buffer
    write = 2,
    /// flush(): commit any device write cache to stable media (no data transfer).
    /// A filesystem calls this to make prior writes durable — e.g. before power-off,
    /// so a shutdown-time write isn't lost in the USB flash controller's cache.
    flush = 3,
};

pub const Request = extern struct {
    operation: u32,
    reserved: u32 = 0,
    lba: u64,
    count: u32, // number of blocks (read/write)
    reserved2: u32 = 0,
    physical: u64, // caller's DMA buffer physical address (read/write)
};

pub const Reply = extern struct {
    status: i32, // 0 on success, negative on failure
    reserved: u32 = 0,
    block_size: u32, // geometry: bytes per block (512)
    reserved2: u32 = 0,
    block_count: u64, // geometry: total blocks; read/write: blocks moved
};

pub const message_maximum: usize = 256;
pub const request_size: usize = @sizeOf(Request);
pub const reply_size: usize = @sizeOf(Reply);
