LCOV - code coverage report
Current view: top level - dev/usb - umass_scsi.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 169 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 9 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : umass_scsi_attach(struct umass_softc *sc)
      86             : {
      87           0 :         struct scsibus_attach_args saa;
      88             :         struct umass_scsi_softc *scbus;
      89             : 
      90           0 :         scbus = malloc(sizeof(*scbus), M_DEVBUF, M_WAITOK | M_ZERO);
      91             : 
      92           0 :         sc->bus = scbus;
      93             : 
      94           0 :         scsi_iopool_init(&scbus->sc_iopool, scbus, umass_io_get, umass_io_put);
      95             : 
      96             :         /* Fill in the link. */
      97           0 :         scbus->sc_link.adapter_buswidth = 2;
      98           0 :         scbus->sc_link.adapter = &umass_scsi_switch;
      99           0 :         scbus->sc_link.adapter_softc = sc;
     100           0 :         scbus->sc_link.adapter_target = UMASS_SCSIID_HOST;
     101           0 :         scbus->sc_link.openings = 1;
     102           0 :         scbus->sc_link.quirks = SDEV_ONLYBIG | sc->sc_busquirks;
     103           0 :         scbus->sc_link.pool = &scbus->sc_iopool;
     104           0 :         scbus->sc_link.luns = sc->maxlun + 1;
     105           0 :         scbus->sc_link.flags = SDEV_UMASS;
     106             : 
     107           0 :         bzero(&saa, sizeof(saa));
     108           0 :         saa.saa_sc_link = &scbus->sc_link;
     109             : 
     110           0 :         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           0 :                 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           0 :                 break;
     124             :         default:
     125             :                 break;
     126             :         }
     127             : 
     128           0 :         sc->sc_refcnt++;
     129           0 :         scbus->sc_child = config_found((struct device *)sc, &saa, scsiprint);
     130           0 :         if (--sc->sc_refcnt < 0)
     131           0 :                 usb_detach_wakeup(&sc->sc_dev);
     132             : 
     133           0 :         return (0);
     134           0 : }
     135             : 
     136             : int
     137           0 : umass_scsi_detach(struct umass_softc *sc, int flags)
     138             : {
     139           0 :         struct umass_scsi_softc *scbus = sc->bus;
     140             :         int rv = 0;
     141             : 
     142           0 :         if (scbus != NULL) {
     143           0 :                 if (scbus->sc_child != NULL)
     144           0 :                         rv = config_detach(scbus->sc_child, flags);
     145           0 :                 free(scbus, M_DEVBUF, sizeof(*scbus));
     146           0 :                 sc->bus = NULL;
     147           0 :         }
     148             : 
     149           0 :         return (rv);
     150             : }
     151             : 
     152             : int
     153           0 : umass_scsi_probe(struct scsi_link *link)
     154             : {
     155           0 :         struct umass_softc *sc = link->adapter_softc;
     156           0 :         struct usb_device_info udi;
     157             :         size_t len;
     158             : 
     159             :         /* dont fake devids when more than one scsi device can attach. */
     160           0 :         if (sc->maxlun > 0)
     161           0 :                 return (0);
     162             : 
     163           0 :         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           0 :         len = strlen(udi.udi_serial);
     171           0 :         if (len >= 12) {
     172           0 :                 char buf[21];
     173           0 :                 snprintf(buf, sizeof(buf), "%04x%04x%s", udi.udi_vendorNo,
     174           0 :                     udi.udi_productNo, udi.udi_serial + len - 12);
     175           0 :                 link->id = devid_alloc(DEVID_SERIAL, DEVID_F_PRINT,
     176             :                     sizeof(buf) - 1, buf);
     177           0 :         }
     178             : 
     179           0 :         return (0);
     180           0 : }
     181             : 
     182             : void
     183           0 : umass_scsi_cmd(struct scsi_xfer *xs)
     184             : {
     185           0 :         struct scsi_link *sc_link = xs->sc_link;
     186           0 :         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           0 :         if (usbd_is_dying(sc->sc_udev)) {
     203           0 :                 xs->error = XS_DRIVER_STUFFUP;
     204           0 :                 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           0 :         cmd = xs->cmd;
     217           0 :         cmdlen = xs->cmdlen;
     218             : 
     219             :         dir = DIR_NONE;
     220           0 :         if (xs->datalen) {
     221           0 :                 switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
     222             :                 case SCSI_DATA_IN:
     223             :                         dir = DIR_IN;
     224           0 :                         break;
     225             :                 case SCSI_DATA_OUT:
     226             :                         dir = DIR_OUT;
     227           0 :                         break;
     228             :                 }
     229             :         }
     230             : 
     231           0 :         if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) {
     232           0 :                 printf("umass_cmd: large datalen, %d\n", xs->datalen);
     233           0 :                 xs->error = XS_DRIVER_STUFFUP;
     234           0 :                 goto done;
     235             :         }
     236             : 
     237           0 :         if (xs->flags & SCSI_POLL) {
     238             :                 DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: sync dir=%d\n", dir));
     239           0 :                 usbd_set_polling(sc->sc_udev, 1);
     240           0 :                 sc->sc_xfer_flags = USBD_SYNCHRONOUS;
     241           0 :                 sc->polled_xfer_status = USBD_INVAL;
     242           0 :                 sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen,
     243           0 :                                           xs->data, xs->datalen, dir,
     244           0 :                                           xs->timeout, umass_scsi_cb, xs);
     245           0 :                 sc->sc_xfer_flags = 0;
     246             :                 DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n",
     247             :                                       sc->polled_xfer_status));
     248           0 :                 usbd_set_polling(sc->sc_udev, 0);
     249             :                 /* scsi_done() has already been called. */
     250           0 :                 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           0 :                 sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen,
     257           0 :                                           xs->data, xs->datalen, dir,
     258           0 :                                           xs->timeout, umass_scsi_cb, xs);
     259             :                 /* scsi_done() has already been called. */
     260           0 :                 return;
     261             :         }
     262             : 
     263             :         /* Return if command finishes early. */
     264             :  done:
     265           0 :         scsi_done(xs);
     266           0 : }
     267             : 
     268             : void
     269           0 : umass_scsi_minphys(struct buf *bp, struct scsi_link *sl)
     270             : {
     271           0 :         if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE)
     272           0 :                 bp->b_bcount = UMASS_MAX_TRANSFER_SIZE;
     273             : 
     274           0 :         minphys(bp);
     275           0 : }
     276             : 
     277             : void
     278           0 : umass_scsi_cb(struct umass_softc *sc, void *priv, int residue, int status)
     279             : {
     280           0 :         struct umass_scsi_softc *scbus = sc->bus;
     281           0 :         struct scsi_xfer *xs = priv;
     282           0 :         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           0 :         xs->resid = residue;
     298             : 
     299           0 :         switch (status) {
     300             :         case STATUS_CMD_OK:
     301           0 :                 xs->error = XS_NOERROR;
     302           0 :                 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           0 :                 if (xs->sc_link->quirks & ADEV_NOSENSE) {
     308             :                         /*
     309             :                          * If no residue and no other USB error,
     310             :                          * command succeeded.
     311             :                          */
     312           0 :                         if (residue == 0) {
     313           0 :                                 xs->error = XS_NOERROR;
     314           0 :                                 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           0 :                         if (xs->cmd->opcode == INQUIRY &&
     323           0 :                             residue < xs->datalen) {
     324           0 :                                 xs->error = XS_NOERROR;
     325           0 :                                 break;
     326             :                         }
     327             : 
     328           0 :                         xs->error = XS_DRIVER_STUFFUP;
     329           0 :                         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           0 :                 sc->sc_sense = 1;
     337           0 :                 memset(&scbus->sc_sense_cmd, 0, sizeof(scbus->sc_sense_cmd));
     338           0 :                 scbus->sc_sense_cmd.opcode = REQUEST_SENSE;
     339           0 :                 scbus->sc_sense_cmd.byte2 = link->lun << SCSI_CMD_LUN_SHIFT;
     340           0 :                 scbus->sc_sense_cmd.length = sizeof(xs->sense);
     341             : 
     342             :                 cmdlen = sizeof(scbus->sc_sense_cmd);
     343           0 :                 if (xs->flags & SCSI_POLL) {
     344           0 :                         usbd_set_polling(sc->sc_udev, 1);
     345           0 :                         sc->sc_xfer_flags = USBD_SYNCHRONOUS;
     346           0 :                         sc->polled_xfer_status = USBD_INVAL;
     347           0 :                 }
     348             :                 /* scsi_done() has already been called. */
     349           0 :                 sc->sc_methods->wire_xfer(sc, link->lun,
     350             :                                           &scbus->sc_sense_cmd, cmdlen,
     351           0 :                                           &xs->sense, sizeof(xs->sense),
     352           0 :                                           DIR_IN, xs->timeout,
     353             :                                           umass_scsi_sense_cb, xs);
     354           0 :                 if (xs->flags & SCSI_POLL) {
     355           0 :                         sc->sc_xfer_flags = 0;
     356           0 :                         usbd_set_polling(sc->sc_udev, 0);
     357           0 :                 }
     358           0 :                 return;
     359             : 
     360             :         case STATUS_WIRE_FAILED:
     361           0 :                 xs->error = XS_RESET;
     362           0 :                 break;
     363             : 
     364             :         default:
     365           0 :                 panic("%s: Unknown status %d in umass_scsi_cb",
     366           0 :                       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           0 :         if ((xs->flags & SCSI_POLL) && (xs->error == XS_NOERROR)) {
     375           0 :                 switch (sc->polled_xfer_status) {
     376             :                 case USBD_NORMAL_COMPLETION:
     377           0 :                         xs->error = XS_NOERROR;
     378           0 :                         break;
     379             :                 case USBD_TIMEOUT:
     380           0 :                         xs->error = XS_TIMEOUT;
     381           0 :                         break;
     382             :                 default:
     383           0 :                         xs->error = XS_DRIVER_STUFFUP;
     384           0 :                         break;
     385             :                 }
     386             :         }
     387             : 
     388           0 :         scsi_done(xs);
     389           0 : }
     390             : 
     391             : /*
     392             :  * Finalise a completed autosense operation
     393             :  */
     394             : void
     395           0 : umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue,
     396             :                     int status)
     397             : {
     398           0 :         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           0 :         sc->sc_sense = 0;
     404           0 :         switch (status) {
     405             :         case STATUS_CMD_OK:
     406             :         case STATUS_CMD_UNKNOWN:
     407             :                 /* getting sense data succeeded */
     408           0 :                 if (residue == 0 || residue == 14)/* XXX */
     409           0 :                         xs->error = XS_SENSE;
     410             :                 else
     411           0 :                         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           0 :                 xs->error = XS_DRIVER_STUFFUP;
     417           0 :                 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           0 :         if ((xs->flags & SCSI_POLL) && (xs->error == XS_NOERROR)) {
     425           0 :                 switch (sc->polled_xfer_status) {
     426             :                 case USBD_NORMAL_COMPLETION:
     427           0 :                         xs->error = XS_NOERROR;
     428           0 :                         break;
     429             :                 case USBD_TIMEOUT:
     430           0 :                         xs->error = XS_TIMEOUT;
     431           0 :                         break;
     432             :                 default:
     433           0 :                         xs->error = XS_DRIVER_STUFFUP;
     434           0 :                         break;
     435             :                 }
     436             :         }
     437             : 
     438           0 :         scsi_done(xs);
     439           0 : }
     440             : 
     441             : void *
     442           0 : umass_io_get(void *cookie)
     443             : {
     444           0 :         struct umass_scsi_softc *scbus = cookie;
     445             :         void *io = NULL;
     446             :         int s;
     447             : 
     448           0 :         s = splusb();
     449           0 :         if (!scbus->sc_open) {
     450           0 :                 scbus->sc_open = 1;
     451             :                 io = scbus; /* just has to be non-NULL */
     452           0 :         }
     453           0 :         splx(s);
     454             : 
     455           0 :         return (io);
     456             : }
     457             : 
     458             : void
     459           0 : umass_io_put(void *cookie, void *io)
     460             : {
     461           0 :         struct umass_scsi_softc *scbus = cookie;
     462             :         int s;
     463             : 
     464           0 :         s = splusb();
     465           0 :         scbus->sc_open = 0;
     466           0 :         splx(s);
     467           0 : }

Generated by: LCOV version 1.13