1 /* $OpenBSD: umass_scsi.c,v 1.43 2015/12/16 14:50:26 mpi Exp $ */ 2 /* $NetBSD: umass_scsipi.c,v 1.9 2003/02/16 23:14:08 augustss Exp $ */ 3 /* 4 * Copyright (c) 2001 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. 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/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/conf.h> 37 #include <sys/buf.h> 38 #include <sys/device.h> 39 #include <sys/ioctl.h> 40 #include <sys/malloc.h> 41 42 #include <dev/usb/usb.h> 43 #include <dev/usb/usbdi.h> 44 #include <dev/usb/usbdi_util.h> 45 46 #include <dev/usb/umassvar.h> 47 #include <dev/usb/umass_scsi.h> 48 49 #include <scsi/scsi_all.h> 50 #include <scsi/scsiconf.h> 51 #include <scsi/scsi_disk.h> 52 #include <machine/bus.h> 53 54 struct umass_scsi_softc { 55 struct device *sc_child; 56 struct scsi_link sc_link; 57 struct scsi_iopool sc_iopool; 58 int sc_open; 59 60 struct scsi_sense sc_sense_cmd; 61 }; 62 63 64 #define UMASS_SCSIID_HOST 0x00 65 #define UMASS_SCSIID_DEVICE 0x01 66 67 int umass_scsi_probe(struct scsi_link *); 68 void umass_scsi_cmd(struct scsi_xfer *); 69 void umass_scsi_minphys(struct buf *, struct scsi_link *); 70 71 struct scsi_adapter umass_scsi_switch = { 72 umass_scsi_cmd, 73 umass_scsi_minphys, 74 umass_scsi_probe 75 }; 76 77 void umass_scsi_cb(struct umass_softc *sc, void *priv, int residue, 78 int status); 79 void umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue, 80 int status); 81 struct umass_scsi_softc *umass_scsi_setup(struct umass_softc *); 82 83 void *umass_io_get(void *); 84 void umass_io_put(void *, void *); 85 86 int 87 umass_scsi_attach(struct umass_softc *sc) 88 { 89 struct scsibus_attach_args saa; 90 struct umass_scsi_softc *scbus; 91 92 scbus = umass_scsi_setup(sc); 93 scbus->sc_link.adapter_target = UMASS_SCSIID_HOST; 94 scbus->sc_link.luns = sc->maxlun + 1; 95 scbus->sc_link.flags &= ~SDEV_ATAPI; 96 scbus->sc_link.flags |= SDEV_UMASS; 97 98 bzero(&saa, sizeof(saa)); 99 saa.saa_sc_link = &scbus->sc_link; 100 101 DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: SCSI\n" 102 "sc = 0x%p, scbus = 0x%p\n", 103 sc->sc_dev.dv_xname, sc, scbus)); 104 105 sc->sc_refcnt++; 106 scbus->sc_child = config_found((struct device *)sc, &saa, scsiprint); 107 if (--sc->sc_refcnt < 0) 108 usb_detach_wakeup(&sc->sc_dev); 109 110 return (0); 111 } 112 113 int 114 umass_atapi_attach(struct umass_softc *sc) 115 { 116 struct scsibus_attach_args saa; 117 struct umass_scsi_softc *scbus; 118 119 scbus = umass_scsi_setup(sc); 120 scbus->sc_link.adapter_target = UMASS_SCSIID_HOST; 121 scbus->sc_link.luns = 1; 122 scbus->sc_link.openings = 1; 123 scbus->sc_link.flags |= SDEV_ATAPI; 124 125 bzero(&saa, sizeof(saa)); 126 saa.saa_sc_link = &scbus->sc_link; 127 128 DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: ATAPI\n" 129 "sc = 0x%p, scbus = 0x%p\n", 130 sc->sc_dev.dv_xname, sc, scbus)); 131 132 sc->sc_refcnt++; 133 scbus->sc_child = config_found((struct device *)sc, &saa, scsiprint); 134 if (--sc->sc_refcnt < 0) 135 usb_detach_wakeup(&sc->sc_dev); 136 137 return (0); 138 } 139 140 struct umass_scsi_softc * 141 umass_scsi_setup(struct umass_softc *sc) 142 { 143 struct umass_scsi_softc *scbus; 144 145 scbus = malloc(sizeof(*scbus), M_DEVBUF, M_WAITOK | M_ZERO); 146 147 sc->bus = scbus; 148 149 scsi_iopool_init(&scbus->sc_iopool, scbus, umass_io_get, umass_io_put); 150 151 /* Fill in the link. */ 152 scbus->sc_link.adapter_buswidth = 2; 153 scbus->sc_link.adapter = &umass_scsi_switch; 154 scbus->sc_link.adapter_softc = sc; 155 scbus->sc_link.openings = 1; 156 scbus->sc_link.quirks |= SDEV_ONLYBIG | sc->sc_busquirks; 157 scbus->sc_link.pool = &scbus->sc_iopool; 158 159 return (scbus); 160 } 161 162 int 163 umass_scsi_detach(struct umass_softc *sc, int flags) 164 { 165 struct umass_scsi_softc *scbus = sc->bus; 166 int rv = 0; 167 168 if (scbus != NULL) { 169 if (scbus->sc_child != NULL) 170 rv = config_detach(scbus->sc_child, flags); 171 free(scbus, M_DEVBUF, sizeof(*scbus)); 172 sc->bus = NULL; 173 } 174 175 return (rv); 176 } 177 178 int 179 umass_scsi_probe(struct scsi_link *link) 180 { 181 struct umass_softc *sc = link->adapter_softc; 182 struct usb_device_info udi; 183 size_t len; 184 185 /* dont fake devids when more than one scsi device can attach. */ 186 if (sc->maxlun > 0) 187 return (0); 188 189 usbd_fill_deviceinfo(sc->sc_udev, &udi, 1); 190 191 /* 192 * Create a fake devid using the vendor and product ids and the last 193 * 12 characters of serial number, as recommended by Section 4.1.1 of 194 * the USB Mass Storage Class - Bulk Only Transport spec. 195 */ 196 len = strlen(udi.udi_serial); 197 if (len >= 12) { 198 char buf[21]; 199 snprintf(buf, sizeof(buf), "%04x%04x%s", udi.udi_vendorNo, 200 udi.udi_productNo, udi.udi_serial + len - 12); 201 link->id = devid_alloc(DEVID_SERIAL, DEVID_F_PRINT, 202 sizeof(buf) - 1, buf); 203 } 204 205 return (0); 206 } 207 208 void 209 umass_scsi_cmd(struct scsi_xfer *xs) 210 { 211 struct scsi_link *sc_link = xs->sc_link; 212 struct umass_softc *sc = sc_link->adapter_softc; 213 struct scsi_generic *cmd; 214 int cmdlen, dir; 215 216 #ifdef UMASS_DEBUG 217 microtime(&sc->tv); 218 #endif 219 220 DIF(UDMASS_UPPER, sc_link->flags |= SCSIDEBUG_LEVEL); 221 222 DPRINTF(UDMASS_CMD, ("%s: umass_scsi_cmd: at %lld.%06ld: %d:%d " 223 "xs=%p cmd=0x%02x datalen=%d (quirks=0x%x, poll=%d)\n", 224 sc->sc_dev.dv_xname, (long long)sc->tv.tv_sec, sc->tv.tv_usec, 225 sc_link->target, sc_link->lun, xs, xs->cmd->opcode, 226 xs->datalen, sc_link->quirks, xs->flags & SCSI_POLL)); 227 228 if (usbd_is_dying(sc->sc_udev)) { 229 xs->error = XS_DRIVER_STUFFUP; 230 goto done; 231 } 232 233 #if defined(UMASS_DEBUG) 234 if (sc_link->target != UMASS_SCSIID_DEVICE) { 235 DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n", 236 sc->sc_dev.dv_xname, sc_link->target)); 237 xs->error = XS_DRIVER_STUFFUP; 238 goto done; 239 } 240 #endif 241 242 cmd = xs->cmd; 243 cmdlen = xs->cmdlen; 244 245 dir = DIR_NONE; 246 if (xs->datalen) { 247 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { 248 case SCSI_DATA_IN: 249 dir = DIR_IN; 250 break; 251 case SCSI_DATA_OUT: 252 dir = DIR_OUT; 253 break; 254 } 255 } 256 257 if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) { 258 printf("umass_cmd: large datalen, %d\n", xs->datalen); 259 xs->error = XS_DRIVER_STUFFUP; 260 goto done; 261 } 262 263 if (xs->flags & SCSI_POLL) { 264 DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: sync dir=%d\n", dir)); 265 usbd_set_polling(sc->sc_udev, 1); 266 sc->sc_xfer_flags = USBD_SYNCHRONOUS; 267 sc->polled_xfer_status = USBD_INVAL; 268 sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen, 269 xs->data, xs->datalen, dir, 270 xs->timeout, umass_scsi_cb, xs); 271 sc->sc_xfer_flags = 0; 272 DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n", 273 sc->polled_xfer_status)); 274 usbd_set_polling(sc->sc_udev, 0); 275 /* scsi_done() has already been called. */ 276 return; 277 } else { 278 DPRINTF(UDMASS_SCSI, 279 ("umass_scsi_cmd: async dir=%d, cmdlen=%d" 280 " datalen=%d\n", 281 dir, cmdlen, xs->datalen)); 282 sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen, 283 xs->data, xs->datalen, dir, 284 xs->timeout, umass_scsi_cb, xs); 285 /* scsi_done() has already been called. */ 286 return; 287 } 288 289 /* Return if command finishes early. */ 290 done: 291 scsi_done(xs); 292 } 293 294 void 295 umass_scsi_minphys(struct buf *bp, struct scsi_link *sl) 296 { 297 if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE) 298 bp->b_bcount = UMASS_MAX_TRANSFER_SIZE; 299 300 minphys(bp); 301 } 302 303 void 304 umass_scsi_cb(struct umass_softc *sc, void *priv, int residue, int status) 305 { 306 struct umass_scsi_softc *scbus = sc->bus; 307 struct scsi_xfer *xs = priv; 308 struct scsi_link *link = xs->sc_link; 309 int cmdlen; 310 #ifdef UMASS_DEBUG 311 struct timeval tv; 312 u_int delta; 313 microtime(&tv); 314 delta = (tv.tv_sec - sc->tv.tv_sec) * 1000000 + 315 tv.tv_usec - sc->tv.tv_usec; 316 #endif 317 318 DPRINTF(UDMASS_CMD, 319 ("umass_scsi_cb: at %lld.%06ld, delta=%u: xs=%p residue=%d" 320 " status=%d\n", (long long)tv.tv_sec, tv.tv_usec, delta, xs, residue, 321 status)); 322 323 xs->resid = residue; 324 325 switch (status) { 326 case STATUS_CMD_OK: 327 xs->error = XS_NOERROR; 328 break; 329 330 case STATUS_CMD_UNKNOWN: 331 DPRINTF(UDMASS_CMD, ("umass_scsi_cb: status cmd unknown\n")); 332 /* we can't issue REQUEST SENSE */ 333 if (xs->sc_link->quirks & ADEV_NOSENSE) { 334 /* 335 * If no residue and no other USB error, 336 * command succeeded. 337 */ 338 if (residue == 0) { 339 xs->error = XS_NOERROR; 340 break; 341 } 342 343 /* 344 * Some devices return a short INQUIRY 345 * response, omitting response data from the 346 * "vendor specific data" on... 347 */ 348 if (xs->cmd->opcode == INQUIRY && 349 residue < xs->datalen) { 350 xs->error = XS_NOERROR; 351 break; 352 } 353 354 xs->error = XS_DRIVER_STUFFUP; 355 break; 356 } 357 /* FALLTHROUGH */ 358 case STATUS_CMD_FAILED: 359 DPRINTF(UDMASS_CMD, ("umass_scsi_cb: status cmd failed for " 360 "scsi op 0x%02x\n", xs->cmd->opcode)); 361 /* fetch sense data */ 362 sc->sc_sense = 1; 363 memset(&scbus->sc_sense_cmd, 0, sizeof(scbus->sc_sense_cmd)); 364 scbus->sc_sense_cmd.opcode = REQUEST_SENSE; 365 scbus->sc_sense_cmd.byte2 = link->lun << SCSI_CMD_LUN_SHIFT; 366 scbus->sc_sense_cmd.length = sizeof(xs->sense); 367 368 cmdlen = sizeof(scbus->sc_sense_cmd); 369 if (xs->flags & SCSI_POLL) { 370 usbd_set_polling(sc->sc_udev, 1); 371 sc->sc_xfer_flags = USBD_SYNCHRONOUS; 372 sc->polled_xfer_status = USBD_INVAL; 373 } 374 /* scsi_done() has already been called. */ 375 sc->sc_methods->wire_xfer(sc, link->lun, 376 &scbus->sc_sense_cmd, cmdlen, 377 &xs->sense, sizeof(xs->sense), 378 DIR_IN, xs->timeout, 379 umass_scsi_sense_cb, xs); 380 if (xs->flags & SCSI_POLL) { 381 sc->sc_xfer_flags = 0; 382 usbd_set_polling(sc->sc_udev, 0); 383 } 384 return; 385 386 case STATUS_WIRE_FAILED: 387 xs->error = XS_RESET; 388 break; 389 390 default: 391 panic("%s: Unknown status %d in umass_scsi_cb", 392 sc->sc_dev.dv_xname, status); 393 } 394 395 DPRINTF(UDMASS_CMD,("umass_scsi_cb: at %lld.%06ld: return error=%d, " 396 "status=0x%x resid=%zu\n", 397 (long long)tv.tv_sec, tv.tv_usec, 398 xs->error, xs->status, xs->resid)); 399 400 if ((xs->flags & SCSI_POLL) && (xs->error == XS_NOERROR)) { 401 switch (sc->polled_xfer_status) { 402 case USBD_NORMAL_COMPLETION: 403 xs->error = XS_NOERROR; 404 break; 405 case USBD_TIMEOUT: 406 xs->error = XS_TIMEOUT; 407 break; 408 default: 409 xs->error = XS_DRIVER_STUFFUP; 410 break; 411 } 412 } 413 414 scsi_done(xs); 415 } 416 417 /* 418 * Finalise a completed autosense operation 419 */ 420 void 421 umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue, 422 int status) 423 { 424 struct scsi_xfer *xs = priv; 425 426 DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: xs=%p residue=%d " 427 "status=%d\n", xs, residue, status)); 428 429 sc->sc_sense = 0; 430 switch (status) { 431 case STATUS_CMD_OK: 432 case STATUS_CMD_UNKNOWN: 433 /* getting sense data succeeded */ 434 if (residue == 0 || residue == 14)/* XXX */ 435 xs->error = XS_SENSE; 436 else 437 xs->error = XS_SHORTSENSE; 438 break; 439 default: 440 DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n", 441 sc->sc_dev.dv_xname, status)); 442 xs->error = XS_DRIVER_STUFFUP; 443 break; 444 } 445 446 DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: return xs->error=%d, " 447 "xs->flags=0x%x xs->resid=%zu\n", xs->error, xs->status, 448 xs->resid)); 449 450 if ((xs->flags & SCSI_POLL) && (xs->error == XS_NOERROR)) { 451 switch (sc->polled_xfer_status) { 452 case USBD_NORMAL_COMPLETION: 453 xs->error = XS_NOERROR; 454 break; 455 case USBD_TIMEOUT: 456 xs->error = XS_TIMEOUT; 457 break; 458 default: 459 xs->error = XS_DRIVER_STUFFUP; 460 break; 461 } 462 } 463 464 scsi_done(xs); 465 } 466 467 void * 468 umass_io_get(void *cookie) 469 { 470 struct umass_scsi_softc *scbus = cookie; 471 void *io = NULL; 472 int s; 473 474 s = splusb(); 475 if (!scbus->sc_open) { 476 scbus->sc_open = 1; 477 io = scbus; /* just has to be non-NULL */ 478 } 479 splx(s); 480 481 return (io); 482 } 483 484 void 485 umass_io_put(void *cookie, void *io) 486 { 487 struct umass_scsi_softc *scbus = cookie; 488 int s; 489 490 s = splusb(); 491 scbus->sc_open = 0; 492 splx(s); 493 } 494