blob: 5fdc4a887fa1c0d4cd8ea4eb01f68b2327d42019 [file] [log] [blame]
// 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);
};