Date: Wed, 13 Sep 2006 16:58:17 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 106070 for review Message-ID: <200609131658.k8DGwH3n027618@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=106070 Change 106070 by hselasky@hselasky_mini_itx on 2006/09/13 16:58:00 Finished reworking "umass". There are lots of changes again. Please test! Affected files ... .. //depot/projects/usb/src/sys/dev/usb/umass.c#5 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/umass.c#5 (text+ko) ==== @@ -1,0 +1,3219 @@ +/*- + * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>, + * Nick Hibma <n_hibma@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/usb/umass.c,v 1.135 2006/03/17 18:16:22 iedowse Exp $ + * $NetBSD: umass.c,v 1.28 2000/04/02 23:46:53 augustss Exp $ + */ + +/* Also already merged from NetBSD: + * $NetBSD: umass.c,v 1.67 2001/11/25 19:05:22 augustss Exp $ + * $NetBSD: umass.c,v 1.90 2002/11/04 19:17:33 pooka Exp $ + * $NetBSD: umass.c,v 1.108 2003/11/07 17:03:25 wiz Exp $ + * $NetBSD: umass.c,v 1.109 2003/12/04 13:57:31 keihan Exp $ + */ + +/* + * Universal Serial Bus Mass Storage Class specs: + * http://www.usb.org/developers/devclass_docs/usb_msc_overview_1.2.pdf + * http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf + * http://www.usb.org/developers/devclass_docs/usb_msc_cbi_1.1.pdf + * http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf + */ + +/* + * Ported to NetBSD by Lennart Augustsson <augustss@NetBSD.org>. + * Parts of the code written by Jason R. Thorpe <thorpej@shagadelic.org>. + */ + +/* + * The driver handles 3 Wire Protocols + * - Command/Bulk/Interrupt (CBI) + * - Command/Bulk/Interrupt with Command Completion Interrupt (CBI with CCI) + * - Mass Storage Bulk-Only (BBB) + * (BBB refers Bulk/Bulk/Bulk for Command/Data/Status phases) + * + * Over these wire protocols it handles the following command protocols + * - SCSI + * - UFI (floppy command set) + * - 8070i (ATAPI) + * + * UFI and 8070i (ATAPI) are transformed versions of the SCSI command set. The + * sc->sc_transform method is used to convert the commands into the appropriate + * format (if at all necessary). For example, UFI requires all commands to be + * 12 bytes in length amongst other things. + * + * The source code below is marked and can be split into a number of pieces + * (in this order): + * + * - probe/attach/detach + * - generic transfer routines + * - BBB + * - CBI + * - CBI_I (in addition to functions from CBI) + * - CAM (Common Access Method) + * - SCSI + * - UFI + * - 8070i (ATAPI) + * + * The protocols are implemented using a state machine, for the transfers as + * well as for the resets. The state machine is contained in umass_t_*_callback. + * The state machine is started through either umass_command_start() or + * umass_reset(). + * + * The reason for doing this is a) CAM performs a lot better this way and b) it + * avoids using tsleep from interrupt context (for example after a failed + * transfer). + */ + +/* + * The SCSI related part of this driver has been derived from the + * dev/ppbus/vpo.c driver, by Nicolas Souchu (nsouch@freebsd.org). + * + * The CAM layer uses so called actions which are messages sent to the host + * adapter for completion. The actions come in through umass_cam_action. The + * appropriate block of routines is called depending on the transport protocol + * in use. When the transfer has finished, these routines call + * umass_cam_cb again to complete the CAM command. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <dev/usb/usb_port.h> +#include <dev/usb/usb.h> +#include <dev/usb/usb_subr.h> + +#include "usbdevs.h" + +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/cam_sim.h> +#include <cam/cam_xpt_sim.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_da.h> + +#include <cam/cam_periph.h> + +#ifdef USB_DEBUG +#define DIF(m, x) \ + do { \ + if (umass_debug & (m)) { x } \ + } while (0) + +#define DPRINTF(sc, m, fmt, ...) \ + do { \ + if (umass_debug & (m)) { \ + printf("%s:%s: " fmt, \ + (sc) ? (const char *)(sc)->sc_name : \ + (const char *)"umassX", \ + __FUNCTION__ ,## __VA_ARGS__); \ + } \ + } while(0) + +#define UDMASS_GEN 0x00010000 /* general */ +#define UDMASS_SCSI 0x00020000 /* scsi */ +#define UDMASS_UFI 0x00040000 /* ufi command set */ +#define UDMASS_ATAPI 0x00080000 /* 8070i command set */ +#define UDMASS_CMD (UDMASS_SCSI|UDMASS_UFI|UDMASS_ATAPI) +#define UDMASS_USB 0x00100000 /* USB general */ +#define UDMASS_BBB 0x00200000 /* Bulk-Only transfers */ +#define UDMASS_CBI 0x00400000 /* CBI transfers */ +#define UDMASS_WIRE (UDMASS_BBB|UDMASS_CBI) +#define UDMASS_ALL 0xffff0000 /* all of the above */ +static int umass_debug = 0; +SYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass"); +SYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW, + &umass_debug, 0, "umass debug level"); +#else +#define DIF(...) /* nop */ +#define DPRINTF(...) /* nop */ +#endif + +#define UMASS_BULK_SIZE (1 << 17) /* bytes, must not be less than (1<<16) */ +#define UMASS_CBI_DIAGNOSTIC_CMDLEN 12 /* bytes */ +#define UMASS_MAX_CMDLEN MAX(12, CAM_MAX_CDBLEN) /* bytes */ + +/* USB transfer definitions */ + +#define UMASS_T_BBB_RESET1 0 /* Bulk-Only */ +#define UMASS_T_BBB_RESET2 1 +#define UMASS_T_BBB_RESET3 2 +#define UMASS_T_BBB_COMMAND 3 +#define UMASS_T_BBB_DATA_READ 4 +#define UMASS_T_BBB_DATA_RD_CS 5 +#define UMASS_T_BBB_DATA_WRITE 6 +#define UMASS_T_BBB_DATA_WR_CS 7 +#define UMASS_T_BBB_STATUS 8 +#define UMASS_T_BBB_MAX 9 + +#define UMASS_T_CBI_RESET1 0 /* CBI */ +#define UMASS_T_CBI_RESET2 1 +#define UMASS_T_CBI_RESET3 2 +#define UMASS_T_CBI_COMMAND 3 +#define UMASS_T_CBI_DATA_READ 4 +#define UMASS_T_CBI_DATA_RD_CS 5 +#define UMASS_T_CBI_DATA_WRITE 6 +#define UMASS_T_CBI_DATA_WR_CS 7 +#define UMASS_T_CBI_STATUS 8 +#define UMASS_T_CBI_RESET4 9 +#define UMASS_T_CBI_MAX 10 + +#define UMASS_T_MAX MAX(UMASS_T_CBI_MAX, UMASS_T_BBB_MAX) + +/* Generic definitions */ + +/* Direction for transfer */ +#define DIR_NONE 0 +#define DIR_IN 1 +#define DIR_OUT 2 + +/* device name */ +#define DEVNAME "umass" +#define DEVNAME_SIM "umass-sim" + +/* Approximate maximum transfer speeds (assumes 33% overhead). */ +#define UMASS_FULL_TRANSFER_SPEED 1000 +#define UMASS_HIGH_TRANSFER_SPEED 40000 +#define UMASS_FLOPPY_TRANSFER_SPEED 20 + +#define UMASS_TIMEOUT 5000 /* ms */ + +/* CAM specific definitions */ + +#define UMASS_SCSIID_MAX 1 /* maximum number of drives expected */ +#define UMASS_SCSIID_HOST UMASS_SCSIID_MAX + +/* Bulk-Only features */ + +#define UR_BBB_RESET 0xff /* Bulk-Only reset */ +#define UR_BBB_GET_MAX_LUN 0xfe /* Get maximum lun */ + +/* Command Block Wrapper */ +typedef struct { + uDWord dCBWSignature; +# define CBWSIGNATURE 0x43425355 + uDWord dCBWTag; + uDWord dCBWDataTransferLength; + uByte bCBWFlags; +# define CBWFLAGS_OUT 0x00 +# define CBWFLAGS_IN 0x80 + uByte bCBWLUN; + uByte bCDBLength; +# define CBWCDBLENGTH 16 + uByte CBWCDB[CBWCDBLENGTH]; +} UPACKED umass_bbb_cbw_t; +#define UMASS_BBB_CBW_SIZE 31 + +/* Command Status Wrapper */ +typedef struct { + uDWord dCSWSignature; +# define CSWSIGNATURE 0x53425355 +# define CSWSIGNATURE_IMAGINATION_DBX1 0x43425355 +# define CSWSIGNATURE_OLYMPUS_C1 0x55425355 + uDWord dCSWTag; + uDWord dCSWDataResidue; + uByte bCSWStatus; +# define CSWSTATUS_GOOD 0x0 +# define CSWSTATUS_FAILED 0x1 +# define CSWSTATUS_PHASE 0x2 +} UPACKED umass_bbb_csw_t; +#define UMASS_BBB_CSW_SIZE 13 + +/* CBI features */ + +#define UR_CBI_ADSC 0x00 + +typedef union { + struct { + u_int8_t type; +# define IDB_TYPE_CCI 0x00 + u_int8_t value; +# define IDB_VALUE_PASS 0x00 +# define IDB_VALUE_FAIL 0x01 +# define IDB_VALUE_PHASE 0x02 +# define IDB_VALUE_PERSISTENT 0x03 +# define IDB_VALUE_STATUS_MASK 0x03 + } UPACKED common; + + struct { + u_int8_t asc; + u_int8_t ascq; + } UPACKED ufi; +} UPACKED umass_cbi_sbl_t; + +struct umass_softc; /* see below */ + +typedef void (umass_callback_t) (struct umass_softc *sc, union ccb *ccb, + u_int32_t residue, u_int8_t status); +#define STATUS_CMD_OK 0 /* everything ok */ +#define STATUS_CMD_UNKNOWN 1 /* will have to fetch sense */ +#define STATUS_CMD_FAILED 2 /* transfer was ok, command failed */ +#define STATUS_WIRE_FAILED 3 /* couldn't even get command across */ + +typedef u_int8_t (umass_transform_t) (struct umass_softc *sc, u_int8_t *cmd_ptr, + u_int8_t cmd_len); + +struct umass_devdescr { + u_int32_t vid; +# define VID_WILDCARD 0xffffffff +# define VID_EOT 0xfffffffe + u_int32_t pid; +# define PID_WILDCARD 0xffffffff +# define PID_EOT 0xfffffffe + u_int32_t rid; +# define RID_WILDCARD 0xffffffff +# define RID_EOT 0xfffffffe + + /* wire and command protocol */ + u_int16_t proto; +# define UMASS_PROTO_BBB 0x0001 /* USB wire protocol */ +# define UMASS_PROTO_CBI 0x0002 +# define UMASS_PROTO_CBI_I 0x0004 +# define UMASS_PROTO_WIRE 0x00ff /* USB wire protocol mask */ +# define UMASS_PROTO_SCSI 0x0100 /* command protocol */ +# define UMASS_PROTO_ATAPI 0x0200 +# define UMASS_PROTO_UFI 0x0400 +# define UMASS_PROTO_RBC 0x0800 +# define UMASS_PROTO_COMMAND 0xff00 /* command protocol mask */ + + /* Device specific quirks */ + u_int16_t quirks; +# define NO_QUIRKS 0x0000 + /* The drive does not support Test Unit Ready. Convert to Start Unit + */ +# define NO_TEST_UNIT_READY 0x0001 + /* The drive does not reset the Unit Attention state after REQUEST + * SENSE has been sent. The INQUIRY command does not reset the UA + * either, and so CAM runs in circles trying to retrieve the initial + * INQUIRY data. + */ +# define RS_NO_CLEAR_UA 0x0002 + /* The drive does not support START STOP. */ +# define NO_START_STOP 0x0004 + /* Don't ask for full inquiry data (255b). */ +# define FORCE_SHORT_INQUIRY 0x0008 + /* Needs to be initialised the Shuttle way */ +# define SHUTTLE_INIT 0x0010 + /* Drive needs to be switched to alternate iface 1 */ +# define ALT_IFACE_1 0x0020 + /* Drive does not do 1Mb/s, but just floppy speeds (20kb/s) */ +# define FLOPPY_SPEED 0x0040 + /* The device can't count and gets the residue of transfers wrong */ +# define IGNORE_RESIDUE 0x0080 + /* No GetMaxLun call */ +# define NO_GETMAXLUN 0x0100 + /* The device uses a weird CSWSIGNATURE. */ +# define WRONG_CSWSIG 0x0200 + /* Device cannot handle INQUIRY so fake a generic response */ +# define NO_INQUIRY 0x0400 + /* Device cannot handle INQUIRY EVPD, return CHECK CONDITION */ +# define NO_INQUIRY_EVPD 0x0800 + /* Pad all RBC requests to 12 bytes. */ +# define RBC_PAD_TO_12 0x1000 +}; + +static const struct umass_devdescr umass_devdescr[] = { + { USB_VENDOR_ASAHIOPTICAL, PID_WILDCARD, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, + RS_NO_CLEAR_UA + }, + { USB_VENDOR_ADDON, USB_PRODUCT_ADDON_ATTACHE, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + IGNORE_RESIDUE + }, + { USB_VENDOR_FUJIPHOTO, USB_PRODUCT_FUJIPHOTO_MASS0100, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, + RS_NO_CLEAR_UA + }, + { USB_VENDOR_ADDON, USB_PRODUCT_ADDON_A256MB, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + IGNORE_RESIDUE + }, + { USB_VENDOR_ADDON, USB_PRODUCT_ADDON_DISKPRO512, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + IGNORE_RESIDUE + }, + { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB2IDE, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE + }, + { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB2IDE_2, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, + FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE + }, + { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE + }, + { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB_2, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + WRONG_CSWSIG + }, + { USB_VENDOR_HITACHI, USB_PRODUCT_HITACHI_DVDCAM_USB, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, + NO_INQUIRY + }, + { USB_VENDOR_HP, USB_PRODUCT_HP_CDW8200, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, + NO_TEST_UNIT_READY | NO_START_STOP + }, + { USB_VENDOR_IMAGINATION, USB_PRODUCT_IMAGINATION_DBX1, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + WRONG_CSWSIG + }, + { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_USBCABLE, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, + NO_TEST_UNIT_READY | NO_START_STOP | ALT_IFACE_1 + }, + { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_IU_CD2, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + NO_QUIRKS + }, + { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_DVR_UEH8, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + NO_QUIRKS + }, + { USB_VENDOR_IOMEGA, USB_PRODUCT_IOMEGA_ZIP100, RID_WILDCARD, + /* XXX This is not correct as there are Zip drives that use ATAPI. + */ + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + NO_TEST_UNIT_READY + }, + { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LDR_H443SU2, RID_WILDCARD, + UMASS_PROTO_SCSI, + NO_QUIRKS + }, + { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LDR_H443U2, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + NO_QUIRKS + }, + { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_DUBPXXG, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE + }, + { USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_DPCM, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_CBI, + NO_TEST_UNIT_READY | NO_START_STOP + }, + { USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_E398, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + FORCE_SHORT_INQUIRY | NO_INQUIRY_EVPD | NO_GETMAXLUN + }, + { USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + IGNORE_RESIDUE | NO_GETMAXLUN | RS_NO_CLEAR_UA + }, + { USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY2, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, + NO_QUIRKS + }, + { USB_VENDOR_NEODIO, USB_PRODUCT_NEODIO_ND3260, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + FORCE_SHORT_INQUIRY + }, + { USB_VENDOR_OLYMPUS, USB_PRODUCT_OLYMPUS_C1, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + WRONG_CSWSIG + }, + { USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_UCF100, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, + NO_INQUIRY | NO_GETMAXLUN + }, + { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXLCB20AN, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + NO_QUIRKS + }, + { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXLCB35AN, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + NO_QUIRKS + }, + { USB_VENDOR_PLEXTOR, USB_PRODUCT_PLEXTOR_40_12_40U, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + NO_TEST_UNIT_READY + }, + { USB_VENDOR_PNY, USB_PRODUCT_PNY_ATTACHE2, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + IGNORE_RESIDUE | NO_START_STOP + }, + { USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ2_256, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + IGNORE_RESIDUE + }, + { USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ4_128, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + IGNORE_RESIDUE + }, + { USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ4_256, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + IGNORE_RESIDUE + }, + { USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_SL11R, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, + NO_INQUIRY + }, + { USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSB, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, + NO_TEST_UNIT_READY | NO_START_STOP | SHUTTLE_INIT + }, + { USB_VENDOR_SIGMATEL, USB_PRODUCT_SIGMATEL_I_BEAD100, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + SHUTTLE_INIT + }, + { USB_VENDOR_SIIG, USB_PRODUCT_SIIG_WINTERREADER, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + IGNORE_RESIDUE + }, + { USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, 0x0500, + UMASS_PROTO_RBC | UMASS_PROTO_CBI, + RBC_PAD_TO_12 + }, + { USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, 0x0600, + UMASS_PROTO_RBC | UMASS_PROTO_CBI, + RBC_PAD_TO_12 + }, + { USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, RID_WILDCARD, + UMASS_PROTO_RBC | UMASS_PROTO_CBI, + NO_QUIRKS + }, + { USB_VENDOR_SONY, USB_PRODUCT_SONY_HANDYCAM, RID_WILDCARD, + UMASS_PROTO_RBC | UMASS_PROTO_CBI, + NO_QUIRKS + }, + { USB_VENDOR_SONY, USB_PRODUCT_SONY_MSC, RID_WILDCARD, + UMASS_PROTO_RBC | UMASS_PROTO_CBI, + NO_QUIRKS + }, + { USB_VENDOR_TREK, USB_PRODUCT_TREK_THUMBDRIVE_8MB, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, + IGNORE_RESIDUE + }, + { USB_VENDOR_TRUMPION, USB_PRODUCT_TRUMPION_C3310, RID_WILDCARD, + UMASS_PROTO_UFI | UMASS_PROTO_CBI, + NO_QUIRKS + }, + { USB_VENDOR_TWINMOS, USB_PRODUCT_TWINMOS_MDIV, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + NO_QUIRKS + }, + { USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_EXTHDD, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE + }, + { USB_VENDOR_YANO, USB_PRODUCT_YANO_U640MO, RID_WILDCARD, + UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, + FORCE_SHORT_INQUIRY + }, + { VID_EOT, PID_EOT, RID_EOT, 0, 0 } +}; + +struct umass_softc { + + struct usbd_memory_wait sc_mem_wait; + struct scsi_sense cam_scsi_sense; + struct scsi_test_unit_ready cam_scsi_test_unit_ready; + struct mtx sc_mtx; + struct { + u_int8_t * data_ptr; + union ccb * ccb; + umass_callback_t * callback; + + u_int32_t data_len; /* bytes */ + u_int32_t data_rem; /* bytes */ + u_int32_t data_timeout; /* ms */ + u_int32_t actlen; /* bytes */ + + u_int8_t cmd_data[UMASS_MAX_CMDLEN]; + u_int8_t cmd_len; /* bytes */ + u_int8_t dir; + u_int8_t lun; + } sc_transfer; + + /* Bulk specific variables for transfers in progress */ + umass_bbb_cbw_t cbw; /* command block wrapper */ + umass_bbb_csw_t csw; /* command status wrapper*/ + + /* CBI specific variables for transfers in progress */ + umass_cbi_sbl_t sbl; /* status block */ + + device_t sc_dev; + struct usbd_device * sc_udev; + struct cam_sim * sc_sim; /* SCSI Interface Module */ + struct usbd_xfer * sc_xfer[UMASS_T_MAX]; + + /* The command transform function is used to convert the SCSI commands + * into their derivatives, like UFI, ATAPI, and friends. + */ + umass_transform_t * sc_transform; + + u_int32_t sc_unit; + + u_int16_t sc_proto; /* wire and cmd protocol */ + u_int16_t sc_quirks; /* they got it almost right */ + + u_int8_t sc_name[16]; + u_int8_t sc_iface_no; /* interface number */ + u_int8_t sc_maxlun; /* maximum LUN number, inclusive */ + u_int8_t sc_last_xfer_index; + u_int8_t sc_reset_count; + u_int8_t sc_status_try; +}; + +struct umass_probe_proto { + u_int16_t quirks; + u_int16_t proto; + + int32_t error; +}; + +/* prototypes */ + +static device_probe_t umass_probe; +static device_attach_t umass_attach; +static device_detach_t umass_detach; + +static void +umass_init_shuttle(struct umass_softc *sc); + +static void +umass_reset(struct umass_softc *sc); + +static void +umass_tr_error(struct usbd_xfer *xfer); + +static void +umass_t_bbb_reset1_callback(struct usbd_xfer *xfer); + +static void +umass_t_bbb_reset2_callback(struct usbd_xfer *xfer); + +static void +umass_t_bbb_reset3_callback(struct usbd_xfer *xfer); + +static void +umass_t_bbb_data_clear_stall_callback(struct usbd_xfer *xfer, + u_int8_t next_xfer, + u_int8_t stall_xfer); +static void +umass_t_bbb_command_callback(struct usbd_xfer *xfer); + +static void +umass_t_bbb_data_read_callback(struct usbd_xfer *xfer); + +static void +umass_t_bbb_data_rd_cs_callback(struct usbd_xfer *xfer); + +static void +umass_t_bbb_data_write_callback(struct usbd_xfer *xfer); + +static void +umass_t_bbb_data_wr_cs_callback(struct usbd_xfer *xfer); + +static void +umass_t_bbb_status_callback(struct usbd_xfer *xfer); + +static void +umass_command_start(struct umass_softc *sc, u_int8_t dir, + void *data_ptr, u_int32_t data_len, + u_int32_t data_timeout, umass_callback_t *callback, + union ccb *ccb); +static u_int8_t +umass_bbb_get_max_lun(struct umass_softc *sc); + +static void +umass_cbi_start_status(struct umass_softc *sc); + +static void +umass_t_cbi_reset1_callback(struct usbd_xfer *xfer); + +static void +umass_t_cbi_reset2_callback(struct usbd_xfer *xfer); + +static void +umass_t_cbi_reset3_callback(struct usbd_xfer *xfer); + +static void +umass_t_cbi_reset4_callback(struct usbd_xfer *xfer); + +static void +umass_t_cbi_data_clear_stall_callback(struct usbd_xfer *xfer, + u_int8_t next_xfer, + u_int8_t stall_xfer); +static void +umass_t_cbi_command_callback(struct usbd_xfer *xfer); + +static void +umass_t_cbi_data_read_callback(struct usbd_xfer *xfer); + +static void +umass_t_cbi_data_rd_cs_callback(struct usbd_xfer *xfer); + +static void +umass_t_cbi_data_write_callback(struct usbd_xfer *xfer); + +static void +umass_t_cbi_data_wr_cs_callback(struct usbd_xfer *xfer); + +static void +umass_t_cbi_status_callback(struct usbd_xfer *xfer); + +static int +umass_cam_attach_sim(struct umass_softc *sc); + +static void +umass_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb); + +static void +umass_cam_rescan(struct umass_softc *sc); + +static void +umass_cam_attach(struct umass_softc *sc); + +static void +umass_cam_detach_sim(struct umass_softc *sc); + +static void +umass_cam_action(struct cam_sim *sim, union ccb *ccb); + +static void +umass_cam_poll(struct cam_sim *sim); + +static void +umass_cam_cb(struct umass_softc *sc, union ccb *ccb, u_int32_t residue, + u_int8_t status); +static void +umass_cam_sense_cb(struct umass_softc *sc, union ccb *ccb, u_int32_t residue, + u_int8_t status); +static void +umass_cam_quirk_cb(struct umass_softc *sc, union ccb *ccb, u_int32_t residue, + u_int8_t status); +static u_int8_t +umass_scsi_transform(struct umass_softc *sc, u_int8_t *cmd_ptr, + u_int8_t cmd_len); +static u_int8_t +umass_rbc_transform(struct umass_softc *sc, u_int8_t *cmd_ptr, u_int8_t cmd_len); + +static u_int8_t +umass_ufi_transform(struct umass_softc *sc, u_int8_t *cmd_ptr, + u_int8_t cmd_len); +static u_int8_t +umass_atapi_transform(struct umass_softc *sc, u_int8_t *cmd_ptr, + u_int8_t cmd_len); +static u_int8_t +umass_no_transform(struct umass_softc *sc, u_int8_t *cmd, + u_int8_t cmdlen); +#ifdef USB_DEBUG +static void +umass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw); + +static void +umass_bbb_dump_csw(struct umass_softc *sc, umass_bbb_csw_t *csw); + +static void +umass_cbi_dump_cmd(struct umass_softc *sc, void *cmd, u_int8_t cmdlen); + +static void +umass_dump_buffer(struct umass_softc *sc, u_int8_t *buffer, u_int32_t buflen, + u_int32_t printlen); +#endif + +struct usbd_config umass_bbb_config[UMASS_T_BBB_MAX] = { + + [UMASS_T_BBB_RESET1] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_bbb_reset1_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_BBB_RESET2] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_bbb_reset2_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_BBB_RESET3] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_bbb_reset3_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_BBB_COMMAND] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_OUT, + .bufsize = sizeof(umass_bbb_cbw_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_bbb_command_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_BBB_DATA_READ] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_IN, + .bufsize = UMASS_BULK_SIZE, + .flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK), + .callback = &umass_t_bbb_data_read_callback, + .timeout = 0, /* overwritten later */ + }, + + [UMASS_T_BBB_DATA_RD_CS] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_bbb_data_rd_cs_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_BBB_DATA_WRITE] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_OUT, + .bufsize = UMASS_BULK_SIZE, + .flags = USBD_USE_DMA, + .callback = &umass_t_bbb_data_write_callback, + .timeout = 0, /* overwritten later */ + }, + + [UMASS_T_BBB_DATA_WR_CS] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_bbb_data_wr_cs_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_BBB_STATUS] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_IN, + .bufsize = sizeof(umass_bbb_csw_t), + .flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK), + .callback = &umass_t_bbb_status_callback, + .timeout = 5000, /* ms */ + }, +}; + +struct usbd_config umass_cbi_config[UMASS_T_CBI_MAX] = { + + [UMASS_T_CBI_RESET1] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = (sizeof(usb_device_request_t) + + UMASS_CBI_DIAGNOSTIC_CMDLEN), + .flags = USBD_USE_DMA, + .callback = &umass_t_cbi_reset1_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_CBI_RESET2] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_cbi_reset2_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_CBI_RESET3] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_cbi_reset3_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_CBI_COMMAND] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = (sizeof(usb_device_request_t) + + UMASS_MAX_CMDLEN), + .flags = USBD_USE_DMA, + .callback = &umass_t_cbi_command_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_CBI_DATA_READ] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_IN, + .bufsize = UMASS_BULK_SIZE, + .flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK), + .callback = &umass_t_cbi_data_read_callback, + .timeout = 0, /* overwritten later */ + }, + + [UMASS_T_CBI_DATA_RD_CS] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_cbi_data_rd_cs_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_CBI_DATA_WRITE] = { + .type = UE_BULK, + .endpoint = -1, /* any */ + .direction = UE_DIR_OUT, + .bufsize = UMASS_BULK_SIZE, + .flags = USBD_USE_DMA, + .callback = &umass_t_cbi_data_write_callback, + .timeout = 0, /* overwritten later */ + }, + + [UMASS_T_CBI_DATA_WR_CS] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_cbi_data_wr_cs_callback, + .timeout = 5000, /* 5 seconds */ + }, + + [UMASS_T_CBI_STATUS] = { + .type = UE_INTERRUPT, + .endpoint = -1, /* any */ + .direction = UE_DIR_IN, + .flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK), + .bufsize = sizeof(umass_cbi_sbl_t), + .callback = &umass_t_cbi_status_callback, + .timeout = 5000, /* ms */ + }, + + [UMASS_T_CBI_RESET4] = { + .type = UE_CONTROL, + .endpoint = 0x00, /* Control pipe */ + .direction = -1, + .bufsize = sizeof(usb_device_request_t), + .flags = USBD_USE_DMA, + .callback = &umass_t_cbi_reset4_callback, + .timeout = 5000, /* ms */ + }, +}; + +/* If device cannot return valid inquiry data, fake it */ +static const u_int8_t fake_inq_data[SHORT_INQUIRY_LENGTH] = { + 0, /*removable*/ 0x80, SCSI_REV_2, SCSI_REV_2, + /*additional_length*/ 31, 0, 0, 0 +}; + +#define UFI_COMMAND_LENGTH 12 /* UFI commands are always 12 bytes */ +#define ATAPI_COMMAND_LENGTH 12 /* ATAPI commands are always 12 bytes */ + +static devclass_t umass_devclass; + +static device_method_t umass_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, umass_probe), + DEVMETHOD(device_attach, umass_attach), + DEVMETHOD(device_detach, umass_detach), + { 0, 0 } +}; + +static driver_t umass_driver = { + .name = "umass", + .methods = umass_methods, + .size = sizeof(struct umass_softc), +}; + +DRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, usbd_driver_load, 0); + +MODULE_DEPEND(umass, usb, 1,1,1); +MODULE_DEPEND(umass, cam, 1,1,1); + +/* + * USB device probe/attach/detach + */ + +/* + * Match the device we are seeing with the + * devices supported. + */ +static struct umass_probe_proto +umass_probe_proto(device_t dev, struct usb_attach_arg *uaa) +{ + const struct umass_devdescr *udd = umass_devdescr; + usb_interface_descriptor_t *id; + struct umass_probe_proto ret; + >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200609131658.k8DGwH3n027618>