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