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/usb_msctest.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 /* $FreeBSD: releng/8.3/sys/dev/usb/usb_msctest.c 228229 2011-12-03 14:38:54Z hselasky $ */
    2 /*-
    3  * Copyright (c) 2008,2011 Hans Petter Selasky. All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * The following file contains code that will detect USB autoinstall
   29  * disks.
   30  *
   31  * TODO: Potentially we could add code to automatically detect USB
   32  * mass storage quirks for not supported SCSI commands!
   33  */
   34 
   35 #include <sys/stdint.h>
   36 #include <sys/stddef.h>
   37 #include <sys/param.h>
   38 #include <sys/queue.h>
   39 #include <sys/types.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/bus.h>
   43 #include <sys/module.h>
   44 #include <sys/lock.h>
   45 #include <sys/mutex.h>
   46 #include <sys/condvar.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/sx.h>
   49 #include <sys/unistd.h>
   50 #include <sys/callout.h>
   51 #include <sys/malloc.h>
   52 #include <sys/priv.h>
   53 
   54 #include <dev/usb/usb.h>
   55 #include <dev/usb/usbdi.h>
   56 #include <dev/usb/usbdi_util.h>
   57 
   58 #define USB_DEBUG_VAR usb_debug
   59 
   60 #include <dev/usb/usb_busdma.h>
   61 #include <dev/usb/usb_process.h>
   62 #include <dev/usb/usb_transfer.h>
   63 #include <dev/usb/usb_msctest.h>
   64 #include <dev/usb/usb_debug.h>
   65 #include <dev/usb/usb_busdma.h>
   66 #include <dev/usb/usb_device.h>
   67 #include <dev/usb/usb_request.h>
   68 #include <dev/usb/usb_util.h>
   69 #include <dev/usb/quirk/usb_quirk.h>
   70 
   71 enum {
   72         ST_COMMAND,
   73         ST_DATA_RD,
   74         ST_DATA_RD_CS,
   75         ST_DATA_WR,
   76         ST_DATA_WR_CS,
   77         ST_STATUS,
   78         ST_MAX,
   79 };
   80 
   81 enum {
   82         DIR_IN,
   83         DIR_OUT,
   84         DIR_NONE,
   85 };
   86 
   87 #define SCSI_MAX_LEN    0x100
   88 #define SCSI_INQ_LEN    0x24
   89 #define SCSI_SENSE_LEN  0xFF
   90 
   91 static uint8_t scsi_test_unit_ready[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
   92 static uint8_t scsi_inquiry[] = { 0x12, 0x00, 0x00, 0x00, SCSI_INQ_LEN, 0x00 };
   93 static uint8_t scsi_rezero_init[] =     { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
   94 static uint8_t scsi_start_stop_unit[] = { 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00 };
   95 static uint8_t scsi_ztestor_eject[] =   { 0x85, 0x01, 0x01, 0x01, 0x18, 0x01,
   96                                           0x01, 0x01, 0x01, 0x01, 0x00, 0x00 };
   97 static uint8_t scsi_cmotech_eject[] =   { 0xff, 0x52, 0x44, 0x45, 0x56, 0x43,
   98                                           0x48, 0x47 };
   99 static uint8_t scsi_huawei_eject[] =    { 0x11, 0x06, 0x00, 0x00, 0x00, 0x00,
  100                                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  101                                           0x00, 0x00, 0x00, 0x00 };
  102 static uint8_t scsi_tct_eject[] =       { 0x06, 0xf5, 0x04, 0x02, 0x52, 0x70 };
  103 static uint8_t scsi_sync_cache[] =      { 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
  104                                           0x00, 0x00, 0x00, 0x00 };
  105 static uint8_t scsi_request_sense[] =   { 0x03, 0x00, 0x00, 0x00, 0x12, 0x00,
  106                                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  107 
  108 #define BULK_SIZE               64      /* dummy */
  109 #define ERR_CSW_FAILED          -1
  110 
  111 /* Command Block Wrapper */
  112 struct bbb_cbw {
  113         uDWord  dCBWSignature;
  114 #define CBWSIGNATURE    0x43425355
  115         uDWord  dCBWTag;
  116         uDWord  dCBWDataTransferLength;
  117         uByte   bCBWFlags;
  118 #define CBWFLAGS_OUT    0x00
  119 #define CBWFLAGS_IN     0x80
  120         uByte   bCBWLUN;
  121         uByte   bCDBLength;
  122 #define CBWCDBLENGTH    16
  123         uByte   CBWCDB[CBWCDBLENGTH];
  124 } __packed;
  125 
  126 /* Command Status Wrapper */
  127 struct bbb_csw {
  128         uDWord  dCSWSignature;
  129 #define CSWSIGNATURE    0x53425355
  130         uDWord  dCSWTag;
  131         uDWord  dCSWDataResidue;
  132         uByte   bCSWStatus;
  133 #define CSWSTATUS_GOOD  0x0
  134 #define CSWSTATUS_FAILED        0x1
  135 #define CSWSTATUS_PHASE 0x2
  136 } __packed;
  137 
  138 struct bbb_transfer {
  139         struct mtx mtx;
  140         struct cv cv;
  141         struct bbb_cbw cbw;
  142         struct bbb_csw csw;
  143 
  144         struct usb_xfer *xfer[ST_MAX];
  145 
  146         uint8_t *data_ptr;
  147 
  148         usb_size_t data_len;            /* bytes */
  149         usb_size_t data_rem;            /* bytes */
  150         usb_timeout_t data_timeout;     /* ms */
  151         usb_frlength_t actlen;          /* bytes */
  152 
  153         uint8_t cmd_len;                /* bytes */
  154         uint8_t dir;
  155         uint8_t lun;
  156         uint8_t state;
  157         uint8_t status_try;
  158         int     error;
  159 
  160         uint8_t buffer[SCSI_MAX_LEN] __aligned(4);
  161 };
  162 
  163 static usb_callback_t bbb_command_callback;
  164 static usb_callback_t bbb_data_read_callback;
  165 static usb_callback_t bbb_data_rd_cs_callback;
  166 static usb_callback_t bbb_data_write_callback;
  167 static usb_callback_t bbb_data_wr_cs_callback;
  168 static usb_callback_t bbb_status_callback;
  169 
  170 static void     bbb_done(struct bbb_transfer *, int);
  171 static void     bbb_transfer_start(struct bbb_transfer *, uint8_t);
  172 static void     bbb_data_clear_stall_callback(struct usb_xfer *, uint8_t,
  173                     uint8_t);
  174 static int      bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t,
  175                     void *, size_t, void *, size_t, usb_timeout_t);
  176 static struct bbb_transfer *bbb_attach(struct usb_device *, uint8_t);
  177 static void     bbb_detach(struct bbb_transfer *);
  178 
  179 static const struct usb_config bbb_config[ST_MAX] = {
  180 
  181         [ST_COMMAND] = {
  182                 .type = UE_BULK,
  183                 .endpoint = UE_ADDR_ANY,
  184                 .direction = UE_DIR_OUT,
  185                 .bufsize = sizeof(struct bbb_cbw),
  186                 .flags = {.ext_buffer = 1,},
  187                 .callback = &bbb_command_callback,
  188                 .timeout = 4 * USB_MS_HZ,       /* 4 seconds */
  189         },
  190 
  191         [ST_DATA_RD] = {
  192                 .type = UE_BULK,
  193                 .endpoint = UE_ADDR_ANY,
  194                 .direction = UE_DIR_IN,
  195                 .bufsize = BULK_SIZE,
  196                 .flags = {.ext_buffer = 1,.proxy_buffer = 1,.short_xfer_ok = 1,},
  197                 .callback = &bbb_data_read_callback,
  198                 .timeout = 4 * USB_MS_HZ,       /* 4 seconds */
  199         },
  200 
  201         [ST_DATA_RD_CS] = {
  202                 .type = UE_CONTROL,
  203                 .endpoint = 0x00,       /* Control pipe */
  204                 .direction = UE_DIR_ANY,
  205                 .bufsize = sizeof(struct usb_device_request),
  206                 .callback = &bbb_data_rd_cs_callback,
  207                 .timeout = 1 * USB_MS_HZ,       /* 1 second  */
  208         },
  209 
  210         [ST_DATA_WR] = {
  211                 .type = UE_BULK,
  212                 .endpoint = UE_ADDR_ANY,
  213                 .direction = UE_DIR_OUT,
  214                 .bufsize = BULK_SIZE,
  215                 .flags = {.ext_buffer = 1,.proxy_buffer = 1,},
  216                 .callback = &bbb_data_write_callback,
  217                 .timeout = 4 * USB_MS_HZ,       /* 4 seconds */
  218         },
  219 
  220         [ST_DATA_WR_CS] = {
  221                 .type = UE_CONTROL,
  222                 .endpoint = 0x00,       /* Control pipe */
  223                 .direction = UE_DIR_ANY,
  224                 .bufsize = sizeof(struct usb_device_request),
  225                 .callback = &bbb_data_wr_cs_callback,
  226                 .timeout = 1 * USB_MS_HZ,       /* 1 second  */
  227         },
  228 
  229         [ST_STATUS] = {
  230                 .type = UE_BULK,
  231                 .endpoint = UE_ADDR_ANY,
  232                 .direction = UE_DIR_IN,
  233                 .bufsize = sizeof(struct bbb_csw),
  234                 .flags = {.ext_buffer = 1,.short_xfer_ok = 1,},
  235                 .callback = &bbb_status_callback,
  236                 .timeout = 1 * USB_MS_HZ,       /* 1 second  */
  237         },
  238 };
  239 
  240 static void
  241 bbb_done(struct bbb_transfer *sc, int error)
  242 {
  243 
  244         sc->error = error;
  245         sc->state = ST_COMMAND;
  246         sc->status_try = 1;
  247         cv_signal(&sc->cv);
  248 }
  249 
  250 static void
  251 bbb_transfer_start(struct bbb_transfer *sc, uint8_t xfer_index)
  252 {
  253         sc->state = xfer_index;
  254         usbd_transfer_start(sc->xfer[xfer_index]);
  255 }
  256 
  257 static void
  258 bbb_data_clear_stall_callback(struct usb_xfer *xfer,
  259     uint8_t next_xfer, uint8_t stall_xfer)
  260 {
  261         struct bbb_transfer *sc = usbd_xfer_softc(xfer);
  262 
  263         if (usbd_clear_stall_callback(xfer, sc->xfer[stall_xfer])) {
  264                 switch (USB_GET_STATE(xfer)) {
  265                 case USB_ST_SETUP:
  266                 case USB_ST_TRANSFERRED:
  267                         bbb_transfer_start(sc, next_xfer);
  268                         break;
  269                 default:
  270                         bbb_done(sc, USB_ERR_STALLED);
  271                         break;
  272                 }
  273         }
  274 }
  275 
  276 static void
  277 bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
  278 {
  279         struct bbb_transfer *sc = usbd_xfer_softc(xfer);
  280         uint32_t tag;
  281 
  282         switch (USB_GET_STATE(xfer)) {
  283         case USB_ST_TRANSFERRED:
  284                 bbb_transfer_start
  285                     (sc, ((sc->dir == DIR_IN) ? ST_DATA_RD :
  286                     (sc->dir == DIR_OUT) ? ST_DATA_WR :
  287                     ST_STATUS));
  288                 break;
  289 
  290         case USB_ST_SETUP:
  291                 sc->status_try = 0;
  292                 tag = UGETDW(sc->cbw.dCBWTag) + 1;
  293                 USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE);
  294                 USETDW(sc->cbw.dCBWTag, tag);
  295                 USETDW(sc->cbw.dCBWDataTransferLength, (uint32_t)sc->data_len);
  296                 sc->cbw.bCBWFlags = ((sc->dir == DIR_IN) ? CBWFLAGS_IN : CBWFLAGS_OUT);
  297                 sc->cbw.bCBWLUN = sc->lun;
  298                 sc->cbw.bCDBLength = sc->cmd_len;
  299                 if (sc->cbw.bCDBLength > sizeof(sc->cbw.CBWCDB)) {
  300                         sc->cbw.bCDBLength = sizeof(sc->cbw.CBWCDB);
  301                         DPRINTFN(0, "Truncating long command\n");
  302                 }
  303                 usbd_xfer_set_frame_data(xfer, 0, &sc->cbw, sizeof(sc->cbw));
  304                 usbd_transfer_submit(xfer);
  305                 break;
  306 
  307         default:                        /* Error */
  308                 bbb_done(sc, error);
  309                 break;
  310         }
  311 }
  312 
  313 static void
  314 bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
  315 {
  316         struct bbb_transfer *sc = usbd_xfer_softc(xfer);
  317         usb_frlength_t max_bulk = usbd_xfer_max_len(xfer);
  318         int actlen, sumlen;
  319 
  320         usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
  321 
  322         switch (USB_GET_STATE(xfer)) {
  323         case USB_ST_TRANSFERRED:
  324                 sc->data_rem -= actlen;
  325                 sc->data_ptr += actlen;
  326                 sc->actlen += actlen;
  327 
  328                 if (actlen < sumlen) {
  329                         /* short transfer */
  330                         sc->data_rem = 0;
  331                 }
  332         case USB_ST_SETUP:
  333                 DPRINTF("max_bulk=%d, data_rem=%d\n",
  334                     max_bulk, sc->data_rem);
  335 
  336                 if (sc->data_rem == 0) {
  337                         bbb_transfer_start(sc, ST_STATUS);
  338                         break;
  339                 }
  340                 if (max_bulk > sc->data_rem) {
  341                         max_bulk = sc->data_rem;
  342                 }
  343                 usbd_xfer_set_timeout(xfer, sc->data_timeout);
  344                 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk);
  345                 usbd_transfer_submit(xfer);
  346                 break;
  347 
  348         default:                        /* Error */
  349                 if (error == USB_ERR_CANCELLED) {
  350                         bbb_done(sc, error);
  351                 } else {
  352                         bbb_transfer_start(sc, ST_DATA_RD_CS);
  353                 }
  354                 break;
  355         }
  356 }
  357 
  358 static void
  359 bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
  360 {
  361         bbb_data_clear_stall_callback(xfer, ST_STATUS,
  362             ST_DATA_RD);
  363 }
  364 
  365 static void
  366 bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
  367 {
  368         struct bbb_transfer *sc = usbd_xfer_softc(xfer);
  369         usb_frlength_t max_bulk = usbd_xfer_max_len(xfer);
  370         int actlen, sumlen;
  371 
  372         usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
  373 
  374         switch (USB_GET_STATE(xfer)) {
  375         case USB_ST_TRANSFERRED:
  376                 sc->data_rem -= actlen;
  377                 sc->data_ptr += actlen;
  378                 sc->actlen += actlen;
  379 
  380                 if (actlen < sumlen) {
  381                         /* short transfer */
  382                         sc->data_rem = 0;
  383                 }
  384         case USB_ST_SETUP:
  385                 DPRINTF("max_bulk=%d, data_rem=%d\n",
  386                     max_bulk, sc->data_rem);
  387 
  388                 if (sc->data_rem == 0) {
  389                         bbb_transfer_start(sc, ST_STATUS);
  390                         return;
  391                 }
  392                 if (max_bulk > sc->data_rem) {
  393                         max_bulk = sc->data_rem;
  394                 }
  395                 usbd_xfer_set_timeout(xfer, sc->data_timeout);
  396                 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk);
  397                 usbd_transfer_submit(xfer);
  398                 return;
  399 
  400         default:                        /* Error */
  401                 if (error == USB_ERR_CANCELLED) {
  402                         bbb_done(sc, error);
  403                 } else {
  404                         bbb_transfer_start(sc, ST_DATA_WR_CS);
  405                 }
  406                 return;
  407 
  408         }
  409 }
  410 
  411 static void
  412 bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
  413 {
  414         bbb_data_clear_stall_callback(xfer, ST_STATUS,
  415             ST_DATA_WR);
  416 }
  417 
  418 static void
  419 bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
  420 {
  421         struct bbb_transfer *sc = usbd_xfer_softc(xfer);
  422         int actlen, sumlen;
  423 
  424         usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
  425 
  426         switch (USB_GET_STATE(xfer)) {
  427         case USB_ST_TRANSFERRED:
  428 
  429                 /* very simple status check */
  430 
  431                 if (actlen < sizeof(sc->csw)) {
  432                         bbb_done(sc, USB_ERR_SHORT_XFER);
  433                 } else if (sc->csw.bCSWStatus == CSWSTATUS_GOOD) {
  434                         bbb_done(sc, 0);        /* success */
  435                 } else {
  436                         bbb_done(sc, ERR_CSW_FAILED);   /* error */
  437                 }
  438                 break;
  439 
  440         case USB_ST_SETUP:
  441                 usbd_xfer_set_frame_data(xfer, 0, &sc->csw, sizeof(sc->csw));
  442                 usbd_transfer_submit(xfer);
  443                 break;
  444 
  445         default:
  446                 DPRINTF("Failed to read CSW: %s, try %d\n",
  447                     usbd_errstr(error), sc->status_try);
  448 
  449                 if (error == USB_ERR_CANCELLED || sc->status_try) {
  450                         bbb_done(sc, error);
  451                 } else {
  452                         sc->status_try = 1;
  453                         bbb_transfer_start(sc, ST_DATA_RD_CS);
  454                 }
  455                 break;
  456         }
  457 }
  458 
  459 /*------------------------------------------------------------------------*
  460  *      bbb_command_start - execute a SCSI command synchronously
  461  *
  462  * Return values
  463  * 0: Success
  464  * Else: Failure
  465  *------------------------------------------------------------------------*/
  466 static int
  467 bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun,
  468     void *data_ptr, size_t data_len, void *cmd_ptr, size_t cmd_len,
  469     usb_timeout_t data_timeout)
  470 {
  471         sc->lun = lun;
  472         sc->dir = data_len ? dir : DIR_NONE;
  473         sc->data_ptr = data_ptr;
  474         sc->data_len = data_len;
  475         sc->data_rem = data_len;
  476         sc->data_timeout = (data_timeout + USB_MS_HZ);
  477         sc->actlen = 0;
  478         sc->cmd_len = cmd_len;
  479         memset(&sc->cbw.CBWCDB, 0, sizeof(sc->cbw.CBWCDB));
  480         memcpy(&sc->cbw.CBWCDB, cmd_ptr, cmd_len);
  481         DPRINTFN(1, "SCSI cmd = %*D\n", (int)cmd_len, &sc->cbw.CBWCDB, ":");
  482 
  483         mtx_lock(&sc->mtx);
  484         usbd_transfer_start(sc->xfer[sc->state]);
  485 
  486         while (usbd_transfer_pending(sc->xfer[sc->state])) {
  487                 cv_wait(&sc->cv, &sc->mtx);
  488         }
  489         mtx_unlock(&sc->mtx);
  490         return (sc->error);
  491 }
  492 
  493 static struct bbb_transfer *
  494 bbb_attach(struct usb_device *udev, uint8_t iface_index)
  495 {
  496         struct usb_interface *iface;
  497         struct usb_interface_descriptor *id;
  498         struct bbb_transfer *sc;
  499         usb_error_t err;
  500         uint8_t do_unlock;
  501 
  502         /* automatic locking */
  503         if (usbd_enum_is_locked(udev)) {
  504                 do_unlock = 0;
  505         } else {
  506                 do_unlock = 1;
  507                 usbd_enum_lock(udev);
  508         }
  509 
  510         /*
  511          * Make sure any driver which is hooked up to this interface,
  512          * like umass is gone:
  513          */
  514         usb_detach_device(udev, iface_index, 0);
  515 
  516         if (do_unlock)
  517                 usbd_enum_unlock(udev);
  518 
  519         iface = usbd_get_iface(udev, iface_index);
  520         if (iface == NULL)
  521                 return (NULL);
  522 
  523         id = iface->idesc;
  524         if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
  525                 return (NULL);
  526 
  527         switch (id->bInterfaceSubClass) {
  528         case UISUBCLASS_SCSI:
  529         case UISUBCLASS_UFI:
  530         case UISUBCLASS_SFF8020I:
  531         case UISUBCLASS_SFF8070I:
  532                 break;
  533         default:
  534                 return (NULL);
  535         }
  536 
  537         switch (id->bInterfaceProtocol) {
  538         case UIPROTO_MASS_BBB_OLD:
  539         case UIPROTO_MASS_BBB:
  540                 break;
  541         default:
  542                 return (NULL);
  543         }
  544 
  545         sc = malloc(sizeof(*sc), M_USB, M_WAITOK | M_ZERO);
  546         mtx_init(&sc->mtx, "USB autoinstall", NULL, MTX_DEF);
  547         cv_init(&sc->cv, "WBBB");
  548 
  549         err = usbd_transfer_setup(udev, &iface_index, sc->xfer, bbb_config,
  550             ST_MAX, sc, &sc->mtx);
  551         if (err) {
  552                 bbb_detach(sc);
  553                 return (NULL);
  554         }
  555         return (sc);
  556 }
  557 
  558 static void
  559 bbb_detach(struct bbb_transfer *sc)
  560 {
  561         usbd_transfer_unsetup(sc->xfer, ST_MAX);
  562         mtx_destroy(&sc->mtx);
  563         cv_destroy(&sc->cv);
  564         free(sc, M_USB);
  565 }
  566 
  567 /*------------------------------------------------------------------------*
  568  *      usb_iface_is_cdrom
  569  *
  570  * Return values:
  571  * 1: This interface is an auto install disk (CD-ROM)
  572  * 0: Not an auto install disk.
  573  *------------------------------------------------------------------------*/
  574 int
  575 usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index)
  576 {
  577         struct bbb_transfer *sc;
  578         uint8_t timeout;
  579         uint8_t is_cdrom;
  580         uint8_t sid_type;
  581         int err;
  582 
  583         sc = bbb_attach(udev, iface_index);
  584         if (sc == NULL)
  585                 return (0);
  586 
  587         is_cdrom = 0;
  588         timeout = 4;    /* tries */
  589         while (--timeout) {
  590                 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
  591                     SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
  592                     USB_MS_HZ);
  593 
  594                 if (err == 0 && sc->actlen > 0) {
  595                         sid_type = sc->buffer[0] & 0x1F;
  596                         if (sid_type == 0x05)
  597                                 is_cdrom = 1;
  598                         break;
  599                 } else if (err != ERR_CSW_FAILED)
  600                         break;  /* non retryable error */
  601                 usb_pause_mtx(NULL, hz);
  602         }
  603         bbb_detach(sc);
  604         return (is_cdrom);
  605 }
  606 
  607 static uint8_t
  608 usb_msc_get_max_lun(struct usb_device *udev, uint8_t iface_index)
  609 {
  610         struct usb_device_request req;
  611         usb_error_t err;
  612         uint8_t buf = 0;
  613 
  614 
  615         /* The Get Max Lun command is a class-specific request. */
  616         req.bmRequestType = UT_READ_CLASS_INTERFACE;
  617         req.bRequest = 0xFE;            /* GET_MAX_LUN */
  618         USETW(req.wValue, 0);
  619         req.wIndex[0] = iface_index;
  620         req.wIndex[1] = 0;
  621         USETW(req.wLength, 1);
  622 
  623         err = usbd_do_request(udev, NULL, &req, &buf);
  624         if (err)
  625                 buf = 0;
  626 
  627         return (buf);
  628 }
  629 
  630 usb_error_t
  631 usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index)
  632 {
  633         struct bbb_transfer *sc;
  634         uint8_t timeout;
  635         uint8_t is_no_direct;
  636         uint8_t sid_type;
  637         int err;
  638 
  639         sc = bbb_attach(udev, iface_index);
  640         if (sc == NULL)
  641                 return (0);
  642 
  643         /*
  644          * Some devices need a delay after that the configuration
  645          * value is set to function properly:
  646          */
  647         usb_pause_mtx(NULL, hz);
  648 
  649         if (usb_msc_get_max_lun(udev, iface_index) == 0) {
  650                 DPRINTF("Device has only got one LUN.\n");
  651                 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_GETMAXLUN);
  652         }
  653 
  654         is_no_direct = 1;
  655         for (timeout = 4; timeout; timeout--) {
  656                 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
  657                     SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
  658                     USB_MS_HZ);
  659 
  660                 if (err == 0 && sc->actlen > 0) {
  661                         sid_type = sc->buffer[0] & 0x1F;
  662                         if (sid_type == 0x00)
  663                                 is_no_direct = 0;
  664                         break;
  665                 } else if (err != ERR_CSW_FAILED)
  666                         break;  /* non retryable error */
  667                 usb_pause_mtx(NULL, hz);
  668         }
  669 
  670         if (is_no_direct) {
  671                 DPRINTF("Device is not direct access.\n");
  672                 goto done;
  673         }
  674 
  675         err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
  676             &scsi_test_unit_ready, sizeof(scsi_test_unit_ready),
  677             USB_MS_HZ);
  678 
  679         if (err != 0) {
  680 
  681                 if (err != ERR_CSW_FAILED)
  682                         goto error;
  683         }
  684 
  685         err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
  686             &scsi_sync_cache, sizeof(scsi_sync_cache),
  687             USB_MS_HZ);
  688 
  689         if (err != 0) {
  690 
  691                 if (err != ERR_CSW_FAILED)
  692                         goto error;
  693 
  694                 DPRINTF("Device doesn't handle synchronize cache\n");
  695 
  696                 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
  697         }
  698 
  699         /* clear sense status of any failed commands on the device */
  700 
  701         err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
  702             SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
  703             USB_MS_HZ);
  704 
  705         DPRINTF("Inquiry = %d\n", err);
  706 
  707         if (err != 0) {
  708 
  709                 if (err != ERR_CSW_FAILED)
  710                         goto error;
  711         }
  712 
  713         err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
  714             SCSI_SENSE_LEN, &scsi_request_sense,
  715             sizeof(scsi_request_sense), USB_MS_HZ);
  716 
  717         DPRINTF("Request sense = %d\n", err);
  718 
  719         if (err != 0) {
  720 
  721                 if (err != ERR_CSW_FAILED)
  722                         goto error;
  723         }
  724 
  725 done:
  726         bbb_detach(sc);
  727         return (0);
  728 
  729 error:
  730         bbb_detach(sc);
  731 
  732         DPRINTF("Device did not respond, enabling all quirks\n");
  733 
  734         usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
  735         usbd_add_dynamic_quirk(udev, UQ_MSC_NO_TEST_UNIT_READY);
  736 
  737         /* Need to re-enumerate the device */
  738         usbd_req_re_enumerate(udev, NULL);
  739 
  740         return (USB_ERR_STALLED);
  741 }
  742 
  743 usb_error_t
  744 usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
  745 {
  746         struct bbb_transfer *sc;
  747         usb_error_t err;
  748 
  749         sc = bbb_attach(udev, iface_index);
  750         if (sc == NULL)
  751                 return (USB_ERR_INVAL);
  752 
  753         err = 0;
  754         switch (method) {
  755         case MSC_EJECT_STOPUNIT:
  756                 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
  757                     &scsi_test_unit_ready, sizeof(scsi_test_unit_ready),
  758                     USB_MS_HZ);
  759                 DPRINTF("Test unit ready status: %s\n", usbd_errstr(err));
  760                 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
  761                     &scsi_start_stop_unit, sizeof(scsi_start_stop_unit),
  762                     USB_MS_HZ);
  763                 break;
  764         case MSC_EJECT_REZERO:
  765                 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
  766                     &scsi_rezero_init, sizeof(scsi_rezero_init),
  767                     USB_MS_HZ);
  768                 break;
  769         case MSC_EJECT_ZTESTOR:
  770                 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
  771                     &scsi_ztestor_eject, sizeof(scsi_ztestor_eject),
  772                     USB_MS_HZ);
  773                 break;
  774         case MSC_EJECT_CMOTECH:
  775                 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
  776                     &scsi_cmotech_eject, sizeof(scsi_cmotech_eject),
  777                     USB_MS_HZ);
  778                 break;
  779         case MSC_EJECT_HUAWEI:
  780                 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
  781                     &scsi_huawei_eject, sizeof(scsi_huawei_eject),
  782                     USB_MS_HZ);
  783                 break;
  784         case MSC_EJECT_TCT:
  785                 /*
  786                  * TCTMobile needs DIR_IN flag. To get it, we
  787                  * supply a dummy data with the command.
  788                  */
  789                 err = bbb_command_start(sc, DIR_IN, 0, &sc->buffer,
  790                     sizeof(sc->buffer), &scsi_tct_eject,
  791                     sizeof(scsi_tct_eject), USB_MS_HZ);
  792                 break;
  793         default:
  794                 printf("usb_msc_eject: unknown eject method (%d)\n", method);
  795                 break;
  796         }
  797         DPRINTF("Eject CD command status: %s\n", usbd_errstr(err));
  798 
  799         bbb_detach(sc);
  800         return (0);
  801 }

Cache object: 75e00d6fb9f847d1589ec397a9ae83e0


[ 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.