Annotation of sys/dev/usb/umass_scsi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: umass_scsi.c,v 1.18 2007/06/13 10:33:52 mbalmer 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: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include "atapiscsi.h"
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/conf.h>
! 46: #include <sys/buf.h>
! 47: #include <sys/device.h>
! 48: #include <sys/ioctl.h>
! 49: #include <sys/malloc.h>
! 50:
! 51: #include <dev/usb/usb.h>
! 52: #include <dev/usb/usbdi.h>
! 53: #include <dev/usb/usbdi_util.h>
! 54: #include <dev/usb/usbdevs.h>
! 55:
! 56: #include <dev/usb/umassvar.h>
! 57: #include <dev/usb/umass_scsi.h>
! 58:
! 59: #include <scsi/scsi_all.h>
! 60: #include <scsi/scsiconf.h>
! 61: #include <scsi/scsi_disk.h>
! 62: #include <machine/bus.h>
! 63:
! 64: struct umass_scsi_softc {
! 65: struct umassbus_softc base;
! 66: struct scsi_link sc_link;
! 67: struct scsi_adapter sc_adapter;
! 68:
! 69: struct scsi_sense sc_sense_cmd;
! 70: };
! 71:
! 72:
! 73: #define UMASS_SCSIID_HOST 0x00
! 74: #define UMASS_SCSIID_DEVICE 0x01
! 75:
! 76: #define UMASS_ATAPI_DRIVE 0
! 77:
! 78: int umass_scsi_cmd(struct scsi_xfer *);
! 79: void umass_scsi_minphys(struct buf *);
! 80:
! 81: void umass_scsi_cb(struct umass_softc *sc, void *priv, int residue,
! 82: int status);
! 83: void umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue,
! 84: int status);
! 85: struct umass_scsi_softc *umass_scsi_setup(struct umass_softc *);
! 86:
! 87: struct scsi_device umass_scsi_dev = { NULL, NULL, NULL, NULL, };
! 88:
! 89: #if NATAPISCSI > 0
! 90: struct scsi_device umass_atapiscsi_dev = { NULL, NULL, NULL, NULL, };
! 91: #endif
! 92:
! 93: int
! 94: umass_scsi_attach(struct umass_softc *sc)
! 95: {
! 96: struct scsibus_attach_args saa;
! 97: struct umass_scsi_softc *scbus;
! 98:
! 99: scbus = umass_scsi_setup(sc);
! 100: scbus->sc_link.adapter_target = UMASS_SCSIID_HOST;
! 101: scbus->sc_link.luns = sc->maxlun + 1;
! 102: scbus->sc_link.flags &= ~SDEV_ATAPI;
! 103: scbus->sc_link.flags |= SDEV_UMASS;
! 104: scbus->sc_link.device = &umass_scsi_dev;
! 105:
! 106: bzero(&saa, sizeof(saa));
! 107: saa.saa_sc_link = &scbus->sc_link;
! 108:
! 109: DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: SCSI\n"
! 110: "sc = 0x%x, scbus = 0x%x\n",
! 111: sc->sc_dev.dv_xname, sc, scbus));
! 112:
! 113: sc->sc_refcnt++;
! 114: scbus->base.sc_child =
! 115: config_found((struct device *)sc, &saa, scsiprint);
! 116: if (--sc->sc_refcnt < 0)
! 117: usb_detach_wakeup(&sc->sc_dev);
! 118:
! 119: return (0);
! 120: }
! 121:
! 122: #if NATAPISCSI > 0
! 123: int
! 124: umass_atapi_attach(struct umass_softc *sc)
! 125: {
! 126: struct scsibus_attach_args saa;
! 127: struct umass_scsi_softc *scbus;
! 128:
! 129: scbus = umass_scsi_setup(sc);
! 130: scbus->sc_link.adapter_target = UMASS_SCSIID_HOST;
! 131: scbus->sc_link.luns = 1;
! 132: scbus->sc_link.openings = 1;
! 133: scbus->sc_link.flags |= SDEV_ATAPI;
! 134: scbus->sc_link.device = &umass_atapiscsi_dev;
! 135:
! 136: bzero(&saa, sizeof(saa));
! 137: saa.saa_sc_link = &scbus->sc_link;
! 138:
! 139: DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: ATAPI\n"
! 140: "sc = 0x%x, scbus = 0x%x\n",
! 141: sc->sc_dev.dv_xname, sc, scbus));
! 142:
! 143: sc->sc_refcnt++;
! 144: scbus->base.sc_child = config_found((struct device *)sc,
! 145: &saa, scsiprint);
! 146: if (--sc->sc_refcnt < 0)
! 147: usb_detach_wakeup(&sc->sc_dev);
! 148:
! 149: return (0);
! 150: }
! 151: #endif
! 152:
! 153: struct umass_scsi_softc *
! 154: umass_scsi_setup(struct umass_softc *sc)
! 155: {
! 156: struct umass_scsi_softc *scbus;
! 157:
! 158: scbus = malloc(sizeof(struct umass_scsi_softc), M_DEVBUF, M_WAITOK);
! 159: memset(&scbus->sc_link, 0, sizeof(struct scsi_link));
! 160: memset(&scbus->sc_adapter, 0, sizeof(struct scsi_adapter));
! 161:
! 162: sc->bus = (struct umassbus_softc *)scbus;
! 163:
! 164: /* Fill in the adapter. */
! 165: scbus->sc_adapter.scsi_cmd = umass_scsi_cmd;
! 166: scbus->sc_adapter.scsi_minphys = umass_scsi_minphys;
! 167:
! 168: /* Fill in the link. */
! 169: scbus->sc_link.adapter_buswidth = 2;
! 170: scbus->sc_link.adapter = &scbus->sc_adapter;
! 171: scbus->sc_link.adapter_softc = sc;
! 172: scbus->sc_link.openings = 1;
! 173: scbus->sc_link.quirks |= SDEV_ONLYBIG | sc->sc_busquirks;
! 174:
! 175: return (scbus);
! 176: }
! 177:
! 178: int
! 179: umass_scsi_cmd(struct scsi_xfer *xs)
! 180: {
! 181: struct scsi_link *sc_link = xs->sc_link;
! 182: struct umass_softc *sc = sc_link->adapter_softc;
! 183:
! 184: struct scsi_generic *cmd;
! 185: int cmdlen, dir, s;
! 186:
! 187: #ifdef UMASS_DEBUG
! 188: microtime(&sc->tv);
! 189: #endif
! 190:
! 191: DIF(UDMASS_UPPER, sc_link->flags |= SCSIDEBUG_LEVEL);
! 192:
! 193: DPRINTF(UDMASS_CMD, ("%s: umass_scsi_cmd: at %lu.%06lu: %d:%d "
! 194: "xs=%p cmd=0x%02x datalen=%d (quirks=0x%x, poll=%d)\n",
! 195: sc->sc_dev.dv_xname, sc->tv.tv_sec, sc->tv.tv_usec,
! 196: sc_link->target, sc_link->lun, xs, xs->cmd->opcode,
! 197: xs->datalen, sc_link->quirks, xs->flags & SCSI_POLL));
! 198:
! 199: #if defined(USB_DEBUG) && defined(SCSIDEBUG)
! 200: if (umassdebug & UDMASS_SCSI)
! 201: show_scsi_xs(xs);
! 202: else if (umassdebug & ~UDMASS_CMD)
! 203: show_scsi_cmd(xs);
! 204: #endif
! 205:
! 206: if (sc->sc_dying) {
! 207: xs->error = XS_DRIVER_STUFFUP;
! 208: goto done;
! 209: }
! 210:
! 211: #if defined(UMASS_DEBUG)
! 212: if (sc_link->target != UMASS_SCSIID_DEVICE) {
! 213: DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n",
! 214: sc->sc_dev.dv_xname, sc_link->target));
! 215: xs->error = XS_DRIVER_STUFFUP;
! 216: goto done;
! 217: }
! 218: #endif
! 219:
! 220: cmd = xs->cmd;
! 221: cmdlen = xs->cmdlen;
! 222:
! 223: dir = DIR_NONE;
! 224: if (xs->datalen) {
! 225: switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
! 226: case SCSI_DATA_IN:
! 227: dir = DIR_IN;
! 228: break;
! 229: case SCSI_DATA_OUT:
! 230: dir = DIR_OUT;
! 231: break;
! 232: }
! 233: }
! 234:
! 235: if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) {
! 236: printf("umass_cmd: large datalen, %d\n", xs->datalen);
! 237: xs->error = XS_DRIVER_STUFFUP;
! 238: goto done;
! 239: }
! 240:
! 241: if (xs->flags & SCSI_POLL) {
! 242: DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: sync dir=%d\n", dir));
! 243: usbd_set_polling(sc->sc_udev, 1);
! 244: sc->sc_xfer_flags = USBD_SYNCHRONOUS;
! 245: sc->polled_xfer_status = USBD_INVAL;
! 246: sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen,
! 247: xs->data, xs->datalen, dir,
! 248: xs->timeout, umass_scsi_cb, xs);
! 249: sc->sc_xfer_flags = 0;
! 250: DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n",
! 251: sc->polled_xfer_status));
! 252: if (xs->error == XS_NOERROR) {
! 253: switch (sc->polled_xfer_status) {
! 254: case USBD_NORMAL_COMPLETION:
! 255: xs->error = XS_NOERROR;
! 256: break;
! 257: case USBD_TIMEOUT:
! 258: xs->error = XS_TIMEOUT;
! 259: break;
! 260: default:
! 261: xs->error = XS_DRIVER_STUFFUP;
! 262: break;
! 263: }
! 264: }
! 265: usbd_set_polling(sc->sc_udev, 0);
! 266: DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done, error=%d\n",
! 267: xs->error));
! 268: } else {
! 269: DPRINTF(UDMASS_SCSI,
! 270: ("umass_scsi_cmd: async dir=%d, cmdlen=%d"
! 271: " datalen=%d\n",
! 272: dir, cmdlen, xs->datalen));
! 273: sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen,
! 274: xs->data, xs->datalen, dir,
! 275: xs->timeout, umass_scsi_cb, xs);
! 276: return (SUCCESSFULLY_QUEUED);
! 277: }
! 278:
! 279: /* Return if command finishes early. */
! 280: done:
! 281: xs->flags |= ITSDONE;
! 282:
! 283: s = splbio();
! 284: scsi_done(xs);
! 285: splx(s);
! 286: if (xs->flags & SCSI_POLL)
! 287: return (COMPLETE);
! 288: else
! 289: return (SUCCESSFULLY_QUEUED);
! 290: }
! 291:
! 292: void
! 293: umass_scsi_minphys(struct buf *bp)
! 294: {
! 295: if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE)
! 296: bp->b_bcount = UMASS_MAX_TRANSFER_SIZE;
! 297:
! 298: minphys(bp);
! 299: }
! 300:
! 301: void
! 302: umass_scsi_cb(struct umass_softc *sc, void *priv, int residue, int status)
! 303: {
! 304: struct umass_scsi_softc *scbus = (struct umass_scsi_softc *)sc->bus;
! 305: struct scsi_xfer *xs = priv;
! 306: struct scsi_link *link = xs->sc_link;
! 307: int cmdlen;
! 308: int s;
! 309: #ifdef UMASS_DEBUG
! 310: struct timeval tv;
! 311: u_int delta;
! 312: microtime(&tv);
! 313: delta = (tv.tv_sec - sc->tv.tv_sec) * 1000000 +
! 314: tv.tv_usec - sc->tv.tv_usec;
! 315: #endif
! 316:
! 317: DPRINTF(UDMASS_CMD,
! 318: ("umass_scsi_cb: at %lu.%06lu, delta=%u: xs=%p residue=%d"
! 319: " status=%d\n", tv.tv_sec, tv.tv_usec, delta, xs, residue,
! 320: status));
! 321:
! 322: xs->resid = residue;
! 323:
! 324: switch (status) {
! 325: case STATUS_CMD_OK:
! 326: xs->error = XS_NOERROR;
! 327: break;
! 328:
! 329: case STATUS_CMD_UNKNOWN:
! 330: DPRINTF(UDMASS_CMD, ("umass_scsi_cb: status cmd unknown\n"));
! 331: /* we can't issue REQUEST SENSE */
! 332: if (xs->sc_link->quirks & ADEV_NOSENSE) {
! 333: /*
! 334: * If no residue and no other USB error,
! 335: * command succeeded.
! 336: */
! 337: if (residue == 0) {
! 338: xs->error = XS_NOERROR;
! 339: break;
! 340: }
! 341:
! 342: /*
! 343: * Some devices return a short INQUIRY
! 344: * response, omitting response data from the
! 345: * "vendor specific data" on...
! 346: */
! 347: if (xs->cmd->opcode == INQUIRY &&
! 348: residue < xs->datalen) {
! 349: xs->error = XS_NOERROR;
! 350: break;
! 351: }
! 352:
! 353: xs->error = XS_DRIVER_STUFFUP;
! 354: break;
! 355: }
! 356: /* FALLTHROUGH */
! 357: case STATUS_CMD_FAILED:
! 358: DPRINTF(UDMASS_CMD, ("umass_scsi_cb: status cmd failed for "
! 359: "scsi op 0x%02x\n", xs->cmd->opcode));
! 360: /* fetch sense data */
! 361: sc->sc_sense = 1;
! 362: memset(&scbus->sc_sense_cmd, 0, sizeof(scbus->sc_sense_cmd));
! 363: scbus->sc_sense_cmd.opcode = REQUEST_SENSE;
! 364: scbus->sc_sense_cmd.byte2 = link->lun << SCSI_CMD_LUN_SHIFT;
! 365: scbus->sc_sense_cmd.length = sizeof(xs->sense);
! 366:
! 367: cmdlen = sizeof(scbus->sc_sense_cmd);
! 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: return;
! 374:
! 375: case STATUS_WIRE_FAILED:
! 376: xs->error = XS_RESET;
! 377: break;
! 378:
! 379: default:
! 380: panic("%s: Unknown status %d in umass_scsi_cb",
! 381: sc->sc_dev.dv_xname, status);
! 382: }
! 383:
! 384: if (xs->flags & SCSI_POLL)
! 385: return;
! 386:
! 387: xs->flags |= ITSDONE;
! 388:
! 389: DPRINTF(UDMASS_CMD,("umass_scsi_cb: at %lu.%06lu: return error=%d, "
! 390: "status=0x%x resid=%d\n",
! 391: tv.tv_sec, tv.tv_usec,
! 392: xs->error, xs->status, xs->resid));
! 393:
! 394: s = splbio();
! 395: scsi_done(xs);
! 396: splx(s);
! 397: }
! 398:
! 399: /*
! 400: * Finalise a completed autosense operation
! 401: */
! 402: void
! 403: umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue,
! 404: int status)
! 405: {
! 406: struct scsi_xfer *xs = priv;
! 407: int s;
! 408:
! 409: DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: xs=%p residue=%d "
! 410: "status=%d\n", xs, residue, status));
! 411:
! 412: sc->sc_sense = 0;
! 413: switch (status) {
! 414: case STATUS_CMD_OK:
! 415: case STATUS_CMD_UNKNOWN:
! 416: /* getting sense data succeeded */
! 417: if (residue == 0 || residue == 14)/* XXX */
! 418: xs->error = XS_SENSE;
! 419: else
! 420: xs->error = XS_SHORTSENSE;
! 421: break;
! 422: default:
! 423: DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n",
! 424: sc->sc_dev.dv_xname, status));
! 425: xs->error = XS_DRIVER_STUFFUP;
! 426: break;
! 427: }
! 428:
! 429: xs->flags |= ITSDONE;
! 430:
! 431: DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: return xs->error=%d, "
! 432: "xs->flags=0x%x xs->resid=%d\n", xs->error, xs->status,
! 433: xs->resid));
! 434:
! 435: s = splbio();
! 436: scsi_done(xs);
! 437: splx(s);
! 438: }
! 439:
CVSweb