| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| library fuchsia.hardware.block; |
| |
| using zx; |
| |
| // !!! IMPORTANT !!! |
| // Most of the definitions in this file need to be kept in sync with: |
| // - //src/lib/storage/block_client/rust/src/lib.rs; |
| // - //zircon/public/system/public/zircon/device/block.h. |
| |
| const BLOCK_FLAG_READONLY uint32 = 0x00000001; |
| const BLOCK_FLAG_REMOVABLE uint32 = 0x00000002; |
| /// Block device has bootdata partition map provided by device metadata. |
| const BLOCK_FLAG_BOOTPART uint32 = 0x00000004; |
| /// Flag advertising trim support. |
| const BLOCK_FLAG_TRIM_SUPPORT uint32 = 0x00000008; |
| |
| const BLOCK_MAX_TRANSFER_UNBOUNDED uint32 = 0xFFFFFFFF; |
| |
| type BlockInfo = struct { |
| /// The number of blocks in this block device. |
| block_count uint64; |
| |
| /// The size of a single block. |
| block_size uint32; |
| |
| /// Max size in bytes per transfer. May be `BLOCK_MAX_TRANSFER_UNBOUNDED` if |
| /// there is no restriction. |
| max_transfer_size uint32; |
| |
| flags uint32; |
| reserved uint32; |
| }; |
| |
| type BlockStats = struct { |
| /// Total number of block ops processed. |
| total_ops uint64; |
| /// Total number of blocks processed. |
| total_blocks uint64; |
| total_reads uint64; |
| total_blocks_read uint64; |
| total_writes uint64; |
| total_blocks_written uint64; |
| }; |
| |
| alias Vmoid = uint16; |
| |
| // Dummy vmoid value reserved for "invalid". Will never be allocated; can be |
| // used as a local value for unallocated / freed ID. |
| const BLOCK_VMOID_INVALID Vmoid = 0; |
| |
| const BLOCK_GUID_LEN uint32 = 16; |
| |
| /// Multiple block I/O operations may be sent at once before a response is |
| /// actually sent back. Block I/O ops may be sent concurrently to different |
| /// vmoids, and they also may be sent to different groups at any point in time. |
| /// |
| /// `MAX_TXN_GROUP_COUNT` "groups" are pre-allocated lanes separated on the |
| /// block server. Using a group allows multiple message to be buffered at once |
| /// on a single communication channel before receiving a response. |
| /// |
| /// Usage of groups is identified by `BLOCKIO_GROUP_ITEM`, and is optional. |
| /// |
| /// These groups may be referred to with a "groupid", in the range [0, |
| /// `MAX_TXN_GROUP_COUNT`). |
| /// |
| /// The protocol to communicate with a single group is as follows: |
| /// 1) SEND [N - 1] messages with an allocated groupid for any value of 1 <= N. |
| /// The `BLOCKIO_GROUP_ITEM` flag is set for these messages. |
| /// 2) SEND a final Nth message with the same groupid. The `BLOCKIO_GROUP_ITEM |
| /// | BLOCKIO_GROUP_LAST` flags are set for this message. |
| /// 3) RECEIVE a single response from the Block I/O server after all N requests |
| /// have completed. This response is sent once all operations either complete |
| /// or a single operation fails. At this point, step (1) may begin again for |
| /// the same groupid. |
| /// |
| /// For `BLOCKIO_READ` and `BLOCKIO_WRITE`, N may be greater than 1. Otherwise, |
| /// N == 1 (skipping step (1) in the protocol above). |
| /// |
| /// Notes: |
| /// - groupids may operate on any number of vmoids at once. |
| /// - If additional requests are sent on the same groupid before step (3) has |
| /// completed, then the additional request will not be processed. If |
| /// `BLOCKIO_GROUP_LAST` is set, an error will be returned. Otherwise, the |
| /// request will be silently dropped. |
| /// - Messages within a group are not guaranteed to be processed in any order |
| /// relative to each other. |
| /// - All requests receive responses, except for ones with `BLOCKIO_GROUP_ITEM` |
| /// that do not have `BLOCKIO_GROUP_LAST` set. |
| /// |
| /// For example, the following is a valid sequence of transactions: |
| /// |
| /// -> (groupid = 1, vmoid = 1, OP = Write | GroupItem, reqid = 1) |
| /// -> (groupid = 1, vmoid = 2, OP = Write | GroupItem, reqid = 2) |
| /// -> (groupid = 2, vmoid = 3, OP = Write | GroupItem | GroupLast, reqid = 0) |
| /// <- Response sent to groupid = 2, reqid = 0 |
| /// -> (groupid = 1, vmoid = 1, OP = Read | GroupItem | GroupLast, reqid = 3) |
| /// <- Response sent to groupid = 1, reqid = 3 |
| /// -> (groupid = 3, vmoid = 1, OP = Write | GroupItem, reqid = 4) |
| /// -> (groupid = don't care, vmoid = 1, OP = Read, reqid = 5) |
| /// <- Response sent to reqid = 5 |
| /// -> (groupid = 3, vmoid = 1, OP = Read | GroupItem | GroupLast, reqid = 6) |
| /// <- Response sent to groupid = 3, reqid = 6 |
| /// |
| /// Each transaction reads or writes up to `length` blocks from the device, |
| /// starting at `dev_offset` blocks, into the VMO associated with `vmoid`, |
| /// starting at `vmo_offset` blocks. If the transaction is out of range, for |
| /// example if `length` is too large or if `dev_offset` is beyond the end of the |
| /// device, `ZX_ERR_OUT_OF_RANGE` is returned. |
| const MAX_TXN_GROUP_COUNT uint32 = 8; |
| |
| /// The Request ID allowing callers to correspond requests with responses. This |
| /// field is entirely for client-side bookkeeping; there is no obligation to |
| /// make request IDs unique. |
| alias Reqid = uint32; |
| alias Groupid = uint16; |
| |
| type BlockFifoRequest = struct { |
| opcode uint32; |
| /// Transmitted in the `block_fifo_response_t`. |
| reqid Reqid; |
| /// Only used if `opcode & BLOCK_GROUP_ITEM`. |
| group Groupid; |
| vmoid Vmoid; |
| length uint32; |
| vmo_offset uint64; |
| dev_offset uint64; |
| trace_flow_id uint64; |
| }; |
| |
| type BlockFifoResponse = struct { |
| status zx.status; |
| reqid Reqid; |
| /// Only valid if transmitted in request. |
| group Groupid; |
| reserved0 Vmoid; |
| /// The number of messages in the transaction completed by the block server. |
| count uint32; |
| reserved1 uint64; |
| reserved2 uint64; |
| reserved3 uint64; |
| }; |
| |
| /// `BLOCK_OP_READ`, `BLOCK_OP_WRITE` |
| // |
| // Note: this data structure is used for the driver <--> driver interfaces, |
| // while `BlockFifoRequest` above is part of a client <--> server interface and |
| // related to the block FIDL API. |
| type BlockReadWrite = resource struct { |
| /// Command and flags. |
| command uint32; |
| |
| /// Available for temporary use. |
| extra uint32; |
| |
| /// VMO of data to read or write. |
| vmo zx.handle:VMO; |
| |
| /// Transfer length in blocks (0 is invalid). |
| length uint32; |
| |
| /// Device offset in blocks. |
| offset_dev uint64; |
| |
| /// VMO offset in blocks. |
| offset_vmo uint64; |
| }; |
| |
| /// `BLOCK_OP_TRIM` |
| type BlockTrim = struct { |
| /// Command and flags. |
| command uint32; |
| |
| /// Transfer length in blocks (0 is invalid). |
| length uint32; |
| |
| /// Device offset in blocks. |
| offset_dev uint64; |
| }; |
| |
| type BlockOp = strict resource union { |
| /// All Commands |
| 1: command uint32; |
| |
| /// Read and Write ops use rw for parameters. |
| 2: rw BlockReadWrite; |
| 3: trim BlockTrim; |
| }; |
| |
| /// Performs a regular data read or write from the device. The operation may |
| /// be cached internally. |
| const BLOCK_OP_READ uint32 = 0x00000001; |
| const BLOCK_OP_WRITE uint32 = 0x00000002; |
| |
| /// Write any controller or device cached data to nonvolatile storage. |
| const BLOCK_OP_FLUSH uint32 = 0x00000003; |
| |
| /// Instructs the device to invalidate a number of blocks, making them usable |
| /// for storing something else. This is basically a "delete" optimization, |
| /// where the device is in charge of discarding the old content without |
| /// clients having to write a given pattern. The operation may be cached |
| /// internally. |
| const BLOCK_OP_TRIM uint32 = 0x00000004; |
| |
| /// Detaches the VMO from the block device. |
| const BLOCK_OP_CLOSE_VMO uint32 = 0x00000005; |
| |
| const BLOCK_OP_MASK uint32 = 0x000000FF; |
| |
| /// Mark this operation as "Force Unit Access" (FUA), indicating that |
| /// it should not complete until the data is written to the non-volatile |
| /// medium (write), and that reads should bypass any on-device caches. |
| const BLOCK_FL_FORCE_ACCESS uint32 = 0x00001000; |
| |
| /// Associate the following request with `group`. |
| const BLOCK_GROUP_ITEM uint32 = 0x00000400; |
| |
| /// Only respond after this request (and all previous within group) have |
| /// completed. Only valid with `BLOCKIO_GROUP_ITEM`. |
| const BLOCK_GROUP_LAST uint32 = 0x00000800; |
| const BLOCK_FLAG_MASK uint32 = 0x0000FF00; |
| |
| @transport("Banjo") |
| @banjo_layout("ddk-protocol") |
| protocol BlockImpl { |
| /// Obtains the parameters of the block device (`block_info_t`) and the |
| /// required size of `block_txn_t`. The `block_txn_t`s submitted via |
| /// `Queue()` must have `block_op_size_out - sizeof(block_op_t)` bytes |
| /// available at the end of the structure for the use of the driver. |
| Query() -> (struct { |
| info BlockInfo; |
| block_op_size uint64; |
| }); |
| |
| /// Submits an I/O request for processing. Ownership of `op` is transferred |
| /// to callee until `completion_cb` is invoked. Success or failure will be |
| /// reported via the `completion_cb`. This callback may be called before the |
| /// `Queue()` method returns. |
| @async |
| Queue(resource struct { |
| @in_out |
| txn BlockOp; |
| }) -> (resource struct { |
| status zx.status; |
| @mutable |
| op BlockOp; |
| }); |
| }; |
| |
| @transport("Banjo") |
| @banjo_layout("ddk-protocol") |
| protocol Block { |
| /// Obtains the parameters of the block device (`block_info_t`) and the |
| /// required size of `block_txn_t`. The `block_txn_t`s submitted via |
| /// `Queue()` must have `block_op_size_out - sizeof(block_op_t)` bytes |
| /// available at the end of the structure for the use of the driver. |
| Query() -> (struct { |
| info BlockInfo; |
| block_op_size uint64; |
| }); |
| |
| /// Submits an I/O request for processing. Ownership of `op` is transferred |
| /// to callee until `completion_cb` is invoked. Success or failure will be |
| /// reported via the `completion_cb`. This callback may be called before the |
| /// `Queue()` method returns. |
| @async |
| Queue(resource struct { |
| @in_out |
| txn BlockOp; |
| }) -> (resource struct { |
| status zx.status; |
| @mutable |
| op BlockOp; |
| }); |
| }; |