1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2012, Bryan Venteicher <bryanv@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice unmodified, this list of conditions, and the following
12 *    disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30
31#ifndef _VIRTIO_SCSIVAR_H
32#define _VIRTIO_SCSIVAR_H
33
34struct vtscsi_softc;
35struct vtscsi_request;
36
37typedef void vtscsi_request_cb_t(struct vtscsi_softc *,
38    struct vtscsi_request *);
39
40struct vtscsi_statistics {
41	unsigned long		scsi_cmd_timeouts;
42	unsigned long		dequeue_no_requests;
43};
44
45struct vtscsi_softc {
46	device_t		 vtscsi_dev;
47	struct mtx		 vtscsi_mtx;
48	uint64_t		 vtscsi_features;
49
50	uint16_t		 vtscsi_flags;
51#define VTSCSI_FLAG_INDIRECT		0x0001
52#define VTSCSI_FLAG_BIDIRECTIONAL	0x0002
53#define VTSCSI_FLAG_HOTPLUG		0x0004
54#define VTSCSI_FLAG_RESET		0x0008
55#define VTSCSI_FLAG_DETACH		0x0010
56
57	uint16_t		 vtscsi_frozen;
58#define VTSCSI_FROZEN_NO_REQUESTS	0x01
59#define VTSCSI_FROZEN_REQUEST_VQ_FULL	0x02
60
61	struct sglist		*vtscsi_sglist;
62
63	struct virtqueue	*vtscsi_control_vq;
64	struct virtqueue	*vtscsi_event_vq;
65	struct virtqueue	*vtscsi_request_vq;
66
67	struct cam_sim		*vtscsi_sim;
68	struct cam_path		*vtscsi_path;
69
70	int			 vtscsi_debug;
71	int			 vtscsi_nrequests;
72	int			 vtscsi_max_nsegs;
73	int			 vtscsi_event_buf_size;
74
75	TAILQ_HEAD(,vtscsi_request)
76				 vtscsi_req_free;
77
78	uint16_t		 vtscsi_max_channel;
79	uint16_t		 vtscsi_max_target;
80	uint32_t		 vtscsi_max_lun;
81
82#define VTSCSI_NUM_EVENT_BUFS	4
83	struct virtio_scsi_event
84				 vtscsi_event_bufs[VTSCSI_NUM_EVENT_BUFS];
85
86	struct vtscsi_statistics vtscsi_stats;
87};
88
89enum vtscsi_request_state {
90	VTSCSI_REQ_STATE_FREE,
91	VTSCSI_REQ_STATE_INUSE,
92	VTSCSI_REQ_STATE_ABORTED,
93	VTSCSI_REQ_STATE_TIMEDOUT
94};
95
96struct vtscsi_request {
97	struct vtscsi_softc			*vsr_softc;
98	union ccb				*vsr_ccb;
99	vtscsi_request_cb_t			*vsr_complete;
100
101	void					*vsr_ptr0;
102/* Request when aborting a timedout command. */
103#define vsr_timedout_req	vsr_ptr0
104
105	enum vtscsi_request_state		 vsr_state;
106
107	uint16_t				 vsr_flags;
108#define VTSCSI_REQ_FLAG_POLLED		0x01
109#define VTSCSI_REQ_FLAG_COMPLETE	0x02
110#define VTSCSI_REQ_FLAG_TIMEOUT_SET	0x04
111
112	union {
113		struct virtio_scsi_cmd_req	 cmd;
114		struct virtio_scsi_ctrl_tmf_req	 tmf;
115		struct virtio_scsi_ctrl_an_req	 an;
116	} vsr_ureq;
117#define vsr_cmd_req 	vsr_ureq.cmd
118#define vsr_tmf_req 	vsr_ureq.tmf
119#define vsr_an_req	vsr_ureq.an
120
121	/* Make request and response non-contiguous. */
122	uint32_t				 vsr_pad;
123
124	union {
125		struct virtio_scsi_cmd_resp	 cmd;
126		struct virtio_scsi_ctrl_tmf_resp tmf;
127		struct virtio_scsi_ctrl_an_resp	 an;
128	} vsr_uresp;
129#define vsr_cmd_resp	vsr_uresp.cmd
130#define vsr_tmf_resp	vsr_uresp.tmf
131#define vsr_an_resp	vsr_uresp.an
132
133	struct callout				 vsr_callout;
134
135	TAILQ_ENTRY(vtscsi_request)		 vsr_link;
136};
137
138/* Private field in the CCB header that points to our request. */
139#define ccbh_vtscsi_req	spriv_ptr0
140
141/* Features desired/implemented by this driver. */
142#define VTSCSI_FEATURES \
143    (VIRTIO_SCSI_F_HOTPLUG		| \
144     VIRTIO_RING_F_INDIRECT_DESC)
145
146#define VTSCSI_MTX(_sc)			&(_sc)->vtscsi_mtx
147#define VTSCSI_LOCK_INIT(_sc, _name) 	mtx_init(VTSCSI_MTX(_sc), _name, \
148					    "VTSCSI Lock", MTX_DEF)
149#define VTSCSI_LOCK(_sc)		mtx_lock(VTSCSI_MTX(_sc))
150#define VTSCSI_UNLOCK(_sc)		mtx_unlock(VTSCSI_MTX(_sc))
151#define VTSCSI_LOCK_OWNED(_sc)		mtx_assert(VTSCSI_MTX(_sc), MA_OWNED)
152#define VTSCSI_LOCK_NOTOWNED(_sc) 	mtx_assert(VTSCSI_MTX(_sc), MA_NOTOWNED)
153#define VTSCSI_LOCK_DESTROY(_sc)	mtx_destroy(VTSCSI_MTX(_sc))
154
155/*
156 * Reasons for either freezing or thawing the SIMQ.
157 *
158 * VirtIO SCSI is a bit unique in the sense that SCSI and TMF
159 * commands go over different queues. Both queues are fed by
160 * the same SIMQ, but we only freeze the SIMQ when the request
161 * (SCSI) virtqueue is full, not caring if the control (TMF)
162 * virtqueue unlikely gets full. However, both queues share the
163 * same pool of requests, so the completion of a TMF command
164 * could cause the SIMQ to be unfrozen.
165 */
166#define VTSCSI_REQUEST		0x01
167#define VTSCSI_REQUEST_VQ	0x02
168
169/* Debug trace levels. */
170#define VTSCSI_INFO	0x01
171#define VTSCSI_ERROR	0x02
172#define VTSCSI_TRACE	0x04
173
174#define vtscsi_dprintf(_sc, _level, _msg, _args ...) do { 		\
175	if ((_sc)->vtscsi_debug & (_level))				\
176		device_printf((_sc)->vtscsi_dev, "%s: "_msg,		\
177		    __FUNCTION__, ##_args);				\
178} while (0)
179
180#define vtscsi_dprintf_req(_req, _level, _msg, _args ...) do {		\
181	struct vtscsi_softc *__sc = (_req)->vsr_softc;			\
182	if ((__sc)->vtscsi_debug & (_level))				\
183		vtscsi_printf_req(_req, __FUNCTION__, _msg, ##_args);	\
184} while (0)
185
186/*
187 * Set the status field in a CCB, optionally clearing non CCB_STATUS_* flags.
188 */
189#define vtscsi_set_ccb_status(_ccbh, _status, _mask) do {		\
190	KASSERT(((_mask) & CAM_STATUS_MASK) == 0,			\
191	    ("%s:%d bad mask: 0x%x", __FUNCTION__, __LINE__, (_mask)));	\
192	(_ccbh)->status &= ~(CAM_STATUS_MASK | (_mask));		\
193	(_ccbh)->status |= (_status);					\
194} while (0)
195
196/*
197 * One segment each for the request and the response.
198 */
199#define VTSCSI_MIN_SEGMENTS	2
200
201/*
202 * Allocate additional requests for internal use such
203 * as TM commands (e.g. aborting timedout commands).
204 */
205#define VTSCSI_RESERVED_REQUESTS	10
206
207/*
208 * How to wait (or not) for request completion.
209 */
210#define VTSCSI_EXECUTE_ASYNC	0
211#define VTSCSI_EXECUTE_POLL	1
212
213#endif /* _VIRTIO_SCSIVAR_H */
214