blob: ac40990f9a32620a2803cea8750e935d289b8029 [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 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;
});
};