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