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