xref: /freebsd/usr.sbin/bhyve/pci_virtio_scsi_ctl.c (revision 9542ddb21dc15986843708d3f845eb23e7090107)
1*9542ddb2SHans Rosenfeld /*-
2*9542ddb2SHans Rosenfeld  * SPDX-License-Identifier: BSD-2-Clause
3*9542ddb2SHans Rosenfeld  *
4*9542ddb2SHans Rosenfeld  * Copyright (c) 2016 Jakub Klama <jceel@FreeBSD.org>.
5*9542ddb2SHans Rosenfeld  * Copyright (c) 2018 Marcelo Araujo <araujo@FreeBSD.org>.
6*9542ddb2SHans Rosenfeld  * Copyright (c) 2026 Hans Rosenfeld
7*9542ddb2SHans Rosenfeld  * All rights reserved.
8*9542ddb2SHans Rosenfeld  *
9*9542ddb2SHans Rosenfeld  * Redistribution and use in source and binary forms, with or without
10*9542ddb2SHans Rosenfeld  * modification, are permitted provided that the following conditions
11*9542ddb2SHans Rosenfeld  * are met:
12*9542ddb2SHans Rosenfeld  * 1. Redistributions of source code must retain the above copyright
13*9542ddb2SHans Rosenfeld  *    notice, this list of conditions and the following disclaimer
14*9542ddb2SHans Rosenfeld  *    in this position and unchanged.
15*9542ddb2SHans Rosenfeld  * 2. Redistributions in binary form must reproduce the above copyright
16*9542ddb2SHans Rosenfeld  *    notice, this list of conditions and the following disclaimer in the
17*9542ddb2SHans Rosenfeld  *    documentation and/or other materials provided with the distribution.
18*9542ddb2SHans Rosenfeld  *
19*9542ddb2SHans Rosenfeld  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20*9542ddb2SHans Rosenfeld  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*9542ddb2SHans Rosenfeld  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*9542ddb2SHans Rosenfeld  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23*9542ddb2SHans Rosenfeld  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*9542ddb2SHans Rosenfeld  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*9542ddb2SHans Rosenfeld  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*9542ddb2SHans Rosenfeld  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*9542ddb2SHans Rosenfeld  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*9542ddb2SHans Rosenfeld  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*9542ddb2SHans Rosenfeld  * SUCH DAMAGE.
30*9542ddb2SHans Rosenfeld  */
31*9542ddb2SHans Rosenfeld 
32*9542ddb2SHans Rosenfeld #include <sys/param.h>
33*9542ddb2SHans Rosenfeld #include <sys/linker_set.h>
34*9542ddb2SHans Rosenfeld #include <sys/types.h>
35*9542ddb2SHans Rosenfeld #include <sys/uio.h>
36*9542ddb2SHans Rosenfeld #include <sys/time.h>
37*9542ddb2SHans Rosenfeld #include <sys/queue.h>
38*9542ddb2SHans Rosenfeld #include <sys/sbuf.h>
39*9542ddb2SHans Rosenfeld 
40*9542ddb2SHans Rosenfeld #include <errno.h>
41*9542ddb2SHans Rosenfeld #include <fcntl.h>
42*9542ddb2SHans Rosenfeld #include <stdio.h>
43*9542ddb2SHans Rosenfeld #include <stdlib.h>
44*9542ddb2SHans Rosenfeld #include <stdbool.h>
45*9542ddb2SHans Rosenfeld #include <string.h>
46*9542ddb2SHans Rosenfeld #include <unistd.h>
47*9542ddb2SHans Rosenfeld #include <assert.h>
48*9542ddb2SHans Rosenfeld #include <pthread.h>
49*9542ddb2SHans Rosenfeld #include <pthread_np.h>
50*9542ddb2SHans Rosenfeld 
51*9542ddb2SHans Rosenfeld #include <cam/scsi/scsi_all.h>
52*9542ddb2SHans Rosenfeld #include <cam/scsi/scsi_message.h>
53*9542ddb2SHans Rosenfeld #include <cam/ctl/ctl.h>
54*9542ddb2SHans Rosenfeld #include <cam/ctl/ctl_io.h>
55*9542ddb2SHans Rosenfeld #include <cam/ctl/ctl_backend.h>
56*9542ddb2SHans Rosenfeld #include <cam/ctl/ctl_ioctl.h>
57*9542ddb2SHans Rosenfeld #include <cam/ctl/ctl_util.h>
58*9542ddb2SHans Rosenfeld #include <cam/ctl/ctl_scsi_all.h>
59*9542ddb2SHans Rosenfeld #include <camlib.h>
60*9542ddb2SHans Rosenfeld 
61*9542ddb2SHans Rosenfeld #include "bhyverun.h"
62*9542ddb2SHans Rosenfeld #include "config.h"
63*9542ddb2SHans Rosenfeld #include "debug.h"
64*9542ddb2SHans Rosenfeld #include "pci_emul.h"
65*9542ddb2SHans Rosenfeld #include "virtio.h"
66*9542ddb2SHans Rosenfeld #include "iov.h"
67*9542ddb2SHans Rosenfeld #include "pci_virtio_scsi.h"
68*9542ddb2SHans Rosenfeld 
69*9542ddb2SHans Rosenfeld struct vtscsi_ctl_backend {
70*9542ddb2SHans Rosenfeld 	struct pci_vtscsi_backend	vcb_backend;
71*9542ddb2SHans Rosenfeld 	int				vcb_iid;
72*9542ddb2SHans Rosenfeld };
73*9542ddb2SHans Rosenfeld 
74*9542ddb2SHans Rosenfeld static int vtscsi_ctl_init(struct pci_vtscsi_softc *,
75*9542ddb2SHans Rosenfeld     struct pci_vtscsi_backend *, nvlist_t *);
76*9542ddb2SHans Rosenfeld static int vtscsi_ctl_open(struct pci_vtscsi_softc *, const char *, long);
77*9542ddb2SHans Rosenfeld static void vtscsi_ctl_reset(struct pci_vtscsi_softc *);
78*9542ddb2SHans Rosenfeld 
79*9542ddb2SHans Rosenfeld static void *vtscsi_ctl_req_alloc(struct pci_vtscsi_softc *);
80*9542ddb2SHans Rosenfeld static void vtscsi_ctl_req_clear(void  *);
81*9542ddb2SHans Rosenfeld static void vtscsi_ctl_req_free(void *);
82*9542ddb2SHans Rosenfeld 
83*9542ddb2SHans Rosenfeld static void vtscsi_ctl_tmf_hdl(struct pci_vtscsi_softc *, int,
84*9542ddb2SHans Rosenfeld     struct pci_vtscsi_ctrl_tmf *);
85*9542ddb2SHans Rosenfeld static void vtscsi_ctl_an_hdl(struct pci_vtscsi_softc *, int,
86*9542ddb2SHans Rosenfeld     struct pci_vtscsi_ctrl_an *);
87*9542ddb2SHans Rosenfeld static int vtscsi_ctl_req_hdl(struct pci_vtscsi_softc *, int,
88*9542ddb2SHans Rosenfeld     struct pci_vtscsi_request *);
89*9542ddb2SHans Rosenfeld 
90*9542ddb2SHans Rosenfeld static int
vtscsi_ctl_count_targets(const char * prefix __unused,const nvlist_t * parent __unused,const char * name __unused,int type,void * arg)91*9542ddb2SHans Rosenfeld vtscsi_ctl_count_targets(const char *prefix __unused,
92*9542ddb2SHans Rosenfeld     const nvlist_t *parent __unused, const char *name __unused, int type,
93*9542ddb2SHans Rosenfeld     void *arg)
94*9542ddb2SHans Rosenfeld {
95*9542ddb2SHans Rosenfeld 	int *count = arg;
96*9542ddb2SHans Rosenfeld 
97*9542ddb2SHans Rosenfeld 	if (type != NV_TYPE_STRING) {
98*9542ddb2SHans Rosenfeld 		EPRINTLN("invalid target \"%s\" type: not a string", name);
99*9542ddb2SHans Rosenfeld 		errno = EINVAL;
100*9542ddb2SHans Rosenfeld 		return (-1);
101*9542ddb2SHans Rosenfeld 	}
102*9542ddb2SHans Rosenfeld 
103*9542ddb2SHans Rosenfeld 	(*count)++;
104*9542ddb2SHans Rosenfeld 
105*9542ddb2SHans Rosenfeld 	return (0);
106*9542ddb2SHans Rosenfeld }
107*9542ddb2SHans Rosenfeld 
108*9542ddb2SHans Rosenfeld static int
vtscsi_ctl_init(struct pci_vtscsi_softc * sc,struct pci_vtscsi_backend * backend,nvlist_t * nvl)109*9542ddb2SHans Rosenfeld vtscsi_ctl_init(struct pci_vtscsi_softc *sc, struct pci_vtscsi_backend *backend,
110*9542ddb2SHans Rosenfeld     nvlist_t *nvl)
111*9542ddb2SHans Rosenfeld {
112*9542ddb2SHans Rosenfeld 	int count = 0;
113*9542ddb2SHans Rosenfeld 	int ret = 0;
114*9542ddb2SHans Rosenfeld 	struct vtscsi_ctl_backend *ctl_backend;
115*9542ddb2SHans Rosenfeld 	const char *value;
116*9542ddb2SHans Rosenfeld 
117*9542ddb2SHans Rosenfeld 	ctl_backend = calloc(1, sizeof(struct vtscsi_ctl_backend));
118*9542ddb2SHans Rosenfeld 	if (ctl_backend == NULL) {
119*9542ddb2SHans Rosenfeld 		EPRINTLN("failed to allocate backend data: %s",
120*9542ddb2SHans Rosenfeld 		    strerror(errno));
121*9542ddb2SHans Rosenfeld 		return (-1);
122*9542ddb2SHans Rosenfeld 	}
123*9542ddb2SHans Rosenfeld 
124*9542ddb2SHans Rosenfeld 	ctl_backend->vcb_backend = *backend;
125*9542ddb2SHans Rosenfeld 	sc->vss_backend = &ctl_backend->vcb_backend;
126*9542ddb2SHans Rosenfeld 
127*9542ddb2SHans Rosenfeld 	value = get_config_value_node(nvl, "iid");
128*9542ddb2SHans Rosenfeld 	if (value != NULL)
129*9542ddb2SHans Rosenfeld 		ctl_backend->vcb_iid = strtoul(value, NULL, 10);
130*9542ddb2SHans Rosenfeld 
131*9542ddb2SHans Rosenfeld 	/*
132*9542ddb2SHans Rosenfeld 	 * Count configured targets. If no targets were configured, use
133*9542ddb2SHans Rosenfeld 	 * /dev/cam/ctl to remain compatible with previous versions.
134*9542ddb2SHans Rosenfeld 	 */
135*9542ddb2SHans Rosenfeld 	nvl = find_relative_config_node(nvl, "target");
136*9542ddb2SHans Rosenfeld 	assert(nvl != NULL);
137*9542ddb2SHans Rosenfeld 
138*9542ddb2SHans Rosenfeld 	ret = walk_config_nodes("", nvl, &count, vtscsi_ctl_count_targets);
139*9542ddb2SHans Rosenfeld 	if (ret != 0)
140*9542ddb2SHans Rosenfeld 		return (ret);
141*9542ddb2SHans Rosenfeld 
142*9542ddb2SHans Rosenfeld 	if (count == 0)
143*9542ddb2SHans Rosenfeld 		set_config_value_node(nvl, "0", "/dev/cam/ctl");
144*9542ddb2SHans Rosenfeld 
145*9542ddb2SHans Rosenfeld 	return (0);
146*9542ddb2SHans Rosenfeld }
147*9542ddb2SHans Rosenfeld 
148*9542ddb2SHans Rosenfeld static int
vtscsi_ctl_open(struct pci_vtscsi_softc * sc __unused,const char * devname,long target)149*9542ddb2SHans Rosenfeld vtscsi_ctl_open(struct pci_vtscsi_softc *sc __unused, const char *devname,
150*9542ddb2SHans Rosenfeld     long target)
151*9542ddb2SHans Rosenfeld {
152*9542ddb2SHans Rosenfeld 	struct pci_vtscsi_target *tgt = &sc->vss_targets[target];
153*9542ddb2SHans Rosenfeld 
154*9542ddb2SHans Rosenfeld 	tgt->vst_fd = open(devname, O_RDWR);
155*9542ddb2SHans Rosenfeld 	if (tgt->vst_fd < 0)
156*9542ddb2SHans Rosenfeld 		return (-1);
157*9542ddb2SHans Rosenfeld 
158*9542ddb2SHans Rosenfeld 	return (0);
159*9542ddb2SHans Rosenfeld }
160*9542ddb2SHans Rosenfeld 
161*9542ddb2SHans Rosenfeld static void
vtscsi_ctl_reset(struct pci_vtscsi_softc * sc __unused)162*9542ddb2SHans Rosenfeld vtscsi_ctl_reset(struct pci_vtscsi_softc *sc __unused)
163*9542ddb2SHans Rosenfeld {
164*9542ddb2SHans Rosenfeld 	/*
165*9542ddb2SHans Rosenfeld 	 * There doesn't seem to be a limit to the maximum number of
166*9542ddb2SHans Rosenfeld 	 * sectors CTL can transfer in one request.
167*9542ddb2SHans Rosenfeld 	 */
168*9542ddb2SHans Rosenfeld 	sc->vss_config.max_sectors = INT32_MAX;
169*9542ddb2SHans Rosenfeld }
170*9542ddb2SHans Rosenfeld 
171*9542ddb2SHans Rosenfeld static void *
vtscsi_ctl_req_alloc(struct pci_vtscsi_softc * sc)172*9542ddb2SHans Rosenfeld vtscsi_ctl_req_alloc(struct pci_vtscsi_softc *sc)
173*9542ddb2SHans Rosenfeld {
174*9542ddb2SHans Rosenfeld 	struct vtscsi_ctl_backend *ctl =
175*9542ddb2SHans Rosenfeld 		(struct vtscsi_ctl_backend *)sc->vss_backend;
176*9542ddb2SHans Rosenfeld 	union ctl_io *io = ctl_scsi_alloc_io(ctl->vcb_iid);
177*9542ddb2SHans Rosenfeld 
178*9542ddb2SHans Rosenfeld 	if (io != NULL)
179*9542ddb2SHans Rosenfeld 		ctl_scsi_zero_io(io);
180*9542ddb2SHans Rosenfeld 
181*9542ddb2SHans Rosenfeld 	return (io);
182*9542ddb2SHans Rosenfeld }
183*9542ddb2SHans Rosenfeld 
184*9542ddb2SHans Rosenfeld static void
vtscsi_ctl_req_clear(void * io)185*9542ddb2SHans Rosenfeld vtscsi_ctl_req_clear(void *io)
186*9542ddb2SHans Rosenfeld {
187*9542ddb2SHans Rosenfeld 	ctl_scsi_zero_io(io);
188*9542ddb2SHans Rosenfeld }
189*9542ddb2SHans Rosenfeld 
190*9542ddb2SHans Rosenfeld static void
vtscsi_ctl_req_free(void * io)191*9542ddb2SHans Rosenfeld vtscsi_ctl_req_free(void *io)
192*9542ddb2SHans Rosenfeld {
193*9542ddb2SHans Rosenfeld 	ctl_scsi_free_io(io);
194*9542ddb2SHans Rosenfeld }
195*9542ddb2SHans Rosenfeld 
196*9542ddb2SHans Rosenfeld static void
vtscsi_ctl_tmf_hdl(struct pci_vtscsi_softc * sc,int fd,struct pci_vtscsi_ctrl_tmf * tmf)197*9542ddb2SHans Rosenfeld vtscsi_ctl_tmf_hdl(struct pci_vtscsi_softc *sc, int fd,
198*9542ddb2SHans Rosenfeld     struct pci_vtscsi_ctrl_tmf *tmf)
199*9542ddb2SHans Rosenfeld {
200*9542ddb2SHans Rosenfeld 	struct vtscsi_ctl_backend *ctl;
201*9542ddb2SHans Rosenfeld 	union ctl_io *io;
202*9542ddb2SHans Rosenfeld 	int err;
203*9542ddb2SHans Rosenfeld 
204*9542ddb2SHans Rosenfeld 	ctl = (struct vtscsi_ctl_backend *)sc->vss_backend;
205*9542ddb2SHans Rosenfeld 
206*9542ddb2SHans Rosenfeld 	io = vtscsi_ctl_req_alloc(sc);
207*9542ddb2SHans Rosenfeld 	if (io == NULL) {
208*9542ddb2SHans Rosenfeld 		tmf->response = VIRTIO_SCSI_S_FAILURE;
209*9542ddb2SHans Rosenfeld 		return;
210*9542ddb2SHans Rosenfeld 	}
211*9542ddb2SHans Rosenfeld 	vtscsi_ctl_req_clear(io);
212*9542ddb2SHans Rosenfeld 
213*9542ddb2SHans Rosenfeld 	io->io_hdr.io_type = CTL_IO_TASK;
214*9542ddb2SHans Rosenfeld 	io->io_hdr.nexus.initid = ctl->vcb_iid;
215*9542ddb2SHans Rosenfeld 	io->io_hdr.nexus.targ_lun = pci_vtscsi_get_lun(sc, tmf->lun);
216*9542ddb2SHans Rosenfeld 	io->taskio.tag_type = CTL_TAG_SIMPLE;
217*9542ddb2SHans Rosenfeld 	io->taskio.tag_num = tmf->id;
218*9542ddb2SHans Rosenfeld 	io->io_hdr.flags |= CTL_FLAG_USER_TAG;
219*9542ddb2SHans Rosenfeld 
220*9542ddb2SHans Rosenfeld 	switch (tmf->subtype) {
221*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_T_TMF_ABORT_TASK:
222*9542ddb2SHans Rosenfeld 		io->taskio.task_action = CTL_TASK_ABORT_TASK;
223*9542ddb2SHans Rosenfeld 		break;
224*9542ddb2SHans Rosenfeld 
225*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
226*9542ddb2SHans Rosenfeld 		io->taskio.task_action = CTL_TASK_ABORT_TASK_SET;
227*9542ddb2SHans Rosenfeld 		break;
228*9542ddb2SHans Rosenfeld 
229*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
230*9542ddb2SHans Rosenfeld 		io->taskio.task_action = CTL_TASK_CLEAR_ACA;
231*9542ddb2SHans Rosenfeld 		break;
232*9542ddb2SHans Rosenfeld 
233*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
234*9542ddb2SHans Rosenfeld 		io->taskio.task_action = CTL_TASK_CLEAR_TASK_SET;
235*9542ddb2SHans Rosenfeld 		break;
236*9542ddb2SHans Rosenfeld 
237*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
238*9542ddb2SHans Rosenfeld 		io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET;
239*9542ddb2SHans Rosenfeld 		break;
240*9542ddb2SHans Rosenfeld 
241*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
242*9542ddb2SHans Rosenfeld 		io->taskio.task_action = CTL_TASK_LUN_RESET;
243*9542ddb2SHans Rosenfeld 		break;
244*9542ddb2SHans Rosenfeld 
245*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_T_TMF_QUERY_TASK:
246*9542ddb2SHans Rosenfeld 		io->taskio.task_action = CTL_TASK_QUERY_TASK;
247*9542ddb2SHans Rosenfeld 		break;
248*9542ddb2SHans Rosenfeld 
249*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
250*9542ddb2SHans Rosenfeld 		io->taskio.task_action = CTL_TASK_QUERY_TASK_SET;
251*9542ddb2SHans Rosenfeld 		break;
252*9542ddb2SHans Rosenfeld 	}
253*9542ddb2SHans Rosenfeld 
254*9542ddb2SHans Rosenfeld 	if (pci_vtscsi_debug) {
255*9542ddb2SHans Rosenfeld 		struct sbuf *sb = sbuf_new_auto();
256*9542ddb2SHans Rosenfeld 		ctl_io_sbuf(io, sb);
257*9542ddb2SHans Rosenfeld 		sbuf_finish(sb);
258*9542ddb2SHans Rosenfeld 		DPRINTF("%s", sbuf_data(sb));
259*9542ddb2SHans Rosenfeld 		sbuf_delete(sb);
260*9542ddb2SHans Rosenfeld 	}
261*9542ddb2SHans Rosenfeld 
262*9542ddb2SHans Rosenfeld 	err = ioctl(fd, CTL_IO, io);
263*9542ddb2SHans Rosenfeld 	if (err != 0) {
264*9542ddb2SHans Rosenfeld 		WPRINTF("CTL_IO: err=%d (%s)", errno, strerror(errno));
265*9542ddb2SHans Rosenfeld 		tmf->response = VIRTIO_SCSI_S_FAILURE;
266*9542ddb2SHans Rosenfeld 	} else {
267*9542ddb2SHans Rosenfeld 		tmf->response = io->taskio.task_status;
268*9542ddb2SHans Rosenfeld 	}
269*9542ddb2SHans Rosenfeld 	vtscsi_ctl_req_free(io);
270*9542ddb2SHans Rosenfeld }
271*9542ddb2SHans Rosenfeld 
272*9542ddb2SHans Rosenfeld static void
vtscsi_ctl_an_hdl(struct pci_vtscsi_softc * sc __unused,int fd __unused,struct pci_vtscsi_ctrl_an * an)273*9542ddb2SHans Rosenfeld vtscsi_ctl_an_hdl(struct pci_vtscsi_softc *sc __unused, int fd __unused,
274*9542ddb2SHans Rosenfeld     struct pci_vtscsi_ctrl_an *an)
275*9542ddb2SHans Rosenfeld {
276*9542ddb2SHans Rosenfeld 	an->response = VIRTIO_SCSI_S_FAILURE;
277*9542ddb2SHans Rosenfeld }
278*9542ddb2SHans Rosenfeld 
279*9542ddb2SHans Rosenfeld static int
vtscsi_ctl_req_hdl(struct pci_vtscsi_softc * sc,int fd,struct pci_vtscsi_request * req)280*9542ddb2SHans Rosenfeld vtscsi_ctl_req_hdl(struct pci_vtscsi_softc *sc, int fd,
281*9542ddb2SHans Rosenfeld     struct pci_vtscsi_request *req)
282*9542ddb2SHans Rosenfeld {
283*9542ddb2SHans Rosenfeld 	union ctl_io *io = req->vsr_backend;
284*9542ddb2SHans Rosenfeld 	void *ext_data_ptr = NULL;
285*9542ddb2SHans Rosenfeld 	uint32_t ext_data_len = 0, ext_sg_entries = 0;
286*9542ddb2SHans Rosenfeld 	struct vtscsi_ctl_backend *ctl;
287*9542ddb2SHans Rosenfeld 	int err, nxferred;
288*9542ddb2SHans Rosenfeld 
289*9542ddb2SHans Rosenfeld 	ctl = (struct vtscsi_ctl_backend *)sc->vss_backend;
290*9542ddb2SHans Rosenfeld 
291*9542ddb2SHans Rosenfeld 	io->io_hdr.nexus.initid = ctl->vcb_iid;
292*9542ddb2SHans Rosenfeld 	io->io_hdr.nexus.targ_lun = pci_vtscsi_get_lun(sc,
293*9542ddb2SHans Rosenfeld 	    req->vsr_cmd_rd->lun);
294*9542ddb2SHans Rosenfeld 
295*9542ddb2SHans Rosenfeld 	io->io_hdr.io_type = CTL_IO_SCSI;
296*9542ddb2SHans Rosenfeld 
297*9542ddb2SHans Rosenfeld 	if (req->vsr_data_niov_in > 0) {
298*9542ddb2SHans Rosenfeld 		ext_data_ptr = (void *)req->vsr_data_iov_in;
299*9542ddb2SHans Rosenfeld 		ext_sg_entries = req->vsr_data_niov_in;
300*9542ddb2SHans Rosenfeld 		ext_data_len = count_iov(req->vsr_data_iov_in,
301*9542ddb2SHans Rosenfeld 		    req->vsr_data_niov_in);
302*9542ddb2SHans Rosenfeld 		io->io_hdr.flags |= CTL_FLAG_DATA_OUT;
303*9542ddb2SHans Rosenfeld 	} else if (req->vsr_data_niov_out > 0) {
304*9542ddb2SHans Rosenfeld 		ext_data_ptr = (void *)req->vsr_data_iov_out;
305*9542ddb2SHans Rosenfeld 		ext_sg_entries = req->vsr_data_niov_out;
306*9542ddb2SHans Rosenfeld 		ext_data_len = count_iov(req->vsr_data_iov_out,
307*9542ddb2SHans Rosenfeld 		    req->vsr_data_niov_out);
308*9542ddb2SHans Rosenfeld 		io->io_hdr.flags |= CTL_FLAG_DATA_IN;
309*9542ddb2SHans Rosenfeld 	}
310*9542ddb2SHans Rosenfeld 
311*9542ddb2SHans Rosenfeld 	io->scsiio.sense_len = sc->vss_config.sense_size;
312*9542ddb2SHans Rosenfeld 	io->scsiio.tag_num = req->vsr_cmd_rd->id;
313*9542ddb2SHans Rosenfeld 	io->io_hdr.flags |= CTL_FLAG_USER_TAG;
314*9542ddb2SHans Rosenfeld 	switch (req->vsr_cmd_rd->task_attr) {
315*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_S_ORDERED:
316*9542ddb2SHans Rosenfeld 		io->scsiio.tag_type = CTL_TAG_ORDERED;
317*9542ddb2SHans Rosenfeld 		break;
318*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_S_HEAD:
319*9542ddb2SHans Rosenfeld 		io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
320*9542ddb2SHans Rosenfeld 		break;
321*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_S_ACA:
322*9542ddb2SHans Rosenfeld 		io->scsiio.tag_type = CTL_TAG_ACA;
323*9542ddb2SHans Rosenfeld 		break;
324*9542ddb2SHans Rosenfeld 	case VIRTIO_SCSI_S_SIMPLE:
325*9542ddb2SHans Rosenfeld 	default:
326*9542ddb2SHans Rosenfeld 		io->scsiio.tag_type = CTL_TAG_SIMPLE;
327*9542ddb2SHans Rosenfeld 		break;
328*9542ddb2SHans Rosenfeld 	}
329*9542ddb2SHans Rosenfeld 	io->scsiio.ext_sg_entries = ext_sg_entries;
330*9542ddb2SHans Rosenfeld 	io->scsiio.ext_data_ptr = ext_data_ptr;
331*9542ddb2SHans Rosenfeld 	io->scsiio.ext_data_len = ext_data_len;
332*9542ddb2SHans Rosenfeld 	io->scsiio.ext_data_filled = 0;
333*9542ddb2SHans Rosenfeld 	io->scsiio.cdb_len = sc->vss_config.cdb_size;
334*9542ddb2SHans Rosenfeld 	memcpy(io->scsiio.cdb, req->vsr_cmd_rd->cdb, sc->vss_config.cdb_size);
335*9542ddb2SHans Rosenfeld 
336*9542ddb2SHans Rosenfeld 	if (pci_vtscsi_debug) {
337*9542ddb2SHans Rosenfeld 		struct sbuf *sb = sbuf_new_auto();
338*9542ddb2SHans Rosenfeld 		ctl_io_sbuf(io, sb);
339*9542ddb2SHans Rosenfeld 		sbuf_finish(sb);
340*9542ddb2SHans Rosenfeld 		DPRINTF("%s", sbuf_data(sb));
341*9542ddb2SHans Rosenfeld 		sbuf_delete(sb);
342*9542ddb2SHans Rosenfeld 	}
343*9542ddb2SHans Rosenfeld 
344*9542ddb2SHans Rosenfeld 	err = ioctl(fd, CTL_IO, io);
345*9542ddb2SHans Rosenfeld 	if (err != 0) {
346*9542ddb2SHans Rosenfeld 		WPRINTF("CTL_IO: err=%d (%s)", errno, strerror(errno));
347*9542ddb2SHans Rosenfeld 		req->vsr_cmd_wr->response = VIRTIO_SCSI_S_FAILURE;
348*9542ddb2SHans Rosenfeld 	} else {
349*9542ddb2SHans Rosenfeld 		req->vsr_cmd_wr->sense_len =
350*9542ddb2SHans Rosenfeld 		    MIN(io->scsiio.sense_len, sc->vss_config.sense_size);
351*9542ddb2SHans Rosenfeld 		req->vsr_cmd_wr->residual = ext_data_len -
352*9542ddb2SHans Rosenfeld 		    io->scsiio.ext_data_filled;
353*9542ddb2SHans Rosenfeld 		req->vsr_cmd_wr->status = io->scsiio.scsi_status;
354*9542ddb2SHans Rosenfeld 		req->vsr_cmd_wr->response = VIRTIO_SCSI_S_OK;
355*9542ddb2SHans Rosenfeld 		memcpy(&req->vsr_cmd_wr->sense, &io->scsiio.sense_data,
356*9542ddb2SHans Rosenfeld 		    req->vsr_cmd_wr->sense_len);
357*9542ddb2SHans Rosenfeld 	}
358*9542ddb2SHans Rosenfeld 
359*9542ddb2SHans Rosenfeld 	nxferred = io->scsiio.ext_data_filled;
360*9542ddb2SHans Rosenfeld 	return (nxferred);
361*9542ddb2SHans Rosenfeld }
362*9542ddb2SHans Rosenfeld 
363*9542ddb2SHans Rosenfeld static const struct pci_vtscsi_backend vtscsi_ctl_backend = {
364*9542ddb2SHans Rosenfeld 	.vsb_name = "ctl",
365*9542ddb2SHans Rosenfeld 	.vsb_init = vtscsi_ctl_init,
366*9542ddb2SHans Rosenfeld 	.vsb_open = vtscsi_ctl_open,
367*9542ddb2SHans Rosenfeld 	.vsb_reset = vtscsi_ctl_reset,
368*9542ddb2SHans Rosenfeld 
369*9542ddb2SHans Rosenfeld 	.vsb_req_alloc = vtscsi_ctl_req_alloc,
370*9542ddb2SHans Rosenfeld 	.vsb_req_clear = vtscsi_ctl_req_clear,
371*9542ddb2SHans Rosenfeld 	.vsb_req_free = vtscsi_ctl_req_free,
372*9542ddb2SHans Rosenfeld 
373*9542ddb2SHans Rosenfeld 	.vsb_tmf_hdl = vtscsi_ctl_tmf_hdl,
374*9542ddb2SHans Rosenfeld 	.vsb_an_hdl = vtscsi_ctl_an_hdl,
375*9542ddb2SHans Rosenfeld 	.vsb_req_hdl = vtscsi_ctl_req_hdl
376*9542ddb2SHans Rosenfeld };
377*9542ddb2SHans Rosenfeld PCI_VTSCSI_BACKEND_SET(vtscsi_ctl_backend);
378