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