1 /* $NetBSD: umass_scsipi.c,v 1.36 2010/11/03 22:34:24 dyoung Exp $ */ 2 3 /* 4 * Copyright (c) 2001, 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (lennart@augustsson.net) at 9 * Carlstedt Research & Technology and by Charles M. Hamnnum. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: umass_scsipi.c,v 1.36 2010/11/03 22:34:24 dyoung Exp $"); 35 36 #include "atapibus.h" 37 #include "scsibus.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/conf.h> 43 #include <sys/buf.h> 44 #include <sys/bufq.h> 45 #include <sys/device.h> 46 #include <sys/ioctl.h> 47 #include <sys/malloc.h> 48 49 /* SCSI & ATAPI */ 50 #include <sys/scsiio.h> 51 #include <dev/scsipi/scsi_spc.h> 52 #include <dev/scsipi/scsi_all.h> 53 #include <dev/scsipi/scsipi_all.h> 54 #include <dev/scsipi/scsiconf.h> 55 56 #include <dev/scsipi/atapiconf.h> 57 58 #include <dev/scsipi/scsipi_disk.h> 59 #include <dev/scsipi/scsi_disk.h> 60 #include <dev/scsipi/scsi_changer.h> 61 62 #include <sys/disk.h> /* XXX */ 63 #include <dev/scsipi/sdvar.h> /* XXX */ 64 65 /* USB */ 66 #include <dev/usb/usb.h> 67 #include <dev/usb/usbdi.h> 68 #include <dev/usb/usbdi_util.h> 69 #include <dev/usb/usbdevs.h> 70 71 #include <dev/usb/umassvar.h> 72 #include <dev/usb/umass_scsipi.h> 73 74 struct umass_scsipi_softc { 75 struct umassbus_softc base; 76 77 struct atapi_adapter sc_atapi_adapter; 78 #define sc_adapter sc_atapi_adapter._generic 79 struct scsipi_channel sc_channel; 80 usbd_status sc_sync_status; 81 struct scsi_request_sense sc_sense_cmd; 82 }; 83 84 85 #define SHORT_INQUIRY_LENGTH 36 /* XXX */ 86 87 #define UMASS_ATAPI_DRIVE 0 88 89 Static void umass_scsipi_request(struct scsipi_channel *, 90 scsipi_adapter_req_t, void *); 91 Static void umass_scsipi_minphys(struct buf *bp); 92 Static int umass_scsipi_ioctl(struct scsipi_channel *, u_long, 93 void *, int, proc_t *); 94 Static int umass_scsipi_getgeom(struct scsipi_periph *periph, 95 struct disk_parms *, u_long sectors); 96 97 Static void umass_scsipi_cb(struct umass_softc *sc, void *priv, 98 int residue, int status); 99 Static void umass_scsipi_sense_cb(struct umass_softc *sc, void *priv, 100 int residue, int status); 101 102 Static struct umass_scsipi_softc *umass_scsipi_setup(struct umass_softc *sc); 103 104 #if NATAPIBUS > 0 105 Static void umass_atapi_probe_device(struct atapibus_softc *, int); 106 107 const struct scsipi_bustype umass_atapi_bustype = { 108 SCSIPI_BUSTYPE_ATAPI, 109 atapi_scsipi_cmd, 110 atapi_interpret_sense, 111 atapi_print_addr, 112 scsi_kill_pending, 113 }; 114 #endif 115 116 117 #if NSCSIBUS > 0 118 int 119 umass_scsi_attach(struct umass_softc *sc) 120 { 121 struct umass_scsipi_softc *scbus; 122 123 scbus = umass_scsipi_setup(sc); 124 125 scbus->sc_channel.chan_bustype = &scsi_bustype; 126 scbus->sc_channel.chan_ntargets = 2; 127 scbus->sc_channel.chan_nluns = sc->maxlun + 1; 128 scbus->sc_channel.chan_id = scbus->sc_channel.chan_ntargets - 1; 129 DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: SCSI\n", 130 device_xname(sc->sc_dev))); 131 132 sc->sc_refcnt++; 133 scbus->base.sc_child = 134 config_found_ia(sc->sc_dev, "scsi", &scbus->sc_channel, 135 scsiprint); 136 if (--sc->sc_refcnt < 0) 137 usb_detach_wakeup(sc->sc_dev); 138 139 return (0); 140 } 141 #endif 142 143 #if NATAPIBUS > 0 144 int 145 umass_atapi_attach(struct umass_softc *sc) 146 { 147 struct umass_scsipi_softc *scbus; 148 149 scbus = umass_scsipi_setup(sc); 150 scbus->sc_atapi_adapter.atapi_probe_device = umass_atapi_probe_device; 151 152 scbus->sc_channel.chan_bustype = &umass_atapi_bustype; 153 scbus->sc_channel.chan_ntargets = 2; 154 scbus->sc_channel.chan_nluns = 1; 155 156 scbus->sc_channel.chan_defquirks |= sc->sc_busquirks; 157 DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: ATAPI\n", 158 device_xname(sc->sc_dev))); 159 160 sc->sc_refcnt++; 161 scbus->base.sc_child = 162 config_found_ia(sc->sc_dev, "atapi", &scbus->sc_channel, 163 atapiprint); 164 if (--sc->sc_refcnt < 0) 165 usb_detach_wakeup(sc->sc_dev); 166 167 return (0); 168 } 169 #endif 170 171 Static struct umass_scsipi_softc * 172 umass_scsipi_setup(struct umass_softc *sc) 173 { 174 struct umass_scsipi_softc *scbus; 175 176 scbus = malloc(sizeof *scbus, M_DEVBUF, M_WAITOK | M_ZERO); 177 sc->bus = &scbus->base; 178 179 /* Only use big commands for USB SCSI devices. */ 180 sc->sc_busquirks |= PQUIRK_ONLYBIG; 181 182 /* Fill in the adapter. */ 183 memset(&scbus->sc_adapter, 0, sizeof(scbus->sc_adapter)); 184 scbus->sc_adapter.adapt_dev = sc->sc_dev; 185 scbus->sc_adapter.adapt_nchannels = 1; 186 scbus->sc_adapter.adapt_request = umass_scsipi_request; 187 scbus->sc_adapter.adapt_minphys = umass_scsipi_minphys; 188 scbus->sc_adapter.adapt_ioctl = umass_scsipi_ioctl; 189 scbus->sc_adapter.adapt_getgeom = umass_scsipi_getgeom; 190 191 /* Fill in the channel. */ 192 memset(&scbus->sc_channel, 0, sizeof(scbus->sc_channel)); 193 scbus->sc_channel.chan_adapter = &scbus->sc_adapter; 194 scbus->sc_channel.chan_channel = 0; 195 scbus->sc_channel.chan_flags = SCSIPI_CHAN_OPENINGS | SCSIPI_CHAN_NOSETTLE; 196 scbus->sc_channel.chan_openings = 1; 197 scbus->sc_channel.chan_max_periph = 1; 198 scbus->sc_channel.chan_defquirks |= sc->sc_busquirks; 199 200 return (scbus); 201 } 202 203 Static void 204 umass_scsipi_request(struct scsipi_channel *chan, 205 scsipi_adapter_req_t req, void *arg) 206 { 207 struct scsipi_adapter *adapt = chan->chan_adapter; 208 struct scsipi_periph *periph; 209 struct scsipi_xfer *xs; 210 struct umass_softc *sc = device_private(adapt->adapt_dev); 211 struct umass_scsipi_softc *scbus = (struct umass_scsipi_softc *)sc->bus; 212 struct scsipi_generic *cmd; 213 int cmdlen; 214 int dir; 215 #ifdef UMASS_DEBUG 216 microtime(&sc->tv); 217 #endif 218 switch(req) { 219 case ADAPTER_REQ_RUN_XFER: 220 xs = arg; 221 periph = xs->xs_periph; 222 DIF(UDMASS_UPPER, periph->periph_dbflags |= SCSIPI_DEBUG_FLAGS); 223 224 DPRINTF(UDMASS_CMD, ("%s: umass_scsi_cmd: at %"PRIu64".%06"PRIu64": %d:%d " 225 "xs=%p cmd=0x%02x datalen=%d (quirks=0x%x, poll=%d)\n", 226 device_xname(sc->sc_dev), sc->tv.tv_sec, (uint64_t)sc->tv.tv_usec, 227 periph->periph_target, periph->periph_lun, 228 xs, xs->cmd->opcode, xs->datalen, 229 periph->periph_quirks, xs->xs_control & XS_CTL_POLL)); 230 #if defined(USB_DEBUG) && defined(SCSIPI_DEBUG) 231 if (umassdebug & UDMASS_SCSI) 232 show_scsipi_xs(xs); 233 else if (umassdebug & ~UDMASS_CMD) 234 show_scsipi_cmd(xs); 235 #endif 236 237 if (sc->sc_dying) { 238 xs->error = XS_DRIVER_STUFFUP; 239 goto done; 240 } 241 242 #ifdef UMASS_DEBUG 243 if (chan->chan_bustype->bustype_type == SCSIPI_BUSTYPE_ATAPI ? 244 periph->periph_target != UMASS_ATAPI_DRIVE : 245 periph->periph_target == chan->chan_id) { 246 DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n", 247 device_xname(sc->sc_dev), 248 periph->periph_target)); 249 xs->error = XS_DRIVER_STUFFUP; 250 goto done; 251 } 252 #endif 253 254 cmd = xs->cmd; 255 cmdlen = xs->cmdlen; 256 257 dir = DIR_NONE; 258 if (xs->datalen) { 259 switch (xs->xs_control & 260 (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 261 case XS_CTL_DATA_IN: 262 dir = DIR_IN; 263 break; 264 case XS_CTL_DATA_OUT: 265 dir = DIR_OUT; 266 break; 267 } 268 } 269 270 if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) { 271 printf("umass_cmd: large datalen, %d\n", xs->datalen); 272 xs->error = XS_DRIVER_STUFFUP; 273 goto done; 274 } 275 276 if (xs->xs_control & XS_CTL_POLL) { 277 /* Use sync transfer. XXX Broken! */ 278 DPRINTF(UDMASS_SCSI, 279 ("umass_scsi_cmd: sync dir=%d\n", dir)); 280 sc->sc_xfer_flags = USBD_SYNCHRONOUS; 281 scbus->sc_sync_status = USBD_INVAL; 282 sc->sc_methods->wire_xfer(sc, periph->periph_lun, cmd, 283 cmdlen, xs->data, 284 xs->datalen, dir, 285 xs->timeout, 0, xs); 286 sc->sc_xfer_flags = 0; 287 DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n", 288 scbus->sc_sync_status)); 289 switch (scbus->sc_sync_status) { 290 case USBD_NORMAL_COMPLETION: 291 xs->error = XS_NOERROR; 292 break; 293 case USBD_TIMEOUT: 294 xs->error = XS_TIMEOUT; 295 break; 296 default: 297 xs->error = XS_DRIVER_STUFFUP; 298 break; 299 } 300 goto done; 301 } else { 302 DPRINTF(UDMASS_SCSI, 303 ("umass_scsi_cmd: async dir=%d, cmdlen=%d" 304 " datalen=%d\n", 305 dir, cmdlen, xs->datalen)); 306 sc->sc_methods->wire_xfer(sc, periph->periph_lun, cmd, 307 cmdlen, xs->data, 308 xs->datalen, dir, 309 xs->timeout, 310 umass_scsipi_cb, xs); 311 return; 312 } 313 314 /* Return if command finishes early. */ 315 done: 316 scsipi_done(xs); 317 return; 318 default: 319 /* Not supported, nothing to do. */ 320 ; 321 } 322 } 323 324 Static void 325 umass_scsipi_minphys(struct buf *bp) 326 { 327 #ifdef DIAGNOSTIC 328 if (bp->b_bcount <= 0) { 329 printf("umass_scsipi_minphys count(%d) <= 0\n", 330 bp->b_bcount); 331 bp->b_bcount = UMASS_MAX_TRANSFER_SIZE; 332 } 333 #endif 334 if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE) 335 bp->b_bcount = UMASS_MAX_TRANSFER_SIZE; 336 minphys(bp); 337 } 338 339 int 340 umass_scsipi_ioctl(struct scsipi_channel *chan, u_long cmd, 341 void *arg, int flag, proc_t *p) 342 { 343 /*struct umass_softc *sc = link->adapter_softc;*/ 344 /*struct umass_scsipi_softc *scbus = sc->bus;*/ 345 346 switch (cmd) { 347 #if 0 348 case SCBUSIORESET: 349 ccb->ccb_h.status = CAM_REQ_INPROG; 350 umass_reset(sc, umass_cam_cb, (void *) ccb); 351 return (0); 352 #endif 353 default: 354 return (ENOTTY); 355 } 356 } 357 358 Static int 359 umass_scsipi_getgeom(struct scsipi_periph *periph, struct disk_parms *dp, 360 u_long sectors) 361 { 362 struct umass_softc *sc = 363 device_private(periph->periph_channel->chan_adapter->adapt_dev); 364 365 /* If it's not a floppy, we don't know what to do. */ 366 if (sc->sc_cmd != UMASS_CPROTO_UFI) 367 return (0); 368 369 switch (sectors) { 370 case 1440: 371 /* Most likely a single density 3.5" floppy. */ 372 dp->heads = 2; 373 dp->sectors = 9; 374 dp->cyls = 80; 375 return (1); 376 case 2880: 377 /* Most likely a double density 3.5" floppy. */ 378 dp->heads = 2; 379 dp->sectors = 18; 380 dp->cyls = 80; 381 return (1); 382 default: 383 return (0); 384 } 385 } 386 387 Static void 388 umass_scsipi_cb(struct umass_softc *sc, void *priv, int residue, int status) 389 { 390 struct umass_scsipi_softc *scbus = (struct umass_scsipi_softc *)sc->bus; 391 struct scsipi_xfer *xs = priv; 392 struct scsipi_periph *periph = xs->xs_periph; 393 int cmdlen; 394 int s; 395 #ifdef UMASS_DEBUG 396 struct timeval tv; 397 u_int delta; 398 microtime(&tv); 399 delta = (tv.tv_sec - sc->tv.tv_sec) * 1000000 + tv.tv_usec - sc->tv.tv_usec; 400 #endif 401 402 DPRINTF(UDMASS_CMD,("umass_scsipi_cb: at %"PRIu64".%06"PRIu64", delta=%u: xs=%p residue=%d" 403 " status=%d\n", tv.tv_sec, (uint64_t)tv.tv_usec, delta, xs, residue, status)); 404 405 xs->resid = residue; 406 407 switch (status) { 408 case STATUS_CMD_OK: 409 xs->error = XS_NOERROR; 410 break; 411 412 case STATUS_CMD_UNKNOWN: 413 /* FALLTHROUGH */ 414 case STATUS_CMD_FAILED: 415 /* fetch sense data */ 416 sc->sc_sense = 1; 417 memset(&scbus->sc_sense_cmd, 0, sizeof(scbus->sc_sense_cmd)); 418 scbus->sc_sense_cmd.opcode = SCSI_REQUEST_SENSE; 419 scbus->sc_sense_cmd.byte2 = periph->periph_lun << 420 SCSI_CMD_LUN_SHIFT; 421 scbus->sc_sense_cmd.length = sizeof(xs->sense); 422 423 if (sc->sc_cmd == UMASS_CPROTO_UFI || 424 sc->sc_cmd == UMASS_CPROTO_ATAPI) 425 cmdlen = UFI_COMMAND_LENGTH; /* XXX */ 426 else 427 cmdlen = sizeof(scbus->sc_sense_cmd); 428 sc->sc_methods->wire_xfer(sc, periph->periph_lun, 429 &scbus->sc_sense_cmd, cmdlen, 430 &xs->sense, sizeof(xs->sense), 431 DIR_IN, xs->timeout, 432 umass_scsipi_sense_cb, xs); 433 return; 434 435 case STATUS_WIRE_FAILED: 436 xs->error = XS_RESET; 437 break; 438 439 default: 440 panic("%s: Unknown status %d in umass_scsipi_cb", 441 device_xname(sc->sc_dev), status); 442 } 443 444 DPRINTF(UDMASS_CMD,("umass_scsipi_cb: at %"PRIu64".%06"PRIu64": return xs->error=" 445 "%d, xs->xs_status=0x%x xs->resid=%d\n", 446 tv.tv_sec, (uint64_t)tv.tv_usec, 447 xs->error, xs->xs_status, xs->resid)); 448 449 s = splbio(); 450 scsipi_done(xs); 451 splx(s); 452 } 453 454 /* 455 * Finalise a completed autosense operation 456 */ 457 Static void 458 umass_scsipi_sense_cb(struct umass_softc *sc, void *priv, int residue, 459 int status) 460 { 461 struct scsipi_xfer *xs = priv; 462 int s; 463 464 DPRINTF(UDMASS_CMD,("umass_scsipi_sense_cb: xs=%p residue=%d " 465 "status=%d\n", xs, residue, status)); 466 467 sc->sc_sense = 0; 468 switch (status) { 469 case STATUS_CMD_OK: 470 case STATUS_CMD_UNKNOWN: 471 /* getting sense data succeeded */ 472 if (residue == 0 || residue == 14)/* XXX */ 473 xs->error = XS_SENSE; 474 else 475 xs->error = XS_SHORTSENSE; 476 break; 477 default: 478 DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n", 479 device_xname(sc->sc_dev), status)); 480 xs->error = XS_DRIVER_STUFFUP; 481 break; 482 } 483 484 DPRINTF(UDMASS_CMD,("umass_scsipi_sense_cb: return xs->error=%d, " 485 "xs->xs_status=0x%x xs->resid=%d\n", xs->error, xs->xs_status, 486 xs->resid)); 487 488 s = splbio(); 489 scsipi_done(xs); 490 splx(s); 491 } 492 493 #if NATAPIBUS > 0 494 Static void 495 umass_atapi_probe_device(struct atapibus_softc *atapi, int target) 496 { 497 struct scsipi_channel *chan = atapi->sc_channel; 498 struct scsipi_periph *periph; 499 struct scsipibus_attach_args sa; 500 char vendor[33], product[65], revision[17]; 501 struct scsipi_inquiry_data inqbuf; 502 503 DPRINTF(UDMASS_SCSI,("umass_atapi_probe_device: atapi=%p target=%d\n", 504 atapi, target)); 505 506 if (target != UMASS_ATAPI_DRIVE) /* only probe drive 0 */ 507 return; 508 509 /* skip if already attached */ 510 if (scsipi_lookup_periph(chan, target, 0) != NULL) 511 return; 512 513 periph = scsipi_alloc_periph(M_NOWAIT); 514 if (periph == NULL) { 515 aprint_error_dev(atapi->sc_dev, 516 "can't allocate link for drive %d\n", target); 517 return; 518 } 519 520 DIF(UDMASS_UPPER, periph->periph_dbflags |= 1); /* XXX 1 */ 521 periph->periph_channel = chan; 522 periph->periph_switch = &atapi_probe_periphsw; 523 periph->periph_target = target; 524 periph->periph_quirks = chan->chan_defquirks; 525 526 DPRINTF(UDMASS_SCSI, ("umass_atapi_probe_device: doing inquiry\n")); 527 /* Now go ask the device all about itself. */ 528 memset(&inqbuf, 0, sizeof(inqbuf)); 529 if (scsipi_inquire(periph, &inqbuf, XS_CTL_DISCOVERY) != 0) { 530 DPRINTF(UDMASS_SCSI, ("umass_atapi_probe_device: " 531 "scsipi_inquire failed\n")); 532 free(periph, M_DEVBUF); 533 return; 534 } 535 536 scsipi_strvis(vendor, 33, inqbuf.vendor, 8); 537 scsipi_strvis(product, 65, inqbuf.product, 16); 538 scsipi_strvis(revision, 17, inqbuf.revision, 4); 539 540 sa.sa_periph = periph; 541 sa.sa_inqbuf.type = inqbuf.device; 542 sa.sa_inqbuf.removable = inqbuf.dev_qual2 & SID_REMOVABLE ? 543 T_REMOV : T_FIXED; 544 if (sa.sa_inqbuf.removable) 545 periph->periph_flags |= PERIPH_REMOVABLE; 546 sa.sa_inqbuf.vendor = vendor; 547 sa.sa_inqbuf.product = product; 548 sa.sa_inqbuf.revision = revision; 549 sa.sa_inqptr = NULL; 550 551 DPRINTF(UDMASS_SCSI, ("umass_atapi_probedev: doing atapi_probedev on " 552 "'%s' '%s' '%s'\n", vendor, product, revision)); 553 atapi_probe_device(atapi, target, periph, &sa); 554 /* atapi_probe_device() frees the periph when there is no device.*/ 555 } 556 #endif 557