1 /* $NetBSD: vatapi.c,v 1.2 2018/06/13 19:59:14 reinoud 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.2 2018/06/13 19:59:14 reinoud 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 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 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 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 = config_found_ia(sc->sc_dev, "atapi", chan, 179 atapiprint); 180 } 181 182 183 /* XXX why is it be called minphys, when it enforces maxphys? */ 184 static void 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 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 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 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 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 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