//! 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);