xref: /netbsd/sys/arch/usermode/dev/vatapi.c (revision beecddb6)
1 /* $NetBSD: vatapi.c,v 1.4 2021/08/07 16:19:07 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 2018 Reinoud Zandijk <reinoud@NetBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: vatapi.c,v 1.4 2021/08/07 16:19:07 thorpej Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/proc.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/buf.h>
37 #include <sys/disk.h>
38 #include <sys/kmem.h>
39 #include <sys/malloc.h>
40 #include <sys/scsiio.h>
41 
42 #include <machine/mainbus.h>
43 #include <machine/thunk.h>
44 #include <machine/intr.h>
45 
46 #include <dev/scsipi/scsi_all.h>	/* for SCSI status */
47 #include <dev/scsipi/scsipi_all.h>
48 #include <dev/scsipi/scsipiconf.h>
49 #include <dev/scsipi/atapiconf.h>
50 
51 #include "opt_scsi.h"
52 
53 /* parameter? */
54 #define VDEV_ATAPI_DRIVE	0
55 #define MAX_SIZE		((1<<16))
56 
57 /* forwards */
58 struct vatapi_softc;
59 
60 static int	vatapi_match(device_t, cfdata_t, void *);
61 static void	vatapi_attach(device_t, device_t, void *);
62 static void	vatapi_callback(device_t self);
63 
64 static void	vatapi_minphys(struct buf *bp);
65 static void	vatapi_kill_pending(struct scsipi_periph *periph);
66 static void	vatapi_scsipi_request(struct scsipi_channel *chan,
67 	scsipi_adapter_req_t req, void *arg);
68 static void	vatapi_probe_device(struct atapibus_softc *, int);
69 
70 static void	vatapi_complete(void *arg);
71 
72 /* for debugging */
73 #ifdef SCSIVERBOSE
74 void	scsipi_print_sense_data_real(struct scsi_sense_data *sense, int verbosity);
75 #endif
76 
77 
78 /* Note its one vdev, one adapter, one channel for now */
79 struct vatapi_softc {
80 	device_t	sc_dev;
81 	device_t	sc_pdev;
82 
83 	int		sc_flags;
84 #define VATAPI_FLAG_POLLING	1
85 #define VATAPI_FLAG_INTR	2
86 	/* backing `device' with its active command */
87 	int		sc_fd;
88 	void		*sc_ih;
89 	struct scsipi_xfer *sc_xs;
90 
91 	/* atapibus */
92 	device_t	sc_vatapibus;
93 	struct atapi_adapter    sc_atapi_adapter;
94 #define sc_adapter sc_atapi_adapter._generic
95 	struct scsipi_channel sc_channel;
96 };
97 
98 CFATTACH_DECL_NEW(vatapi_thunkbus, sizeof(struct vatapi_softc),
99     vatapi_match, vatapi_attach, NULL, NULL);
100 
101 
102 static const struct scsipi_bustype vatapi_bustype = {
103 	SCSIPI_BUSTYPE_ATAPI,
104 	atapi_scsipi_cmd,
105 	atapi_interpret_sense,
106 	atapi_print_addr,
107 	vatapi_kill_pending,
108 	NULL
109 };
110 
111 int
vatapi_match(device_t parent,cfdata_t match,void * opaque)112 vatapi_match(device_t parent, cfdata_t match, void *opaque)
113 {
114 	struct thunkbus_attach_args *taa = opaque;
115 
116 	if (taa->taa_type != THUNKBUS_TYPE_VATAPI)
117 		return 0;
118 
119 	return 1;
120 }
121 
122 static void
vatapi_attach(device_t parent,device_t self,void * opaque)123 vatapi_attach(device_t parent, device_t self, void *opaque)
124 {
125 	struct vatapi_softc *sc = device_private(self);
126 	struct thunkbus_attach_args *taa = opaque;
127 
128 	sc->sc_dev = self;
129 	sc->sc_pdev = parent;
130 
131 	/* open device */
132 	sc->sc_fd = thunk_open(taa->u.vdev.path, O_RDWR, 0);
133 	if (sc->sc_fd < 0) {
134 		aprint_error(": error %d opening path\n", thunk_geterrno());
135 		return;
136 	}
137 
138 	aprint_naive("\n");
139 	aprint_normal("\n");
140 
141 	sc->sc_ih = softint_establish(SOFTINT_BIO,
142 		vatapi_complete, sc);
143 
144 	/* rest of the configuration is deferred */
145 	config_interrupts(self, vatapi_callback);
146 }
147 
148 static void
vatapi_callback(device_t self)149 vatapi_callback(device_t self)
150 {
151 	struct vatapi_softc *sc = device_private(self);
152 	struct scsipi_adapter *adapt = &sc->sc_adapter;
153 	struct scsipi_channel *chan  = &sc->sc_channel;
154 
155 	/* set up the scsipi adapter and channel */
156 	memset(adapt, 0, sizeof(*adapt));
157 	adapt->adapt_dev = sc->sc_dev;
158 	adapt->adapt_nchannels = 1;
159 	adapt->adapt_request   = vatapi_scsipi_request;
160 	adapt->adapt_minphys   = vatapi_minphys;
161 	adapt->adapt_flags     = 0; //SCSIPI_ADAPT_POLL_ONLY;
162 	sc->sc_atapi_adapter.atapi_probe_device = vatapi_probe_device;
163 
164 	memset(chan,  0, sizeof(*chan));
165 	chan->chan_adapter    = adapt;
166 	chan->chan_bustype    = &vatapi_bustype;
167 	chan->chan_channel    = 0;	/* location */
168 	chan->chan_flags      = SCSIPI_CHAN_OPENINGS;
169 	chan->chan_openings   = 1;
170 	chan->chan_max_periph = 1;
171 	chan->chan_ntargets   = 1;
172 	chan->chan_nluns      = 1;
173 
174 	/* set polling */
175 	//sc->sc_flags = VATAPI_FLAG_POLLING;
176 
177 	/* we `discovered' an atapi adapter */
178 	sc->sc_vatapibus =
179 	    config_found(sc->sc_dev, chan, atapiprint, CFARGS_NONE);
180 }
181 
182 
183 /* XXX why is it be called minphys, when it enforces maxphys? */
184 static void
vatapi_minphys(struct buf * bp)185 vatapi_minphys(struct buf *bp)
186 {
187 	if (bp->b_bcount > MAX_SIZE)
188 		bp->b_bcount = MAX_SIZE;
189 	minphys(bp);
190 }
191 
192 /*
193  * ATAPI device probing
194  */
195 static void
vatapi_probe_device(struct atapibus_softc * atapi,int target)196 vatapi_probe_device(struct atapibus_softc *atapi, int target)
197 {
198 	struct scsipi_channel *chan = atapi->sc_channel;
199 	struct scsipi_periph *periph;
200 	struct scsipibus_attach_args sa;
201 	char vendor[33], product[65], revision[17];
202 	struct scsipi_inquiry_data inqbuf;
203 
204 	if (target != VDEV_ATAPI_DRIVE)	/* only probe drive 0 */
205 		return;
206 
207 	/* skip if already attached */
208 	if (scsipi_lookup_periph(chan, target, 0) != NULL)
209 		return;
210 
211 	/* allocate and set up periph structure */
212 	periph = scsipi_alloc_periph(M_NOWAIT);
213 	if (periph == NULL) {
214 		aprint_error_dev(atapi->sc_dev,
215 		    "can't allocate link for drive %d\n", target);
216 		return;
217 	}
218 	periph->periph_channel = chan;
219 	periph->periph_switch = &atapi_probe_periphsw;
220 	periph->periph_target = target;
221 	periph->periph_quirks = chan->chan_defquirks;
222 
223 	/* inquiry */
224 	aprint_verbose("%s: inquiry devices\n", __func__);
225 	memset(&inqbuf, 0, sizeof(inqbuf));
226 	if (scsipi_inquire(periph, &inqbuf, XS_CTL_DISCOVERY) != 0) {
227 		aprint_error_dev(atapi->sc_dev, ": scsipi_inquire failed\n");
228 		free(periph, M_DEVBUF);
229 		return;
230 	}
231 
232 #define scsipi_strvis(a, al, b, bl) strlcpy(a, b, al)
233 	scsipi_strvis(vendor, 33, inqbuf.vendor, 8);
234 	scsipi_strvis(product, 65, inqbuf.product, 16);
235 	scsipi_strvis(revision, 17, inqbuf.revision, 4);
236 #undef scsipi_strvis
237 
238 	sa.sa_periph = periph;
239 	sa.sa_inqbuf.type = inqbuf.device;
240 	sa.sa_inqbuf.removable = inqbuf.dev_qual2 & SID_REMOVABLE ?
241 	    T_REMOV : T_FIXED;
242 	if (sa.sa_inqbuf.removable)
243 		periph->periph_flags |= PERIPH_REMOVABLE;
244 	sa.sa_inqbuf.vendor = vendor;
245 	sa.sa_inqbuf.product = product;
246 	sa.sa_inqbuf.revision = revision;
247 	sa.sa_inqptr = NULL;
248 
249 	/* ATAPI demands only READ10 and higher IIRC */
250 	periph->periph_quirks |= PQUIRK_ONLYBIG;
251 
252 	aprint_verbose(": probedev on vendor '%s' product '%s' revision '%s'\n",
253 		vendor, product, revision);
254 
255 	atapi_probe_device(atapi, target, periph, &sa);
256 	/* atapi_probe_device() frees the periph when there is no device.*/
257 }
258 
259 /*
260  * Issue a request for a periph.
261  */
262 static void
vatapi_scsipi_request(struct scsipi_channel * chan,scsipi_adapter_req_t req,void * arg)263 vatapi_scsipi_request(struct scsipi_channel *chan,
264 	scsipi_adapter_req_t req, void *arg)
265 {
266 	device_t sc_dev = chan->chan_adapter->adapt_dev;
267 	struct vatapi_softc *sc = device_private(sc_dev);
268  	struct scsipi_xfer *xs = arg;
269 
270 	switch (req) {
271  	case ADAPTER_REQ_GROW_RESOURCES:
272  	case ADAPTER_REQ_SET_XFER_MODE:
273 		return;
274 	case ADAPTER_REQ_RUN_XFER :
275 		KASSERT(sc->sc_xs == NULL);
276 
277 		/* queue the command */
278 		KASSERT(sc->sc_xs == NULL);
279 		sc->sc_xs = xs;
280 		softint_schedule(sc->sc_ih);
281 	}
282 }
283 
284 
285 static void
vatapi_report_problem(scsireq_t * kreq)286 vatapi_report_problem(scsireq_t *kreq)
287 {
288 #ifdef SCSIVERBOSE
289 	printf("vatapi cmd failed: ");
290 	for (int i = 0; i < kreq->cmdlen; i++) {
291 		printf("%02x ", kreq->cmd[i]);
292 	}
293 	printf("\n");
294 	scsipi_print_sense_data_real(
295 		(struct scsi_sense_data *) kreq->sense, 1);
296 #endif
297 }
298 
299 
300 static void
vatapi_complete(void * arg)301 vatapi_complete(void *arg)
302 {
303 	struct vatapi_softc *sc = arg;
304  	struct scsipi_xfer *xs = sc->sc_xs;
305 	scsireq_t kreq;
306 
307 	memset(&kreq, 0, sizeof(kreq));
308 	memcpy(kreq.cmd, xs->cmd, xs->cmdlen);
309 	kreq.cmdlen = xs->cmdlen;
310 	kreq.databuf = xs->data;		/* in virt? */
311 	kreq.datalen = xs->datalen;
312 	kreq.timeout = xs->timeout;
313 
314 	kreq.flags = (xs->xs_control & XS_CTL_DATA_IN) ?
315 		SCCMD_READ : SCCMD_WRITE;
316 
317 	kreq.senselen = sizeof(struct scsi_sense_data);
318 
319 	xs->error = XS_SHORTSENSE;
320 	/* this is silly, but better make sure */
321 	thunk_assert_presence((vaddr_t) kreq.databuf,
322 		(size_t) kreq.datalen);
323 
324 	if (thunk_ioctl(sc->sc_fd, SCIOCCOMMAND, &kreq) != -1) {
325 		switch (kreq.retsts) {
326 		case SCCMD_OK :
327 			xs->resid = 0;
328 			xs->error = 0;
329 			break;
330 		case SCCMD_TIMEOUT :
331 			break;
332 		case SCCMD_BUSY :
333 			break;
334 		case SCCMD_SENSE :
335 			xs->error = XS_SHORTSENSE;	/* ATAPI */
336 			memcpy(&xs->sense.scsi_sense, kreq.sense,
337 				sizeof(struct scsi_sense_data));
338 			vatapi_report_problem(&kreq);
339 			break;
340 		default:
341 			thunk_printf("unhandled/unknown retstst %d\n", kreq.retsts);
342 			break;
343 		}
344 	} else {
345 		printf("thunk_ioctl == -1, errno %d\n", thunk_geterrno());
346 	}
347 	sc->sc_xs = NULL;
348 	scsipi_done(xs);
349 }
350 
351 
352 /*
353  * Kill off all pending xfers for a periph.
354  *
355  * Must be called at splbio().
356  */
357 static void
vatapi_kill_pending(struct scsipi_periph * periph)358 vatapi_kill_pending(struct scsipi_periph *periph)
359 {
360 	/* do we need to do anything ? (yet?) */
361 	printf("%s: target %d\n", __func__, periph->periph_target);
362 }
363 
364