summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/vioscsi/vioscsi.h
blob: b032ef28c8cf60a32ea080f76cb32e4fc1d3cd15 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
 * Copyright 2022 RackTop Systems, Inc.
 */

#ifndef _VIOSCSI_H_
#define	_VIOSCSI_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/types.h>
#include <sys/atomic.h>
#include <sys/kmem.h>
#include <sys/conf.h>
#include <sys/devops.h>
#include <sys/ksynch.h>
#include <sys/modctl.h>
#include <sys/debug.h>
#include <sys/list.h>
#include <sys/stddef.h>

#include <sys/scsi/scsi.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>

#include <virtio.h>

#define	VIRTIO_SCSI_CDB_SIZE	32
#define	VIRTIO_SCSI_SENSE_SIZE	96

/*
 * Feature bits:
 */
#define	VIRTIO_SCSI_F_INOUT		(0x1 << 0)
#define	VIRTIO_SCSI_F_HOTPLUG		(0x1 << 1)
#define	VIRTIO_SCSI_F_CHANGE		(0x1 << 2)
#define	VIRTIO_SCSI_F_T10_PI		(0x1 << 3)

/*
 * Register offset in bytes:
 */
#define	VIRTIO_SCSI_CFG_NUM_QUEUES	0
#define	VIRTIO_SCSI_CFG_SEG_MAX		4
#define	VIRTIO_SCSI_CFG_MAX_SECTORS	8
#define	VIRTIO_SCSI_CFG_CMD_PER_LUN	12
#define	VIRTIO_SCSI_CFG_EVI_SIZE	16
#define	VIRTIO_SCSI_CFG_SENSE_SIZE	20
#define	VIRTIO_SCSI_CFG_CDB_SIZE	24
#define	VIRTIO_SCSI_CFG_MAX_CHANNEL	28
#define	VIRTIO_SCSI_CFG_MAX_TARGET	30
#define	VIRTIO_SCSI_CFG_MAX_LUN		32

/*
 * Response codes:
 */
#define	VIRTIO_SCSI_S_OK			0
#define	VIRTIO_SCSI_S_FUNCTION_COMPLETED	0
#define	VIRTIO_SCSI_S_OVERRUN			1
#define	VIRTIO_SCSI_S_ABORTED			2
#define	VIRTIO_SCSI_S_BAD_TARGET		3
#define	VIRTIO_SCSI_S_RESET			4
#define	VIRTIO_SCSI_S_BUSY			5
#define	VIRTIO_SCSI_S_TRANSPORT_FAILURE		6
#define	VIRTIO_SCSI_S_TARGET_FAILURE		7
#define	VIRTIO_SCSI_S_NEXUS_FAILURE		8
#define	VIRTIO_SCSI_S_FAILURE			9
#define	VIRTIO_SCSI_S_FUNCTION_SUCCEEDED	10
#define	VIRTIO_SCSI_S_FUNCTION_REJECTED		11
#define	VIRTIO_SCSI_S_INCORRECT_LUN		12

/*
 * Control queue type codes:
 */
#define	VIRTIO_SCSI_T_TMF			0
#define	VIRTIO_SCSI_T_AN_QUERY			1
#define	VIRTIO_SCSI_T_AN_SUBSCRIBE		2

/*
 * Task management codes:
 */
#define	VIRTIO_SCSI_T_TMF_ABORT_TASK		0
#define	VIRTIO_SCSI_T_TMF_ABORT_TASK_SET	1
#define	VIRTIO_SCSI_T_TMF_CLEAR_ACA		2
#define	VIRTIO_SCSI_T_TMF_CLEAR_ACA_TASK_SET	3
#define	VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET	4
#define	VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET	5
#define	VIRTIO_SCSI_T_TMF_QUERY_TASK		6
#define	VIRTIO_SCSI_T_TMF_QUERY_TASK_SET	7

/*
 * Events:
 */
#define	VIRTIO_SCSI_T_EVENTS_MISSED		0x80000000
#define	VIRTIO_SCSI_T_NO_EVENT			0
#define	VIRTIO_SCSI_T_TRANSPORT_RESET		1
#define	VIRTIO_SCSI_T_ASYNC_NOTIFY		2

/*
 * Task attributes:
 */
#define	VIRTIO_SCSI_S_SIMPLE			0
#define	VIRTIO_SCSI_S_ORDERED			1
#define	VIRTIO_SCSI_S_HEAD			2
#define	VIRTIO_SCSI_S_ACA			3

/*
 * Reasons of reset event:
 */
#define	VIRTIO_SCSI_EVT_RESET_HARD		0
#define	VIRTIO_SCSI_EVT_RESET_RESCAN		1
#define	VIRTIO_SCSI_EVT_RESET_REMOVED		2

/*
 * We need to support INOUT, and we want hotplug notifications:
 */
#define	VIOSCSI_WANTED_FEATURES	(VIRTIO_SCSI_F_INOUT | VIRTIO_SCSI_F_HOTPLUG)

#define	VIOSCSI_MAX_TARGET			256
#define	VIOSCSI_MIN_SEGS			3
#define	VIOSCSI_NUM_EVENTS			16

/*
 * Data structures:
 */

#pragma pack(1)

/*
 * virtio SCSI command request:
 */
struct virtio_scsi_cmd_req {
	uint8_t		lun[8];
	uint64_t	tag;
	uint8_t		task_attr;
	uint8_t		prio;
	uint8_t		crn;
	uint8_t		cdb[VIRTIO_SCSI_CDB_SIZE];
};

/*
 * Virtio SCSI response:
 */
struct virtio_scsi_cmd_resp {
	uint32_t	sense_len;
	uint32_t	res_id;
	uint16_t	status_qualifier;
	uint8_t		status;
	uint8_t		response;
	uint8_t		sense[VIRTIO_SCSI_SENSE_SIZE];
};

/*
 * Task management request:
 */
struct virtio_scsi_ctrl_tmf_req {
	uint32_t	type;
	uint32_t	subtype;
	uint8_t		lun[8];
	uint64_t	tag;
};

/*
 * Task management response:
 */
struct virtio_scsi_ctrl_tmf_resp {
	uint8_t		response;
};

/*
 * Asynchronous notification request:
 */
struct virtio_scsi_ctrl_an_req {
	uint32_t	type;
	uint8_t		lun[8];
	uint32_t	event_requested;
};

/*
 * Asynchronous notification response:
 */
struct virtio_scsi_ctrl_an_resp {
	uint32_t	event_actual;
	uint8_t		response;
};

/*
 * Events delivered on the event queue:
 */
struct virtio_scsi_event {
	uint32_t	event;
	uint8_t		lun[8];
	uint32_t	reason;
};

#pragma pack()

typedef union {
	struct virtio_scsi_cmd_req		cmd;
	struct virtio_scsi_ctrl_tmf_req		tmf;
	struct virtio_scsi_ctrl_an_req		anr;
} vioscsi_req_t;

typedef union {
	struct virtio_scsi_cmd_resp		cmd;
	struct virtio_scsi_ctrl_tmf_resp	tmf;
	struct virtio_scsi_ctrl_an_resp		anr;
} vioscsi_res_t;

struct virtio_scsi_op {
	vioscsi_req_t	req;
	vioscsi_res_t	res;
};

#define	VIOSCSI_REQ_OFFSET	offsetof(struct virtio_scsi_op, req)
#define	VIOSCSI_RES_OFFSET	offsetof(struct virtio_scsi_op, res)

typedef struct vioscsi_request vioscsi_request_t;
typedef	struct vioscsi_event vioscsi_event_t;
typedef struct vioscsi_softc vioscsi_softc_t;
typedef struct vioscsi_dev vioscsi_dev_t;
typedef struct virtio_scsi_event vioscsi_evt_t;
typedef struct virtio_scsi_ctrl_tmf_req vioscsi_tmf_req_t;
typedef struct virtio_scsi_ctrl_tmf_resp vioscsi_tmf_res_t;
typedef struct virtio_scsi_cmd_req vioscsi_cmd_req_t;
typedef struct virtio_scsi_cmd_resp vioscsi_cmd_res_t;
typedef struct virtio_scsi_op vioscsi_op_t;

struct vioscsi_request {
	list_node_t		vr_node;
	struct scsi_pkt		*vr_pkt;
	virtio_queue_t		*vr_vq;
	virtio_dma_t		*vr_dma;
	virtio_chain_t		*vr_vic;
	vioscsi_dev_t		*vr_dev;
	vioscsi_req_t		*vr_req;
	vioscsi_res_t		*vr_res;
	uint64_t		vr_req_pa;
	uint64_t		vr_res_pa;
	boolean_t		vr_poll;
	uint8_t			vr_expired;	/* access using atomics */
	uint8_t			vr_done;	/* access using atomics */
	uint8_t			vr_task_attr;
	uint8_t			vr_target;
	uint16_t		vr_lun;
	clock_t			vr_time;	/* seconds */
	clock_t			vr_start;	/* ticks */
	clock_t			vr_expire;	/* ticks */
};

struct vioscsi_dev {
	list_node_t		vd_node;
	uint8_t			vd_target;
	uint16_t		vd_lun;
	struct scsi_device	*vd_sd;
	vioscsi_softc_t		*vd_sc;
	int			vd_num_cmd;
	int			vd_max_cmd;
	boolean_t		vd_rescan;
	list_t			vd_reqs;
	timeout_id_t		vd_timeout;
	kmutex_t		vd_lock;
};

struct vioscsi_event {
	virtio_chain_t		*ve_vic;
	virtio_dma_t		*ve_dma;
	vioscsi_evt_t		*ve_evt;
};

struct vioscsi_softc {
	dev_info_t		*vs_dip;
	virtio_t		*vs_virtio;
	uint64_t		vs_features;

	virtio_queue_t		*vs_ctl_vq;
	virtio_queue_t		*vs_evt_vq;
	virtio_queue_t		*vs_cmd_vq;

	scsi_hba_tran_t		*vs_tran;
	scsi_hba_tgtmap_t	*vs_tgtmap;
	ddi_taskq_t		*vs_tq;

	uint32_t		vs_max_target;
	uint32_t		vs_max_lun;
	uint32_t		vs_cdb_size;
	uint32_t		vs_max_seg;
	uint32_t		vs_cmd_per_lun;

	vioscsi_event_t		vs_events[VIOSCSI_NUM_EVENTS];

	void			*vs_intr_pri;
	kmutex_t		vs_lock;
	list_t			vs_devs;
};

#ifdef __cplusplus
}
#endif

#endif /* _VIOSCSI_H_ */