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