xref: /illumos-gate/usr/src/cmd/bhyve/common/pci_virtio_scsi.h (revision 044ca4189dfeaedde4c89a0f91f13fcfb6d55ac5)
1f032f69dSHans Rosenfeld /*-
2f032f69dSHans Rosenfeld  * SPDX-License-Identifier: BSD-2-Clause
3f032f69dSHans Rosenfeld  *
4f032f69dSHans Rosenfeld  * Copyright (c) 2016 Jakub Klama <jceel@FreeBSD.org>.
5f032f69dSHans Rosenfeld  * Copyright (c) 2018 Marcelo Araujo <araujo@FreeBSD.org>.
6f032f69dSHans Rosenfeld  * Copyright (c) 2026 Hans Rosenfeld
7f032f69dSHans Rosenfeld  * All rights reserved.
8f032f69dSHans Rosenfeld  *
9f032f69dSHans Rosenfeld  * Redistribution and use in source and binary forms, with or without
10f032f69dSHans Rosenfeld  * modification, are permitted provided that the following conditions
11f032f69dSHans Rosenfeld  * are met:
12f032f69dSHans Rosenfeld  * 1. Redistributions of source code must retain the above copyright
13f032f69dSHans Rosenfeld  *    notice, this list of conditions and the following disclaimer
14f032f69dSHans Rosenfeld  *    in this position and unchanged.
15f032f69dSHans Rosenfeld  * 2. Redistributions in binary form must reproduce the above copyright
16f032f69dSHans Rosenfeld  *    notice, this list of conditions and the following disclaimer in the
17f032f69dSHans Rosenfeld  *    documentation and/or other materials provided with the distribution.
18f032f69dSHans Rosenfeld  *
19f032f69dSHans Rosenfeld  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20f032f69dSHans Rosenfeld  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21f032f69dSHans Rosenfeld  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22f032f69dSHans Rosenfeld  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23f032f69dSHans Rosenfeld  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24f032f69dSHans Rosenfeld  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25f032f69dSHans Rosenfeld  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26f032f69dSHans Rosenfeld  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27f032f69dSHans Rosenfeld  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28f032f69dSHans Rosenfeld  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29f032f69dSHans Rosenfeld  * SUCH DAMAGE.
30f032f69dSHans Rosenfeld  */
31f032f69dSHans Rosenfeld 
32f032f69dSHans Rosenfeld #ifndef	_PCI_VIRTIO_SCSI_H_
33f032f69dSHans Rosenfeld #define	_PCI_VIRTIO_SCSI_H_
34f032f69dSHans Rosenfeld 
35*044ca418SHans Rosenfeld #include "iov.h"
36*044ca418SHans Rosenfeld 
37f032f69dSHans Rosenfeld extern int pci_vtscsi_debug;
38f032f69dSHans Rosenfeld 
39f032f69dSHans Rosenfeld #define	WPRINTF(msg, params...)	PRINTLN("virtio-scsi: " msg, ##params)
40f032f69dSHans Rosenfeld #define	DPRINTF(msg, params...)	if (pci_vtscsi_debug) WPRINTF(msg, ##params)
41f032f69dSHans Rosenfeld 
42f032f69dSHans Rosenfeld /* Absolute limits given by the VirtIO SCSI spec */
43f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_MAX_CHANNEL	0
44f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_MAX_TARGET	255
45f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_MAX_LUN	16383
46*044ca418SHans Rosenfeld #define	VIRTIO_SCSI_HDR_SEG	2
47*044ca418SHans Rosenfeld #define	VIRTIO_SCSI_ADDL_Q	2
48f032f69dSHans Rosenfeld 
49f032f69dSHans Rosenfeld /* Features specific to VirtIO SCSI, none of which we currently support */
50f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_F_INOUT	(1 << 0)
51f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_F_HOTPLUG	(1 << 1)
52f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_F_CHANGE	(1 << 2)
53f032f69dSHans Rosenfeld 
54*044ca418SHans Rosenfeld /* Default limits which we set. All of these are configurable. */
55*044ca418SHans Rosenfeld #define	VTSCSI_DEF_RINGSZ	64
56*044ca418SHans Rosenfeld #define	VTSCSI_MIN_RINGSZ	4
57*044ca418SHans Rosenfeld #define	VTSCSI_MAX_RINGSZ	4096
58*044ca418SHans Rosenfeld 
59*044ca418SHans Rosenfeld #define	VTSCSI_DEF_THR_PER_Q	16
60*044ca418SHans Rosenfeld #define	VTSCSI_MIN_THR_PER_Q	1
61*044ca418SHans Rosenfeld #define	VTSCSI_MAX_THR_PER_Q	256
62*044ca418SHans Rosenfeld 
63*044ca418SHans Rosenfeld #define	VTSCSI_DEF_MAXSEG	64
64*044ca418SHans Rosenfeld #define	VTSCSI_MIN_MAXSEG	(VIRTIO_SCSI_HDR_SEG + 1)
65*044ca418SHans Rosenfeld #define	VTSCSI_MAX_MAXSEG	\
66*044ca418SHans Rosenfeld     (4096 - VIRTIO_SCSI_HDR_SEG - SPLIT_IOV_ADDL_IOV)
67*044ca418SHans Rosenfeld 
68*044ca418SHans Rosenfeld #define	VTSCSI_DEF_REQUESTQ	1
69*044ca418SHans Rosenfeld #define	VTSCSI_MIN_REQUESTQ	1
70*044ca418SHans Rosenfeld #define	VTSCSI_MAX_REQUESTQ	(32 - VIRTIO_SCSI_ADDL_Q)
71f032f69dSHans Rosenfeld 
72f032f69dSHans Rosenfeld /*
73f032f69dSHans Rosenfeld  * Device-specific config space registers
74f032f69dSHans Rosenfeld  *
75f032f69dSHans Rosenfeld  * The guest driver may try to modify cdb_size and sense_size by writing the
76f032f69dSHans Rosenfeld  * respective config space registers. Since we currently ignore all writes to
77f032f69dSHans Rosenfeld  * config space, these macros are essentially constant.
78f032f69dSHans Rosenfeld  */
79f032f69dSHans Rosenfeld #define	VTSCSI_IN_HEADER_LEN(_sc)	\
80f032f69dSHans Rosenfeld 	(sizeof(struct pci_vtscsi_req_cmd_rd) + _sc->vss_config.cdb_size)
81f032f69dSHans Rosenfeld 
82f032f69dSHans Rosenfeld #define	VTSCSI_OUT_HEADER_LEN(_sc)	\
83f032f69dSHans Rosenfeld 	(sizeof(struct pci_vtscsi_req_cmd_wr) + _sc->vss_config.sense_size)
84f032f69dSHans Rosenfeld 
85f032f69dSHans Rosenfeld struct pci_vtscsi_config {
86f032f69dSHans Rosenfeld 	uint32_t				num_queues;
87f032f69dSHans Rosenfeld 	uint32_t				seg_max;
88f032f69dSHans Rosenfeld 	uint32_t				max_sectors;
89f032f69dSHans Rosenfeld 	uint32_t				cmd_per_lun;
90f032f69dSHans Rosenfeld 	uint32_t				event_info_size;
91f032f69dSHans Rosenfeld 	uint32_t				sense_size;
92f032f69dSHans Rosenfeld 	uint32_t				cdb_size;
93f032f69dSHans Rosenfeld 	uint16_t				max_channel;
94f032f69dSHans Rosenfeld 	uint16_t				max_target;
95f032f69dSHans Rosenfeld 	uint32_t				max_lun;
96f032f69dSHans Rosenfeld } __attribute__((packed));
97f032f69dSHans Rosenfeld 
98f032f69dSHans Rosenfeld 
99f032f69dSHans Rosenfeld /*
100f032f69dSHans Rosenfeld  * I/O request state
101f032f69dSHans Rosenfeld  *
102*044ca418SHans Rosenfeld  * Each pci_vtscsi_queue has configurable number of pci_vtscsi_request
103*044ca418SHans Rosenfeld  * structures pre-allocated on vsq_free_requests. For each I/O request
104*044ca418SHans Rosenfeld  * coming in on the I/O virtqueue, the request queue handler takes
105*044ca418SHans Rosenfeld  * pci_vtscsi_request off vsq_free_requests, fills in the data from the
106*044ca418SHans Rosenfeld  * I/O virtqueue, puts it on vsq_requests, and signals vsq_cv.
107f032f69dSHans Rosenfeld  *
108*044ca418SHans Rosenfeld  * Each pci_vtscsi_queue will have a configurable number of worker threads,
109f032f69dSHans Rosenfeld  * which wait on vsq_cv. When signalled, they repeatedly take a single
110f032f69dSHans Rosenfeld  * pci_vtscsi_request off vsq_requests and hand it to the backend, which
111f032f69dSHans Rosenfeld  * processes it synchronously. After completion, the pci_vtscsi_request
112f032f69dSHans Rosenfeld  * is re-initialized and put back onto vsq_free_requests.
113f032f69dSHans Rosenfeld  *
114f032f69dSHans Rosenfeld  * The worker threads exit when vsq_cv is signalled after vsw_exiting was set.
115*044ca418SHans Rosenfeld  *
116*044ca418SHans Rosenfeld  * The I/O vectors for each request are kept in the preallocated iovec array
117*044ca418SHans Rosenfeld  * vsr_iov, and pointers to the respective header/data in/out portions are set
118*044ca418SHans Rosenfeld  * up to point into the array when the request is queued for processing.
119*044ca418SHans Rosenfeld  *
120*044ca418SHans Rosenfeld  * The number of iovecs preallocated for vsr_iov is derived from the configured
121*044ca418SHans Rosenfeld  * 'seg_max' parameter defined by the virtio spec:
122*044ca418SHans Rosenfeld  *   - 'seg_max' parameter specifies the maximum number of I/O data vectors
123*044ca418SHans Rosenfeld  *     we support in any request
124*044ca418SHans Rosenfeld  *   - we need 2 additional iovecs for the I/O headers (VIRTIO_SCSI_HDR_SEG)
125*044ca418SHans Rosenfeld  *   - we need another 2 additional iovecs for split_iov() (SPLIT_IOV_ADDL_IOV)
126*044ca418SHans Rosenfeld  *
127*044ca418SHans Rosenfeld  * The only time we explicitly need the full size of vsr_iov after preallocation
128*044ca418SHans Rosenfeld  * is during re-initialization after completing a request, and implicitly in the
129*044ca418SHans Rosenfeld  * calls to split_iov() the set up the pointers. In all other cases, we use only
130*044ca418SHans Rosenfeld  * 'seg_max' + VIRTIO_SCSI_HDR_SEG, and we advertise only 'seg_max' to the guest
131*044ca418SHans Rosenfeld  * in accordance to the virtio spec.
132f032f69dSHans Rosenfeld  */
133f032f69dSHans Rosenfeld STAILQ_HEAD(pci_vtscsi_req_queue, pci_vtscsi_request);
134f032f69dSHans Rosenfeld 
135f032f69dSHans Rosenfeld struct pci_vtscsi_queue {
136f032f69dSHans Rosenfeld 	struct pci_vtscsi_softc			*vsq_sc;
137f032f69dSHans Rosenfeld 	struct vqueue_info			*vsq_vq;
138f032f69dSHans Rosenfeld 	pthread_mutex_t				vsq_rmtx;
139f032f69dSHans Rosenfeld 	pthread_mutex_t				vsq_fmtx;
140f032f69dSHans Rosenfeld 	pthread_mutex_t				vsq_qmtx;
141f032f69dSHans Rosenfeld 	pthread_cond_t				vsq_cv;
142f032f69dSHans Rosenfeld 	struct pci_vtscsi_req_queue		vsq_requests;
143f032f69dSHans Rosenfeld 	struct pci_vtscsi_req_queue		vsq_free_requests;
144f032f69dSHans Rosenfeld 	LIST_HEAD(, pci_vtscsi_worker)		vsq_workers;
145f032f69dSHans Rosenfeld };
146f032f69dSHans Rosenfeld 
147f032f69dSHans Rosenfeld struct pci_vtscsi_worker {
148f032f69dSHans Rosenfeld 	struct pci_vtscsi_queue			*vsw_queue;
149f032f69dSHans Rosenfeld 	pthread_t				vsw_thread;
150f032f69dSHans Rosenfeld 	bool					vsw_exiting;
151f032f69dSHans Rosenfeld 	LIST_ENTRY(pci_vtscsi_worker)		vsw_link;
152f032f69dSHans Rosenfeld };
153f032f69dSHans Rosenfeld 
154f032f69dSHans Rosenfeld struct pci_vtscsi_request {
155f032f69dSHans Rosenfeld 	struct pci_vtscsi_queue			*vsr_queue;
156*044ca418SHans Rosenfeld 	struct iovec				*vsr_iov;
157f032f69dSHans Rosenfeld 	struct iovec				*vsr_iov_in;
158f032f69dSHans Rosenfeld 	struct iovec				*vsr_iov_out;
159f032f69dSHans Rosenfeld 	struct iovec				*vsr_data_iov_in;
160f032f69dSHans Rosenfeld 	struct iovec				*vsr_data_iov_out;
161f032f69dSHans Rosenfeld 	struct pci_vtscsi_req_cmd_rd		*vsr_cmd_rd;
162f032f69dSHans Rosenfeld 	struct pci_vtscsi_req_cmd_wr		*vsr_cmd_wr;
163f032f69dSHans Rosenfeld 	void					*vsr_backend;
164f032f69dSHans Rosenfeld 	size_t					vsr_niov_in;
165f032f69dSHans Rosenfeld 	size_t					vsr_niov_out;
166f032f69dSHans Rosenfeld 	size_t					vsr_data_niov_in;
167f032f69dSHans Rosenfeld 	size_t					vsr_data_niov_out;
168f032f69dSHans Rosenfeld 	uint32_t				vsr_idx;
169f032f69dSHans Rosenfeld 	STAILQ_ENTRY(pci_vtscsi_request)	vsr_link;
170f032f69dSHans Rosenfeld };
171f032f69dSHans Rosenfeld 
172f032f69dSHans Rosenfeld /*
173f032f69dSHans Rosenfeld  * Per-target state.
174f032f69dSHans Rosenfeld  */
175f032f69dSHans Rosenfeld struct pci_vtscsi_target {
176f032f69dSHans Rosenfeld 	uint8_t					vst_target;
177f032f69dSHans Rosenfeld 	int					vst_fd;
178f032f69dSHans Rosenfeld 	int					vst_max_sectors;
179f032f69dSHans Rosenfeld };
180f032f69dSHans Rosenfeld 
181f032f69dSHans Rosenfeld /*
182f032f69dSHans Rosenfeld  * Per-device softc
183f032f69dSHans Rosenfeld  */
184f032f69dSHans Rosenfeld struct pci_vtscsi_softc {
185f032f69dSHans Rosenfeld 	struct virtio_softc			vss_vs;
186*044ca418SHans Rosenfeld 	struct virtio_consts			vss_vi_consts;
187*044ca418SHans Rosenfeld 	struct vqueue_info			*vss_vq;
188*044ca418SHans Rosenfeld 	struct pci_vtscsi_queue			*vss_queues;
189f032f69dSHans Rosenfeld 	pthread_mutex_t				vss_mtx;
190f032f69dSHans Rosenfeld 	uint32_t				vss_features;
191f032f69dSHans Rosenfeld 	size_t					vss_num_target;
192*044ca418SHans Rosenfeld 	uint32_t				vss_ctl_ringsz;
193*044ca418SHans Rosenfeld 	uint32_t				vss_evt_ringsz;
194*044ca418SHans Rosenfeld 	uint32_t				vss_req_ringsz;
195*044ca418SHans Rosenfeld 	uint32_t				vss_thr_per_q;
196*044ca418SHans Rosenfeld 	struct pci_vtscsi_config		vss_default_config;
197f032f69dSHans Rosenfeld 	struct pci_vtscsi_config		vss_config;
198f032f69dSHans Rosenfeld 	struct pci_vtscsi_target		*vss_targets;
199f032f69dSHans Rosenfeld 	struct pci_vtscsi_backend		*vss_backend;
200f032f69dSHans Rosenfeld };
201f032f69dSHans Rosenfeld 
202f032f69dSHans Rosenfeld /*
203f032f69dSHans Rosenfeld  * VirtIO-SCSI Task Management Function control requests
204f032f69dSHans Rosenfeld  */
205f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF			0
206f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF_ABORT_TASK		0
207f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF_ABORT_TASK_SET	1
208f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF_CLEAR_ACA		2
209f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET	3
210f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET	4
211f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET	5
212f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF_QUERY_TASK		6
213f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF_QUERY_TASK_SET	7
214f032f69dSHans Rosenfeld 
215f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_TMF_MAX_FUNC		VIRTIO_SCSI_T_TMF_QUERY_TASK_SET
216f032f69dSHans Rosenfeld 
217f032f69dSHans Rosenfeld /* command-specific response values */
218f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_FUNCTION_COMPLETE		0
219f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_FUNCTION_SUCCEEDED	10
220f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_FUNCTION_REJECTED		11
221f032f69dSHans Rosenfeld 
222f032f69dSHans Rosenfeld struct pci_vtscsi_ctrl_tmf {
223f032f69dSHans Rosenfeld 	const uint32_t	type;
224f032f69dSHans Rosenfeld 	const uint32_t	subtype;
225f032f69dSHans Rosenfeld 	const uint8_t	lun[8];
226f032f69dSHans Rosenfeld 	const uint64_t	id;
227f032f69dSHans Rosenfeld 	uint8_t		response;
228f032f69dSHans Rosenfeld } __attribute__((packed));
229f032f69dSHans Rosenfeld 
230f032f69dSHans Rosenfeld 
231f032f69dSHans Rosenfeld /*
232f032f69dSHans Rosenfeld  * VirtIO-SCSI Asynchronous Notification control requests
233f032f69dSHans Rosenfeld  */
234f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_T_AN_QUERY			1
235f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_EVT_ASYNC_OPERATIONAL_CHANGE 2
236f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_EVT_ASYNC_POWER_MGMT	4
237f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_EVT_ASYNC_EXTERNAL_REQUEST	8
238f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_EVT_ASYNC_MEDIA_CHANGE	16
239f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_EVT_ASYNC_MULTI_HOST	32
240f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_EVT_ASYNC_DEVICE_BUSY	64
241f032f69dSHans Rosenfeld 
242f032f69dSHans Rosenfeld struct pci_vtscsi_ctrl_an {
243f032f69dSHans Rosenfeld 	const uint32_t	type;
244f032f69dSHans Rosenfeld 	const uint8_t	lun[8];
245f032f69dSHans Rosenfeld 	const uint32_t	event_requested;
246f032f69dSHans Rosenfeld 	uint32_t	event_actual;
247f032f69dSHans Rosenfeld 	uint8_t		response;
248f032f69dSHans Rosenfeld } __attribute__((packed));
249f032f69dSHans Rosenfeld 
250f032f69dSHans Rosenfeld /* command-specific response values */
251f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_OK			0
252f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_OVERRUN			1
253f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_ABORTED			2
254f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_BAD_TARGET		3
255f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_RESET			4
256f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_BUSY			5
257f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_TRANSPORT_FAILURE		6
258f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_TARGET_FAILURE		7
259f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_NEXUS_FAILURE		8
260f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_FAILURE			9
261f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_INCORRECT_LUN		12
262f032f69dSHans Rosenfeld 
263f032f69dSHans Rosenfeld struct pci_vtscsi_event {
264f032f69dSHans Rosenfeld 	uint32_t	event;
265f032f69dSHans Rosenfeld 	uint8_t		lun[8];
266f032f69dSHans Rosenfeld 	uint32_t	reason;
267f032f69dSHans Rosenfeld } __attribute__((packed));
268f032f69dSHans Rosenfeld 
269f032f69dSHans Rosenfeld /*
270f032f69dSHans Rosenfeld  * VirtIO-SCSI I/O requests
271f032f69dSHans Rosenfeld  */
272f032f69dSHans Rosenfeld struct pci_vtscsi_req_cmd_rd {
273f032f69dSHans Rosenfeld 	const uint8_t	lun[8];
274f032f69dSHans Rosenfeld 	const uint64_t	id;
275f032f69dSHans Rosenfeld 	const uint8_t	task_attr;
276f032f69dSHans Rosenfeld 	const uint8_t	prio;
277f032f69dSHans Rosenfeld 	const uint8_t	crn;
278f032f69dSHans Rosenfeld 	const uint8_t	cdb[];
279f032f69dSHans Rosenfeld } __attribute__((packed));
280f032f69dSHans Rosenfeld 
281f032f69dSHans Rosenfeld /* task_attr */
282f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_SIMPLE			0
283f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_ORDERED			1
284f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_HEAD			2
285f032f69dSHans Rosenfeld #define	VIRTIO_SCSI_S_ACA			3
286f032f69dSHans Rosenfeld 
287f032f69dSHans Rosenfeld struct pci_vtscsi_req_cmd_wr {
288f032f69dSHans Rosenfeld 	uint32_t	sense_len;
289f032f69dSHans Rosenfeld 	uint32_t	residual;
290f032f69dSHans Rosenfeld 	uint16_t	status_qualifier;
291f032f69dSHans Rosenfeld 	uint8_t		status;
292f032f69dSHans Rosenfeld 	uint8_t		response;
293f032f69dSHans Rosenfeld 	uint8_t		sense[];
294f032f69dSHans Rosenfeld } __attribute__((packed));
295f032f69dSHans Rosenfeld 
296f032f69dSHans Rosenfeld /*
297f032f69dSHans Rosenfeld  * Backend interface
298f032f69dSHans Rosenfeld  */
299f032f69dSHans Rosenfeld struct pci_vtscsi_backend {
300f032f69dSHans Rosenfeld 	const char	*vsb_name;
301f032f69dSHans Rosenfeld 	int		(*vsb_init)(struct pci_vtscsi_softc *,
302f032f69dSHans Rosenfeld 			    struct pci_vtscsi_backend *, nvlist_t *);
303f032f69dSHans Rosenfeld 	int		(*vsb_open)(struct pci_vtscsi_softc *, const char *,
304f032f69dSHans Rosenfeld 			    long);
305f032f69dSHans Rosenfeld 	void		(*vsb_reset)(struct pci_vtscsi_softc *);
306f032f69dSHans Rosenfeld 
307f032f69dSHans Rosenfeld 	void*		(*vsb_req_alloc)(struct pci_vtscsi_softc *);
308f032f69dSHans Rosenfeld 	void		(*vsb_req_clear)(void *);
309f032f69dSHans Rosenfeld 	void		(*vsb_req_free)(void *);
310f032f69dSHans Rosenfeld 
311f032f69dSHans Rosenfeld 	void		(*vsb_tmf_hdl)(struct pci_vtscsi_softc *, int,
312f032f69dSHans Rosenfeld 			    struct pci_vtscsi_ctrl_tmf *);
313f032f69dSHans Rosenfeld 	void		(*vsb_an_hdl)(struct pci_vtscsi_softc *, int,
314f032f69dSHans Rosenfeld 			    struct pci_vtscsi_ctrl_an *);
315f032f69dSHans Rosenfeld 	int		(*vsb_req_hdl)(struct pci_vtscsi_softc *, int,
316f032f69dSHans Rosenfeld 			    struct pci_vtscsi_request *);
317f032f69dSHans Rosenfeld };
318f032f69dSHans Rosenfeld #define	PCI_VTSCSI_BACKEND_SET(x)	DATA_SET(pci_vtscsi_backend_set, x)
319f032f69dSHans Rosenfeld 
320f032f69dSHans Rosenfeld /*
321f032f69dSHans Rosenfeld  * LUN address parsing
322f032f69dSHans Rosenfeld  *
323f032f69dSHans Rosenfeld  * The LUN address consists of 8 bytes. While the spec describes this as 0x01,
324f032f69dSHans Rosenfeld  * followed by the target byte, followed by a "single-level LUN structure",
325f032f69dSHans Rosenfeld  * this is actually the same as a hierarchical LUN address as defined by SAM-5,
326f032f69dSHans Rosenfeld  * consisting of four levels of addressing, where in each level the two MSB of
327f032f69dSHans Rosenfeld  * byte 0 select the address mode used in the remaining bits and bytes.
328f032f69dSHans Rosenfeld  *
329f032f69dSHans Rosenfeld  *
330f032f69dSHans Rosenfeld  * Only the first two levels are acutally used by virtio-scsi:
331f032f69dSHans Rosenfeld  *
332f032f69dSHans Rosenfeld  * Level 1: 0x01, 0xTT: Peripheral Device Addressing: Bus 1, Target 0-255
333f032f69dSHans Rosenfeld  * Level 2: 0xLL, 0xLL: Peripheral Device Addressing: Bus MBZ, LUN 0-255
334f032f69dSHans Rosenfeld  *                  or: Flat Space Addressing: LUN (0-16383)
335f032f69dSHans Rosenfeld  * Level 3 and 4: not used, MBZ
336f032f69dSHans Rosenfeld  *
337f032f69dSHans Rosenfeld  *
338f032f69dSHans Rosenfeld  * Alternatively, the first level may contain an extended LUN address to select
339f032f69dSHans Rosenfeld  * the REPORT_LUNS well-known logical unit:
340f032f69dSHans Rosenfeld  *
341f032f69dSHans Rosenfeld  * Level 1: 0xC1, 0x01: Extended LUN Adressing, Well-Known LUN 1 (REPORT_LUNS)
342f032f69dSHans Rosenfeld  * Level 2, 3, and 4: not used, MBZ
343f032f69dSHans Rosenfeld  *
344f032f69dSHans Rosenfeld  * The virtio spec says that we SHOULD implement the REPORT_LUNS well-known
345f032f69dSHans Rosenfeld  * logical unit  but we currently don't.
346f032f69dSHans Rosenfeld  *
347f032f69dSHans Rosenfeld  * According to the virtio spec, these are the only LUNS address formats to be
348f032f69dSHans Rosenfeld  * used with virtio-scsi.
349f032f69dSHans Rosenfeld  */
350f032f69dSHans Rosenfeld 
351f032f69dSHans Rosenfeld /*
352f032f69dSHans Rosenfeld  * Check that the given LUN address conforms to the virtio spec, does not
353f032f69dSHans Rosenfeld  * address an unknown target, and especially does not address the REPORT_LUNS
354f032f69dSHans Rosenfeld  * well-known logical unit.
355f032f69dSHans Rosenfeld  */
356f032f69dSHans Rosenfeld static inline bool
pci_vtscsi_check_lun(struct pci_vtscsi_softc * sc,const uint8_t * lun)357f032f69dSHans Rosenfeld pci_vtscsi_check_lun(struct pci_vtscsi_softc *sc, const uint8_t *lun)
358f032f69dSHans Rosenfeld {
359f032f69dSHans Rosenfeld 	if (lun[0] == 0xC1)
360f032f69dSHans Rosenfeld 		return (false);
361f032f69dSHans Rosenfeld 
362f032f69dSHans Rosenfeld 	if (lun[0] != 0x01)
363f032f69dSHans Rosenfeld 		return (false);
364f032f69dSHans Rosenfeld 
365f032f69dSHans Rosenfeld 	if (lun[1] >= sc->vss_num_target)
366f032f69dSHans Rosenfeld 		return (false);
367f032f69dSHans Rosenfeld 
368f032f69dSHans Rosenfeld 	if (lun[1] != sc->vss_targets[lun[1]].vst_target)
369f032f69dSHans Rosenfeld 		return (false);
370f032f69dSHans Rosenfeld 
371f032f69dSHans Rosenfeld 	if (sc->vss_targets[lun[1]].vst_fd < 0)
372f032f69dSHans Rosenfeld 		return (false);
373f032f69dSHans Rosenfeld 
374f032f69dSHans Rosenfeld 	if (lun[2] != 0x00 && (lun[2] & 0xc0) != 0x40)
375f032f69dSHans Rosenfeld 		return (false);
376f032f69dSHans Rosenfeld 
377f032f69dSHans Rosenfeld 	if (lun[4] != 0 || lun[5] != 0 || lun[6] != 0 || lun[7] != 0)
378f032f69dSHans Rosenfeld 		return (false);
379f032f69dSHans Rosenfeld 
380f032f69dSHans Rosenfeld 	return (true);
381f032f69dSHans Rosenfeld }
382f032f69dSHans Rosenfeld 
383f032f69dSHans Rosenfeld /*
384f032f69dSHans Rosenfeld  * Get the target id from a LUN address.
385f032f69dSHans Rosenfeld  *
386f032f69dSHans Rosenfeld  * Every code path using this function must have called pci_vtscsi_check_lun()
387f032f69dSHans Rosenfeld  * before to make sure the LUN address is valid.
388f032f69dSHans Rosenfeld  */
389f032f69dSHans Rosenfeld static inline uint8_t
pci_vtscsi_get_target(struct pci_vtscsi_softc * sc,const uint8_t * lun)390f032f69dSHans Rosenfeld pci_vtscsi_get_target(struct pci_vtscsi_softc *sc, const uint8_t *lun)
391f032f69dSHans Rosenfeld {
392f032f69dSHans Rosenfeld 	assert(lun[0] == 0x01);
393f032f69dSHans Rosenfeld 	assert(lun[1] < sc->vss_num_target);
394f032f69dSHans Rosenfeld 	assert(lun[1] == sc->vss_targets[lun[1]].vst_target);
395f032f69dSHans Rosenfeld 	assert(sc->vss_targets[lun[1]].vst_fd >= 0);
396f032f69dSHans Rosenfeld 	assert(lun[2] == 0x00 || (lun[2] & 0xc0) == 0x40);
397f032f69dSHans Rosenfeld 
398f032f69dSHans Rosenfeld 	return (lun[1]);
399f032f69dSHans Rosenfeld }
400f032f69dSHans Rosenfeld 
401f032f69dSHans Rosenfeld /*
402f032f69dSHans Rosenfeld  * Get the LUN id from a LUN address.
403f032f69dSHans Rosenfeld  *
404f032f69dSHans Rosenfeld  * Every code path using this function must have called pci_vtscsi_check_lun()
405f032f69dSHans Rosenfeld  * before to make sure the LUN address is valid.
406f032f69dSHans Rosenfeld  */
407f032f69dSHans Rosenfeld static inline uint16_t
pci_vtscsi_get_lun(struct pci_vtscsi_softc * sc,const uint8_t * lun)408f032f69dSHans Rosenfeld pci_vtscsi_get_lun(struct pci_vtscsi_softc *sc, const uint8_t *lun)
409f032f69dSHans Rosenfeld {
410f032f69dSHans Rosenfeld 	assert(lun[0] == 0x01);
411f032f69dSHans Rosenfeld 	assert(lun[1] < sc->vss_num_target);
412f032f69dSHans Rosenfeld 	assert(lun[1] == sc->vss_targets[lun[1]].vst_target);
413f032f69dSHans Rosenfeld 	assert(sc->vss_targets[lun[1]].vst_fd >= 0);
414f032f69dSHans Rosenfeld 	assert(lun[2] == 0x00 || (lun[2] & 0xc0) == 0x40);
415f032f69dSHans Rosenfeld 
416f032f69dSHans Rosenfeld 	return (((lun[2] << 8) | lun[3]) & 0x3fff);
417f032f69dSHans Rosenfeld }
418f032f69dSHans Rosenfeld 
419f032f69dSHans Rosenfeld #endif	/* _PCI_VIRTIO_SCSI_H_ */
420