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