| // 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 uint32 BLOCK_FLAG_READONLY = 0x00000001; |
| const uint32 BLOCK_FLAG_REMOVABLE = 0x00000002; |
| /// Block device has bootdata partition map provided by device metadata. |
| const uint32 BLOCK_FLAG_BOOTPART = 0x00000004; |
| /// Flag advertising trim support. |
| const uint32 BLOCK_FLAG_TRIM_SUPPORT = 0x00000008; |
| |
| const uint32 BLOCK_MAX_TRANSFER_UNBOUNDED = 0xFFFFFFFF; |
| |
| struct BlockInfo { |
| /// The number of blocks in this block device. |
| uint64 block_count; |
| |
| /// The size of a single block. |
| uint32 block_size; |
| |
| /// Max size in bytes per transfer. |
| /// May be BLOCK_MAX_TRANSFER_UNBOUNDED if there |
| /// is no restriction. |
| uint32 max_transfer_size; |
| |
| uint32 flags; |
| uint32 reserved; |
| }; |
| |
| struct BlockStats { |
| /// Total number of block ops processed |
| uint64 total_ops; |
| /// Total number of blocks processed |
| uint64 total_blocks; |
| uint64 total_reads; |
| uint64 total_blocks_read; |
| uint64 total_writes; |
| uint64 total_blocks_written; |
| }; |
| |
| 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 uint32 BLOCK_VMOID_INVALID = 0; |
| |
| const uint32 BLOCK_GUID_LEN = 16; |
| |
| /// Multiple Block IO operations may be sent at once before a response is actually sent back. |
| /// Block IO 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 IO 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 uint32 MAX_TXN_GROUP_COUNT = 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; |
| |
| struct BlockFifoRequest { |
| uint32 opcode; |
| /// Transmitted in the block_fifo_response_t. |
| Reqid reqid; |
| /// Only used if opcode & BLOCK_GROUP_ITEM. |
| Groupid group; |
| Vmoid vmoid; |
| uint32 length; |
| uint64 vmo_offset; |
| uint64 dev_offset; |
| uint64 trace_flow_id; |
| }; |
| |
| struct BlockFifoResponse { |
| zx.status status; |
| Reqid reqid; |
| /// Only valid if transmitted in request. |
| Groupid group; |
| uint16 reserved0; |
| /// The number of messages in the transaction completed by the block server. |
| uint32 count; |
| uint64 reserved1; |
| uint64 reserved2; |
| uint64 reserved3; |
| }; |
| |
| /// `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. |
| resource struct BlockReadWrite { |
| /// Command and flags. |
| uint32 command; |
| |
| /// Available for temporary use. |
| uint32 extra; |
| |
| /// VMO of data to read or write. |
| zx.handle:VMO vmo; |
| |
| /// Transfer length in blocks (0 is invalid). |
| uint32 length; |
| |
| /// Device offset in blocks. |
| uint64 offset_dev; |
| |
| /// VMO offset in blocks. |
| uint64 offset_vmo; |
| }; |
| |
| /// `BLOCK_OP_TRIM` |
| struct BlockTrim { |
| /// Command and flags. |
| uint32 command; |
| |
| /// Transfer length in blocks (0 is invalid). |
| uint32 length; |
| |
| /// Device offset in blocks. |
| uint64 offset_dev; |
| }; |
| |
| resource union BlockOp { |
| /// All Commands |
| 1: uint32 command; |
| |
| /// Read and Write ops use rw for parameters. |
| 2: BlockReadWrite rw; |
| 3: BlockTrim trim; |
| }; |
| |
| /// Performs a regular data read or write from the device. The operation may |
| /// be cached internally. |
| const uint32 BLOCK_OP_READ = 0x00000001; |
| const uint32 BLOCK_OP_WRITE = 0x00000002; |
| |
| /// Write any controller or device cached data to nonvolatile storage. |
| /// This operation always implies BARRIER_BEFORE and BARRIER_AFTER, |
| /// meaning that previous operations will complete before it starts |
| /// and later operations will not start until it is done. |
| const uint32 BLOCK_OP_FLUSH = 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 uint32 BLOCK_OP_TRIM = 0x00000004; |
| |
| /// Detaches the VMO from the block device. |
| const uint32 BLOCK_OP_CLOSE_VMO = 0x00000005; |
| |
| const uint32 BLOCK_OP_MASK = 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 uint32 BLOCK_FL_FORCE_ACCESS = 0x00001000; |
| |
| /// Require that this operation will not begin until all previous |
| /// operations have completed. |
| /// |
| /// Prevents earlier operations from being reordered after this one. |
| const uint32 BLOCK_FL_BARRIER_BEFORE = 0x00000100; |
| |
| /// Require that this operation complete before any subsequent |
| /// operations are started. |
| /// |
| /// Prevents later operations from being reordered before this one. |
| const uint32 BLOCK_FL_BARRIER_AFTER = 0x00000200; |
| |
| /// Associate the following request with |group|. |
| const uint32 BLOCK_GROUP_ITEM = 0x00000400; |
| |
| /// Only respond after this request (and all previous within group) have completed. |
| /// Only valid with BLOCKIO_GROUP_ITEM. |
| const uint32 BLOCK_GROUP_LAST = 0x00000800; |
| const uint32 BLOCK_FLAG_MASK = 0x0000FF00; |
| |
| [Transport = "Banjo", BanjoLayout = "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() -> (BlockInfo info, uint64 block_op_size); |
| |
| /// Submits an IO 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([InOut] BlockOp txn) -> (zx.status status, [Mutable] BlockOp op); |
| }; |
| |
| [Transport = "Banjo", BanjoLayout = "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() -> (BlockInfo info, uint64 block_op_size); |
| |
| /// Submits an IO 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([InOut] BlockOp txn) -> (zx.status status, [Mutable] BlockOp op); |
| }; |