/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2019 Joyent, Inc. * Copyright 2020 Oxide Computer Company */ /* * VIRTIO BLOCK DRIVER */ #ifndef _VIOBLK_H #define _VIOBLK_H #include "virtio.h" #ifdef __cplusplus extern "C" { #endif /* * VIRTIO BLOCK CONFIGURATION REGISTERS * * These are offsets into the device-specific configuration space available * through the virtio_dev_*() family of functions. */ #define VIRTIO_BLK_CONFIG_CAPACITY 0x00 /* 64 R */ #define VIRTIO_BLK_CONFIG_SIZE_MAX 0x08 /* 32 R */ #define VIRTIO_BLK_CONFIG_SEG_MAX 0x0C /* 32 R */ #define VIRTIO_BLK_CONFIG_GEOMETRY_C 0x10 /* 16 R */ #define VIRTIO_BLK_CONFIG_GEOMETRY_H 0x12 /* 8 R */ #define VIRTIO_BLK_CONFIG_GEOMETRY_S 0x13 /* 8 R */ #define VIRTIO_BLK_CONFIG_BLK_SIZE 0x14 /* 32 R */ #define VIRTIO_BLK_CONFIG_TOPO_PBEXP 0x18 /* 8 R */ #define VIRTIO_BLK_CONFIG_TOPO_ALIGN 0x19 /* 8 R */ #define VIRTIO_BLK_CONFIG_TOPO_MIN_SZ 0x1A /* 16 R */ #define VIRTIO_BLK_CONFIG_TOPO_OPT_SZ 0x1C /* 32 R */ #define VIRTIO_BLK_CONFIG_WRITEBACK 0x20 /* 8 R */ /* unused 0x21 */ /* 8 R */ #define VIRTIO_BLK_CONFIG_NUM_QUEUES 0x22 /* 16 R */ #define VIRTIO_BLK_CONFIG_MAX_DISCARD_SECT 0x24 /* 32 R */ #define VIRTIO_BLK_CONFIG_MAX_DISCARD_SEG 0x28 /* 32 R */ #define VIRTIO_BLK_CONFIG_DISCARD_ALIGN 0x2C /* 32 R */ #define VIRTIO_BLK_CONFIG_MAX_WRITE_ZERO_SECT 0x30 /* 32 R */ #define VIRTIO_BLK_CONFIG_MAX_WRITE_ZERO_SEG 0x34 /* 32 R */ #define VIRTIO_BLK_CONFIG_WRITE_ZERO_UNMAP 0x38 /* 8 R */ /* * VIRTIO BLOCK VIRTQUEUES * * Virtio block devices have just one queue which is used to make the various * supported I/O requests. */ #define VIRTIO_BLK_VIRTQ_IO 0 /* * VIRTIO BLOCK FEATURE BITS */ #define VIRTIO_BLK_F_BARRIER (1ULL << 0) #define VIRTIO_BLK_F_SIZE_MAX (1ULL << 1) #define VIRTIO_BLK_F_SEG_MAX (1ULL << 2) #define VIRTIO_BLK_F_GEOMETRY (1ULL << 4) #define VIRTIO_BLK_F_RO (1ULL << 5) #define VIRTIO_BLK_F_BLK_SIZE (1ULL << 6) #define VIRTIO_BLK_F_SCSI (1ULL << 7) #define VIRTIO_BLK_F_FLUSH (1ULL << 9) #define VIRTIO_BLK_F_TOPOLOGY (1ULL << 10) #define VIRTIO_BLK_F_CONFIG_WCE (1ULL << 11) #define VIRTIO_BLK_F_MQ (1ULL << 12) #define VIRTIO_BLK_F_DISCARD (1ULL << 13) #define VIRTIO_BLK_F_WRITE_ZEROES (1ULL << 14) /* * These features are supported by the driver and we will request them from the * device. */ #define VIRTIO_BLK_WANTED_FEATURES (VIRTIO_BLK_F_RO | \ VIRTIO_BLK_F_BLK_SIZE | \ VIRTIO_BLK_F_FLUSH | \ VIRTIO_BLK_F_TOPOLOGY | \ VIRTIO_BLK_F_SEG_MAX | \ VIRTIO_BLK_F_SIZE_MAX | \ VIRTIO_BLK_F_DISCARD) /* * VIRTIO BLOCK REQUEST HEADER * * This structure appears at the start of each I/O request buffer. Note that * neither the data payload nor the status byte appear in this structure as * both are handled in separate descriptor entries. */ struct vioblk_req_hdr { uint32_t vbh_type; uint32_t vbh_ioprio; uint64_t vbh_sector; } __packed; /* * VIRTIO BLOCK REQUEST HEADER: COMMANDS (vbh_type) * * Each of these is a command type, except for BARRIER which is logically * OR-ed with one of the other types. */ #define VIRTIO_BLK_T_IN 0 #define VIRTIO_BLK_T_OUT 1 #define VIRTIO_BLK_T_SCSI_CMD 2 #define VIRTIO_BLK_T_SCSI_CMD_OUT 3 #define VIRTIO_BLK_T_FLUSH 4 #define VIRTIO_BLK_T_FLUSH_OUT 5 #define VIRTIO_BLK_T_GET_ID 8 #define VIRTIO_BLK_T_DISCARD 11 #define VIRTIO_BLK_T_WRITE_ZEROES 13 #define VIRTIO_BLK_T_BARRIER 0x80000000 /* * VIRTIO BLOCK DISCARD/WRITE ZEROS DATA * * For hosts that support the DISCARD or WRITE ZEROES features, instead of * data, the vioblk_discard_write_zeros struct is used as the 'data' for * the request. */ struct vioblk_discard_write_zeroes { uint64_t vdwz_sector; uint32_t vdwz_num_sectors; uint32_t vdwz_flags; } __packed; /* * vdwz_flags values */ /* For a WRITE ZEROES request, also unmap the block */ #define VIRTIO_BLK_WRITE_ZEROS_UNMAP (1U << 0) /* * The GET_ID command type does not appear in the specification, but * implementations in the wild use a 20 byte buffer into which the device will * write an ASCII string. The string should not be assumed to be * NUL-terminated. */ #define VIRTIO_BLK_ID_BYTES 20 /* * VIRTIO BLOCK REQUEST HEADER: STATUS CODES * * These are returned in the writeable status byte descriptor included at the * end of each request passed to the device. */ #define VIRTIO_BLK_S_OK 0 #define VIRTIO_BLK_S_IOERR 1 #define VIRTIO_BLK_S_UNSUPP 2 /* * DRIVER PARAMETERS */ /* * In the event that the device does not negotiate DMA parameters, we have to * make a best guess. */ #define VIRTIO_BLK_DEFAULT_MAX_SEG 128 #define VIRTIO_BLK_DEFAULT_MAX_SIZE 4096 /* * We allocate a fixed number of request buffers in advance and place them in a * per-instance free list. */ #define VIRTIO_BLK_REQ_BUFS 256 /* * TYPE DEFINITIONS */ typedef enum vioblk_req_status { VIOBLK_REQSTAT_ALLOCATED = (0x1 << 0), VIOBLK_REQSTAT_INFLIGHT = (0x1 << 1), VIOBLK_REQSTAT_COMPLETE = (0x1 << 2), VIOBLK_REQSTAT_POLLED = (0x1 << 3), VIOBLK_REQSTAT_POLL_COMPLETE = (0x1 << 4), } vioblk_req_status_t; typedef struct vioblk_req { vioblk_req_status_t vbr_status; uint64_t vbr_seqno; int vbr_type; int vbr_error; virtio_dma_t *vbr_dma; virtio_chain_t *vbr_chain; bd_xfer_t *vbr_xfer; list_node_t vbr_link; } vioblk_req_t; typedef struct vioblk_stats { struct kstat_named vbs_rw_outofmemory; struct kstat_named vbs_rw_badoffset; struct kstat_named vbs_rw_queuemax; struct kstat_named vbs_rw_cookiesmax; struct kstat_named vbs_rw_cacheflush; struct kstat_named vbs_intr_queuemax; struct kstat_named vbs_intr_total; struct kstat_named vbs_io_errors; struct kstat_named vbs_unsupp_errors; struct kstat_named vbs_nxio_errors; } vioblk_stats_t; typedef struct vioblk { dev_info_t *vib_dip; virtio_t *vib_virtio; virtio_queue_t *vib_vq; kmutex_t vib_mutex; kcondvar_t vib_cv; bd_handle_t vib_bd_h; ddi_dma_attr_t vib_bd_dma_attr; list_t vib_reqs; uint_t vib_nreqs_alloc; uint_t vib_reqs_capacity; vioblk_req_t *vib_reqs_mem; kstat_t *vib_kstat; vioblk_stats_t *vib_stats; uint64_t vib_nblks; boolean_t vib_readonly; uint_t vib_blk_size; uint_t vib_pblk_size; uint_t vib_seg_max; uint_t vib_seg_size_max; boolean_t vib_can_discard; /* Write Once */ uint_t vib_max_discard_sectors; /* WO */ uint_t vib_max_discard_seg; /* WO */ uint_t vib_discard_sector_align; /* WO */ boolean_t vib_devid_fetched; char vib_devid[VIRTIO_BLK_ID_BYTES + 1]; uint8_t vib_rawid[VIRTIO_BLK_ID_BYTES]; } vioblk_t; #ifdef __cplusplus } #endif #endif /* _VIOBLK_H */