xref: /illumos-gate/usr/src/cmd/bhyve/common/pci_virtio_scsi_uscsi.c (revision 5f016a21b06f5c6d125fdb35da2350c7d582f5ad)
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