1*5f016a21SHans Rosenfeld /*-
2*5f016a21SHans Rosenfeld * SPDX-License-Identifier: BSD-2-Clause
3*5f016a21SHans Rosenfeld *
4*5f016a21SHans Rosenfeld * Copyright (c) 2016 Jakub Klama <jceel@FreeBSD.org>.
5*5f016a21SHans Rosenfeld * Copyright (c) 2018 Marcelo Araujo <araujo@FreeBSD.org>.
6*5f016a21SHans Rosenfeld * Copyright (c) 2026 Hans Rosenfeld
7*5f016a21SHans Rosenfeld * All rights reserved.
8*5f016a21SHans Rosenfeld *
9*5f016a21SHans Rosenfeld * Redistribution and use in source and binary forms, with or without
10*5f016a21SHans Rosenfeld * modification, are permitted provided that the following conditions
11*5f016a21SHans Rosenfeld * are met:
12*5f016a21SHans Rosenfeld * 1. Redistributions of source code must retain the above copyright
13*5f016a21SHans Rosenfeld * notice, this list of conditions and the following disclaimer
14*5f016a21SHans Rosenfeld * in this position and unchanged.
15*5f016a21SHans Rosenfeld * 2. Redistributions in binary form must reproduce the above copyright
16*5f016a21SHans Rosenfeld * notice, this list of conditions and the following disclaimer in the
17*5f016a21SHans Rosenfeld * documentation and/or other materials provided with the distribution.
18*5f016a21SHans Rosenfeld *
19*5f016a21SHans Rosenfeld * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20*5f016a21SHans Rosenfeld * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*5f016a21SHans Rosenfeld * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*5f016a21SHans Rosenfeld * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23*5f016a21SHans Rosenfeld * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*5f016a21SHans Rosenfeld * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*5f016a21SHans Rosenfeld * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*5f016a21SHans Rosenfeld * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*5f016a21SHans Rosenfeld * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*5f016a21SHans Rosenfeld * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*5f016a21SHans Rosenfeld * SUCH DAMAGE.
30*5f016a21SHans Rosenfeld */
31*5f016a21SHans Rosenfeld
32*5f016a21SHans Rosenfeld #include <sys/param.h>
33*5f016a21SHans Rosenfeld #include <sys/linker_set.h>
34*5f016a21SHans Rosenfeld #include <sys/types.h>
35*5f016a21SHans Rosenfeld #include <sys/uio.h>
36*5f016a21SHans Rosenfeld #include <sys/time.h>
37*5f016a21SHans Rosenfeld #include <sys/queue.h>
38*5f016a21SHans Rosenfeld
39*5f016a21SHans Rosenfeld #include <alloca.h>
40*5f016a21SHans Rosenfeld #include <errno.h>
41*5f016a21SHans Rosenfeld #include <fcntl.h>
42*5f016a21SHans Rosenfeld #include <stdio.h>
43*5f016a21SHans Rosenfeld #include <stdlib.h>
44*5f016a21SHans Rosenfeld #include <stdbool.h>
45*5f016a21SHans Rosenfeld #include <string.h>
46*5f016a21SHans Rosenfeld #include <unistd.h>
47*5f016a21SHans Rosenfeld #include <assert.h>
48*5f016a21SHans Rosenfeld #include <pthread.h>
49*5f016a21SHans Rosenfeld #include <pthread_np.h>
50*5f016a21SHans Rosenfeld
51*5f016a21SHans Rosenfeld #include <scsi/libscsi.h>
52*5f016a21SHans Rosenfeld #include <sys/scsi/generic/commands.h>
53*5f016a21SHans Rosenfeld #include <sys/scsi/generic/status.h>
54*5f016a21SHans Rosenfeld #include <sys/scsi/impl/uscsi.h>
55*5f016a21SHans Rosenfeld
56*5f016a21SHans Rosenfeld #include "bhyverun.h"
57*5f016a21SHans Rosenfeld #include "config.h"
58*5f016a21SHans Rosenfeld #include "debug.h"
59*5f016a21SHans Rosenfeld #include "pci_emul.h"
60*5f016a21SHans Rosenfeld #include "virtio.h"
61*5f016a21SHans Rosenfeld #include "iov.h"
62*5f016a21SHans Rosenfeld #include "privileges.h"
63*5f016a21SHans Rosenfeld #include "pci_virtio_scsi.h"
64*5f016a21SHans Rosenfeld
65*5f016a21SHans Rosenfeld struct vtscsi_uscsi_backend {
66*5f016a21SHans Rosenfeld struct pci_vtscsi_backend vub_backend;
67*5f016a21SHans Rosenfeld libscsi_hdl_t *vub_scsi_hdl;
68*5f016a21SHans Rosenfeld };
69*5f016a21SHans Rosenfeld
70*5f016a21SHans Rosenfeld static int vtscsi_uscsi_init(struct pci_vtscsi_softc *,
71*5f016a21SHans Rosenfeld struct pci_vtscsi_backend *, nvlist_t *);
72*5f016a21SHans Rosenfeld static int vtscsi_uscsi_open(struct pci_vtscsi_softc *, const char *, long);
73*5f016a21SHans Rosenfeld static void vtscsi_uscsi_reset(struct pci_vtscsi_softc *);
74*5f016a21SHans Rosenfeld
75*5f016a21SHans Rosenfeld static void *vtscsi_uscsi_req_alloc(struct pci_vtscsi_softc *);
76*5f016a21SHans Rosenfeld static void vtscsi_uscsi_req_clear(void *);
77*5f016a21SHans Rosenfeld static void vtscsi_uscsi_req_free(void *);
78*5f016a21SHans Rosenfeld
79*5f016a21SHans Rosenfeld static void vtscsi_uscsi_tmf_hdl(struct pci_vtscsi_softc *, int,
80*5f016a21SHans Rosenfeld struct pci_vtscsi_ctrl_tmf *);
81*5f016a21SHans Rosenfeld static void vtscsi_uscsi_an_hdl(struct pci_vtscsi_softc *, int,
82*5f016a21SHans Rosenfeld struct pci_vtscsi_ctrl_an *);
83*5f016a21SHans Rosenfeld static int vtscsi_uscsi_req_hdl(struct pci_vtscsi_softc *, int,
84*5f016a21SHans Rosenfeld struct pci_vtscsi_request *);
85*5f016a21SHans Rosenfeld
86*5f016a21SHans Rosenfeld static void vtscsi_uscsi_make_check_condition(struct uscsi_cmd *, char, char,
87*5f016a21SHans Rosenfeld char);
88*5f016a21SHans Rosenfeld static void vtscsi_uscsi_filter_post_report_luns(struct uscsi_cmd *);
89*5f016a21SHans Rosenfeld static void vtscsi_uscsi_filter_post(struct uscsi_cmd *);
90*5f016a21SHans Rosenfeld
91*5f016a21SHans Rosenfeld
92*5f016a21SHans Rosenfeld static int
vtscsi_uscsi_init(struct pci_vtscsi_softc * sc,struct pci_vtscsi_backend * backend,nvlist_t * nvl __unused)93*5f016a21SHans Rosenfeld vtscsi_uscsi_init(struct pci_vtscsi_softc *sc,
94*5f016a21SHans Rosenfeld struct pci_vtscsi_backend *backend, nvlist_t *nvl __unused)
95*5f016a21SHans Rosenfeld {
96*5f016a21SHans Rosenfeld struct vtscsi_uscsi_backend *uscsi_backend;
97*5f016a21SHans Rosenfeld libscsi_errno_t serr;
98*5f016a21SHans Rosenfeld
99*5f016a21SHans Rosenfeld uscsi_backend = calloc(1, sizeof (struct vtscsi_uscsi_backend));
100*5f016a21SHans Rosenfeld if (uscsi_backend == NULL) {
101*5f016a21SHans Rosenfeld EPRINTLN("failed to allocate backend data: %s",
102*5f016a21SHans Rosenfeld strerror(errno));
103*5f016a21SHans Rosenfeld return (-1);
104*5f016a21SHans Rosenfeld }
105*5f016a21SHans Rosenfeld
106*5f016a21SHans Rosenfeld uscsi_backend->vub_backend = *backend;
107*5f016a21SHans Rosenfeld
108*5f016a21SHans Rosenfeld uscsi_backend->vub_scsi_hdl = libscsi_init(LIBSCSI_VERSION, &serr);
109*5f016a21SHans Rosenfeld if (uscsi_backend->vub_scsi_hdl == NULL) {
110*5f016a21SHans Rosenfeld EPRINTLN("failed to initialize libscsi: %s",
111*5f016a21SHans Rosenfeld libscsi_strerror(serr));
112*5f016a21SHans Rosenfeld free(uscsi_backend);
113*5f016a21SHans Rosenfeld return (-1);
114*5f016a21SHans Rosenfeld }
115*5f016a21SHans Rosenfeld
116*5f016a21SHans Rosenfeld sc->vss_backend = &uscsi_backend->vub_backend;
117*5f016a21SHans Rosenfeld
118*5f016a21SHans Rosenfeld return (0);
119*5f016a21SHans Rosenfeld }
120*5f016a21SHans Rosenfeld
121*5f016a21SHans Rosenfeld static int
vtscsi_uscsi_open(struct pci_vtscsi_softc * sc,const char * path,long target)122*5f016a21SHans Rosenfeld vtscsi_uscsi_open(struct pci_vtscsi_softc *sc, const char *path, long target)
123*5f016a21SHans Rosenfeld {
124*5f016a21SHans Rosenfeld struct pci_vtscsi_target *tgt = &sc->vss_targets[target];
125*5f016a21SHans Rosenfeld uscsi_xfer_t maxxfer = 0;
126*5f016a21SHans Rosenfeld
127*5f016a21SHans Rosenfeld /*
128*5f016a21SHans Rosenfeld * Most SCSI target drivers require the SYS_DEVICES privilege to send
129*5f016a21SHans Rosenfeld * USCSI commands.
130*5f016a21SHans Rosenfeld */
131*5f016a21SHans Rosenfeld illumos_priv_add_min(PRIV_SYS_DEVICES, "scsi");
132*5f016a21SHans Rosenfeld
133*5f016a21SHans Rosenfeld /*
134*5f016a21SHans Rosenfeld * Open the target.
135*5f016a21SHans Rosenfeld */
136*5f016a21SHans Rosenfeld tgt->vst_fd = open(path, O_RDWR);
137*5f016a21SHans Rosenfeld if (tgt->vst_fd < 0)
138*5f016a21SHans Rosenfeld return (-1);
139*5f016a21SHans Rosenfeld
140*5f016a21SHans Rosenfeld /*
141*5f016a21SHans Rosenfeld * Get the maximum transfer size of the backend device.
142*5f016a21SHans Rosenfeld */
143*5f016a21SHans Rosenfeld if (ioctl(tgt->vst_fd, USCSIMAXXFER, &maxxfer) < 0) {
144*5f016a21SHans Rosenfeld int errno_save = errno;
145*5f016a21SHans Rosenfeld
146*5f016a21SHans Rosenfeld if (errno == ENOTTY) {
147*5f016a21SHans Rosenfeld /*
148*5f016a21SHans Rosenfeld * The underlying device doesn't support this ioctl.
149*5f016a21SHans Rosenfeld * Limit max_sectors to 128MB, which is as good as
150*5f016a21SHans Rosenfeld * any other assumption.
151*5f016a21SHans Rosenfeld */
152*5f016a21SHans Rosenfeld tgt->vst_max_sectors = 128 << (20 - 9);
153*5f016a21SHans Rosenfeld return (0);
154*5f016a21SHans Rosenfeld }
155*5f016a21SHans Rosenfeld
156*5f016a21SHans Rosenfeld WPRINTF("USCSIMAXXFER: unexpected error: errno=%d (%s)",
157*5f016a21SHans Rosenfeld strerrorname_np(errno), strerror(errno));
158*5f016a21SHans Rosenfeld (void) close(tgt->vst_fd);
159*5f016a21SHans Rosenfeld tgt->vst_fd = -1;
160*5f016a21SHans Rosenfeld errno = errno_save;
161*5f016a21SHans Rosenfeld return (-1);
162*5f016a21SHans Rosenfeld }
163*5f016a21SHans Rosenfeld
164*5f016a21SHans Rosenfeld /*
165*5f016a21SHans Rosenfeld * Even though the virtio spec isn't particularly verbose about what
166*5f016a21SHans Rosenfeld * "max_sectors" actually means and what size a sector is, Linux seems
167*5f016a21SHans Rosenfeld * to treat it as a number of 512b sectors.
168*5f016a21SHans Rosenfeld *
169*5f016a21SHans Rosenfeld * In any case, we need to limit maxxfer such that it fits into a signed
170*5f016a21SHans Rosenfeld * 32bit int.
171*5f016a21SHans Rosenfeld */
172*5f016a21SHans Rosenfeld if (maxxfer > INT32_MAX)
173*5f016a21SHans Rosenfeld maxxfer = INT32_MAX;
174*5f016a21SHans Rosenfeld
175*5f016a21SHans Rosenfeld tgt->vst_max_sectors = maxxfer >> 9;
176*5f016a21SHans Rosenfeld
177*5f016a21SHans Rosenfeld return (0);
178*5f016a21SHans Rosenfeld }
179*5f016a21SHans Rosenfeld
180*5f016a21SHans Rosenfeld static void
vtscsi_uscsi_reset(struct pci_vtscsi_softc * sc)181*5f016a21SHans Rosenfeld vtscsi_uscsi_reset(struct pci_vtscsi_softc *sc)
182*5f016a21SHans Rosenfeld {
183*5f016a21SHans Rosenfeld size_t i;
184*5f016a21SHans Rosenfeld
185*5f016a21SHans Rosenfeld sc->vss_config.max_sectors = INT32_MAX;
186*5f016a21SHans Rosenfeld
187*5f016a21SHans Rosenfeld /*
188*5f016a21SHans Rosenfeld * As we may be configured to use a variety of differing backend devices
189*5f016a21SHans Rosenfeld * with varying maximum transfer sizes but virtio-scsi supports only one
190*5f016a21SHans Rosenfeld * max_sectors limit per instance, we'll use the smallest maximum
191*5f016a21SHans Rosenfeld * transfer size found.
192*5f016a21SHans Rosenfeld */
193*5f016a21SHans Rosenfeld for (i = 0; i < sc->vss_num_target; i++) {
194*5f016a21SHans Rosenfeld struct pci_vtscsi_target *tgt = &sc->vss_targets[i];
195*5f016a21SHans Rosenfeld
196*5f016a21SHans Rosenfeld if (tgt->vst_max_sectors < sc->vss_config.max_sectors)
197*5f016a21SHans Rosenfeld sc->vss_config.max_sectors = tgt->vst_max_sectors;
198*5f016a21SHans Rosenfeld }
199*5f016a21SHans Rosenfeld }
200*5f016a21SHans Rosenfeld
201*5f016a21SHans Rosenfeld static void *
vtscsi_uscsi_req_alloc(struct pci_vtscsi_softc * sc)202*5f016a21SHans Rosenfeld vtscsi_uscsi_req_alloc(struct pci_vtscsi_softc *sc)
203*5f016a21SHans Rosenfeld {
204*5f016a21SHans Rosenfeld return (calloc(1, sizeof (struct uscsi_cmd)));
205*5f016a21SHans Rosenfeld }
206*5f016a21SHans Rosenfeld
207*5f016a21SHans Rosenfeld static void
vtscsi_uscsi_req_clear(void * io)208*5f016a21SHans Rosenfeld vtscsi_uscsi_req_clear(void *io)
209*5f016a21SHans Rosenfeld {
210*5f016a21SHans Rosenfeld bzero(io, sizeof (struct uscsi_cmd));
211*5f016a21SHans Rosenfeld }
212*5f016a21SHans Rosenfeld
213*5f016a21SHans Rosenfeld static void
vtscsi_uscsi_req_free(void * io)214*5f016a21SHans Rosenfeld vtscsi_uscsi_req_free(void *io)
215*5f016a21SHans Rosenfeld {
216*5f016a21SHans Rosenfeld free(io);
217*5f016a21SHans Rosenfeld }
218*5f016a21SHans Rosenfeld
219*5f016a21SHans Rosenfeld static void
vtscsi_uscsi_tmf_hdl(struct pci_vtscsi_softc * sc __unused,int fd,struct pci_vtscsi_ctrl_tmf * tmf)220*5f016a21SHans Rosenfeld vtscsi_uscsi_tmf_hdl(struct pci_vtscsi_softc *sc __unused, int fd,
221*5f016a21SHans Rosenfeld struct pci_vtscsi_ctrl_tmf *tmf)
222*5f016a21SHans Rosenfeld {
223*5f016a21SHans Rosenfeld struct uscsi_cmd cmd;
224*5f016a21SHans Rosenfeld int err;
225*5f016a21SHans Rosenfeld
226*5f016a21SHans Rosenfeld /* We currently support only LUN 0. */
227*5f016a21SHans Rosenfeld if (pci_vtscsi_get_lun(sc, tmf->lun) != 0) {
228*5f016a21SHans Rosenfeld tmf->response = VIRTIO_SCSI_S_BAD_TARGET;
229*5f016a21SHans Rosenfeld return;
230*5f016a21SHans Rosenfeld }
231*5f016a21SHans Rosenfeld
232*5f016a21SHans Rosenfeld tmf->response = VIRTIO_SCSI_S_FUNCTION_COMPLETE;
233*5f016a21SHans Rosenfeld
234*5f016a21SHans Rosenfeld memset(&cmd, 0, sizeof (cmd));
235*5f016a21SHans Rosenfeld cmd.uscsi_status = -1;
236*5f016a21SHans Rosenfeld cmd.uscsi_flags = USCSI_DIAGNOSE | USCSI_SILENT;
237*5f016a21SHans Rosenfeld
238*5f016a21SHans Rosenfeld
239*5f016a21SHans Rosenfeld /* The only TMF requests that we can handle here are RESETs. */
240*5f016a21SHans Rosenfeld switch (tmf->subtype) {
241*5f016a21SHans Rosenfeld case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
242*5f016a21SHans Rosenfeld cmd.uscsi_flags |= USCSI_RESET_TARGET;
243*5f016a21SHans Rosenfeld break;
244*5f016a21SHans Rosenfeld
245*5f016a21SHans Rosenfeld case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
246*5f016a21SHans Rosenfeld cmd.uscsi_flags |= USCSI_RESET_LUN;
247*5f016a21SHans Rosenfeld break;
248*5f016a21SHans Rosenfeld
249*5f016a21SHans Rosenfeld default:
250*5f016a21SHans Rosenfeld /*
251*5f016a21SHans Rosenfeld * For all other TMF requests, return FUNCTION COMPLETE as
252*5f016a21SHans Rosenfeld * there is nothing we can or need to do for them.
253*5f016a21SHans Rosenfeld *
254*5f016a21SHans Rosenfeld * See the comments in pci_vtscsi_tmf_handle() for additional
255*5f016a21SHans Rosenfeld * information on how the common code and the backend-specific
256*5f016a21SHans Rosenfeld * code interact for TMF requests.
257*5f016a21SHans Rosenfeld */
258*5f016a21SHans Rosenfeld tmf->response = VIRTIO_SCSI_S_FUNCTION_COMPLETE;
259*5f016a21SHans Rosenfeld return;
260*5f016a21SHans Rosenfeld }
261*5f016a21SHans Rosenfeld
262*5f016a21SHans Rosenfeld err = ioctl(fd, USCSICMD, &cmd);
263*5f016a21SHans Rosenfeld
264*5f016a21SHans Rosenfeld if (err != 0) {
265*5f016a21SHans Rosenfeld WPRINTF("USCSICMD: unexpected TMF error, errno=%d (%s)",
266*5f016a21SHans Rosenfeld strerrorname_np(errno), strerror(errno));
267*5f016a21SHans Rosenfeld tmf->response = VIRTIO_SCSI_S_FAILURE;
268*5f016a21SHans Rosenfeld }
269*5f016a21SHans Rosenfeld }
270*5f016a21SHans Rosenfeld
271*5f016a21SHans Rosenfeld static void
vtscsi_uscsi_an_hdl(struct pci_vtscsi_softc * sc __unused,int fd __unused,struct pci_vtscsi_ctrl_an * an)272*5f016a21SHans Rosenfeld vtscsi_uscsi_an_hdl(struct pci_vtscsi_softc *sc __unused, int fd __unused,
273*5f016a21SHans Rosenfeld struct pci_vtscsi_ctrl_an *an)
274*5f016a21SHans Rosenfeld {
275*5f016a21SHans Rosenfeld /* We currently support only LUN 0. */
276*5f016a21SHans Rosenfeld if (pci_vtscsi_get_lun(sc, an->lun) != 0) {
277*5f016a21SHans Rosenfeld an->response = VIRTIO_SCSI_S_BAD_TARGET;
278*5f016a21SHans Rosenfeld return;
279*5f016a21SHans Rosenfeld }
280*5f016a21SHans Rosenfeld
281*5f016a21SHans Rosenfeld an->response = VIRTIO_SCSI_S_FAILURE;
282*5f016a21SHans Rosenfeld }
283*5f016a21SHans Rosenfeld
284*5f016a21SHans Rosenfeld static int
vtscsi_uscsi_req_hdl(struct pci_vtscsi_softc * sc,int fd,struct pci_vtscsi_request * req)285*5f016a21SHans Rosenfeld vtscsi_uscsi_req_hdl(struct pci_vtscsi_softc *sc, int fd,
286*5f016a21SHans Rosenfeld struct pci_vtscsi_request *req)
287*5f016a21SHans Rosenfeld {
288*5f016a21SHans Rosenfeld struct vtscsi_uscsi_backend *uscsi =
289*5f016a21SHans Rosenfeld (struct vtscsi_uscsi_backend *)sc->vss_backend;
290*5f016a21SHans Rosenfeld struct uscsi_cmd *cmd = req->vsr_backend;
291*5f016a21SHans Rosenfeld void *ext_data = NULL;
292*5f016a21SHans Rosenfeld ssize_t ext_data_len = 0;
293*5f016a21SHans Rosenfeld int nxferred = 0;
294*5f016a21SHans Rosenfeld
295*5f016a21SHans Rosenfeld /* We currently support only LUN 0. */
296*5f016a21SHans Rosenfeld if (pci_vtscsi_get_lun(sc, req->vsr_cmd_rd->lun) != 0) {
297*5f016a21SHans Rosenfeld req->vsr_cmd_wr->response = VIRTIO_SCSI_S_BAD_TARGET;
298*5f016a21SHans Rosenfeld return (0);
299*5f016a21SHans Rosenfeld }
300*5f016a21SHans Rosenfeld
301*5f016a21SHans Rosenfeld if (req->vsr_data_niov_in > 0) {
302*5f016a21SHans Rosenfeld ext_data_len = iov_to_buf(req->vsr_data_iov_in,
303*5f016a21SHans Rosenfeld req->vsr_data_niov_in, &ext_data);
304*5f016a21SHans Rosenfeld cmd->uscsi_flags |= USCSI_WRITE;
305*5f016a21SHans Rosenfeld } else if (req->vsr_data_niov_out > 0) {
306*5f016a21SHans Rosenfeld ext_data_len = count_iov(req->vsr_data_iov_out,
307*5f016a21SHans Rosenfeld req->vsr_data_niov_out);
308*5f016a21SHans Rosenfeld ext_data = malloc(ext_data_len);
309*5f016a21SHans Rosenfeld cmd->uscsi_flags |= USCSI_READ;
310*5f016a21SHans Rosenfeld }
311*5f016a21SHans Rosenfeld
312*5f016a21SHans Rosenfeld /* Stop here if we failed to allocate ext_data. */
313*5f016a21SHans Rosenfeld if (ext_data == NULL && ext_data_len != 0) {
314*5f016a21SHans Rosenfeld WPRINTF("failed to allocate buffer for ext_data");
315*5f016a21SHans Rosenfeld req->vsr_cmd_wr->response = VIRTIO_SCSI_S_FAILURE;
316*5f016a21SHans Rosenfeld return (0);
317*5f016a21SHans Rosenfeld }
318*5f016a21SHans Rosenfeld
319*5f016a21SHans Rosenfeld cmd->uscsi_buflen = ext_data_len;
320*5f016a21SHans Rosenfeld cmd->uscsi_bufaddr = ext_data;
321*5f016a21SHans Rosenfeld
322*5f016a21SHans Rosenfeld cmd->uscsi_cdb = (caddr_t)req->vsr_cmd_rd->cdb;
323*5f016a21SHans Rosenfeld cmd->uscsi_cdblen = libscsi_cmd_cdblen(uscsi->vub_scsi_hdl,
324*5f016a21SHans Rosenfeld req->vsr_cmd_rd->cdb[0]);
325*5f016a21SHans Rosenfeld
326*5f016a21SHans Rosenfeld cmd->uscsi_status = -1;
327*5f016a21SHans Rosenfeld
328*5f016a21SHans Rosenfeld /*
329*5f016a21SHans Rosenfeld * We set an unreasonably large timeout here. The virtio spec doesn't
330*5f016a21SHans Rosenfeld * provide a way for the guest driver to pass a I/O timeout value to
331*5f016a21SHans Rosenfeld * the device, but if our timeout here is larger than any timeout the
332*5f016a21SHans Rosenfeld * guest uses, we can expect them to abort the command before we would.
333*5f016a21SHans Rosenfeld *
334*5f016a21SHans Rosenfeld * INT16_MAX corresponds to a bit over 9 hours, which should be enough.
335*5f016a21SHans Rosenfeld */
336*5f016a21SHans Rosenfeld cmd->uscsi_timeout = INT16_MAX;
337*5f016a21SHans Rosenfeld cmd->uscsi_flags |= USCSI_DIAGNOSE;
338*5f016a21SHans Rosenfeld cmd->uscsi_rqlen = sc->vss_config.sense_size;
339*5f016a21SHans Rosenfeld cmd->uscsi_rqbuf = (caddr_t)req->vsr_cmd_wr->sense;
340*5f016a21SHans Rosenfeld cmd->uscsi_flags |= USCSI_RQENABLE;
341*5f016a21SHans Rosenfeld
342*5f016a21SHans Rosenfeld switch (req->vsr_cmd_rd->task_attr) {
343*5f016a21SHans Rosenfeld case VIRTIO_SCSI_S_ORDERED:
344*5f016a21SHans Rosenfeld cmd->uscsi_flags |= USCSI_OTAG;
345*5f016a21SHans Rosenfeld break;
346*5f016a21SHans Rosenfeld case VIRTIO_SCSI_S_HEAD:
347*5f016a21SHans Rosenfeld cmd->uscsi_flags |= USCSI_HEAD|USCSI_HTAG;
348*5f016a21SHans Rosenfeld break;
349*5f016a21SHans Rosenfeld case VIRTIO_SCSI_S_SIMPLE:
350*5f016a21SHans Rosenfeld break;
351*5f016a21SHans Rosenfeld
352*5f016a21SHans Rosenfeld case VIRTIO_SCSI_S_ACA:
353*5f016a21SHans Rosenfeld /*
354*5f016a21SHans Rosenfeld * I haven't found any indication in our code that would
355*5f016a21SHans Rosenfeld * suggest that we support ACA in any way in illumos. In
356*5f016a21SHans Rosenfeld * fact, scsi_transport() asserts that NACA isn't set in
357*5f016a21SHans Rosenfeld * a packet, and scsi_uscsi_pktinit() warns about it and
358*5f016a21SHans Rosenfeld * clears the flag if found set. There's a tunable to
359*5f016a21SHans Rosenfeld * override that behaviour (scsi_pkt_allow_naca), but there
360*5f016a21SHans Rosenfeld * really seems to be no code properly handling ACA or
361*5f016a21SHans Rosenfeld * setting the ACA flag.
362*5f016a21SHans Rosenfeld *
363*5f016a21SHans Rosenfeld * I guess this makes sense since we're doing ARQ anyway,
364*5f016a21SHans Rosenfeld * so let's just pretend no target is ever in ACA state
365*5f016a21SHans Rosenfeld * and thus no packet will ever require this.
366*5f016a21SHans Rosenfeld */
367*5f016a21SHans Rosenfeld default:
368*5f016a21SHans Rosenfeld WPRINTF("USCSICMD: unexpected task attr in request: 0x%x",
369*5f016a21SHans Rosenfeld req->vsr_cmd_rd->task_attr);
370*5f016a21SHans Rosenfeld req->vsr_cmd_wr->response = VIRTIO_SCSI_S_FAILURE;
371*5f016a21SHans Rosenfeld return (0);
372*5f016a21SHans Rosenfeld }
373*5f016a21SHans Rosenfeld
374*5f016a21SHans Rosenfeld errno = 0;
375*5f016a21SHans Rosenfeld (void) ioctl(fd, USCSICMD, cmd);
376*5f016a21SHans Rosenfeld
377*5f016a21SHans Rosenfeld switch (errno) {
378*5f016a21SHans Rosenfeld case EIO:
379*5f016a21SHans Rosenfeld /*
380*5f016a21SHans Rosenfeld * EIO may indicate that a SCSI error occured. If that's the
381*5f016a21SHans Rosenfeld * case, uscsi_status should have been set to a valid value,
382*5f016a21SHans Rosenfeld * and we want to continue to process the request normally.
383*5f016a21SHans Rosenfeld */
384*5f016a21SHans Rosenfeld if (cmd->uscsi_status == -1) {
385*5f016a21SHans Rosenfeld req->vsr_cmd_wr->response = VIRTIO_SCSI_S_FAILURE;
386*5f016a21SHans Rosenfeld break;
387*5f016a21SHans Rosenfeld }
388*5f016a21SHans Rosenfeld
389*5f016a21SHans Rosenfeld /*FALLTHRU*/
390*5f016a21SHans Rosenfeld case 0:
391*5f016a21SHans Rosenfeld /*
392*5f016a21SHans Rosenfeld * If the command completed successfully, apply any necessary
393*5f016a21SHans Rosenfeld * post-completion filtering.
394*5f016a21SHans Rosenfeld */
395*5f016a21SHans Rosenfeld if (cmd->uscsi_status == STATUS_GOOD)
396*5f016a21SHans Rosenfeld vtscsi_uscsi_filter_post(cmd);
397*5f016a21SHans Rosenfeld
398*5f016a21SHans Rosenfeld req->vsr_cmd_wr->sense_len =
399*5f016a21SHans Rosenfeld sc->vss_config.sense_size - cmd->uscsi_rqresid;
400*5f016a21SHans Rosenfeld req->vsr_cmd_wr->residual = cmd->uscsi_resid;
401*5f016a21SHans Rosenfeld req->vsr_cmd_wr->status = cmd->uscsi_status;
402*5f016a21SHans Rosenfeld req->vsr_cmd_wr->response = VIRTIO_SCSI_S_OK;
403*5f016a21SHans Rosenfeld
404*5f016a21SHans Rosenfeld nxferred = ext_data_len - req->vsr_cmd_wr->residual;
405*5f016a21SHans Rosenfeld
406*5f016a21SHans Rosenfeld if (req->vsr_data_niov_out > 0) {
407*5f016a21SHans Rosenfeld (void) buf_to_iov(ext_data, nxferred,
408*5f016a21SHans Rosenfeld req->vsr_data_iov_out, req->vsr_data_niov_out);
409*5f016a21SHans Rosenfeld }
410*5f016a21SHans Rosenfeld break;
411*5f016a21SHans Rosenfeld
412*5f016a21SHans Rosenfeld case EAGAIN:
413*5f016a21SHans Rosenfeld /*
414*5f016a21SHans Rosenfeld * Despite not being documented in uscsi(4I), sd(4D) returns
415*5f016a21SHans Rosenfeld * this when the device is busy formatting.
416*5f016a21SHans Rosenfeld */
417*5f016a21SHans Rosenfeld req->vsr_cmd_wr->response = VIRTIO_SCSI_S_BUSY;
418*5f016a21SHans Rosenfeld break;
419*5f016a21SHans Rosenfeld
420*5f016a21SHans Rosenfeld case EINVAL:
421*5f016a21SHans Rosenfeld /*
422*5f016a21SHans Rosenfeld * This may happen if packet allocation fails, which in turn
423*5f016a21SHans Rosenfeld * may happen if we didn't honor USCSIMAXXFER.
424*5f016a21SHans Rosenfeld */
425*5f016a21SHans Rosenfeld req->vsr_cmd_wr->response = VIRTIO_SCSI_S_OVERRUN;
426*5f016a21SHans Rosenfeld break;
427*5f016a21SHans Rosenfeld
428*5f016a21SHans Rosenfeld case EFAULT:
429*5f016a21SHans Rosenfeld /*
430*5f016a21SHans Rosenfeld * EFAULT should never happen as we never send bogus memory
431*5f016a21SHans Rosenfeld * addresses in our USCSI commands.
432*5f016a21SHans Rosenfeld */
433*5f016a21SHans Rosenfeld
434*5f016a21SHans Rosenfeld case EPERM:
435*5f016a21SHans Rosenfeld /*
436*5f016a21SHans Rosenfeld * EPERM should never happen as we have the SYS_DEVICES
437*5f016a21SHans Rosenfeld * privilege.
438*5f016a21SHans Rosenfeld */
439*5f016a21SHans Rosenfeld
440*5f016a21SHans Rosenfeld default:
441*5f016a21SHans Rosenfeld WPRINTF("USCSICMD: unexpected I/O error: errno=%d (%s)",
442*5f016a21SHans Rosenfeld strerrorname_np(errno), strerror(errno));
443*5f016a21SHans Rosenfeld abort();
444*5f016a21SHans Rosenfeld }
445*5f016a21SHans Rosenfeld
446*5f016a21SHans Rosenfeld free(ext_data);
447*5f016a21SHans Rosenfeld
448*5f016a21SHans Rosenfeld return (nxferred);
449*5f016a21SHans Rosenfeld }
450*5f016a21SHans Rosenfeld
451*5f016a21SHans Rosenfeld /*
452*5f016a21SHans Rosenfeld * Return a CHECK CONDITION and fill in the sense data with the given sense key,
453*5f016a21SHans Rosenfeld * additional sense code, and additional sense qualifier.
454*5f016a21SHans Rosenfeld */
455*5f016a21SHans Rosenfeld static void
vtscsi_uscsi_make_check_condition(struct uscsi_cmd * cmd,char key,char asc,char qual)456*5f016a21SHans Rosenfeld vtscsi_uscsi_make_check_condition(struct uscsi_cmd *cmd, char key, char asc,
457*5f016a21SHans Rosenfeld char qual)
458*5f016a21SHans Rosenfeld {
459*5f016a21SHans Rosenfeld cmd->uscsi_status = STATUS_CHECK;
460*5f016a21SHans Rosenfeld cmd->uscsi_resid = cmd->uscsi_buflen;
461*5f016a21SHans Rosenfeld cmd->uscsi_rqstatus = STATUS_GOOD;
462*5f016a21SHans Rosenfeld
463*5f016a21SHans Rosenfeld bzero(cmd->uscsi_rqbuf, cmd->uscsi_rqlen);
464*5f016a21SHans Rosenfeld
465*5f016a21SHans Rosenfeld if (cmd->uscsi_rqlen >= 1)
466*5f016a21SHans Rosenfeld cmd->uscsi_rqbuf[0] = 0x70;
467*5f016a21SHans Rosenfeld if (cmd->uscsi_rqlen >= 3)
468*5f016a21SHans Rosenfeld cmd->uscsi_rqbuf[2] = key;
469*5f016a21SHans Rosenfeld if (cmd->uscsi_rqlen >= 8)
470*5f016a21SHans Rosenfeld cmd->uscsi_rqbuf[7] = cmd->uscsi_rqlen - 8;
471*5f016a21SHans Rosenfeld if (cmd->uscsi_rqlen >= 13)
472*5f016a21SHans Rosenfeld cmd->uscsi_rqbuf[12] = asc;
473*5f016a21SHans Rosenfeld if (cmd->uscsi_rqlen >= 14)
474*5f016a21SHans Rosenfeld cmd->uscsi_rqbuf[13] = qual;
475*5f016a21SHans Rosenfeld }
476*5f016a21SHans Rosenfeld
477*5f016a21SHans Rosenfeld /*
478*5f016a21SHans Rosenfeld * We currently only support LUN 0. Make sure we never report anything else.
479*5f016a21SHans Rosenfeld *
480*5f016a21SHans Rosenfeld * We make no assumption about the buffer size. If it's large enough to hold the
481*5f016a21SHans Rosenfeld * LUN list length, we'll set the LUN list length to 8. The resid is adjusted if
482*5f016a21SHans Rosenfeld * the buffer size is larger than 16 bytes, which is the length needed to hold
483*5f016a21SHans Rosenfeld * one LUN address.
484*5f016a21SHans Rosenfeld */
485*5f016a21SHans Rosenfeld static void
vtscsi_uscsi_filter_post_report_luns(struct uscsi_cmd * cmd)486*5f016a21SHans Rosenfeld vtscsi_uscsi_filter_post_report_luns(struct uscsi_cmd *cmd)
487*5f016a21SHans Rosenfeld {
488*5f016a21SHans Rosenfeld uint8_t report = (uint8_t)cmd->uscsi_cdb[2];
489*5f016a21SHans Rosenfeld
490*5f016a21SHans Rosenfeld bzero(cmd->uscsi_bufaddr, cmd->uscsi_buflen);
491*5f016a21SHans Rosenfeld
492*5f016a21SHans Rosenfeld switch (report) {
493*5f016a21SHans Rosenfeld case 0:
494*5f016a21SHans Rosenfeld case 2:
495*5f016a21SHans Rosenfeld /*
496*5f016a21SHans Rosenfeld * We'll overwrite the output from the device to report just one
497*5f016a21SHans Rosenfeld * LUN with an all-zero address:
498*5f016a21SHans Rosenfeld * - LUN list length is 8
499*5f016a21SHans Rosenfeld * - LUN 1 address is 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
500*5f016a21SHans Rosenfeld */
501*5f016a21SHans Rosenfeld if (cmd->uscsi_buflen >= 4)
502*5f016a21SHans Rosenfeld cmd->uscsi_bufaddr[3] = 8;
503*5f016a21SHans Rosenfeld if (cmd->uscsi_buflen >= 16)
504*5f016a21SHans Rosenfeld cmd->uscsi_resid = cmd->uscsi_buflen - 16;
505*5f016a21SHans Rosenfeld break;
506*5f016a21SHans Rosenfeld case 1:
507*5f016a21SHans Rosenfeld /*
508*5f016a21SHans Rosenfeld * We don't report any Well-Known LUNs either, because we have
509*5f016a21SHans Rosenfeld * no way to address them anyway using USCSICMD.
510*5f016a21SHans Rosenfeld */
511*5f016a21SHans Rosenfeld cmd->uscsi_resid = cmd->uscsi_buflen;
512*5f016a21SHans Rosenfeld break;
513*5f016a21SHans Rosenfeld default:
514*5f016a21SHans Rosenfeld /*
515*5f016a21SHans Rosenfeld * All other values for "select report" are either invalid or
516*5f016a21SHans Rosenfeld * vendor-specific and thus unsupported. Return the command with
517*5f016a21SHans Rosenfeld * CHECK CONDITION, and fill in sense data to report a ILLEGAL
518*5f016a21SHans Rosenfeld * REQUEST with INVALID FIELD IN CDB.
519*5f016a21SHans Rosenfeld */
520*5f016a21SHans Rosenfeld vtscsi_uscsi_make_check_condition(cmd, KEY_ILLEGAL_REQUEST,
521*5f016a21SHans Rosenfeld 0x24, 0x00);
522*5f016a21SHans Rosenfeld }
523*5f016a21SHans Rosenfeld }
524*5f016a21SHans Rosenfeld
525*5f016a21SHans Rosenfeld static void
vtscsi_uscsi_filter_post(struct uscsi_cmd * cmd)526*5f016a21SHans Rosenfeld vtscsi_uscsi_filter_post(struct uscsi_cmd *cmd)
527*5f016a21SHans Rosenfeld {
528*5f016a21SHans Rosenfeld switch ((uint8_t)cmd->uscsi_cdb[0]) {
529*5f016a21SHans Rosenfeld case SCMD_REPORT_LUNS:
530*5f016a21SHans Rosenfeld vtscsi_uscsi_filter_post_report_luns(cmd);
531*5f016a21SHans Rosenfeld break;
532*5f016a21SHans Rosenfeld
533*5f016a21SHans Rosenfeld default:
534*5f016a21SHans Rosenfeld break;
535*5f016a21SHans Rosenfeld }
536*5f016a21SHans Rosenfeld }
537*5f016a21SHans Rosenfeld
538*5f016a21SHans Rosenfeld static const struct pci_vtscsi_backend vtscsi_uscsi_backend = {
539*5f016a21SHans Rosenfeld .vsb_name = "uscsi",
540*5f016a21SHans Rosenfeld .vsb_init = vtscsi_uscsi_init,
541*5f016a21SHans Rosenfeld .vsb_open = vtscsi_uscsi_open,
542*5f016a21SHans Rosenfeld .vsb_reset = vtscsi_uscsi_reset,
543*5f016a21SHans Rosenfeld
544*5f016a21SHans Rosenfeld .vsb_req_alloc = vtscsi_uscsi_req_alloc,
545*5f016a21SHans Rosenfeld .vsb_req_clear = vtscsi_uscsi_req_clear,
546*5f016a21SHans Rosenfeld .vsb_req_free = vtscsi_uscsi_req_free,
547*5f016a21SHans Rosenfeld
548*5f016a21SHans Rosenfeld .vsb_tmf_hdl = vtscsi_uscsi_tmf_hdl,
549*5f016a21SHans Rosenfeld .vsb_an_hdl = vtscsi_uscsi_an_hdl,
550*5f016a21SHans Rosenfeld .vsb_req_hdl = vtscsi_uscsi_req_hdl
551*5f016a21SHans Rosenfeld };
552*5f016a21SHans Rosenfeld PCI_VTSCSI_BACKEND_SET(vtscsi_uscsi_backend);
553