xref: /illumos-gate/usr/src/uts/common/io/vioblk/vioblk.h (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019 Joyent, Inc.
14  * Copyright 2020 Oxide Computer Company
15  */
16 
17 /*
18  * VIRTIO BLOCK DRIVER
19  */
20 
21 #ifndef _VIOBLK_H
22 #define	_VIOBLK_H
23 
24 #include "virtio.h"
25 
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29 
30 /*
31  * VIRTIO BLOCK CONFIGURATION REGISTERS
32  *
33  * These are offsets into the device-specific configuration space available
34  * through the virtio_dev_*() family of functions.
35  */
36 #define	VIRTIO_BLK_CONFIG_CAPACITY		0x00	/* 64 R   */
37 #define	VIRTIO_BLK_CONFIG_SIZE_MAX		0x08	/* 32 R   */
38 #define	VIRTIO_BLK_CONFIG_SEG_MAX		0x0C	/* 32 R   */
39 #define	VIRTIO_BLK_CONFIG_GEOMETRY_C		0x10	/* 16 R   */
40 #define	VIRTIO_BLK_CONFIG_GEOMETRY_H		0x12	/*  8 R   */
41 #define	VIRTIO_BLK_CONFIG_GEOMETRY_S		0x13	/*  8 R   */
42 #define	VIRTIO_BLK_CONFIG_BLK_SIZE		0x14	/* 32 R   */
43 #define	VIRTIO_BLK_CONFIG_TOPO_PBEXP		0x18	/*  8 R   */
44 #define	VIRTIO_BLK_CONFIG_TOPO_ALIGN		0x19	/*  8 R   */
45 #define	VIRTIO_BLK_CONFIG_TOPO_MIN_SZ		0x1A	/* 16 R   */
46 #define	VIRTIO_BLK_CONFIG_TOPO_OPT_SZ		0x1C	/* 32 R   */
47 #define	VIRTIO_BLK_CONFIG_WRITEBACK		0x20	/*  8 R	  */
48 				/* unused	0x21 */ /*  8 R   */
49 #define	VIRTIO_BLK_CONFIG_NUM_QUEUES		0x22	/* 16 R   */
50 #define	VIRTIO_BLK_CONFIG_MAX_DISCARD_SECT	0x24	/* 32 R   */
51 #define	VIRTIO_BLK_CONFIG_MAX_DISCARD_SEG	0x28	/* 32 R   */
52 #define	VIRTIO_BLK_CONFIG_DISCARD_ALIGN		0x2C	/* 32 R   */
53 #define	VIRTIO_BLK_CONFIG_MAX_WRITE_ZERO_SECT	0x30	/* 32 R   */
54 #define	VIRTIO_BLK_CONFIG_MAX_WRITE_ZERO_SEG	0x34	/* 32 R   */
55 #define	VIRTIO_BLK_CONFIG_WRITE_ZERO_UNMAP	0x38	/*  8 R   */
56 
57 /*
58  * VIRTIO BLOCK VIRTQUEUES
59  *
60  * Virtio block devices have just one queue which is used to make the various
61  * supported I/O requests.
62  */
63 #define	VIRTIO_BLK_VIRTQ_IO		0
64 
65 /*
66  * VIRTIO BLOCK FEATURE BITS
67  */
68 #define	VIRTIO_BLK_F_BARRIER		(1ULL << 0)
69 #define	VIRTIO_BLK_F_SIZE_MAX		(1ULL << 1)
70 #define	VIRTIO_BLK_F_SEG_MAX		(1ULL << 2)
71 #define	VIRTIO_BLK_F_GEOMETRY		(1ULL << 4)
72 #define	VIRTIO_BLK_F_RO			(1ULL << 5)
73 #define	VIRTIO_BLK_F_BLK_SIZE		(1ULL << 6)
74 #define	VIRTIO_BLK_F_SCSI		(1ULL << 7)
75 #define	VIRTIO_BLK_F_FLUSH		(1ULL << 9)
76 #define	VIRTIO_BLK_F_TOPOLOGY		(1ULL << 10)
77 #define	VIRTIO_BLK_F_CONFIG_WCE		(1ULL << 11)
78 #define	VIRTIO_BLK_F_MQ			(1ULL << 12)
79 #define	VIRTIO_BLK_F_DISCARD		(1ULL << 13)
80 #define	VIRTIO_BLK_F_WRITE_ZEROES	(1ULL << 14)
81 
82 /*
83  * These features are supported by the driver and we will request them from the
84  * device.
85  */
86 #define	VIRTIO_BLK_WANTED_FEATURES	(VIRTIO_BLK_F_RO |		\
87 					VIRTIO_BLK_F_BLK_SIZE |		\
88 					VIRTIO_BLK_F_FLUSH |		\
89 					VIRTIO_BLK_F_TOPOLOGY |		\
90 					VIRTIO_BLK_F_SEG_MAX |		\
91 					VIRTIO_BLK_F_SIZE_MAX |		\
92 					VIRTIO_BLK_F_DISCARD)
93 
94 /*
95  * VIRTIO BLOCK REQUEST HEADER
96  *
97  * This structure appears at the start of each I/O request buffer.  Note that
98  * neither the data payload nor the status byte appear in this structure as
99  * both are handled in separate descriptor entries.
100  */
101 struct vioblk_req_hdr {
102 	uint32_t			vbh_type;
103 	uint32_t			vbh_ioprio;
104 	uint64_t			vbh_sector;
105 } __packed;
106 
107 /*
108  * VIRTIO BLOCK REQUEST HEADER: COMMANDS (vbh_type)
109  *
110  * Each of these is a command type, except for BARRIER which is logically
111  * OR-ed with one of the other types.
112  */
113 #define	VIRTIO_BLK_T_IN			0
114 #define	VIRTIO_BLK_T_OUT		1
115 #define	VIRTIO_BLK_T_SCSI_CMD		2
116 #define	VIRTIO_BLK_T_SCSI_CMD_OUT	3
117 #define	VIRTIO_BLK_T_FLUSH		4
118 #define	VIRTIO_BLK_T_FLUSH_OUT		5
119 #define	VIRTIO_BLK_T_GET_ID		8
120 #define	VIRTIO_BLK_T_DISCARD		11
121 #define	VIRTIO_BLK_T_WRITE_ZEROES	13
122 #define	VIRTIO_BLK_T_BARRIER		0x80000000
123 
124 /*
125  * VIRTIO BLOCK DISCARD/WRITE ZEROS DATA
126  *
127  * For hosts that support the DISCARD or WRITE ZEROES features, instead of
128  * data, the vioblk_discard_write_zeros struct is used as the 'data' for
129  * the request.
130  */
131 struct vioblk_discard_write_zeroes {
132 	uint64_t	vdwz_sector;
133 	uint32_t	vdwz_num_sectors;
134 	uint32_t	vdwz_flags;
135 } __packed;
136 
137 /*
138  * vdwz_flags values
139  */
140 
141 /* For a WRITE ZEROES request, also unmap the block */
142 #define	VIRTIO_BLK_WRITE_ZEROS_UNMAP	(1U << 0)
143 
144 /*
145  * The GET_ID command type does not appear in the specification, but
146  * implementations in the wild use a 20 byte buffer into which the device will
147  * write an ASCII string.  The string should not be assumed to be
148  * NUL-terminated.
149  */
150 #define	VIRTIO_BLK_ID_BYTES		20
151 
152 /*
153  * VIRTIO BLOCK REQUEST HEADER: STATUS CODES
154  *
155  * These are returned in the writeable status byte descriptor included at the
156  * end of each request passed to the device.
157  */
158 #define	VIRTIO_BLK_S_OK			0
159 #define	VIRTIO_BLK_S_IOERR		1
160 #define	VIRTIO_BLK_S_UNSUPP		2
161 
162 /*
163  * DRIVER PARAMETERS
164  */
165 
166 /*
167  * In the event that the device does not negotiate DMA parameters, we have to
168  * make a best guess.
169  */
170 #define	VIRTIO_BLK_DEFAULT_MAX_SEG	128
171 #define	VIRTIO_BLK_DEFAULT_MAX_SIZE	4096
172 
173 /*
174  * We allocate a fixed number of request buffers in advance and place them in a
175  * per-instance free list.
176  */
177 #define	VIRTIO_BLK_REQ_BUFS		256
178 
179 /*
180  * TYPE DEFINITIONS
181  */
182 
183 typedef enum vioblk_req_status {
184 	VIOBLK_REQSTAT_ALLOCATED =	(0x1 << 0),
185 	VIOBLK_REQSTAT_INFLIGHT =	(0x1 << 1),
186 	VIOBLK_REQSTAT_COMPLETE =	(0x1 << 2),
187 	VIOBLK_REQSTAT_POLLED =		(0x1 << 3),
188 	VIOBLK_REQSTAT_POLL_COMPLETE =	(0x1 << 4),
189 } vioblk_req_status_t;
190 
191 typedef struct vioblk_req {
192 	vioblk_req_status_t		vbr_status;
193 	uint64_t			vbr_seqno;
194 	int				vbr_type;
195 	int				vbr_error;
196 	virtio_dma_t			*vbr_dma;
197 	virtio_chain_t			*vbr_chain;
198 	bd_xfer_t			*vbr_xfer;
199 	list_node_t			vbr_link;
200 } vioblk_req_t;
201 
202 typedef struct vioblk_stats {
203 	struct kstat_named		vbs_rw_outofmemory;
204 	struct kstat_named		vbs_rw_badoffset;
205 	struct kstat_named		vbs_rw_queuemax;
206 	struct kstat_named		vbs_rw_cookiesmax;
207 	struct kstat_named		vbs_rw_cacheflush;
208 	struct kstat_named		vbs_intr_queuemax;
209 	struct kstat_named		vbs_intr_total;
210 	struct kstat_named		vbs_io_errors;
211 	struct kstat_named		vbs_unsupp_errors;
212 	struct kstat_named		vbs_nxio_errors;
213 } vioblk_stats_t;
214 
215 typedef struct vioblk {
216 	dev_info_t			*vib_dip;
217 	virtio_t			*vib_virtio;
218 	virtio_queue_t			*vib_vq;
219 
220 	kmutex_t			vib_mutex;
221 	kcondvar_t			vib_cv;
222 
223 	bd_handle_t			vib_bd_h;
224 	ddi_dma_attr_t			vib_bd_dma_attr;
225 
226 	list_t				vib_reqs;
227 	uint_t				vib_nreqs_alloc;
228 	uint_t				vib_reqs_capacity;
229 	vioblk_req_t			*vib_reqs_mem;
230 
231 	kstat_t				*vib_kstat;
232 	vioblk_stats_t			*vib_stats;
233 
234 	uint64_t			vib_nblks;
235 	boolean_t			vib_readonly;
236 	uint_t				vib_blk_size;
237 	uint_t				vib_pblk_size;
238 	uint_t				vib_seg_max;
239 	uint_t				vib_seg_size_max;
240 
241 	boolean_t			vib_can_discard;	/* Write Once */
242 	uint_t				vib_max_discard_sectors;	/* WO */
243 	uint_t				vib_max_discard_seg;		/* WO */
244 	uint_t				vib_discard_sector_align;	/* WO */
245 
246 	boolean_t			vib_devid_fetched;
247 	char				vib_devid[VIRTIO_BLK_ID_BYTES + 1];
248 	uint8_t				vib_rawid[VIRTIO_BLK_ID_BYTES];
249 } vioblk_t;
250 
251 #ifdef __cplusplus
252 }
253 #endif
254 
255 #endif /* _VIOBLK_H */
256