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