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