The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/storage/cfumass.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2016 The FreeBSD Foundation
    5  *
    6  * This software was developed by Edward Tomasz Napierala under sponsorship
    7  * from the FreeBSD Foundation.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  *
   30  */
   31 /*
   32  * USB Mass Storage Class Bulk-Only (BBB) Transport target.
   33  *
   34  * http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf
   35  *
   36  * This code implements the USB Mass Storage frontend driver for the CAM
   37  * Target Layer (ctl(4)) subsystem.
   38  */
   39 
   40 #include <sys/cdefs.h>
   41 __FBSDID("$FreeBSD$");
   42 
   43 #include <sys/param.h>
   44 #include <sys/bus.h>
   45 #include <sys/kernel.h>
   46 #include <sys/lock.h>
   47 #include <sys/module.h>
   48 #include <sys/mutex.h>
   49 #include <sys/refcount.h>
   50 #include <sys/stdint.h>
   51 #include <sys/sysctl.h>
   52 #include <sys/systm.h>
   53 
   54 #include <dev/usb/usb.h>
   55 #include <dev/usb/usbdi.h>
   56 #include "usbdevs.h"
   57 #include "usb_if.h"
   58 
   59 #include <cam/scsi/scsi_all.h>
   60 #include <cam/scsi/scsi_da.h>
   61 #include <cam/ctl/ctl_io.h>
   62 #include <cam/ctl/ctl.h>
   63 #include <cam/ctl/ctl_backend.h>
   64 #include <cam/ctl/ctl_error.h>
   65 #include <cam/ctl/ctl_frontend.h>
   66 #include <cam/ctl/ctl_debug.h>
   67 #include <cam/ctl/ctl_ha.h>
   68 #include <cam/ctl/ctl_ioctl.h>
   69 #include <cam/ctl/ctl_private.h>
   70 
   71 SYSCTL_NODE(_hw_usb, OID_AUTO, cfumass, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
   72     "CAM Target Layer USB Mass Storage Frontend");
   73 static int debug = 1;
   74 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, debug, CTLFLAG_RWTUN,
   75     &debug, 1, "Enable debug messages");
   76 static int max_lun = 0;
   77 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, max_lun, CTLFLAG_RWTUN,
   78     &max_lun, 1, "Maximum advertised LUN number");
   79 static int ignore_stop = 1;
   80 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, ignore_stop, CTLFLAG_RWTUN,
   81     &ignore_stop, 1, "Ignore START STOP UNIT with START and LOEJ bits cleared");
   82 
   83 /*
   84  * The driver uses a single, global CTL port.  It could create its ports
   85  * in cfumass_attach() instead, but that would make it impossible to specify
   86  * "port cfumass0" in ctl.conf(5), as the port generally wouldn't exist
   87  * at the time ctld(8) gets run.
   88  */
   89 struct ctl_port cfumass_port;
   90 bool            cfumass_port_online;
   91 volatile u_int  cfumass_refcount;
   92 
   93 #ifndef CFUMASS_BULK_SIZE 
   94 #define CFUMASS_BULK_SIZE       (1U << 17)      /* bytes */
   95 #endif
   96 
   97 /*
   98  * USB transfer definitions.
   99  */
  100 #define CFUMASS_T_COMMAND       0
  101 #define CFUMASS_T_DATA_OUT      1
  102 #define CFUMASS_T_DATA_IN       2
  103 #define CFUMASS_T_STATUS        3
  104 #define CFUMASS_T_MAX           4
  105 
  106 /*
  107  * USB interface specific control requests.
  108  */
  109 #define UR_RESET        0xff    /* Bulk-Only Mass Storage Reset */
  110 #define UR_GET_MAX_LUN  0xfe    /* Get Max LUN */
  111 
  112 /*
  113  * Command Block Wrapper.
  114  */
  115 struct cfumass_cbw_t {
  116         uDWord  dCBWSignature;
  117 #define CBWSIGNATURE            0x43425355 /* "USBC" */
  118         uDWord  dCBWTag;
  119         uDWord  dCBWDataTransferLength;
  120         uByte   bCBWFlags;
  121 #define CBWFLAGS_OUT            0x00
  122 #define CBWFLAGS_IN             0x80
  123         uByte   bCBWLUN;
  124         uByte   bCDBLength;
  125 #define CBWCBLENGTH             16
  126         uByte   CBWCB[CBWCBLENGTH];
  127 } __packed;
  128 
  129 #define CFUMASS_CBW_SIZE        31
  130 CTASSERT(sizeof(struct cfumass_cbw_t) == CFUMASS_CBW_SIZE);
  131 
  132 /*
  133  * Command Status Wrapper.
  134  */
  135 struct cfumass_csw_t {
  136         uDWord  dCSWSignature;
  137 #define CSWSIGNATURE            0x53425355 /* "USBS" */
  138         uDWord  dCSWTag;
  139         uDWord  dCSWDataResidue;
  140         uByte   bCSWStatus;
  141 #define CSWSTATUS_GOOD          0x0
  142 #define CSWSTATUS_FAILED        0x1
  143 #define CSWSTATUS_PHASE         0x2
  144 } __packed;
  145 
  146 #define CFUMASS_CSW_SIZE        13
  147 CTASSERT(sizeof(struct cfumass_csw_t) == CFUMASS_CSW_SIZE);
  148 
  149 struct cfumass_softc {
  150         device_t                sc_dev;
  151         struct usb_device       *sc_udev;
  152         struct usb_xfer         *sc_xfer[CFUMASS_T_MAX];
  153 
  154         struct cfumass_cbw_t *sc_cbw;
  155         struct cfumass_csw_t *sc_csw;
  156 
  157         struct mtx      sc_mtx;
  158         int             sc_online;
  159         int             sc_ctl_initid;
  160 
  161         /*
  162          * This is used to communicate between CTL callbacks
  163          * and USB callbacks; basically, it holds the state
  164          * for the current command ("the" command, since there
  165          * is no queueing in USB Mass Storage).
  166          */
  167         bool            sc_current_stalled;
  168 
  169         /*
  170          * The following are set upon receiving a SCSI command.
  171          */
  172         int             sc_current_tag;
  173         int             sc_current_transfer_length;
  174         int             sc_current_flags;
  175 
  176         /*
  177          * The following are set in ctl_datamove().
  178          */
  179         int             sc_current_residue;
  180         union ctl_io    *sc_ctl_io;
  181 
  182         /*
  183          * The following is set in cfumass_done().
  184          */
  185         int             sc_current_status;
  186 
  187         /*
  188          * Number of requests queued to CTL.
  189          */
  190         volatile u_int  sc_queued;
  191 };
  192 
  193 /*
  194  * USB interface.
  195  */
  196 static device_probe_t           cfumass_probe;
  197 static device_attach_t          cfumass_attach;
  198 static device_detach_t          cfumass_detach;
  199 static device_suspend_t         cfumass_suspend;
  200 static device_resume_t          cfumass_resume;
  201 static usb_handle_request_t     cfumass_handle_request;
  202 
  203 static usb_callback_t           cfumass_t_command_callback;
  204 static usb_callback_t           cfumass_t_data_callback;
  205 static usb_callback_t           cfumass_t_status_callback;
  206 
  207 static device_method_t cfumass_methods[] = {
  208         /* USB interface. */
  209         DEVMETHOD(usb_handle_request, cfumass_handle_request),
  210 
  211         /* Device interface. */
  212         DEVMETHOD(device_probe, cfumass_probe),
  213         DEVMETHOD(device_attach, cfumass_attach),
  214         DEVMETHOD(device_detach, cfumass_detach),
  215         DEVMETHOD(device_suspend, cfumass_suspend),
  216         DEVMETHOD(device_resume, cfumass_resume),
  217 
  218         DEVMETHOD_END
  219 };
  220 
  221 static driver_t cfumass_driver = {
  222         .name = "cfumass",
  223         .methods = cfumass_methods,
  224         .size = sizeof(struct cfumass_softc),
  225 };
  226 
  227 DRIVER_MODULE(cfumass, uhub, cfumass_driver, NULL, NULL);
  228 MODULE_VERSION(cfumass, 0);
  229 MODULE_DEPEND(cfumass, usb, 1, 1, 1);
  230 MODULE_DEPEND(cfumass, usb_template, 1, 1, 1);
  231 
  232 static struct usb_config cfumass_config[CFUMASS_T_MAX] = {
  233         [CFUMASS_T_COMMAND] = {
  234                 .type = UE_BULK,
  235                 .endpoint = UE_ADDR_ANY,
  236                 .direction = UE_DIR_OUT,
  237                 .bufsize = sizeof(struct cfumass_cbw_t),
  238                 .callback = &cfumass_t_command_callback,
  239                 .usb_mode = USB_MODE_DEVICE,
  240         },
  241 
  242         [CFUMASS_T_DATA_OUT] = {
  243                 .type = UE_BULK,
  244                 .endpoint = UE_ADDR_ANY,
  245                 .direction = UE_DIR_OUT,
  246                 .bufsize = CFUMASS_BULK_SIZE,
  247                 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
  248                     .ext_buffer = 1},
  249                 .callback = &cfumass_t_data_callback,
  250                 .usb_mode = USB_MODE_DEVICE,
  251         },
  252 
  253         [CFUMASS_T_DATA_IN] = {
  254                 .type = UE_BULK,
  255                 .endpoint = UE_ADDR_ANY,
  256                 .direction = UE_DIR_IN,
  257                 .bufsize = CFUMASS_BULK_SIZE,
  258                 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
  259                     .ext_buffer = 1},
  260                 .callback = &cfumass_t_data_callback,
  261                 .usb_mode = USB_MODE_DEVICE,
  262         },
  263 
  264         [CFUMASS_T_STATUS] = {
  265                 .type = UE_BULK,
  266                 .endpoint = UE_ADDR_ANY,
  267                 .direction = UE_DIR_IN,
  268                 .bufsize = sizeof(struct cfumass_csw_t),
  269                 .flags = {.short_xfer_ok = 1},
  270                 .callback = &cfumass_t_status_callback,
  271                 .usb_mode = USB_MODE_DEVICE,
  272         },
  273 };
  274 
  275 /*
  276  * CTL frontend interface.
  277  */
  278 static int      cfumass_init(void);
  279 static int      cfumass_shutdown(void);
  280 static void     cfumass_online(void *arg);
  281 static void     cfumass_offline(void *arg);
  282 static void     cfumass_datamove(union ctl_io *io);
  283 static void     cfumass_done(union ctl_io *io);
  284 
  285 static struct ctl_frontend cfumass_frontend = {
  286         .name = "umass",
  287         .init = cfumass_init,
  288         .shutdown = cfumass_shutdown,
  289 };
  290 CTL_FRONTEND_DECLARE(ctlcfumass, cfumass_frontend);
  291 
  292 #define CFUMASS_DEBUG(S, X, ...)                                        \
  293         do {                                                            \
  294                 if (debug > 1) {                                        \
  295                         device_printf(S->sc_dev, "%s: " X "\n",         \
  296                             __func__, ## __VA_ARGS__);                  \
  297                 }                                                       \
  298         } while (0)
  299 
  300 #define CFUMASS_WARN(S, X, ...)                                         \
  301         do {                                                            \
  302                 if (debug > 0) {                                        \
  303                         device_printf(S->sc_dev, "WARNING: %s: " X "\n",\
  304                             __func__, ## __VA_ARGS__);                  \
  305                 }                                                       \
  306         } while (0)
  307 
  308 #define CFUMASS_LOCK(X)         mtx_lock(&X->sc_mtx)
  309 #define CFUMASS_UNLOCK(X)       mtx_unlock(&X->sc_mtx)
  310 
  311 static void     cfumass_transfer_start(struct cfumass_softc *sc,
  312                     uint8_t xfer_index);
  313 static void     cfumass_terminate(struct cfumass_softc *sc);
  314 
  315 static int
  316 cfumass_probe(device_t dev)
  317 {
  318         struct usb_attach_arg *uaa;
  319         struct usb_interface_descriptor *id;
  320 
  321         uaa = device_get_ivars(dev);
  322 
  323         if (uaa->usb_mode != USB_MODE_DEVICE)
  324                 return (ENXIO);
  325 
  326         /*
  327          * Check for a compliant device.
  328          */
  329         id = usbd_get_interface_descriptor(uaa->iface);
  330         if ((id == NULL) ||
  331             (id->bInterfaceClass != UICLASS_MASS) ||
  332             (id->bInterfaceSubClass != UISUBCLASS_SCSI) ||
  333             (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) {
  334                 return (ENXIO);
  335         }
  336 
  337         return (BUS_PROBE_GENERIC);
  338 }
  339 
  340 static int
  341 cfumass_attach(device_t dev)
  342 {
  343         struct cfumass_softc *sc;
  344         struct usb_attach_arg *uaa;
  345         int error;
  346 
  347         sc = device_get_softc(dev);
  348         uaa = device_get_ivars(dev);
  349 
  350         sc->sc_dev = dev;
  351         sc->sc_udev = uaa->device;
  352 
  353         CFUMASS_DEBUG(sc, "go");
  354 
  355         usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE);
  356         device_set_usb_desc(dev);
  357 
  358         mtx_init(&sc->sc_mtx, "cfumass", NULL, MTX_DEF);
  359         refcount_acquire(&cfumass_refcount);
  360 
  361         error = usbd_transfer_setup(uaa->device,
  362             &uaa->info.bIfaceIndex, sc->sc_xfer, cfumass_config,
  363             CFUMASS_T_MAX, sc, &sc->sc_mtx);
  364         if (error != 0) {
  365                 CFUMASS_WARN(sc, "usbd_transfer_setup() failed: %s",
  366                     usbd_errstr(error));
  367                 refcount_release(&cfumass_refcount);
  368                 return (ENXIO);
  369         }
  370 
  371         sc->sc_cbw =
  372             usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_COMMAND], 0);
  373         sc->sc_csw =
  374             usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_STATUS], 0);
  375 
  376         sc->sc_ctl_initid = ctl_add_initiator(&cfumass_port, -1, 0, NULL);
  377         if (sc->sc_ctl_initid < 0) {
  378                 CFUMASS_WARN(sc, "ctl_add_initiator() failed with error %d",
  379                     sc->sc_ctl_initid);
  380                 usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX);
  381                 refcount_release(&cfumass_refcount);
  382                 return (ENXIO);
  383         }
  384 
  385         refcount_init(&sc->sc_queued, 0);
  386 
  387         CFUMASS_LOCK(sc);
  388         cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
  389         CFUMASS_UNLOCK(sc);
  390 
  391         return (0);
  392 }
  393 
  394 static int
  395 cfumass_detach(device_t dev)
  396 {
  397         struct cfumass_softc *sc;
  398         int error;
  399 
  400         sc = device_get_softc(dev);
  401 
  402         CFUMASS_DEBUG(sc, "go");
  403 
  404         CFUMASS_LOCK(sc);
  405         cfumass_terminate(sc);
  406         CFUMASS_UNLOCK(sc);
  407         usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX);
  408 
  409         if (sc->sc_ctl_initid != -1) {
  410                 error = ctl_remove_initiator(&cfumass_port, sc->sc_ctl_initid);
  411                 if (error != 0) {
  412                         CFUMASS_WARN(sc, "ctl_remove_initiator() failed "
  413                             "with error %d", error);
  414                 }
  415                 sc->sc_ctl_initid = -1;
  416         }
  417 
  418         mtx_destroy(&sc->sc_mtx);
  419         refcount_release(&cfumass_refcount);
  420 
  421         return (0);
  422 }
  423 
  424 static int
  425 cfumass_suspend(device_t dev)
  426 {
  427         struct cfumass_softc *sc;
  428 
  429         sc = device_get_softc(dev);
  430         CFUMASS_DEBUG(sc, "go");
  431 
  432         return (0);
  433 }
  434 
  435 static int
  436 cfumass_resume(device_t dev)
  437 {
  438         struct cfumass_softc *sc;
  439 
  440         sc = device_get_softc(dev);
  441         CFUMASS_DEBUG(sc, "go");
  442 
  443         return (0);
  444 }
  445 
  446 static void
  447 cfumass_transfer_start(struct cfumass_softc *sc, uint8_t xfer_index)
  448 {
  449 
  450         usbd_transfer_start(sc->sc_xfer[xfer_index]);
  451 }
  452 
  453 static void
  454 cfumass_transfer_stop_and_drain(struct cfumass_softc *sc, uint8_t xfer_index)
  455 {
  456 
  457         usbd_transfer_stop(sc->sc_xfer[xfer_index]);
  458         CFUMASS_UNLOCK(sc);
  459         usbd_transfer_drain(sc->sc_xfer[xfer_index]);
  460         CFUMASS_LOCK(sc);
  461 }
  462 
  463 static void
  464 cfumass_terminate(struct cfumass_softc *sc)
  465 {
  466         int last;
  467 
  468         for (;;) {
  469                 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_COMMAND);
  470                 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_DATA_IN);
  471                 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_DATA_OUT);
  472 
  473                 if (sc->sc_ctl_io != NULL) {
  474                         CFUMASS_DEBUG(sc, "terminating CTL transfer");
  475                         ctl_set_data_phase_error(&sc->sc_ctl_io->scsiio);
  476                         ctl_datamove_done(sc->sc_ctl_io, false);
  477                         sc->sc_ctl_io = NULL;
  478                 }
  479 
  480                 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_STATUS);
  481 
  482                 refcount_acquire(&sc->sc_queued);
  483                 last = refcount_release(&sc->sc_queued);
  484                 if (last != 0)
  485                         break;
  486 
  487                 CFUMASS_DEBUG(sc, "%d CTL tasks pending", sc->sc_queued);
  488                 msleep(__DEVOLATILE(void *, &sc->sc_queued), &sc->sc_mtx,
  489                     0, "cfumass_reset", hz / 100);
  490         }
  491 }
  492 
  493 static int
  494 cfumass_handle_request(device_t dev,
  495     const void *preq, void **pptr, uint16_t *plen,
  496     uint16_t offset, uint8_t *pstate)
  497 {
  498         static uint8_t max_lun_tmp;
  499         struct cfumass_softc *sc;
  500         const struct usb_device_request *req;
  501         uint8_t is_complete;
  502 
  503         sc = device_get_softc(dev);
  504         req = preq;
  505         is_complete = *pstate;
  506 
  507         CFUMASS_DEBUG(sc, "go");
  508 
  509         if (is_complete)
  510                 return (ENXIO);
  511 
  512         if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
  513             (req->bRequest == UR_RESET)) {
  514                 CFUMASS_WARN(sc, "received Bulk-Only Mass Storage Reset");
  515                 *plen = 0;
  516 
  517                 CFUMASS_LOCK(sc);
  518                 cfumass_terminate(sc);
  519                 cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
  520                 CFUMASS_UNLOCK(sc);
  521 
  522                 CFUMASS_DEBUG(sc, "Bulk-Only Mass Storage Reset done");
  523                 return (0);
  524         }
  525 
  526         if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
  527             (req->bRequest == UR_GET_MAX_LUN)) {
  528                 CFUMASS_DEBUG(sc, "received Get Max LUN");
  529                 if (offset == 0) {
  530                         *plen = 1;
  531                         /*
  532                          * The protocol doesn't support LUN numbers higher
  533                          * than 15.  Also, some initiators (namely Windows XP
  534                          * SP3 Version 2002) can't properly query the number
  535                          * of LUNs, resulting in inaccessible "fake" ones - thus
  536                          * the default limit of one LUN.
  537                          */
  538                         if (max_lun < 0 || max_lun > 15) {
  539                                 CFUMASS_WARN(sc,
  540                                     "invalid hw.usb.cfumass.max_lun, must be "
  541                                     "between 0 and 15; defaulting to 0");
  542                                 max_lun_tmp = 0;
  543                         } else {
  544                                 max_lun_tmp = max_lun;
  545                         }
  546                         *pptr = &max_lun_tmp;
  547                 } else {
  548                         *plen = 0;
  549                 }
  550                 return (0);
  551         }
  552 
  553         return (ENXIO);
  554 }
  555 
  556 static int
  557 cfumass_quirk(struct cfumass_softc *sc, unsigned char *cdb, int cdb_len)
  558 {
  559         struct scsi_start_stop_unit *sssu;
  560 
  561         switch (cdb[0]) {
  562         case START_STOP_UNIT:
  563                 /*
  564                  * Some initiators - eg OSX, Darwin Kernel Version 15.6.0,
  565                  * root:xnu-3248.60.11~2/RELEASE_X86_64 - attempt to stop
  566                  * the unit on eject, but fail to start it when it's plugged
  567                  * back.  Just ignore the command.
  568                  */
  569 
  570                 if (cdb_len < sizeof(*sssu)) {
  571                         CFUMASS_DEBUG(sc, "received START STOP UNIT with "
  572                             "bCDBLength %d, should be %zd",
  573                             cdb_len, sizeof(*sssu));
  574                         break;
  575                 }
  576 
  577                 sssu = (struct scsi_start_stop_unit *)cdb;
  578                 if ((sssu->how & SSS_PC_MASK) != 0)
  579                         break;
  580 
  581                 if ((sssu->how & SSS_START) != 0)
  582                         break;
  583 
  584                 if ((sssu->how & SSS_LOEJ) != 0)
  585                         break;
  586                 
  587                 if (ignore_stop == 0) {
  588                         break;
  589                 } else if (ignore_stop == 1) {
  590                         CFUMASS_WARN(sc, "ignoring START STOP UNIT request");
  591                 } else {
  592                         CFUMASS_DEBUG(sc, "ignoring START STOP UNIT request");
  593                 }
  594 
  595                 sc->sc_current_status = 0;
  596                 cfumass_transfer_start(sc, CFUMASS_T_STATUS);
  597 
  598                 return (1);
  599         default:
  600                 break;
  601         }
  602 
  603         return (0);
  604 }
  605 
  606 static void
  607 cfumass_t_command_callback(struct usb_xfer *xfer, usb_error_t usb_error)
  608 {
  609         struct cfumass_softc *sc;
  610         uint32_t signature;
  611         union ctl_io *io;
  612         int error = 0;
  613 
  614         sc = usbd_xfer_softc(xfer);
  615 
  616         KASSERT(sc->sc_ctl_io == NULL,
  617             ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
  618 
  619         switch (USB_GET_STATE(xfer)) {
  620         case USB_ST_TRANSFERRED:
  621                 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
  622 
  623                 signature = UGETDW(sc->sc_cbw->dCBWSignature);
  624                 if (signature != CBWSIGNATURE) {
  625                         CFUMASS_WARN(sc, "wrong dCBWSignature 0x%08x, "
  626                             "should be 0x%08x", signature, CBWSIGNATURE);
  627                         break;
  628                 }
  629 
  630                 if (sc->sc_cbw->bCDBLength <= 0 ||
  631                     sc->sc_cbw->bCDBLength > sizeof(sc->sc_cbw->CBWCB)) {
  632                         CFUMASS_WARN(sc, "invalid bCDBLength %d, should be <= %zd",
  633                             sc->sc_cbw->bCDBLength, sizeof(sc->sc_cbw->CBWCB));
  634                         break;
  635                 }
  636 
  637                 sc->sc_current_stalled = false;
  638                 sc->sc_current_status = 0;
  639                 sc->sc_current_tag = UGETDW(sc->sc_cbw->dCBWTag);
  640                 sc->sc_current_transfer_length =
  641                     UGETDW(sc->sc_cbw->dCBWDataTransferLength);
  642                 sc->sc_current_flags = sc->sc_cbw->bCBWFlags;
  643 
  644                 /*
  645                  * Make sure to report proper residue if the datamove wasn't
  646                  * required, or wasn't called due to SCSI error.
  647                  */
  648                 sc->sc_current_residue = sc->sc_current_transfer_length;
  649 
  650                 if (cfumass_quirk(sc,
  651                     sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength) != 0)
  652                         break;
  653 
  654                 if (!cfumass_port_online) {
  655                         CFUMASS_DEBUG(sc, "cfumass port is offline; stalling");
  656                         usbd_xfer_set_stall(xfer);
  657                         break;
  658                 }
  659 
  660                 /*
  661                  * Those CTL functions cannot be called with mutex held.
  662                  */
  663                 CFUMASS_UNLOCK(sc);
  664                 io = ctl_alloc_io(cfumass_port.ctl_pool_ref);
  665                 ctl_zero_io(io);
  666                 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = sc;
  667                 io->io_hdr.io_type = CTL_IO_SCSI;
  668                 io->io_hdr.nexus.initid = sc->sc_ctl_initid;
  669                 io->io_hdr.nexus.targ_port = cfumass_port.targ_port;
  670                 io->io_hdr.nexus.targ_lun = ctl_decode_lun(sc->sc_cbw->bCBWLUN);
  671                 io->scsiio.tag_num = UGETDW(sc->sc_cbw->dCBWTag);
  672                 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
  673                 io->scsiio.cdb_len = sc->sc_cbw->bCDBLength;
  674                 memcpy(io->scsiio.cdb, sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength);
  675                 refcount_acquire(&sc->sc_queued);
  676                 error = ctl_queue(io);
  677                 if (error != CTL_RETVAL_COMPLETE) {
  678                         CFUMASS_WARN(sc,
  679                             "ctl_queue() failed; error %d; stalling", error);
  680                         ctl_free_io(io);
  681                         refcount_release(&sc->sc_queued);
  682                         CFUMASS_LOCK(sc);
  683                         usbd_xfer_set_stall(xfer);
  684                         break;
  685                 }
  686 
  687                 CFUMASS_LOCK(sc);
  688                 break;
  689 
  690         case USB_ST_SETUP:
  691 tr_setup:
  692                 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
  693 
  694                 usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_cbw));
  695                 usbd_transfer_submit(xfer);
  696                 break;
  697 
  698         default:
  699                 if (usb_error == USB_ERR_CANCELLED) {
  700                         CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
  701                         break;
  702                 }
  703 
  704                 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
  705 
  706                 goto tr_setup;
  707         }
  708 }
  709 
  710 static void
  711 cfumass_t_data_callback(struct usb_xfer *xfer, usb_error_t usb_error)
  712 {
  713         struct cfumass_softc *sc = usbd_xfer_softc(xfer);
  714         union ctl_io *io = sc->sc_ctl_io;
  715         uint32_t max_bulk;
  716         struct ctl_sg_entry sg_entry, *sglist;
  717         int actlen, sumlen, sg_count;
  718 
  719         switch (USB_GET_STATE(xfer)) {
  720         case USB_ST_TRANSFERRED:
  721                 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
  722 
  723                 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
  724                 sc->sc_current_residue -= actlen;
  725                 io->scsiio.ext_data_filled += actlen;
  726                 io->scsiio.kern_data_resid -= actlen;
  727                 if (actlen < sumlen ||
  728                     sc->sc_current_residue == 0 ||
  729                     io->scsiio.kern_data_resid == 0) {
  730                         sc->sc_ctl_io = NULL;
  731                         ctl_datamove_done(io, false);
  732                         break;
  733                 }
  734                 /* FALLTHROUGH */
  735 
  736         case USB_ST_SETUP:
  737 tr_setup:
  738                 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
  739 
  740                 if (io->scsiio.kern_sg_entries > 0) {
  741                         sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
  742                         sg_count = io->scsiio.kern_sg_entries;
  743                 } else {
  744                         sglist = &sg_entry;
  745                         sglist->addr = io->scsiio.kern_data_ptr;
  746                         sglist->len = io->scsiio.kern_data_len;
  747                         sg_count = 1;
  748                 }
  749 
  750                 sumlen = io->scsiio.ext_data_filled -
  751                     io->scsiio.kern_rel_offset;
  752                 while (sumlen >= sglist->len && sg_count > 0) {
  753                         sumlen -= sglist->len;
  754                         sglist++;
  755                         sg_count--;
  756                 }
  757                 KASSERT(sg_count > 0, ("Run out of S/G list entries"));
  758 
  759                 max_bulk = usbd_xfer_max_len(xfer);
  760                 actlen = min(sglist->len - sumlen, max_bulk);
  761                 actlen = min(actlen, sc->sc_current_transfer_length -
  762                     io->scsiio.ext_data_filled);
  763                 CFUMASS_DEBUG(sc, "requested %d, done %d, max_bulk %d, "
  764                     "segment %zd => transfer %d",
  765                     sc->sc_current_transfer_length, io->scsiio.ext_data_filled,
  766                     max_bulk, sglist->len - sumlen, actlen);
  767 
  768                 usbd_xfer_set_frame_data(xfer, 0,
  769                     (uint8_t *)sglist->addr + sumlen, actlen);
  770                 usbd_transfer_submit(xfer);
  771                 break;
  772 
  773         default:
  774                 if (usb_error == USB_ERR_CANCELLED) {
  775                         CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
  776                         break;
  777                 }
  778                 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
  779                 goto tr_setup;
  780         }
  781 }
  782 
  783 static void
  784 cfumass_t_status_callback(struct usb_xfer *xfer, usb_error_t usb_error)
  785 {
  786         struct cfumass_softc *sc;
  787 
  788         sc = usbd_xfer_softc(xfer);
  789 
  790         KASSERT(sc->sc_ctl_io == NULL,
  791             ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
  792 
  793         switch (USB_GET_STATE(xfer)) {
  794         case USB_ST_TRANSFERRED:
  795                 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
  796 
  797                 cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
  798                 break;
  799 
  800         case USB_ST_SETUP:
  801 tr_setup:
  802                 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
  803 
  804                 if (sc->sc_current_residue > 0 && !sc->sc_current_stalled) {
  805                         CFUMASS_DEBUG(sc, "non-zero residue, stalling");
  806                         usbd_xfer_set_stall(xfer);
  807                         sc->sc_current_stalled = true;
  808                 }
  809 
  810                 USETDW(sc->sc_csw->dCSWSignature, CSWSIGNATURE);
  811                 USETDW(sc->sc_csw->dCSWTag, sc->sc_current_tag);
  812                 USETDW(sc->sc_csw->dCSWDataResidue, sc->sc_current_residue);
  813                 sc->sc_csw->bCSWStatus = sc->sc_current_status;
  814 
  815                 usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_csw));
  816                 usbd_transfer_submit(xfer);
  817                 break;
  818 
  819         default:
  820                 if (usb_error == USB_ERR_CANCELLED) {
  821                         CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
  822                         break;
  823                 }
  824 
  825                 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s",
  826                     usbd_errstr(usb_error));
  827 
  828                 goto tr_setup;
  829         }
  830 }
  831 
  832 static void
  833 cfumass_online(void *arg __unused)
  834 {
  835 
  836         cfumass_port_online = true;
  837 }
  838 
  839 static void
  840 cfumass_offline(void *arg __unused)
  841 {
  842 
  843         cfumass_port_online = false;
  844 }
  845 
  846 static void
  847 cfumass_datamove(union ctl_io *io)
  848 {
  849         struct cfumass_softc *sc;
  850 
  851         sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
  852 
  853         CFUMASS_DEBUG(sc, "go");
  854 
  855         CFUMASS_LOCK(sc);
  856 
  857         KASSERT(sc->sc_ctl_io == NULL,
  858             ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
  859         sc->sc_ctl_io = io;
  860 
  861         if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) {
  862                 /*
  863                  * Verify that CTL wants us to send the data in the direction
  864                  * expected by the initiator.
  865                  */
  866                 if (sc->sc_current_flags != CBWFLAGS_IN) {
  867                         CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x",
  868                             sc->sc_current_flags, CBWFLAGS_IN);
  869                         goto fail;
  870                 }
  871 
  872                 cfumass_transfer_start(sc, CFUMASS_T_DATA_IN);
  873         } else {
  874                 if (sc->sc_current_flags != CBWFLAGS_OUT) {
  875                         CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x",
  876                             sc->sc_current_flags, CBWFLAGS_OUT);
  877                         goto fail;
  878                 }
  879 
  880                 cfumass_transfer_start(sc, CFUMASS_T_DATA_OUT);
  881         }
  882 
  883         CFUMASS_UNLOCK(sc);
  884         return;
  885 
  886 fail:
  887         ctl_set_data_phase_error(&io->scsiio);
  888         ctl_datamove_done(io, true);
  889         sc->sc_ctl_io = NULL;
  890 }
  891 
  892 static void
  893 cfumass_done(union ctl_io *io)
  894 {
  895         struct cfumass_softc *sc;
  896 
  897         sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
  898 
  899         CFUMASS_DEBUG(sc, "go");
  900 
  901         KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
  902             ("invalid CTL status %#x", io->io_hdr.status));
  903         KASSERT(sc->sc_ctl_io == NULL,
  904             ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
  905 
  906         if (io->io_hdr.io_type == CTL_IO_TASK &&
  907             io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) {
  908                 /*
  909                  * Implicit task termination has just completed; nothing to do.
  910                  */
  911                 ctl_free_io(io);
  912                 return;
  913         }
  914 
  915         /*
  916          * Do not return status for aborted commands.
  917          * There are exceptions, but none supported by CTL yet.
  918          */
  919         if (((io->io_hdr.flags & CTL_FLAG_ABORT) &&
  920              (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) ||
  921             (io->io_hdr.flags & CTL_FLAG_STATUS_SENT)) {
  922                 ctl_free_io(io);
  923                 return;
  924         }
  925 
  926         if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)
  927                 sc->sc_current_status = 0;
  928         else
  929                 sc->sc_current_status = 1;
  930 
  931         /* XXX: How should we report BUSY, RESERVATION CONFLICT, etc? */
  932         if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR &&
  933             io->scsiio.scsi_status == SCSI_STATUS_CHECK_COND)
  934                 ctl_queue_sense(io);
  935         else
  936                 ctl_free_io(io);
  937 
  938         CFUMASS_LOCK(sc);
  939         cfumass_transfer_start(sc, CFUMASS_T_STATUS);
  940         CFUMASS_UNLOCK(sc);
  941 
  942         refcount_release(&sc->sc_queued);
  943 }
  944 
  945 int
  946 cfumass_init(void)
  947 {
  948         int error;
  949 
  950         cfumass_port.frontend = &cfumass_frontend;
  951         cfumass_port.port_type = CTL_PORT_UMASS;
  952         cfumass_port.num_requested_ctl_io = 1;
  953         cfumass_port.port_name = "cfumass";
  954         cfumass_port.physical_port = 0;
  955         cfumass_port.virtual_port = 0;
  956         cfumass_port.port_online = cfumass_online;
  957         cfumass_port.port_offline = cfumass_offline;
  958         cfumass_port.onoff_arg = NULL;
  959         cfumass_port.fe_datamove = cfumass_datamove;
  960         cfumass_port.fe_done = cfumass_done;
  961         cfumass_port.targ_port = -1;
  962 
  963         error = ctl_port_register(&cfumass_port);
  964         if (error != 0) {
  965                 printf("%s: ctl_port_register() failed "
  966                     "with error %d", __func__, error);
  967         }
  968 
  969         cfumass_port_online = true;
  970         refcount_init(&cfumass_refcount, 0);
  971 
  972         return (error);
  973 }
  974 
  975 int
  976 cfumass_shutdown(void)
  977 {
  978         int error;
  979 
  980         if (cfumass_refcount > 0) {
  981                 if (debug > 1) {
  982                         printf("%s: still have %u attachments; "
  983                             "returning EBUSY\n", __func__, cfumass_refcount);
  984                 }
  985                 return (EBUSY);
  986         }
  987 
  988         error = ctl_port_deregister(&cfumass_port);
  989         if (error != 0) {
  990                 printf("%s: ctl_port_deregister() failed "
  991                     "with error %d\n", __func__, error);
  992         }
  993 
  994         return (error);
  995 }

Cache object: 8986912077c57de3b1d203bf841ae385


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.