umass.c revision 199675
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/storage/umass.c 199675 2009-11-22 21:21:22Z thompsa $"); 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>, 6189002Sed * Nick Hibma <n_hibma@FreeBSD.org> 7184610Salfred * All rights reserved. 8184610Salfred * 9184610Salfred * Redistribution and use in source and binary forms, with or without 10184610Salfred * modification, are permitted provided that the following conditions 11184610Salfred * are met: 12184610Salfred * 1. Redistributions of source code must retain the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer. 14184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 15184610Salfred * notice, this list of conditions and the following disclaimer in the 16184610Salfred * documentation and/or other materials provided with the distribution. 17184610Salfred * 18184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28184610Salfred * SUCH DAMAGE. 29184610Salfred * 30184610Salfred * $FreeBSD: head/sys/dev/usb/storage/umass.c 199675 2009-11-22 21:21:22Z thompsa $ 31184610Salfred * $NetBSD: umass.c,v 1.28 2000/04/02 23:46:53 augustss Exp $ 32184610Salfred */ 33184610Salfred 34184610Salfred/* Also already merged from NetBSD: 35184610Salfred * $NetBSD: umass.c,v 1.67 2001/11/25 19:05:22 augustss Exp $ 36184610Salfred * $NetBSD: umass.c,v 1.90 2002/11/04 19:17:33 pooka Exp $ 37184610Salfred * $NetBSD: umass.c,v 1.108 2003/11/07 17:03:25 wiz Exp $ 38184610Salfred * $NetBSD: umass.c,v 1.109 2003/12/04 13:57:31 keihan Exp $ 39184610Salfred */ 40184610Salfred 41184610Salfred/* 42184610Salfred * Universal Serial Bus Mass Storage Class specs: 43184610Salfred * http://www.usb.org/developers/devclass_docs/usb_msc_overview_1.2.pdf 44184610Salfred * http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf 45184610Salfred * http://www.usb.org/developers/devclass_docs/usb_msc_cbi_1.1.pdf 46184610Salfred * http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf 47184610Salfred */ 48184610Salfred 49184610Salfred/* 50184610Salfred * Ported to NetBSD by Lennart Augustsson <augustss@NetBSD.org>. 51184610Salfred * Parts of the code written by Jason R. Thorpe <thorpej@shagadelic.org>. 52184610Salfred */ 53184610Salfred 54184610Salfred/* 55184610Salfred * The driver handles 3 Wire Protocols 56184610Salfred * - Command/Bulk/Interrupt (CBI) 57184610Salfred * - Command/Bulk/Interrupt with Command Completion Interrupt (CBI with CCI) 58184610Salfred * - Mass Storage Bulk-Only (BBB) 59184610Salfred * (BBB refers Bulk/Bulk/Bulk for Command/Data/Status phases) 60184610Salfred * 61184610Salfred * Over these wire protocols it handles the following command protocols 62184610Salfred * - SCSI 63184610Salfred * - UFI (floppy command set) 64184610Salfred * - 8070i (ATAPI) 65184610Salfred * 66184610Salfred * UFI and 8070i (ATAPI) are transformed versions of the SCSI command set. The 67184610Salfred * sc->sc_transform method is used to convert the commands into the appropriate 68184610Salfred * format (if at all necessary). For example, UFI requires all commands to be 69184610Salfred * 12 bytes in length amongst other things. 70184610Salfred * 71184610Salfred * The source code below is marked and can be split into a number of pieces 72184610Salfred * (in this order): 73184610Salfred * 74184610Salfred * - probe/attach/detach 75184610Salfred * - generic transfer routines 76184610Salfred * - BBB 77184610Salfred * - CBI 78184610Salfred * - CBI_I (in addition to functions from CBI) 79184610Salfred * - CAM (Common Access Method) 80184610Salfred * - SCSI 81184610Salfred * - UFI 82184610Salfred * - 8070i (ATAPI) 83184610Salfred * 84184610Salfred * The protocols are implemented using a state machine, for the transfers as 85184610Salfred * well as for the resets. The state machine is contained in umass_t_*_callback. 86184610Salfred * The state machine is started through either umass_command_start() or 87184610Salfred * umass_reset(). 88184610Salfred * 89184610Salfred * The reason for doing this is a) CAM performs a lot better this way and b) it 90184610Salfred * avoids using tsleep from interrupt context (for example after a failed 91184610Salfred * transfer). 92184610Salfred */ 93184610Salfred 94184610Salfred/* 95184610Salfred * The SCSI related part of this driver has been derived from the 96189002Sed * dev/ppbus/vpo.c driver, by Nicolas Souchu (nsouch@FreeBSD.org). 97184610Salfred * 98184610Salfred * The CAM layer uses so called actions which are messages sent to the host 99184610Salfred * adapter for completion. The actions come in through umass_cam_action. The 100184610Salfred * appropriate block of routines is called depending on the transport protocol 101184610Salfred * in use. When the transfer has finished, these routines call 102184610Salfred * umass_cam_cb again to complete the CAM command. 103184610Salfred */ 104184610Salfred 105194677Sthompsa#include <sys/stdint.h> 106194677Sthompsa#include <sys/stddef.h> 107194677Sthompsa#include <sys/param.h> 108194677Sthompsa#include <sys/queue.h> 109194677Sthompsa#include <sys/types.h> 110194677Sthompsa#include <sys/systm.h> 111194677Sthompsa#include <sys/kernel.h> 112194677Sthompsa#include <sys/bus.h> 113194677Sthompsa#include <sys/linker_set.h> 114194677Sthompsa#include <sys/module.h> 115194677Sthompsa#include <sys/lock.h> 116194677Sthompsa#include <sys/mutex.h> 117194677Sthompsa#include <sys/condvar.h> 118194677Sthompsa#include <sys/sysctl.h> 119194677Sthompsa#include <sys/sx.h> 120194677Sthompsa#include <sys/unistd.h> 121194677Sthompsa#include <sys/callout.h> 122194677Sthompsa#include <sys/malloc.h> 123194677Sthompsa#include <sys/priv.h> 124194677Sthompsa 125194677Sthompsa#include <dev/usb/usb.h> 126194677Sthompsa#include <dev/usb/usbdi.h> 127196826Strasz#include <dev/usb/usb_device.h> 128188746Sthompsa#include "usbdevs.h" 129184610Salfred 130184610Salfred#include <cam/cam.h> 131184610Salfred#include <cam/cam_ccb.h> 132184610Salfred#include <cam/cam_sim.h> 133184610Salfred#include <cam/cam_xpt_sim.h> 134184610Salfred#include <cam/scsi/scsi_all.h> 135184610Salfred#include <cam/scsi/scsi_da.h> 136184610Salfred 137184610Salfred#include <cam/cam_periph.h> 138184610Salfred 139194677Sthompsa#define UMASS_EXT_BUFFER 140194677Sthompsa#ifdef UMASS_EXT_BUFFER 141184610Salfred/* this enables loading of virtual buffers into DMA */ 142184610Salfred#define UMASS_USB_FLAGS .ext_buffer=1, 143184610Salfred#else 144184610Salfred#define UMASS_USB_FLAGS 145184610Salfred#endif 146184610Salfred 147184610Salfred#if USB_DEBUG 148184610Salfred#define DIF(m, x) \ 149184610Salfred do { \ 150184610Salfred if (umass_debug & (m)) { x ; } \ 151184610Salfred } while (0) 152184610Salfred 153184610Salfred#define DPRINTF(sc, m, fmt, ...) \ 154184610Salfred do { \ 155184610Salfred if (umass_debug & (m)) { \ 156184610Salfred printf("%s:%s: " fmt, \ 157184610Salfred (sc) ? (const char *)(sc)->sc_name : \ 158184610Salfred (const char *)"umassX", \ 159184610Salfred __FUNCTION__ ,## __VA_ARGS__); \ 160184610Salfred } \ 161184610Salfred } while (0) 162184610Salfred 163184610Salfred#define UDMASS_GEN 0x00010000 /* general */ 164184610Salfred#define UDMASS_SCSI 0x00020000 /* scsi */ 165184610Salfred#define UDMASS_UFI 0x00040000 /* ufi command set */ 166184610Salfred#define UDMASS_ATAPI 0x00080000 /* 8070i command set */ 167184610Salfred#define UDMASS_CMD (UDMASS_SCSI|UDMASS_UFI|UDMASS_ATAPI) 168184610Salfred#define UDMASS_USB 0x00100000 /* USB general */ 169184610Salfred#define UDMASS_BBB 0x00200000 /* Bulk-Only transfers */ 170184610Salfred#define UDMASS_CBI 0x00400000 /* CBI transfers */ 171184610Salfred#define UDMASS_WIRE (UDMASS_BBB|UDMASS_CBI) 172184610Salfred#define UDMASS_ALL 0xffff0000 /* all of the above */ 173184610Salfredstatic int umass_debug = 0; 174184610Salfred 175192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass"); 176192502SthompsaSYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW, 177184610Salfred &umass_debug, 0, "umass debug level"); 178199675Sthompsa 179199675SthompsaTUNABLE_INT("hw.usb.umass.debug", &umass_debug); 180184610Salfred#else 181184610Salfred#define DIF(...) do { } while (0) 182184610Salfred#define DPRINTF(...) do { } while (0) 183184610Salfred#endif 184184610Salfred 185184610Salfred#define UMASS_GONE ((struct umass_softc *)1) 186184610Salfred 187184610Salfred#define UMASS_BULK_SIZE (1 << 17) 188184610Salfred#define UMASS_CBI_DIAGNOSTIC_CMDLEN 12 /* bytes */ 189184610Salfred#define UMASS_MAX_CMDLEN MAX(12, CAM_MAX_CDBLEN) /* bytes */ 190184610Salfred 191184610Salfred/* USB transfer definitions */ 192184610Salfred 193184610Salfred#define UMASS_T_BBB_RESET1 0 /* Bulk-Only */ 194184610Salfred#define UMASS_T_BBB_RESET2 1 195184610Salfred#define UMASS_T_BBB_RESET3 2 196184610Salfred#define UMASS_T_BBB_COMMAND 3 197184610Salfred#define UMASS_T_BBB_DATA_READ 4 198184610Salfred#define UMASS_T_BBB_DATA_RD_CS 5 199184610Salfred#define UMASS_T_BBB_DATA_WRITE 6 200184610Salfred#define UMASS_T_BBB_DATA_WR_CS 7 201184610Salfred#define UMASS_T_BBB_STATUS 8 202184610Salfred#define UMASS_T_BBB_MAX 9 203184610Salfred 204184610Salfred#define UMASS_T_CBI_RESET1 0 /* CBI */ 205184610Salfred#define UMASS_T_CBI_RESET2 1 206184610Salfred#define UMASS_T_CBI_RESET3 2 207184610Salfred#define UMASS_T_CBI_COMMAND 3 208184610Salfred#define UMASS_T_CBI_DATA_READ 4 209184610Salfred#define UMASS_T_CBI_DATA_RD_CS 5 210184610Salfred#define UMASS_T_CBI_DATA_WRITE 6 211184610Salfred#define UMASS_T_CBI_DATA_WR_CS 7 212184610Salfred#define UMASS_T_CBI_STATUS 8 213184610Salfred#define UMASS_T_CBI_RESET4 9 214184610Salfred#define UMASS_T_CBI_MAX 10 215184610Salfred 216184610Salfred#define UMASS_T_MAX MAX(UMASS_T_CBI_MAX, UMASS_T_BBB_MAX) 217184610Salfred 218184610Salfred/* Generic definitions */ 219184610Salfred 220184610Salfred/* Direction for transfer */ 221184610Salfred#define DIR_NONE 0 222184610Salfred#define DIR_IN 1 223184610Salfred#define DIR_OUT 2 224184610Salfred 225184610Salfred/* device name */ 226184610Salfred#define DEVNAME "umass" 227184610Salfred#define DEVNAME_SIM "umass-sim" 228184610Salfred 229184610Salfred/* Approximate maximum transfer speeds (assumes 33% overhead). */ 230184610Salfred#define UMASS_FULL_TRANSFER_SPEED 1000 231184610Salfred#define UMASS_HIGH_TRANSFER_SPEED 40000 232184610Salfred#define UMASS_FLOPPY_TRANSFER_SPEED 20 233184610Salfred 234184610Salfred#define UMASS_TIMEOUT 5000 /* ms */ 235184610Salfred 236184610Salfred/* CAM specific definitions */ 237184610Salfred 238184610Salfred#define UMASS_SCSIID_MAX 1 /* maximum number of drives expected */ 239184610Salfred#define UMASS_SCSIID_HOST UMASS_SCSIID_MAX 240184610Salfred 241184610Salfred/* Bulk-Only features */ 242184610Salfred 243184610Salfred#define UR_BBB_RESET 0xff /* Bulk-Only reset */ 244184610Salfred#define UR_BBB_GET_MAX_LUN 0xfe /* Get maximum lun */ 245184610Salfred 246184610Salfred/* Command Block Wrapper */ 247184610Salfredtypedef struct { 248184610Salfred uDWord dCBWSignature; 249184610Salfred#define CBWSIGNATURE 0x43425355 250184610Salfred uDWord dCBWTag; 251184610Salfred uDWord dCBWDataTransferLength; 252184610Salfred uByte bCBWFlags; 253184610Salfred#define CBWFLAGS_OUT 0x00 254184610Salfred#define CBWFLAGS_IN 0x80 255184610Salfred uByte bCBWLUN; 256184610Salfred uByte bCDBLength; 257184610Salfred#define CBWCDBLENGTH 16 258184610Salfred uByte CBWCDB[CBWCDBLENGTH]; 259184610Salfred} __packed umass_bbb_cbw_t; 260184610Salfred 261184610Salfred#define UMASS_BBB_CBW_SIZE 31 262184610Salfred 263184610Salfred/* Command Status Wrapper */ 264184610Salfredtypedef struct { 265184610Salfred uDWord dCSWSignature; 266184610Salfred#define CSWSIGNATURE 0x53425355 267184610Salfred#define CSWSIGNATURE_IMAGINATION_DBX1 0x43425355 268184610Salfred#define CSWSIGNATURE_OLYMPUS_C1 0x55425355 269184610Salfred uDWord dCSWTag; 270184610Salfred uDWord dCSWDataResidue; 271184610Salfred uByte bCSWStatus; 272184610Salfred#define CSWSTATUS_GOOD 0x0 273184610Salfred#define CSWSTATUS_FAILED 0x1 274184610Salfred#define CSWSTATUS_PHASE 0x2 275184610Salfred} __packed umass_bbb_csw_t; 276184610Salfred 277184610Salfred#define UMASS_BBB_CSW_SIZE 13 278184610Salfred 279184610Salfred/* CBI features */ 280184610Salfred 281184610Salfred#define UR_CBI_ADSC 0x00 282184610Salfred 283184610Salfredtypedef union { 284184610Salfred struct { 285184610Salfred uint8_t type; 286184610Salfred#define IDB_TYPE_CCI 0x00 287184610Salfred uint8_t value; 288184610Salfred#define IDB_VALUE_PASS 0x00 289184610Salfred#define IDB_VALUE_FAIL 0x01 290184610Salfred#define IDB_VALUE_PHASE 0x02 291184610Salfred#define IDB_VALUE_PERSISTENT 0x03 292184610Salfred#define IDB_VALUE_STATUS_MASK 0x03 293184610Salfred } __packed common; 294184610Salfred 295184610Salfred struct { 296184610Salfred uint8_t asc; 297184610Salfred uint8_t ascq; 298184610Salfred } __packed ufi; 299184610Salfred} __packed umass_cbi_sbl_t; 300184610Salfred 301184610Salfredstruct umass_softc; /* see below */ 302184610Salfred 303184610Salfredtypedef void (umass_callback_t)(struct umass_softc *sc, union ccb *ccb, 304184610Salfred uint32_t residue, uint8_t status); 305184610Salfred 306184610Salfred#define STATUS_CMD_OK 0 /* everything ok */ 307184610Salfred#define STATUS_CMD_UNKNOWN 1 /* will have to fetch sense */ 308184610Salfred#define STATUS_CMD_FAILED 2 /* transfer was ok, command failed */ 309184610Salfred#define STATUS_WIRE_FAILED 3 /* couldn't even get command across */ 310184610Salfred 311184610Salfredtypedef uint8_t (umass_transform_t)(struct umass_softc *sc, uint8_t *cmd_ptr, 312184610Salfred uint8_t cmd_len); 313184610Salfred 314184610Salfredstruct umass_devdescr { 315184610Salfred uint32_t vid; 316184610Salfred#define VID_WILDCARD 0xffffffff 317184610Salfred#define VID_EOT 0xfffffffe 318184610Salfred uint32_t pid; 319184610Salfred#define PID_WILDCARD 0xffffffff 320184610Salfred#define PID_EOT 0xfffffffe 321184610Salfred uint32_t rid; 322184610Salfred#define RID_WILDCARD 0xffffffff 323184610Salfred#define RID_EOT 0xfffffffe 324184610Salfred 325184610Salfred /* wire and command protocol */ 326184610Salfred uint16_t proto; 327192052Sthompsa#define UMASS_PROTO_DEFAULT 0x0000 /* use protocol indicated by USB descriptors */ 328184610Salfred#define UMASS_PROTO_BBB 0x0001 /* USB wire protocol */ 329184610Salfred#define UMASS_PROTO_CBI 0x0002 330184610Salfred#define UMASS_PROTO_CBI_I 0x0004 331184610Salfred#define UMASS_PROTO_WIRE 0x00ff /* USB wire protocol mask */ 332184610Salfred#define UMASS_PROTO_SCSI 0x0100 /* command protocol */ 333184610Salfred#define UMASS_PROTO_ATAPI 0x0200 334184610Salfred#define UMASS_PROTO_UFI 0x0400 335184610Salfred#define UMASS_PROTO_RBC 0x0800 336184610Salfred#define UMASS_PROTO_COMMAND 0xff00 /* command protocol mask */ 337184610Salfred 338184610Salfred /* Device specific quirks */ 339184610Salfred uint16_t quirks; 340184610Salfred#define NO_QUIRKS 0x0000 341184610Salfred /* 342184610Salfred * The drive does not support Test Unit Ready. Convert to Start Unit 343184610Salfred */ 344184610Salfred#define NO_TEST_UNIT_READY 0x0001 345184610Salfred /* 346184610Salfred * The drive does not reset the Unit Attention state after REQUEST 347184610Salfred * SENSE has been sent. The INQUIRY command does not reset the UA 348184610Salfred * either, and so CAM runs in circles trying to retrieve the initial 349184610Salfred * INQUIRY data. 350184610Salfred */ 351184610Salfred#define RS_NO_CLEAR_UA 0x0002 352184610Salfred /* The drive does not support START STOP. */ 353184610Salfred#define NO_START_STOP 0x0004 354184610Salfred /* Don't ask for full inquiry data (255b). */ 355184610Salfred#define FORCE_SHORT_INQUIRY 0x0008 356184610Salfred /* Needs to be initialised the Shuttle way */ 357184610Salfred#define SHUTTLE_INIT 0x0010 358184610Salfred /* Drive needs to be switched to alternate iface 1 */ 359184610Salfred#define ALT_IFACE_1 0x0020 360184610Salfred /* Drive does not do 1Mb/s, but just floppy speeds (20kb/s) */ 361184610Salfred#define FLOPPY_SPEED 0x0040 362184610Salfred /* The device can't count and gets the residue of transfers wrong */ 363184610Salfred#define IGNORE_RESIDUE 0x0080 364184610Salfred /* No GetMaxLun call */ 365184610Salfred#define NO_GETMAXLUN 0x0100 366184610Salfred /* The device uses a weird CSWSIGNATURE. */ 367184610Salfred#define WRONG_CSWSIG 0x0200 368184610Salfred /* Device cannot handle INQUIRY so fake a generic response */ 369184610Salfred#define NO_INQUIRY 0x0400 370184610Salfred /* Device cannot handle INQUIRY EVPD, return CHECK CONDITION */ 371184610Salfred#define NO_INQUIRY_EVPD 0x0800 372184610Salfred /* Pad all RBC requests to 12 bytes. */ 373184610Salfred#define RBC_PAD_TO_12 0x1000 374184610Salfred /* 375184610Salfred * Device reports number of sectors from READ_CAPACITY, not max 376184610Salfred * sector number. 377184610Salfred */ 378184610Salfred#define READ_CAPACITY_OFFBY1 0x2000 379184610Salfred /* 380184610Salfred * Device cannot handle a SCSI synchronize cache command. Normally 381184610Salfred * this quirk would be handled in the cam layer, but for IDE bridges 382184610Salfred * we need to associate the quirk with the bridge and not the 383184610Salfred * underlying disk device. This is handled by faking a success 384184610Salfred * result. 385184610Salfred */ 386184610Salfred#define NO_SYNCHRONIZE_CACHE 0x4000 387184610Salfred}; 388184610Salfred 389184610Salfredstatic const struct umass_devdescr umass_devdescr[] = { 390184610Salfred {USB_VENDOR_ASAHIOPTICAL, PID_WILDCARD, RID_WILDCARD, 391192052Sthompsa UMASS_PROTO_DEFAULT, 392184610Salfred RS_NO_CLEAR_UA 393184610Salfred }, 394184610Salfred {USB_VENDOR_ADDON, USB_PRODUCT_ADDON_ATTACHE, RID_WILDCARD, 395184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 396184610Salfred IGNORE_RESIDUE 397184610Salfred }, 398184610Salfred {USB_VENDOR_ADDON, USB_PRODUCT_ADDON_A256MB, RID_WILDCARD, 399184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 400184610Salfred IGNORE_RESIDUE 401184610Salfred }, 402184610Salfred {USB_VENDOR_ADDON, USB_PRODUCT_ADDON_DISKPRO512, RID_WILDCARD, 403184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 404184610Salfred IGNORE_RESIDUE 405184610Salfred }, 406184610Salfred {USB_VENDOR_ADDONICS2, USB_PRODUCT_ADDONICS2_CABLE_205, RID_WILDCARD, 407184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 408184610Salfred NO_QUIRKS 409184610Salfred }, 410184610Salfred {USB_VENDOR_AIPTEK, USB_PRODUCT_AIPTEK_POCKETCAM3M, RID_WILDCARD, 411184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 412184610Salfred NO_QUIRKS 413184610Salfred }, 414193171Sdeischen {USB_VENDOR_AIPTEK2, USB_PRODUCT_AIPTEK2_SUNPLUS_TECH, RID_WILDCARD, 415193171Sdeischen UMASS_PROTO_DEFAULT, 416193171Sdeischen NO_SYNCHRONIZE_CACHE 417193171Sdeischen }, 418196495Salfred {USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_SDCR_6335, RID_WILDCARD, 419196495Salfred UMASS_PROTO_DEFAULT, 420196495Salfred NO_TEST_UNIT_READY | NO_SYNCHRONIZE_CACHE 421196495Salfred }, 422192052Sthompsa {USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_AU6390, RID_WILDCARD, 423192052Sthompsa UMASS_PROTO_DEFAULT, 424192052Sthompsa NO_SYNCHRONIZE_CACHE 425192052Sthompsa }, 426184610Salfred {USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_UMCR_9361, RID_WILDCARD, 427184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 428184610Salfred NO_GETMAXLUN 429184610Salfred }, 430186730Salfred {USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_TRANSCEND, RID_WILDCARD, 431186730Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 432186730Salfred NO_GETMAXLUN 433186730Salfred }, 434184610Salfred {USB_VENDOR_ASAHIOPTICAL, USB_PRODUCT_ASAHIOPTICAL_OPTIO230, RID_WILDCARD, 435184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 436184610Salfred NO_INQUIRY 437184610Salfred }, 438184610Salfred {USB_VENDOR_ASAHIOPTICAL, USB_PRODUCT_ASAHIOPTICAL_OPTIO330, RID_WILDCARD, 439184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 440184610Salfred NO_INQUIRY 441184610Salfred }, 442184610Salfred {USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2SCSI, RID_WILDCARD, 443184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 444184610Salfred NO_QUIRKS 445184610Salfred }, 446184610Salfred {USB_VENDOR_CASIO, USB_PRODUCT_CASIO_QV_DIGICAM, RID_WILDCARD, 447184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_CBI, 448184610Salfred NO_INQUIRY 449184610Salfred }, 450184610Salfred {USB_VENDOR_CCYU, USB_PRODUCT_CCYU_ED1064, RID_WILDCARD, 451184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 452184610Salfred NO_QUIRKS 453184610Salfred }, 454184610Salfred {USB_VENDOR_CENTURY, USB_PRODUCT_CENTURY_EX35QUAT, RID_WILDCARD, 455184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 456184610Salfred FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE 457184610Salfred }, 458192052Sthompsa {USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_XX6830XX, RID_WILDCARD, 459192052Sthompsa UMASS_PROTO_DEFAULT, 460192052Sthompsa NO_GETMAXLUN | NO_SYNCHRONIZE_CACHE 461192052Sthompsa }, 462184610Salfred {USB_VENDOR_DESKNOTE, USB_PRODUCT_DESKNOTE_UCR_61S2B, RID_WILDCARD, 463184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 464184610Salfred NO_QUIRKS 465184610Salfred }, 466184610Salfred {USB_VENDOR_DMI, USB_PRODUCT_DMI_CFSM_RW, RID_WILDCARD, 467184610Salfred UMASS_PROTO_SCSI, 468184610Salfred NO_GETMAXLUN 469184610Salfred }, 470184610Salfred {USB_VENDOR_EPSON, USB_PRODUCT_EPSON_STYLUS_875DC, RID_WILDCARD, 471184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_CBI, 472184610Salfred NO_INQUIRY 473184610Salfred }, 474184610Salfred {USB_VENDOR_EPSON, USB_PRODUCT_EPSON_STYLUS_895, RID_WILDCARD, 475184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 476184610Salfred NO_GETMAXLUN 477184610Salfred }, 478184610Salfred {USB_VENDOR_FEIYA, USB_PRODUCT_FEIYA_5IN1, RID_WILDCARD, 479184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 480184610Salfred NO_QUIRKS 481184610Salfred }, 482184610Salfred {USB_VENDOR_FREECOM, USB_PRODUCT_FREECOM_DVD, RID_WILDCARD, 483184610Salfred UMASS_PROTO_SCSI, 484184610Salfred NO_QUIRKS 485184610Salfred }, 486184610Salfred {USB_VENDOR_FUJIPHOTO, USB_PRODUCT_FUJIPHOTO_MASS0100, RID_WILDCARD, 487184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, 488184610Salfred RS_NO_CLEAR_UA 489184610Salfred }, 490184610Salfred {USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB2IDE, RID_WILDCARD, 491184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 492184610Salfred FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE 493190189Sthompsa | NO_SYNCHRONIZE_CACHE 494184610Salfred }, 495184610Salfred {USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB2IDE_2, RID_WILDCARD, 496184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, 497184610Salfred FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE 498184610Salfred }, 499184610Salfred {USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB, RID_WILDCARD, 500184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 501184610Salfred FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE 502184610Salfred }, 503184610Salfred {USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB_2, RID_WILDCARD, 504184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 505184610Salfred WRONG_CSWSIG 506184610Salfred }, 507184610Salfred {USB_VENDOR_HAGIWARA, USB_PRODUCT_HAGIWARA_FG, RID_WILDCARD, 508184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 509184610Salfred NO_QUIRKS 510184610Salfred }, 511184610Salfred {USB_VENDOR_HAGIWARA, USB_PRODUCT_HAGIWARA_FGSM, RID_WILDCARD, 512184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 513184610Salfred NO_QUIRKS 514184610Salfred }, 515184610Salfred {USB_VENDOR_HITACHI, USB_PRODUCT_HITACHI_DVDCAM_DZ_MV100A, RID_WILDCARD, 516184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_CBI, 517184610Salfred NO_GETMAXLUN 518184610Salfred }, 519184610Salfred {USB_VENDOR_HITACHI, USB_PRODUCT_HITACHI_DVDCAM_USB, RID_WILDCARD, 520184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, 521184610Salfred NO_INQUIRY 522184610Salfred }, 523184610Salfred {USB_VENDOR_HP, USB_PRODUCT_HP_CDW4E, RID_WILDCARD, 524184610Salfred UMASS_PROTO_ATAPI, 525184610Salfred NO_QUIRKS 526184610Salfred }, 527184610Salfred {USB_VENDOR_HP, USB_PRODUCT_HP_CDW8200, RID_WILDCARD, 528184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, 529184610Salfred NO_TEST_UNIT_READY | NO_START_STOP 530184610Salfred }, 531184610Salfred {USB_VENDOR_IMAGINATION, USB_PRODUCT_IMAGINATION_DBX1, RID_WILDCARD, 532184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 533184610Salfred WRONG_CSWSIG 534184610Salfred }, 535184610Salfred {USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_USBCABLE, RID_WILDCARD, 536184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, 537184610Salfred NO_TEST_UNIT_READY | NO_START_STOP | ALT_IFACE_1 538184610Salfred }, 539184610Salfred {USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_ATAPI, RID_WILDCARD, 540184610Salfred UMASS_PROTO_RBC | UMASS_PROTO_CBI, 541184610Salfred NO_QUIRKS 542184610Salfred }, 543184610Salfred {USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_STORAGE_V2, RID_WILDCARD, 544184610Salfred UMASS_PROTO_RBC | UMASS_PROTO_CBI, 545184610Salfred NO_QUIRKS 546184610Salfred }, 547184610Salfred {USB_VENDOR_IODATA, USB_PRODUCT_IODATA_IU_CD2, RID_WILDCARD, 548184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 549184610Salfred NO_QUIRKS 550184610Salfred }, 551184610Salfred {USB_VENDOR_IODATA, USB_PRODUCT_IODATA_DVR_UEH8, RID_WILDCARD, 552184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 553184610Salfred NO_QUIRKS 554184610Salfred }, 555184610Salfred {USB_VENDOR_IOMEGA, USB_PRODUCT_IOMEGA_ZIP100, RID_WILDCARD, 556184610Salfred /* 557184610Salfred * XXX This is not correct as there are Zip drives that use 558184610Salfred * ATAPI. 559184610Salfred */ 560184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 561184610Salfred NO_TEST_UNIT_READY 562184610Salfred }, 563184610Salfred {USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_FINECAM_L3, RID_WILDCARD, 564184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 565184610Salfred NO_INQUIRY 566184610Salfred }, 567184610Salfred {USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_FINECAM_S3X, RID_WILDCARD, 568184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, 569184610Salfred NO_INQUIRY 570184610Salfred }, 571184610Salfred {USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_FINECAM_S4, RID_WILDCARD, 572184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, 573184610Salfred NO_INQUIRY 574184610Salfred }, 575184610Salfred {USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_FINECAM_S5, RID_WILDCARD, 576184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 577184610Salfred NO_INQUIRY 578184610Salfred }, 579184610Salfred {USB_VENDOR_LACIE, USB_PRODUCT_LACIE_HD, RID_WILDCARD, 580184610Salfred UMASS_PROTO_RBC | UMASS_PROTO_CBI, 581184610Salfred NO_QUIRKS 582184610Salfred }, 583184610Salfred {USB_VENDOR_LEXAR, USB_PRODUCT_LEXAR_CF_READER, RID_WILDCARD, 584184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 585184610Salfred NO_INQUIRY 586184610Salfred }, 587184610Salfred {USB_VENDOR_LEXAR, USB_PRODUCT_LEXAR_JUMPSHOT, RID_WILDCARD, 588184610Salfred UMASS_PROTO_SCSI, 589184610Salfred NO_QUIRKS 590184610Salfred }, 591184610Salfred {USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LDR_H443SU2, RID_WILDCARD, 592184610Salfred UMASS_PROTO_SCSI, 593184610Salfred NO_QUIRKS 594184610Salfred }, 595184610Salfred {USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LDR_H443U2, RID_WILDCARD, 596184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 597184610Salfred NO_QUIRKS 598184610Salfred }, 599184610Salfred {USB_VENDOR_MELCO, USB_PRODUCT_MELCO_DUBPXXG, RID_WILDCARD, 600184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 601184610Salfred FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE 602184610Salfred }, 603184610Salfred {USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_DPCM, RID_WILDCARD, 604184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_CBI, 605184610Salfred NO_TEST_UNIT_READY | NO_START_STOP 606184610Salfred }, 607184610Salfred {USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_SCSIDB25, RID_WILDCARD, 608184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 609184610Salfred NO_QUIRKS 610184610Salfred }, 611184610Salfred {USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_SCSIHD50, RID_WILDCARD, 612184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 613184610Salfred NO_QUIRKS 614184610Salfred }, 615184610Salfred {USB_VENDOR_MINOLTA, USB_PRODUCT_MINOLTA_E223, RID_WILDCARD, 616184610Salfred UMASS_PROTO_SCSI, 617184610Salfred NO_QUIRKS 618184610Salfred }, 619184610Salfred {USB_VENDOR_MINOLTA, USB_PRODUCT_MINOLTA_F300, RID_WILDCARD, 620184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 621184610Salfred NO_QUIRKS 622184610Salfred }, 623184610Salfred {USB_VENDOR_MITSUMI, USB_PRODUCT_MITSUMI_CDRRW, RID_WILDCARD, 624184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, 625184610Salfred NO_QUIRKS 626184610Salfred }, 627184610Salfred {USB_VENDOR_MITSUMI, USB_PRODUCT_MITSUMI_FDD, RID_WILDCARD, 628184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 629184610Salfred NO_GETMAXLUN 630184610Salfred }, 631184610Salfred {USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_E398, RID_WILDCARD, 632184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 633184610Salfred FORCE_SHORT_INQUIRY | NO_INQUIRY_EVPD | NO_GETMAXLUN 634184610Salfred }, 635192052Sthompsa {USB_VENDOR_MPMAN, PID_WILDCARD, RID_WILDCARD, 636192052Sthompsa UMASS_PROTO_DEFAULT, 637192052Sthompsa NO_SYNCHRONIZE_CACHE 638192052Sthompsa }, 639184610Salfred {USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY, RID_WILDCARD, 640184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 641184610Salfred IGNORE_RESIDUE | NO_GETMAXLUN | RS_NO_CLEAR_UA 642184610Salfred }, 643184610Salfred {USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY2, RID_WILDCARD, 644184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, 645184610Salfred NO_QUIRKS 646184610Salfred }, 647184610Salfred {USB_VENDOR_MYSON, USB_PRODUCT_MYSON_HEDEN, RID_WILDCARD, 648192052Sthompsa UMASS_PROTO_DEFAULT, 649190263Simp IGNORE_RESIDUE | NO_SYNCHRONIZE_CACHE 650184610Salfred }, 651194582Sremko {USB_VENDOR_MYSON, USB_PRODUCT_MYSON_HEDEN_8813, RID_WILDCARD, 652194584Sremko UMASS_PROTO_DEFAULT, 653194582Sremko NO_SYNCHRONIZE_CACHE 654194582Sremko }, 655187726Sthompsa {USB_VENDOR_MYSON, USB_PRODUCT_MYSON_STARREADER, RID_WILDCARD, 656192052Sthompsa UMASS_PROTO_DEFAULT, 657187726Sthompsa NO_SYNCHRONIZE_CACHE 658187726Sthompsa }, 659184610Salfred {USB_VENDOR_NEODIO, USB_PRODUCT_NEODIO_ND3260, RID_WILDCARD, 660184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 661184610Salfred FORCE_SHORT_INQUIRY 662184610Salfred }, 663184610Salfred {USB_VENDOR_NETAC, USB_PRODUCT_NETAC_CF_CARD, RID_WILDCARD, 664184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 665184610Salfred NO_INQUIRY 666184610Salfred }, 667184610Salfred {USB_VENDOR_NETAC, USB_PRODUCT_NETAC_ONLYDISK, RID_WILDCARD, 668184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 669184610Salfred IGNORE_RESIDUE 670184610Salfred }, 671184610Salfred {USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_CLIK_40, RID_WILDCARD, 672184610Salfred UMASS_PROTO_ATAPI, 673184610Salfred NO_INQUIRY 674184610Salfred }, 675184610Salfred {USB_VENDOR_NIKON, USB_PRODUCT_NIKON_D300, RID_WILDCARD, 676184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 677184610Salfred NO_QUIRKS 678184610Salfred }, 679184610Salfred {USB_VENDOR_OLYMPUS, USB_PRODUCT_OLYMPUS_C1, RID_WILDCARD, 680184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 681184610Salfred WRONG_CSWSIG 682184610Salfred }, 683184610Salfred {USB_VENDOR_OLYMPUS, USB_PRODUCT_OLYMPUS_C700, RID_WILDCARD, 684199062Sthompsa UMASS_PROTO_DEFAULT, 685184610Salfred NO_GETMAXLUN 686184610Salfred }, 687186730Salfred {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_SDS_HOTFIND_D, RID_WILDCARD, 688186730Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 689186730Salfred NO_GETMAXLUN | NO_SYNCHRONIZE_CACHE 690186730Salfred }, 691184610Salfred {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_CFMS_RW, RID_WILDCARD, 692184610Salfred UMASS_PROTO_SCSI, 693184610Salfred NO_QUIRKS 694184610Salfred }, 695184610Salfred {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_CFSM_COMBO, RID_WILDCARD, 696184610Salfred UMASS_PROTO_SCSI, 697184610Salfred NO_QUIRKS 698184610Salfred }, 699184610Salfred {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_CFSM_READER, RID_WILDCARD, 700184610Salfred UMASS_PROTO_SCSI, 701184610Salfred NO_QUIRKS 702184610Salfred }, 703184610Salfred {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_CFSM_READER2, RID_WILDCARD, 704184610Salfred UMASS_PROTO_SCSI, 705184610Salfred NO_QUIRKS 706184610Salfred }, 707184610Salfred {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_MDCFE_B_CF_READER, RID_WILDCARD, 708184610Salfred UMASS_PROTO_SCSI, 709184610Salfred NO_QUIRKS 710184610Salfred }, 711184610Salfred {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_MDSM_B_READER, RID_WILDCARD, 712184610Salfred UMASS_PROTO_SCSI, 713184610Salfred NO_INQUIRY 714184610Salfred }, 715184610Salfred {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_READER, RID_WILDCARD, 716184610Salfred UMASS_PROTO_SCSI, 717184610Salfred NO_QUIRKS 718184610Salfred }, 719184610Salfred {USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_UCF100, RID_WILDCARD, 720184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, 721184610Salfred NO_INQUIRY | NO_GETMAXLUN 722184610Salfred }, 723184610Salfred {USB_VENDOR_ONSPEC2, USB_PRODUCT_ONSPEC2_IMAGEMATE_SDDR55, RID_WILDCARD, 724184610Salfred UMASS_PROTO_SCSI, 725184610Salfred NO_GETMAXLUN 726184610Salfred }, 727184610Salfred {USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXL840AN, RID_WILDCARD, 728184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, 729184610Salfred NO_GETMAXLUN 730184610Salfred }, 731184610Salfred {USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXLCB20AN, RID_WILDCARD, 732184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 733184610Salfred NO_QUIRKS 734184610Salfred }, 735184610Salfred {USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXLCB35AN, RID_WILDCARD, 736184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 737184610Salfred NO_QUIRKS 738184610Salfred }, 739184610Salfred {USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_LS120CAM, RID_WILDCARD, 740184610Salfred UMASS_PROTO_UFI, 741184610Salfred NO_QUIRKS 742184610Salfred }, 743196495Salfred { USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_SPE3030CC, RID_WILDCARD, 744196495Salfred UMASS_PROTO_DEFAULT, 745196495Salfred NO_SYNCHRONIZE_CACHE 746196495Salfred }, 747184610Salfred {USB_VENDOR_PLEXTOR, USB_PRODUCT_PLEXTOR_40_12_40U, RID_WILDCARD, 748184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 749184610Salfred NO_TEST_UNIT_READY 750184610Salfred }, 751184610Salfred {USB_VENDOR_PNY, USB_PRODUCT_PNY_ATTACHE2, RID_WILDCARD, 752184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 753184610Salfred IGNORE_RESIDUE | NO_START_STOP 754184610Salfred }, 755184610Salfred {USB_VENDOR_SAMSUNG_TECHWIN, USB_PRODUCT_SAMSUNG_TECHWIN_DIGIMAX_410, RID_WILDCARD, 756184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 757184610Salfred NO_INQUIRY 758184610Salfred }, 759184610Salfred {USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR05A, RID_WILDCARD, 760184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_CBI, 761184610Salfred READ_CAPACITY_OFFBY1 | NO_GETMAXLUN 762184610Salfred }, 763184610Salfred {USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR09, RID_WILDCARD, 764184610Salfred UMASS_PROTO_SCSI, 765184610Salfred READ_CAPACITY_OFFBY1 | NO_GETMAXLUN 766184610Salfred }, 767184610Salfred {USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR12, RID_WILDCARD, 768184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_CBI, 769184610Salfred READ_CAPACITY_OFFBY1 | NO_GETMAXLUN 770184610Salfred }, 771184610Salfred {USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ2_256, RID_WILDCARD, 772184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 773184610Salfred IGNORE_RESIDUE 774184610Salfred }, 775184610Salfred {USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ4_128, RID_WILDCARD, 776184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 777184610Salfred IGNORE_RESIDUE 778184610Salfred }, 779184610Salfred {USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ4_256, RID_WILDCARD, 780184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 781184610Salfred IGNORE_RESIDUE 782184610Salfred }, 783184610Salfred {USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR31, RID_WILDCARD, 784184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 785184610Salfred READ_CAPACITY_OFFBY1 786184610Salfred }, 787184610Salfred {USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_SL11R, RID_WILDCARD, 788184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, 789184610Salfred NO_INQUIRY 790184610Salfred }, 791184610Salfred {USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSB, RID_WILDCARD, 792184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, 793184610Salfred NO_TEST_UNIT_READY | NO_START_STOP | SHUTTLE_INIT 794184610Salfred }, 795184610Salfred {USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_CDRW, RID_WILDCARD, 796184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, 797184610Salfred NO_QUIRKS 798184610Salfred }, 799184610Salfred {USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_CF, RID_WILDCARD, 800184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, 801184610Salfred NO_QUIRKS 802184610Salfred }, 803184610Salfred {USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSBATAPI, RID_WILDCARD, 804184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, 805184610Salfred NO_QUIRKS 806184610Salfred }, 807184610Salfred {USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSBCFSM, RID_WILDCARD, 808184610Salfred UMASS_PROTO_SCSI, 809184610Salfred NO_QUIRKS 810184610Salfred }, 811184610Salfred {USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSCSI, RID_WILDCARD, 812184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 813184610Salfred NO_QUIRKS 814184610Salfred }, 815184610Salfred {USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_HIFD, RID_WILDCARD, 816184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_CBI, 817184610Salfred NO_GETMAXLUN 818184610Salfred }, 819184610Salfred {USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_SDDR09, RID_WILDCARD, 820184610Salfred UMASS_PROTO_SCSI, 821184610Salfred NO_GETMAXLUN 822184610Salfred }, 823184610Salfred {USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_ZIOMMC, RID_WILDCARD, 824184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_CBI, 825184610Salfred NO_GETMAXLUN 826184610Salfred }, 827184610Salfred {USB_VENDOR_SIGMATEL, USB_PRODUCT_SIGMATEL_I_BEAD100, RID_WILDCARD, 828184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 829184610Salfred SHUTTLE_INIT 830184610Salfred }, 831184610Salfred {USB_VENDOR_SIIG, USB_PRODUCT_SIIG_WINTERREADER, RID_WILDCARD, 832184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 833184610Salfred IGNORE_RESIDUE 834184610Salfred }, 835184610Salfred {USB_VENDOR_SKANHEX, USB_PRODUCT_SKANHEX_MD_7425, RID_WILDCARD, 836184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 837184610Salfred NO_INQUIRY 838184610Salfred }, 839184610Salfred {USB_VENDOR_SKANHEX, USB_PRODUCT_SKANHEX_SX_520Z, RID_WILDCARD, 840184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 841184610Salfred NO_INQUIRY 842184610Salfred }, 843184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_HANDYCAM, 0x0500, 844184610Salfred UMASS_PROTO_RBC | UMASS_PROTO_CBI, 845184610Salfred RBC_PAD_TO_12 846184610Salfred }, 847184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_40_MS, RID_WILDCARD, 848184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 849184610Salfred NO_INQUIRY 850184610Salfred }, 851184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, 0x0500, 852184610Salfred UMASS_PROTO_RBC | UMASS_PROTO_CBI, 853184610Salfred RBC_PAD_TO_12 854184610Salfred }, 855184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, 0x0600, 856184610Salfred UMASS_PROTO_RBC | UMASS_PROTO_CBI, 857184610Salfred RBC_PAD_TO_12 858184610Salfred }, 859184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, RID_WILDCARD, 860184610Salfred UMASS_PROTO_RBC | UMASS_PROTO_CBI, 861184610Salfred NO_QUIRKS 862184610Salfred }, 863184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_HANDYCAM, RID_WILDCARD, 864184610Salfred UMASS_PROTO_RBC | UMASS_PROTO_CBI, 865184610Salfred NO_QUIRKS 866184610Salfred }, 867184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_MSC, RID_WILDCARD, 868184610Salfred UMASS_PROTO_RBC | UMASS_PROTO_CBI, 869184610Salfred NO_QUIRKS 870184610Salfred }, 871184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_MS_MSC_U03, RID_WILDCARD, 872184610Salfred UMASS_PROTO_UFI | UMASS_PROTO_CBI, 873184610Salfred NO_GETMAXLUN 874184610Salfred }, 875184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_MS_NW_MS7, RID_WILDCARD, 876184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 877184610Salfred NO_GETMAXLUN 878184610Salfred }, 879184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_MS_PEG_N760C, RID_WILDCARD, 880184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 881184610Salfred NO_INQUIRY 882184610Salfred }, 883184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_MSACUS1, RID_WILDCARD, 884184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 885184610Salfred NO_GETMAXLUN 886184610Salfred }, 887184610Salfred {USB_VENDOR_SONY, USB_PRODUCT_SONY_PORTABLE_HDD_V2, RID_WILDCARD, 888184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 889184610Salfred NO_QUIRKS 890184610Salfred }, 891189905Sthompsa {USB_VENDOR_SUPERTOP, USB_PRODUCT_SUPERTOP_IDE, RID_WILDCARD, 892192052Sthompsa UMASS_PROTO_DEFAULT, 893189905Sthompsa IGNORE_RESIDUE | NO_SYNCHRONIZE_CACHE 894189905Sthompsa }, 895184610Salfred {USB_VENDOR_TAUGA, USB_PRODUCT_TAUGA_CAMERAMATE, RID_WILDCARD, 896184610Salfred UMASS_PROTO_SCSI, 897184610Salfred NO_QUIRKS 898184610Salfred }, 899184610Salfred {USB_VENDOR_TEAC, USB_PRODUCT_TEAC_FD05PUB, RID_WILDCARD, 900184610Salfred UMASS_PROTO_UFI | UMASS_PROTO_CBI, 901184610Salfred NO_QUIRKS 902184610Salfred }, 903196495Salfred {USB_VENDOR_TECLAST, USB_PRODUCT_TECLAST_TLC300, RID_WILDCARD, 904196495Salfred UMASS_PROTO_DEFAULT, 905196495Salfred NO_TEST_UNIT_READY | NO_SYNCHRONIZE_CACHE 906196495Salfred }, 907184610Salfred {USB_VENDOR_TREK, USB_PRODUCT_TREK_MEMKEY, RID_WILDCARD, 908184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 909184610Salfred NO_INQUIRY 910184610Salfred }, 911184610Salfred {USB_VENDOR_TREK, USB_PRODUCT_TREK_THUMBDRIVE_8MB, RID_WILDCARD, 912184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, 913184610Salfred IGNORE_RESIDUE 914184610Salfred }, 915184610Salfred {USB_VENDOR_TRUMPION, USB_PRODUCT_TRUMPION_C3310, RID_WILDCARD, 916184610Salfred UMASS_PROTO_UFI | UMASS_PROTO_CBI, 917184610Salfred NO_QUIRKS 918184610Salfred }, 919184610Salfred {USB_VENDOR_TRUMPION, USB_PRODUCT_TRUMPION_MP3, RID_WILDCARD, 920184610Salfred UMASS_PROTO_RBC, 921184610Salfred NO_QUIRKS 922184610Salfred }, 923184610Salfred {USB_VENDOR_TRUMPION, USB_PRODUCT_TRUMPION_T33520, RID_WILDCARD, 924184610Salfred UMASS_PROTO_SCSI, 925184610Salfred NO_QUIRKS 926184610Salfred }, 927184610Salfred {USB_VENDOR_TWINMOS, USB_PRODUCT_TWINMOS_MDIV, RID_WILDCARD, 928184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 929184610Salfred NO_QUIRKS 930184610Salfred }, 931184610Salfred {USB_VENDOR_VIA, USB_PRODUCT_VIA_USB2IDEBRIDGE, RID_WILDCARD, 932184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 933184610Salfred NO_SYNCHRONIZE_CACHE 934184610Salfred }, 935184610Salfred {USB_VENDOR_VIVITAR, USB_PRODUCT_VIVITAR_35XX, RID_WILDCARD, 936184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 937184610Salfred NO_INQUIRY 938184610Salfred }, 939184610Salfred {USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_COMBO, RID_WILDCARD, 940184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 941184610Salfred FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE 942184610Salfred }, 943184610Salfred {USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_EXTHDD, RID_WILDCARD, 944184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 945184610Salfred FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE 946184610Salfred }, 947184610Salfred {USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_MYBOOK, RID_WILDCARD, 948184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 949184610Salfred NO_INQUIRY_EVPD 950184610Salfred }, 951197565Sthompsa {USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_MYPASSWORD, RID_WILDCARD, 952197565Sthompsa UMASS_PROTO_DEFAULT, 953197565Sthompsa FORCE_SHORT_INQUIRY 954197565Sthompsa }, 955184610Salfred {USB_VENDOR_WINMAXGROUP, USB_PRODUCT_WINMAXGROUP_FLASH64MC, RID_WILDCARD, 956184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 957184610Salfred NO_INQUIRY 958184610Salfred }, 959184610Salfred {USB_VENDOR_YANO, USB_PRODUCT_YANO_FW800HD, RID_WILDCARD, 960184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 961184610Salfred FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE 962184610Salfred }, 963184610Salfred {USB_VENDOR_YANO, USB_PRODUCT_YANO_U640MO, RID_WILDCARD, 964184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, 965184610Salfred FORCE_SHORT_INQUIRY 966184610Salfred }, 967184610Salfred {USB_VENDOR_YEDATA, USB_PRODUCT_YEDATA_FLASHBUSTERU, RID_WILDCARD, 968184610Salfred UMASS_PROTO_SCSI | UMASS_PROTO_CBI, 969184610Salfred NO_GETMAXLUN 970184610Salfred }, 971184610Salfred {USB_VENDOR_ZORAN, USB_PRODUCT_ZORAN_EX20DSC, RID_WILDCARD, 972184610Salfred UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, 973184610Salfred NO_QUIRKS 974184610Salfred }, 975187163Sthompsa {USB_VENDOR_MEIZU, USB_PRODUCT_MEIZU_M6_SL, RID_WILDCARD, 976187163Sthompsa UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 977187163Sthompsa NO_INQUIRY | NO_SYNCHRONIZE_CACHE 978187163Sthompsa }, 979195080Sdelphij {USB_VENDOR_ACTIONS, USB_PRODUCT_ACTIONS_MP4, RID_WILDCARD, 980195080Sdelphij UMASS_PROTO_SCSI | UMASS_PROTO_BBB, 981195080Sdelphij NO_SYNCHRONIZE_CACHE 982195080Sdelphij }, 983196495Salfred {USB_VENDOR_ASUS, USB_PRODUCT_ASUS_GMSC, RID_WILDCARD, 984196495Salfred UMASS_PROTO_DEFAULT, 985196495Salfred NO_SYNCHRONIZE_CACHE 986196495Salfred }, 987184610Salfred {VID_EOT, PID_EOT, RID_EOT, 0, 0} 988184610Salfred}; 989184610Salfred 990184610Salfredstruct umass_softc { 991184610Salfred 992184610Salfred struct scsi_sense cam_scsi_sense; 993184610Salfred struct scsi_test_unit_ready cam_scsi_test_unit_ready; 994184610Salfred struct mtx sc_mtx; 995184610Salfred struct { 996184610Salfred uint8_t *data_ptr; 997184610Salfred union ccb *ccb; 998184610Salfred umass_callback_t *callback; 999184610Salfred 1000184610Salfred uint32_t data_len; /* bytes */ 1001184610Salfred uint32_t data_rem; /* bytes */ 1002184610Salfred uint32_t data_timeout; /* ms */ 1003184610Salfred uint32_t actlen; /* bytes */ 1004184610Salfred 1005184610Salfred uint8_t cmd_data[UMASS_MAX_CMDLEN]; 1006184610Salfred uint8_t cmd_len; /* bytes */ 1007184610Salfred uint8_t dir; 1008184610Salfred uint8_t lun; 1009184610Salfred } sc_transfer; 1010184610Salfred 1011184610Salfred /* Bulk specific variables for transfers in progress */ 1012184610Salfred umass_bbb_cbw_t cbw; /* command block wrapper */ 1013184610Salfred umass_bbb_csw_t csw; /* command status wrapper */ 1014184610Salfred 1015184610Salfred /* CBI specific variables for transfers in progress */ 1016184610Salfred umass_cbi_sbl_t sbl; /* status block */ 1017184610Salfred 1018184610Salfred device_t sc_dev; 1019192984Sthompsa struct usb_device *sc_udev; 1020184610Salfred struct cam_sim *sc_sim; /* SCSI Interface Module */ 1021192984Sthompsa struct usb_xfer *sc_xfer[UMASS_T_MAX]; 1022184610Salfred 1023184610Salfred /* 1024184610Salfred * The command transform function is used to convert the SCSI 1025184610Salfred * commands into their derivatives, like UFI, ATAPI, and friends. 1026184610Salfred */ 1027184610Salfred umass_transform_t *sc_transform; 1028184610Salfred 1029184610Salfred uint32_t sc_unit; 1030184610Salfred 1031184610Salfred uint16_t sc_proto; /* wire and cmd protocol */ 1032184610Salfred uint16_t sc_quirks; /* they got it almost right */ 1033184610Salfred 1034184610Salfred uint8_t sc_name[16]; 1035184610Salfred uint8_t sc_iface_no; /* interface number */ 1036184610Salfred uint8_t sc_maxlun; /* maximum LUN number, inclusive */ 1037184610Salfred uint8_t sc_last_xfer_index; 1038184610Salfred uint8_t sc_status_try; 1039184610Salfred}; 1040184610Salfred 1041184610Salfredstruct umass_probe_proto { 1042184610Salfred uint16_t quirks; 1043184610Salfred uint16_t proto; 1044184610Salfred 1045184610Salfred int32_t error; 1046184610Salfred}; 1047184610Salfred 1048184610Salfred/* prototypes */ 1049184610Salfred 1050184610Salfredstatic device_probe_t umass_probe; 1051184610Salfredstatic device_attach_t umass_attach; 1052184610Salfredstatic device_detach_t umass_detach; 1053184610Salfred 1054193045Sthompsastatic usb_callback_t umass_tr_error; 1055193045Sthompsastatic usb_callback_t umass_t_bbb_reset1_callback; 1056193045Sthompsastatic usb_callback_t umass_t_bbb_reset2_callback; 1057193045Sthompsastatic usb_callback_t umass_t_bbb_reset3_callback; 1058193045Sthompsastatic usb_callback_t umass_t_bbb_command_callback; 1059193045Sthompsastatic usb_callback_t umass_t_bbb_data_read_callback; 1060193045Sthompsastatic usb_callback_t umass_t_bbb_data_rd_cs_callback; 1061193045Sthompsastatic usb_callback_t umass_t_bbb_data_write_callback; 1062193045Sthompsastatic usb_callback_t umass_t_bbb_data_wr_cs_callback; 1063193045Sthompsastatic usb_callback_t umass_t_bbb_status_callback; 1064193045Sthompsastatic usb_callback_t umass_t_cbi_reset1_callback; 1065193045Sthompsastatic usb_callback_t umass_t_cbi_reset2_callback; 1066193045Sthompsastatic usb_callback_t umass_t_cbi_reset3_callback; 1067193045Sthompsastatic usb_callback_t umass_t_cbi_reset4_callback; 1068193045Sthompsastatic usb_callback_t umass_t_cbi_command_callback; 1069193045Sthompsastatic usb_callback_t umass_t_cbi_data_read_callback; 1070193045Sthompsastatic usb_callback_t umass_t_cbi_data_rd_cs_callback; 1071193045Sthompsastatic usb_callback_t umass_t_cbi_data_write_callback; 1072193045Sthompsastatic usb_callback_t umass_t_cbi_data_wr_cs_callback; 1073193045Sthompsastatic usb_callback_t umass_t_cbi_status_callback; 1074184610Salfred 1075185948Sthompsastatic void umass_cancel_ccb(struct umass_softc *); 1076185948Sthompsastatic void umass_init_shuttle(struct umass_softc *); 1077185948Sthompsastatic void umass_reset(struct umass_softc *); 1078192984Sthompsastatic void umass_t_bbb_data_clear_stall_callback(struct usb_xfer *, 1079194677Sthompsa uint8_t, uint8_t, usb_error_t); 1080185948Sthompsastatic void umass_command_start(struct umass_softc *, uint8_t, void *, 1081185948Sthompsa uint32_t, uint32_t, umass_callback_t *, union ccb *); 1082185948Sthompsastatic uint8_t umass_bbb_get_max_lun(struct umass_softc *); 1083185948Sthompsastatic void umass_cbi_start_status(struct umass_softc *); 1084192984Sthompsastatic void umass_t_cbi_data_clear_stall_callback(struct usb_xfer *, 1085194677Sthompsa uint8_t, uint8_t, usb_error_t); 1086185948Sthompsastatic int umass_cam_attach_sim(struct umass_softc *); 1087185948Sthompsastatic void umass_cam_rescan_callback(struct cam_periph *, union ccb *); 1088185948Sthompsastatic void umass_cam_rescan(struct umass_softc *); 1089185948Sthompsastatic void umass_cam_attach(struct umass_softc *); 1090185948Sthompsastatic void umass_cam_detach_sim(struct umass_softc *); 1091185948Sthompsastatic void umass_cam_action(struct cam_sim *, union ccb *); 1092185948Sthompsastatic void umass_cam_poll(struct cam_sim *); 1093185948Sthompsastatic void umass_cam_cb(struct umass_softc *, union ccb *, uint32_t, 1094185948Sthompsa uint8_t); 1095185948Sthompsastatic void umass_cam_sense_cb(struct umass_softc *, union ccb *, uint32_t, 1096185948Sthompsa uint8_t); 1097185948Sthompsastatic void umass_cam_quirk_cb(struct umass_softc *, union ccb *, uint32_t, 1098185948Sthompsa uint8_t); 1099185948Sthompsastatic uint8_t umass_scsi_transform(struct umass_softc *, uint8_t *, uint8_t); 1100185948Sthompsastatic uint8_t umass_rbc_transform(struct umass_softc *, uint8_t *, uint8_t); 1101185948Sthompsastatic uint8_t umass_ufi_transform(struct umass_softc *, uint8_t *, uint8_t); 1102185948Sthompsastatic uint8_t umass_atapi_transform(struct umass_softc *, uint8_t *, 1103185948Sthompsa uint8_t); 1104185948Sthompsastatic uint8_t umass_no_transform(struct umass_softc *, uint8_t *, uint8_t); 1105185948Sthompsastatic uint8_t umass_std_transform(struct umass_softc *, union ccb *, uint8_t 1106185948Sthompsa *, uint8_t); 1107184610Salfred 1108184610Salfred#if USB_DEBUG 1109185948Sthompsastatic void umass_bbb_dump_cbw(struct umass_softc *, umass_bbb_cbw_t *); 1110185948Sthompsastatic void umass_bbb_dump_csw(struct umass_softc *, umass_bbb_csw_t *); 1111185948Sthompsastatic void umass_cbi_dump_cmd(struct umass_softc *, void *, uint8_t); 1112185948Sthompsastatic void umass_dump_buffer(struct umass_softc *, uint8_t *, uint32_t, 1113185948Sthompsa uint32_t); 1114184610Salfred#endif 1115184610Salfred 1116194099Sthompsastatic struct usb_config umass_bbb_config[UMASS_T_BBB_MAX] = { 1117184610Salfred 1118184610Salfred [UMASS_T_BBB_RESET1] = { 1119184610Salfred .type = UE_CONTROL, 1120184610Salfred .endpoint = 0x00, /* Control pipe */ 1121184610Salfred .direction = UE_DIR_ANY, 1122192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1123190734Sthompsa .callback = &umass_t_bbb_reset1_callback, 1124190734Sthompsa .timeout = 5000, /* 5 seconds */ 1125190734Sthompsa .interval = 500, /* 500 milliseconds */ 1126184610Salfred }, 1127184610Salfred 1128184610Salfred [UMASS_T_BBB_RESET2] = { 1129184610Salfred .type = UE_CONTROL, 1130184610Salfred .endpoint = 0x00, /* Control pipe */ 1131184610Salfred .direction = UE_DIR_ANY, 1132192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1133190734Sthompsa .callback = &umass_t_bbb_reset2_callback, 1134190734Sthompsa .timeout = 5000, /* 5 seconds */ 1135190734Sthompsa .interval = 50, /* 50 milliseconds */ 1136184610Salfred }, 1137184610Salfred 1138184610Salfred [UMASS_T_BBB_RESET3] = { 1139184610Salfred .type = UE_CONTROL, 1140184610Salfred .endpoint = 0x00, /* Control pipe */ 1141184610Salfred .direction = UE_DIR_ANY, 1142192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1143190734Sthompsa .callback = &umass_t_bbb_reset3_callback, 1144190734Sthompsa .timeout = 5000, /* 5 seconds */ 1145190734Sthompsa .interval = 50, /* 50 milliseconds */ 1146184610Salfred }, 1147184610Salfred 1148184610Salfred [UMASS_T_BBB_COMMAND] = { 1149184610Salfred .type = UE_BULK, 1150184610Salfred .endpoint = UE_ADDR_ANY, 1151184610Salfred .direction = UE_DIR_OUT, 1152190734Sthompsa .bufsize = sizeof(umass_bbb_cbw_t), 1153190734Sthompsa .callback = &umass_t_bbb_command_callback, 1154190734Sthompsa .timeout = 5000, /* 5 seconds */ 1155184610Salfred }, 1156184610Salfred 1157184610Salfred [UMASS_T_BBB_DATA_READ] = { 1158184610Salfred .type = UE_BULK, 1159184610Salfred .endpoint = UE_ADDR_ANY, 1160184610Salfred .direction = UE_DIR_IN, 1161190734Sthompsa .bufsize = UMASS_BULK_SIZE, 1162190734Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS}, 1163190734Sthompsa .callback = &umass_t_bbb_data_read_callback, 1164190734Sthompsa .timeout = 0, /* overwritten later */ 1165184610Salfred }, 1166184610Salfred 1167184610Salfred [UMASS_T_BBB_DATA_RD_CS] = { 1168184610Salfred .type = UE_CONTROL, 1169184610Salfred .endpoint = 0x00, /* Control pipe */ 1170184610Salfred .direction = UE_DIR_ANY, 1171192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1172190734Sthompsa .callback = &umass_t_bbb_data_rd_cs_callback, 1173190734Sthompsa .timeout = 5000, /* 5 seconds */ 1174184610Salfred }, 1175184610Salfred 1176184610Salfred [UMASS_T_BBB_DATA_WRITE] = { 1177184610Salfred .type = UE_BULK, 1178184610Salfred .endpoint = UE_ADDR_ANY, 1179184610Salfred .direction = UE_DIR_OUT, 1180190734Sthompsa .bufsize = UMASS_BULK_SIZE, 1181190734Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS}, 1182190734Sthompsa .callback = &umass_t_bbb_data_write_callback, 1183190734Sthompsa .timeout = 0, /* overwritten later */ 1184184610Salfred }, 1185184610Salfred 1186184610Salfred [UMASS_T_BBB_DATA_WR_CS] = { 1187184610Salfred .type = UE_CONTROL, 1188184610Salfred .endpoint = 0x00, /* Control pipe */ 1189184610Salfred .direction = UE_DIR_ANY, 1190192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1191190734Sthompsa .callback = &umass_t_bbb_data_wr_cs_callback, 1192190734Sthompsa .timeout = 5000, /* 5 seconds */ 1193184610Salfred }, 1194184610Salfred 1195184610Salfred [UMASS_T_BBB_STATUS] = { 1196184610Salfred .type = UE_BULK, 1197184610Salfred .endpoint = UE_ADDR_ANY, 1198184610Salfred .direction = UE_DIR_IN, 1199190734Sthompsa .bufsize = sizeof(umass_bbb_csw_t), 1200190734Sthompsa .flags = {.short_xfer_ok = 1,}, 1201190734Sthompsa .callback = &umass_t_bbb_status_callback, 1202190734Sthompsa .timeout = 5000, /* ms */ 1203184610Salfred }, 1204184610Salfred}; 1205184610Salfred 1206194099Sthompsastatic struct usb_config umass_cbi_config[UMASS_T_CBI_MAX] = { 1207184610Salfred 1208184610Salfred [UMASS_T_CBI_RESET1] = { 1209184610Salfred .type = UE_CONTROL, 1210184610Salfred .endpoint = 0x00, /* Control pipe */ 1211184610Salfred .direction = UE_DIR_ANY, 1212192984Sthompsa .bufsize = (sizeof(struct usb_device_request) + 1213184610Salfred UMASS_CBI_DIAGNOSTIC_CMDLEN), 1214190734Sthompsa .callback = &umass_t_cbi_reset1_callback, 1215190734Sthompsa .timeout = 5000, /* 5 seconds */ 1216190734Sthompsa .interval = 500, /* 500 milliseconds */ 1217184610Salfred }, 1218184610Salfred 1219184610Salfred [UMASS_T_CBI_RESET2] = { 1220184610Salfred .type = UE_CONTROL, 1221184610Salfred .endpoint = 0x00, /* Control pipe */ 1222184610Salfred .direction = UE_DIR_ANY, 1223192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1224190734Sthompsa .callback = &umass_t_cbi_reset2_callback, 1225190734Sthompsa .timeout = 5000, /* 5 seconds */ 1226190734Sthompsa .interval = 50, /* 50 milliseconds */ 1227184610Salfred }, 1228184610Salfred 1229184610Salfred [UMASS_T_CBI_RESET3] = { 1230184610Salfred .type = UE_CONTROL, 1231184610Salfred .endpoint = 0x00, /* Control pipe */ 1232184610Salfred .direction = UE_DIR_ANY, 1233192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1234190734Sthompsa .callback = &umass_t_cbi_reset3_callback, 1235190734Sthompsa .timeout = 5000, /* 5 seconds */ 1236190734Sthompsa .interval = 50, /* 50 milliseconds */ 1237184610Salfred }, 1238184610Salfred 1239184610Salfred [UMASS_T_CBI_COMMAND] = { 1240184610Salfred .type = UE_CONTROL, 1241184610Salfred .endpoint = 0x00, /* Control pipe */ 1242184610Salfred .direction = UE_DIR_ANY, 1243192984Sthompsa .bufsize = (sizeof(struct usb_device_request) + 1244184610Salfred UMASS_MAX_CMDLEN), 1245190734Sthompsa .callback = &umass_t_cbi_command_callback, 1246190734Sthompsa .timeout = 5000, /* 5 seconds */ 1247184610Salfred }, 1248184610Salfred 1249184610Salfred [UMASS_T_CBI_DATA_READ] = { 1250184610Salfred .type = UE_BULK, 1251184610Salfred .endpoint = UE_ADDR_ANY, 1252184610Salfred .direction = UE_DIR_IN, 1253190734Sthompsa .bufsize = UMASS_BULK_SIZE, 1254190734Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS}, 1255190734Sthompsa .callback = &umass_t_cbi_data_read_callback, 1256190734Sthompsa .timeout = 0, /* overwritten later */ 1257184610Salfred }, 1258184610Salfred 1259184610Salfred [UMASS_T_CBI_DATA_RD_CS] = { 1260184610Salfred .type = UE_CONTROL, 1261184610Salfred .endpoint = 0x00, /* Control pipe */ 1262184610Salfred .direction = UE_DIR_ANY, 1263192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1264190734Sthompsa .callback = &umass_t_cbi_data_rd_cs_callback, 1265190734Sthompsa .timeout = 5000, /* 5 seconds */ 1266184610Salfred }, 1267184610Salfred 1268184610Salfred [UMASS_T_CBI_DATA_WRITE] = { 1269184610Salfred .type = UE_BULK, 1270184610Salfred .endpoint = UE_ADDR_ANY, 1271184610Salfred .direction = UE_DIR_OUT, 1272190734Sthompsa .bufsize = UMASS_BULK_SIZE, 1273190734Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS}, 1274190734Sthompsa .callback = &umass_t_cbi_data_write_callback, 1275190734Sthompsa .timeout = 0, /* overwritten later */ 1276184610Salfred }, 1277184610Salfred 1278184610Salfred [UMASS_T_CBI_DATA_WR_CS] = { 1279184610Salfred .type = UE_CONTROL, 1280184610Salfred .endpoint = 0x00, /* Control pipe */ 1281184610Salfred .direction = UE_DIR_ANY, 1282192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1283190734Sthompsa .callback = &umass_t_cbi_data_wr_cs_callback, 1284190734Sthompsa .timeout = 5000, /* 5 seconds */ 1285184610Salfred }, 1286184610Salfred 1287184610Salfred [UMASS_T_CBI_STATUS] = { 1288184610Salfred .type = UE_INTERRUPT, 1289184610Salfred .endpoint = UE_ADDR_ANY, 1290184610Salfred .direction = UE_DIR_IN, 1291190734Sthompsa .flags = {.short_xfer_ok = 1,}, 1292190734Sthompsa .bufsize = sizeof(umass_cbi_sbl_t), 1293190734Sthompsa .callback = &umass_t_cbi_status_callback, 1294190734Sthompsa .timeout = 5000, /* ms */ 1295184610Salfred }, 1296184610Salfred 1297184610Salfred [UMASS_T_CBI_RESET4] = { 1298184610Salfred .type = UE_CONTROL, 1299184610Salfred .endpoint = 0x00, /* Control pipe */ 1300184610Salfred .direction = UE_DIR_ANY, 1301192984Sthompsa .bufsize = sizeof(struct usb_device_request), 1302190734Sthompsa .callback = &umass_t_cbi_reset4_callback, 1303190734Sthompsa .timeout = 5000, /* ms */ 1304184610Salfred }, 1305184610Salfred}; 1306184610Salfred 1307184610Salfred/* If device cannot return valid inquiry data, fake it */ 1308184610Salfredstatic const uint8_t fake_inq_data[SHORT_INQUIRY_LENGTH] = { 1309184610Salfred 0, /* removable */ 0x80, SCSI_REV_2, SCSI_REV_2, 1310184610Salfred /* additional_length */ 31, 0, 0, 0 1311184610Salfred}; 1312184610Salfred 1313184610Salfred#define UFI_COMMAND_LENGTH 12 /* UFI commands are always 12 bytes */ 1314184610Salfred#define ATAPI_COMMAND_LENGTH 12 /* ATAPI commands are always 12 bytes */ 1315184610Salfred 1316184610Salfredstatic devclass_t umass_devclass; 1317184610Salfred 1318184610Salfredstatic device_method_t umass_methods[] = { 1319184610Salfred /* Device interface */ 1320184610Salfred DEVMETHOD(device_probe, umass_probe), 1321184610Salfred DEVMETHOD(device_attach, umass_attach), 1322184610Salfred DEVMETHOD(device_detach, umass_detach), 1323184610Salfred {0, 0} 1324184610Salfred}; 1325184610Salfred 1326184610Salfredstatic driver_t umass_driver = { 1327184610Salfred .name = "umass", 1328184610Salfred .methods = umass_methods, 1329184610Salfred .size = sizeof(struct umass_softc), 1330184610Salfred}; 1331184610Salfred 1332189275SthompsaDRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, NULL, 0); 1333188942SthompsaMODULE_DEPEND(umass, usb, 1, 1, 1); 1334184610SalfredMODULE_DEPEND(umass, cam, 1, 1, 1); 1335184610Salfred 1336184610Salfred/* 1337184610Salfred * USB device probe/attach/detach 1338184610Salfred */ 1339184610Salfred 1340192052Sthompsastatic uint16_t 1341192984Sthompsaumass_get_proto(struct usb_interface *iface) 1342192052Sthompsa{ 1343192984Sthompsa struct usb_interface_descriptor *id; 1344192052Sthompsa uint16_t retval; 1345192052Sthompsa 1346192052Sthompsa retval = 0; 1347192052Sthompsa 1348192052Sthompsa /* Check for a standards compliant device */ 1349194228Sthompsa id = usbd_get_interface_descriptor(iface); 1350192052Sthompsa if ((id == NULL) || 1351192052Sthompsa (id->bInterfaceClass != UICLASS_MASS)) { 1352192052Sthompsa goto done; 1353192052Sthompsa } 1354192052Sthompsa switch (id->bInterfaceSubClass) { 1355192052Sthompsa case UISUBCLASS_SCSI: 1356192052Sthompsa retval |= UMASS_PROTO_SCSI; 1357192052Sthompsa break; 1358192052Sthompsa case UISUBCLASS_UFI: 1359192052Sthompsa retval |= UMASS_PROTO_UFI; 1360192052Sthompsa break; 1361192052Sthompsa case UISUBCLASS_RBC: 1362192052Sthompsa retval |= UMASS_PROTO_RBC; 1363192052Sthompsa break; 1364192052Sthompsa case UISUBCLASS_SFF8020I: 1365192052Sthompsa case UISUBCLASS_SFF8070I: 1366192052Sthompsa retval |= UMASS_PROTO_ATAPI; 1367192052Sthompsa break; 1368192052Sthompsa default: 1369192052Sthompsa retval = 0; 1370192052Sthompsa goto done; 1371192052Sthompsa } 1372192052Sthompsa 1373192052Sthompsa switch (id->bInterfaceProtocol) { 1374192052Sthompsa case UIPROTO_MASS_CBI: 1375192052Sthompsa retval |= UMASS_PROTO_CBI; 1376192052Sthompsa break; 1377192052Sthompsa case UIPROTO_MASS_CBI_I: 1378192052Sthompsa retval |= UMASS_PROTO_CBI_I; 1379192052Sthompsa break; 1380192052Sthompsa case UIPROTO_MASS_BBB_OLD: 1381192052Sthompsa case UIPROTO_MASS_BBB: 1382192052Sthompsa retval |= UMASS_PROTO_BBB; 1383192052Sthompsa break; 1384192052Sthompsa default: 1385192052Sthompsa retval = 0; 1386192052Sthompsa goto done; 1387192052Sthompsa } 1388192052Sthompsadone: 1389192052Sthompsa return (retval); 1390192052Sthompsa} 1391192052Sthompsa 1392184610Salfred/* 1393184610Salfred * Match the device we are seeing with the 1394184610Salfred * devices supported. 1395184610Salfred */ 1396184610Salfredstatic struct umass_probe_proto 1397192984Sthompsaumass_probe_proto(device_t dev, struct usb_attach_arg *uaa) 1398184610Salfred{ 1399184610Salfred const struct umass_devdescr *udd = umass_devdescr; 1400184610Salfred struct umass_probe_proto ret; 1401184610Salfred 1402192052Sthompsa memset(&ret, 0, sizeof(ret)); 1403184610Salfred 1404184610Salfred /* 1405184610Salfred * An entry specifically for Y-E Data devices as they don't fit in 1406184610Salfred * the device description table. 1407184610Salfred */ 1408184610Salfred if ((uaa->info.idVendor == USB_VENDOR_YEDATA) && 1409184610Salfred (uaa->info.idProduct == USB_PRODUCT_YEDATA_FLASHBUSTERU)) { 1410184610Salfred 1411184610Salfred /* 1412184610Salfred * Revisions < 1.28 do not handle the interrupt endpoint 1413184610Salfred * very well. 1414184610Salfred */ 1415184610Salfred if (uaa->info.bcdDevice < 0x128) { 1416184610Salfred ret.proto = UMASS_PROTO_UFI | UMASS_PROTO_CBI; 1417184610Salfred } else { 1418184610Salfred ret.proto = UMASS_PROTO_UFI | UMASS_PROTO_CBI_I; 1419184610Salfred } 1420184610Salfred 1421184610Salfred /* 1422184610Salfred * Revisions < 1.28 do not have the TEST UNIT READY command 1423184610Salfred * Revisions == 1.28 have a broken TEST UNIT READY 1424184610Salfred */ 1425184610Salfred if (uaa->info.bcdDevice <= 0x128) { 1426184610Salfred ret.quirks |= NO_TEST_UNIT_READY; 1427184610Salfred } 1428184610Salfred ret.quirks |= RS_NO_CLEAR_UA | FLOPPY_SPEED; 1429184610Salfred goto done; 1430184610Salfred } 1431184610Salfred /* 1432184610Salfred * Check the list of supported devices for a match. While looking, 1433184610Salfred * check for wildcarded and fully matched. First match wins. 1434184610Salfred */ 1435184610Salfred for (; udd->vid != VID_EOT; udd++) { 1436184610Salfred if (((udd->vid == uaa->info.idVendor) || 1437184610Salfred (udd->vid == VID_WILDCARD)) && 1438184610Salfred ((udd->pid == uaa->info.idProduct) || 1439184610Salfred (udd->pid == PID_WILDCARD))) { 1440184610Salfred if (udd->rid == RID_WILDCARD) { 1441184610Salfred ret.proto = udd->proto; 1442184610Salfred ret.quirks = udd->quirks; 1443192052Sthompsa if (ret.proto == UMASS_PROTO_DEFAULT) 1444192052Sthompsa goto default_proto; 1445192052Sthompsa else 1446192052Sthompsa goto done; 1447184610Salfred } else if (udd->rid == uaa->info.bcdDevice) { 1448184610Salfred ret.proto = udd->proto; 1449184610Salfred ret.quirks = udd->quirks; 1450192052Sthompsa if (ret.proto == UMASS_PROTO_DEFAULT) 1451192052Sthompsa goto default_proto; 1452192052Sthompsa else 1453192052Sthompsa goto done; 1454184610Salfred } /* else RID does not match */ 1455184610Salfred } 1456184610Salfred } 1457184610Salfred 1458192052Sthompsadefault_proto: 1459192052Sthompsa ret.proto = umass_get_proto(uaa->iface); 1460192052Sthompsa if (ret.proto == 0) 1461184610Salfred ret.error = ENXIO; 1462192052Sthompsa else 1463192052Sthompsa ret.error = 0; 1464184610Salfreddone: 1465184610Salfred return (ret); 1466184610Salfred} 1467184610Salfred 1468184610Salfredstatic int 1469184610Salfredumass_probe(device_t dev) 1470184610Salfred{ 1471192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 1472184610Salfred struct umass_probe_proto temp; 1473184610Salfred 1474192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) { 1475184610Salfred return (ENXIO); 1476184610Salfred } 1477184610Salfred if (uaa->use_generic == 0) { 1478184610Salfred /* give other drivers a try first */ 1479184610Salfred return (ENXIO); 1480184610Salfred } 1481184610Salfred temp = umass_probe_proto(dev, uaa); 1482184610Salfred 1483184610Salfred return (temp.error); 1484184610Salfred} 1485184610Salfred 1486184610Salfredstatic int 1487184610Salfredumass_attach(device_t dev) 1488184610Salfred{ 1489184610Salfred struct umass_softc *sc = device_get_softc(dev); 1490192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 1491184610Salfred struct umass_probe_proto temp = umass_probe_proto(dev, uaa); 1492192984Sthompsa struct usb_interface_descriptor *id; 1493184610Salfred int32_t err; 1494184610Salfred 1495184610Salfred /* 1496184610Salfred * NOTE: the softc struct is bzero-ed in device_set_driver. 1497184610Salfred * We can safely call umass_detach without specifically 1498184610Salfred * initializing the struct. 1499184610Salfred */ 1500184610Salfred 1501184610Salfred sc->sc_dev = dev; 1502184610Salfred sc->sc_udev = uaa->device; 1503184610Salfred sc->sc_proto = temp.proto; 1504184610Salfred sc->sc_quirks = temp.quirks; 1505184610Salfred sc->sc_unit = device_get_unit(dev); 1506184610Salfred 1507184610Salfred snprintf(sc->sc_name, sizeof(sc->sc_name), 1508184610Salfred "%s", device_get_nameunit(dev)); 1509184610Salfred 1510194228Sthompsa device_set_usb_desc(dev); 1511184610Salfred 1512188415Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), 1513188415Sthompsa NULL, MTX_DEF | MTX_RECURSE); 1514188415Sthompsa 1515184610Salfred /* get interface index */ 1516184610Salfred 1517194228Sthompsa id = usbd_get_interface_descriptor(uaa->iface); 1518184610Salfred if (id == NULL) { 1519184610Salfred device_printf(dev, "failed to get " 1520184610Salfred "interface number\n"); 1521184610Salfred goto detach; 1522184610Salfred } 1523184610Salfred sc->sc_iface_no = id->bInterfaceNumber; 1524184610Salfred 1525184610Salfred#if USB_DEBUG 1526184610Salfred device_printf(dev, " "); 1527184610Salfred 1528184610Salfred switch (sc->sc_proto & UMASS_PROTO_COMMAND) { 1529184610Salfred case UMASS_PROTO_SCSI: 1530184610Salfred printf("SCSI"); 1531184610Salfred break; 1532184610Salfred case UMASS_PROTO_ATAPI: 1533184610Salfred printf("8070i (ATAPI)"); 1534184610Salfred break; 1535184610Salfred case UMASS_PROTO_UFI: 1536184610Salfred printf("UFI"); 1537184610Salfred break; 1538184610Salfred case UMASS_PROTO_RBC: 1539184610Salfred printf("RBC"); 1540184610Salfred break; 1541184610Salfred default: 1542184610Salfred printf("(unknown 0x%02x)", 1543184610Salfred sc->sc_proto & UMASS_PROTO_COMMAND); 1544184610Salfred break; 1545184610Salfred } 1546184610Salfred 1547184610Salfred printf(" over "); 1548184610Salfred 1549184610Salfred switch (sc->sc_proto & UMASS_PROTO_WIRE) { 1550184610Salfred case UMASS_PROTO_BBB: 1551184610Salfred printf("Bulk-Only"); 1552184610Salfred break; 1553184610Salfred case UMASS_PROTO_CBI: /* uses Comand/Bulk pipes */ 1554184610Salfred printf("CBI"); 1555184610Salfred break; 1556184610Salfred case UMASS_PROTO_CBI_I: /* uses Comand/Bulk/Interrupt pipes */ 1557184610Salfred printf("CBI with CCI"); 1558184610Salfred break; 1559184610Salfred default: 1560184610Salfred printf("(unknown 0x%02x)", 1561184610Salfred sc->sc_proto & UMASS_PROTO_WIRE); 1562184610Salfred } 1563184610Salfred 1564184610Salfred printf("; quirks = 0x%04x\n", sc->sc_quirks); 1565184610Salfred#endif 1566184610Salfred 1567184610Salfred if (sc->sc_quirks & ALT_IFACE_1) { 1568194228Sthompsa err = usbd_set_alt_interface_index 1569184610Salfred (uaa->device, uaa->info.bIfaceIndex, 1); 1570184610Salfred 1571184610Salfred if (err) { 1572184610Salfred DPRINTF(sc, UDMASS_USB, "could not switch to " 1573184610Salfred "Alt Interface 1\n"); 1574184610Salfred goto detach; 1575184610Salfred } 1576184610Salfred } 1577184610Salfred /* allocate all required USB transfers */ 1578184610Salfred 1579184610Salfred if (sc->sc_proto & UMASS_PROTO_BBB) { 1580184610Salfred 1581194228Sthompsa err = usbd_transfer_setup(uaa->device, 1582184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, umass_bbb_config, 1583188415Sthompsa UMASS_T_BBB_MAX, sc, &sc->sc_mtx); 1584184610Salfred 1585184610Salfred /* skip reset first time */ 1586184610Salfred sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND; 1587184610Salfred 1588184610Salfred } else if (sc->sc_proto & (UMASS_PROTO_CBI | UMASS_PROTO_CBI_I)) { 1589184610Salfred 1590194228Sthompsa err = usbd_transfer_setup(uaa->device, 1591184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, umass_cbi_config, 1592184610Salfred (sc->sc_proto & UMASS_PROTO_CBI_I) ? 1593184610Salfred UMASS_T_CBI_MAX : (UMASS_T_CBI_MAX - 2), sc, 1594188415Sthompsa &sc->sc_mtx); 1595184610Salfred 1596184610Salfred /* skip reset first time */ 1597184610Salfred sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND; 1598184610Salfred 1599184610Salfred } else { 1600184610Salfred err = USB_ERR_INVAL; 1601184610Salfred } 1602184610Salfred 1603184610Salfred if (err) { 1604184610Salfred device_printf(dev, "could not setup required " 1605194228Sthompsa "transfers, %s\n", usbd_errstr(err)); 1606184610Salfred goto detach; 1607184610Salfred } 1608184610Salfred sc->sc_transform = 1609184610Salfred (sc->sc_proto & UMASS_PROTO_SCSI) ? &umass_scsi_transform : 1610184610Salfred (sc->sc_proto & UMASS_PROTO_UFI) ? &umass_ufi_transform : 1611184610Salfred (sc->sc_proto & UMASS_PROTO_ATAPI) ? &umass_atapi_transform : 1612184610Salfred (sc->sc_proto & UMASS_PROTO_RBC) ? &umass_rbc_transform : 1613184610Salfred &umass_no_transform; 1614184610Salfred 1615184610Salfred /* from here onwards the device can be used. */ 1616184610Salfred 1617184610Salfred if (sc->sc_quirks & SHUTTLE_INIT) { 1618184610Salfred umass_init_shuttle(sc); 1619184610Salfred } 1620184610Salfred /* get the maximum LUN supported by the device */ 1621184610Salfred 1622184610Salfred if (((sc->sc_proto & UMASS_PROTO_WIRE) == UMASS_PROTO_BBB) && 1623184610Salfred !(sc->sc_quirks & NO_GETMAXLUN)) 1624184610Salfred sc->sc_maxlun = umass_bbb_get_max_lun(sc); 1625184610Salfred else 1626184610Salfred sc->sc_maxlun = 0; 1627184610Salfred 1628184610Salfred /* Prepare the SCSI command block */ 1629184610Salfred sc->cam_scsi_sense.opcode = REQUEST_SENSE; 1630184610Salfred sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY; 1631184610Salfred 1632184610Salfred /* 1633184610Salfred * some devices need a delay after that the configuration value is 1634184610Salfred * set to function properly: 1635184610Salfred */ 1636194228Sthompsa usb_pause_mtx(NULL, hz); 1637184610Salfred 1638184610Salfred /* register the SIM */ 1639184610Salfred err = umass_cam_attach_sim(sc); 1640184610Salfred if (err) { 1641184610Salfred goto detach; 1642184610Salfred } 1643184610Salfred /* scan the SIM */ 1644184610Salfred umass_cam_attach(sc); 1645184610Salfred 1646184610Salfred DPRINTF(sc, UDMASS_GEN, "Attach finished\n"); 1647184610Salfred 1648184610Salfred return (0); /* success */ 1649184610Salfred 1650184610Salfreddetach: 1651184610Salfred umass_detach(dev); 1652184610Salfred return (ENXIO); /* failure */ 1653184610Salfred} 1654184610Salfred 1655184610Salfredstatic int 1656184610Salfredumass_detach(device_t dev) 1657184610Salfred{ 1658184610Salfred struct umass_softc *sc = device_get_softc(dev); 1659184610Salfred 1660184610Salfred DPRINTF(sc, UDMASS_USB, "\n"); 1661184610Salfred 1662184610Salfred /* teardown our statemachine */ 1663184610Salfred 1664194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UMASS_T_MAX); 1665184610Salfred 1666184610Salfred#if (__FreeBSD_version >= 700037) 1667188415Sthompsa mtx_lock(&sc->sc_mtx); 1668184610Salfred#endif 1669184610Salfred umass_cam_detach_sim(sc); 1670184610Salfred 1671184610Salfred#if (__FreeBSD_version >= 700037) 1672188415Sthompsa mtx_unlock(&sc->sc_mtx); 1673184610Salfred#endif 1674199061Sthompsa mtx_destroy(&sc->sc_mtx); 1675184610Salfred 1676184610Salfred return (0); /* success */ 1677184610Salfred} 1678184610Salfred 1679184610Salfredstatic void 1680184610Salfredumass_init_shuttle(struct umass_softc *sc) 1681184610Salfred{ 1682192984Sthompsa struct usb_device_request req; 1683193045Sthompsa usb_error_t err; 1684184610Salfred uint8_t status[2] = {0, 0}; 1685184610Salfred 1686184610Salfred /* 1687184610Salfred * The Linux driver does this, but no one can tell us what the 1688184610Salfred * command does. 1689184610Salfred */ 1690184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 1691184610Salfred req.bRequest = 1; /* XXX unknown command */ 1692184610Salfred USETW(req.wValue, 0); 1693184610Salfred req.wIndex[0] = sc->sc_iface_no; 1694184610Salfred req.wIndex[1] = 0; 1695184610Salfred USETW(req.wLength, sizeof(status)); 1696194228Sthompsa err = usbd_do_request(sc->sc_udev, NULL, &req, &status); 1697184610Salfred 1698184610Salfred DPRINTF(sc, UDMASS_GEN, "Shuttle init returned 0x%02x%02x\n", 1699184610Salfred status[0], status[1]); 1700184610Salfred} 1701184610Salfred 1702184610Salfred/* 1703184610Salfred * Generic functions to handle transfers 1704184610Salfred */ 1705184610Salfred 1706184610Salfredstatic void 1707184610Salfredumass_transfer_start(struct umass_softc *sc, uint8_t xfer_index) 1708184610Salfred{ 1709184610Salfred DPRINTF(sc, UDMASS_GEN, "transfer index = " 1710184610Salfred "%d\n", xfer_index); 1711184610Salfred 1712184610Salfred if (sc->sc_xfer[xfer_index]) { 1713184610Salfred sc->sc_last_xfer_index = xfer_index; 1714194228Sthompsa usbd_transfer_start(sc->sc_xfer[xfer_index]); 1715184610Salfred } else { 1716184610Salfred umass_cancel_ccb(sc); 1717184610Salfred } 1718184610Salfred} 1719184610Salfred 1720184610Salfredstatic void 1721184610Salfredumass_reset(struct umass_softc *sc) 1722184610Salfred{ 1723184610Salfred DPRINTF(sc, UDMASS_GEN, "resetting device\n"); 1724184610Salfred 1725184610Salfred /* 1726184610Salfred * stop the last transfer, if not already stopped: 1727184610Salfred */ 1728194228Sthompsa usbd_transfer_stop(sc->sc_xfer[sc->sc_last_xfer_index]); 1729184610Salfred umass_transfer_start(sc, 0); 1730184610Salfred} 1731184610Salfred 1732184610Salfredstatic void 1733184610Salfredumass_cancel_ccb(struct umass_softc *sc) 1734184610Salfred{ 1735184610Salfred union ccb *ccb; 1736184610Salfred 1737188415Sthompsa mtx_assert(&sc->sc_mtx, MA_OWNED); 1738184610Salfred 1739184610Salfred ccb = sc->sc_transfer.ccb; 1740184610Salfred sc->sc_transfer.ccb = NULL; 1741184610Salfred sc->sc_last_xfer_index = 0; 1742184610Salfred 1743184610Salfred if (ccb) { 1744184610Salfred (sc->sc_transfer.callback) 1745184610Salfred (sc, ccb, (sc->sc_transfer.data_len - 1746184610Salfred sc->sc_transfer.actlen), STATUS_WIRE_FAILED); 1747184610Salfred } 1748184610Salfred} 1749184610Salfred 1750184610Salfredstatic void 1751194677Sthompsaumass_tr_error(struct usb_xfer *xfer, usb_error_t error) 1752184610Salfred{ 1753194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 1754184610Salfred 1755194677Sthompsa if (error != USB_ERR_CANCELLED) { 1756184610Salfred 1757184610Salfred DPRINTF(sc, UDMASS_GEN, "transfer error, %s -> " 1758194677Sthompsa "reset\n", usbd_errstr(error)); 1759184610Salfred } 1760184610Salfred umass_cancel_ccb(sc); 1761184610Salfred} 1762184610Salfred 1763184610Salfred/* 1764184610Salfred * BBB protocol specific functions 1765184610Salfred */ 1766184610Salfred 1767184610Salfredstatic void 1768194677Sthompsaumass_t_bbb_reset1_callback(struct usb_xfer *xfer, usb_error_t error) 1769184610Salfred{ 1770194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 1771192984Sthompsa struct usb_device_request req; 1772194677Sthompsa struct usb_page_cache *pc; 1773184610Salfred 1774184610Salfred switch (USB_GET_STATE(xfer)) { 1775184610Salfred case USB_ST_TRANSFERRED: 1776184610Salfred umass_transfer_start(sc, UMASS_T_BBB_RESET2); 1777184610Salfred return; 1778184610Salfred 1779184610Salfred case USB_ST_SETUP: 1780184610Salfred /* 1781184610Salfred * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class) 1782184610Salfred * 1783184610Salfred * For Reset Recovery the host shall issue in the following order: 1784184610Salfred * a) a Bulk-Only Mass Storage Reset 1785184610Salfred * b) a Clear Feature HALT to the Bulk-In endpoint 1786184610Salfred * c) a Clear Feature HALT to the Bulk-Out endpoint 1787184610Salfred * 1788184610Salfred * This is done in 3 steps, using 3 transfers: 1789184610Salfred * UMASS_T_BBB_RESET1 1790184610Salfred * UMASS_T_BBB_RESET2 1791184610Salfred * UMASS_T_BBB_RESET3 1792184610Salfred */ 1793184610Salfred 1794184610Salfred DPRINTF(sc, UDMASS_BBB, "BBB reset!\n"); 1795184610Salfred 1796184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1797184610Salfred req.bRequest = UR_BBB_RESET; /* bulk only reset */ 1798184610Salfred USETW(req.wValue, 0); 1799184610Salfred req.wIndex[0] = sc->sc_iface_no; 1800184610Salfred req.wIndex[1] = 0; 1801184610Salfred USETW(req.wLength, 0); 1802184610Salfred 1803194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1804194677Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 1805184610Salfred 1806194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 1807194677Sthompsa usbd_xfer_set_frames(xfer, 1); 1808194228Sthompsa usbd_transfer_submit(xfer); 1809184610Salfred return; 1810184610Salfred 1811184610Salfred default: /* Error */ 1812194677Sthompsa umass_tr_error(xfer, error); 1813184610Salfred return; 1814184610Salfred 1815184610Salfred } 1816184610Salfred} 1817184610Salfred 1818184610Salfredstatic void 1819194677Sthompsaumass_t_bbb_reset2_callback(struct usb_xfer *xfer, usb_error_t error) 1820184610Salfred{ 1821184610Salfred umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_RESET3, 1822194677Sthompsa UMASS_T_BBB_DATA_READ, error); 1823184610Salfred} 1824184610Salfred 1825184610Salfredstatic void 1826194677Sthompsaumass_t_bbb_reset3_callback(struct usb_xfer *xfer, usb_error_t error) 1827184610Salfred{ 1828184610Salfred umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_COMMAND, 1829194677Sthompsa UMASS_T_BBB_DATA_WRITE, error); 1830184610Salfred} 1831184610Salfred 1832184610Salfredstatic void 1833192984Sthompsaumass_t_bbb_data_clear_stall_callback(struct usb_xfer *xfer, 1834194677Sthompsa uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error) 1835184610Salfred{ 1836194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 1837184610Salfred 1838184610Salfred switch (USB_GET_STATE(xfer)) { 1839184610Salfred case USB_ST_TRANSFERRED: 1840184610Salfredtr_transferred: 1841184610Salfred umass_transfer_start(sc, next_xfer); 1842184610Salfred return; 1843184610Salfred 1844184610Salfred case USB_ST_SETUP: 1845194228Sthompsa if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) { 1846184610Salfred goto tr_transferred; 1847184610Salfred } 1848184610Salfred return; 1849184610Salfred 1850184610Salfred default: /* Error */ 1851194677Sthompsa umass_tr_error(xfer, error); 1852184610Salfred return; 1853184610Salfred 1854184610Salfred } 1855184610Salfred} 1856184610Salfred 1857184610Salfredstatic void 1858194677Sthompsaumass_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error) 1859184610Salfred{ 1860194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 1861184610Salfred union ccb *ccb = sc->sc_transfer.ccb; 1862194677Sthompsa struct usb_page_cache *pc; 1863184610Salfred uint32_t tag; 1864184610Salfred 1865184610Salfred switch (USB_GET_STATE(xfer)) { 1866184610Salfred case USB_ST_TRANSFERRED: 1867184610Salfred umass_transfer_start 1868184610Salfred (sc, ((sc->sc_transfer.dir == DIR_IN) ? UMASS_T_BBB_DATA_READ : 1869184610Salfred (sc->sc_transfer.dir == DIR_OUT) ? UMASS_T_BBB_DATA_WRITE : 1870184610Salfred UMASS_T_BBB_STATUS)); 1871184610Salfred return; 1872184610Salfred 1873184610Salfred case USB_ST_SETUP: 1874184610Salfred 1875184610Salfred sc->sc_status_try = 0; 1876184610Salfred 1877184610Salfred if (ccb) { 1878184610Salfred 1879184610Salfred /* 1880184610Salfred * the initial value is not important, 1881184610Salfred * as long as the values are unique: 1882184610Salfred */ 1883184610Salfred tag = UGETDW(sc->cbw.dCBWTag) + 1; 1884184610Salfred 1885184610Salfred USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE); 1886184610Salfred USETDW(sc->cbw.dCBWTag, tag); 1887184610Salfred 1888184610Salfred /* 1889184610Salfred * dCBWDataTransferLength: 1890184610Salfred * This field indicates the number of bytes of data that the host 1891184610Salfred * intends to transfer on the IN or OUT Bulk endpoint(as indicated by 1892184610Salfred * the Direction bit) during the execution of this command. If this 1893184610Salfred * field is set to 0, the device will expect that no data will be 1894184610Salfred * transferred IN or OUT during this command, regardless of the value 1895184610Salfred * of the Direction bit defined in dCBWFlags. 1896184610Salfred */ 1897184610Salfred USETDW(sc->cbw.dCBWDataTransferLength, sc->sc_transfer.data_len); 1898184610Salfred 1899184610Salfred /* 1900184610Salfred * dCBWFlags: 1901184610Salfred * The bits of the Flags field are defined as follows: 1902184610Salfred * Bits 0-6 reserved 1903184610Salfred * Bit 7 Direction - this bit shall be ignored if the 1904184610Salfred * dCBWDataTransferLength field is zero. 1905184610Salfred * 0 = data Out from host to device 1906184610Salfred * 1 = data In from device to host 1907184610Salfred */ 1908184610Salfred sc->cbw.bCBWFlags = ((sc->sc_transfer.dir == DIR_IN) ? 1909184610Salfred CBWFLAGS_IN : CBWFLAGS_OUT); 1910184610Salfred sc->cbw.bCBWLUN = sc->sc_transfer.lun; 1911184610Salfred 1912184610Salfred if (sc->sc_transfer.cmd_len > sizeof(sc->cbw.CBWCDB)) { 1913184610Salfred sc->sc_transfer.cmd_len = sizeof(sc->cbw.CBWCDB); 1914184610Salfred DPRINTF(sc, UDMASS_BBB, "Truncating long command!\n"); 1915184610Salfred } 1916184610Salfred sc->cbw.bCDBLength = sc->sc_transfer.cmd_len; 1917184610Salfred 1918184610Salfred bcopy(sc->sc_transfer.cmd_data, sc->cbw.CBWCDB, 1919184610Salfred sc->sc_transfer.cmd_len); 1920184610Salfred 1921184610Salfred bzero(sc->sc_transfer.cmd_data + sc->sc_transfer.cmd_len, 1922184610Salfred sizeof(sc->cbw.CBWCDB) - sc->sc_transfer.cmd_len); 1923184610Salfred 1924184610Salfred DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw)); 1925184610Salfred 1926194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1927194677Sthompsa usbd_copy_in(pc, 0, &sc->cbw, sizeof(sc->cbw)); 1928194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(sc->cbw)); 1929184610Salfred 1930194228Sthompsa usbd_transfer_submit(xfer); 1931184610Salfred } 1932184610Salfred return; 1933184610Salfred 1934184610Salfred default: /* Error */ 1935194677Sthompsa umass_tr_error(xfer, error); 1936184610Salfred return; 1937184610Salfred 1938184610Salfred } 1939184610Salfred} 1940184610Salfred 1941184610Salfredstatic void 1942194677Sthompsaumass_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error) 1943184610Salfred{ 1944194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 1945194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 1946194677Sthompsa#ifndef UMASS_EXT_BUFFER 1947194677Sthompsa struct usb_page_cache *pc; 1948194677Sthompsa#endif 1949194677Sthompsa int actlen, sumlen; 1950184610Salfred 1951194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 1952194677Sthompsa 1953184610Salfred switch (USB_GET_STATE(xfer)) { 1954184610Salfred case USB_ST_TRANSFERRED: 1955194677Sthompsa#ifndef UMASS_EXT_BUFFER 1956194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 1957194677Sthompsa usbd_copy_out(pc, 0, sc->sc_transfer.data_ptr, actlen); 1958194677Sthompsa#endif 1959194677Sthompsa sc->sc_transfer.data_rem -= actlen; 1960194677Sthompsa sc->sc_transfer.data_ptr += actlen; 1961194677Sthompsa sc->sc_transfer.actlen += actlen; 1962184610Salfred 1963194677Sthompsa if (actlen < sumlen) { 1964184610Salfred /* short transfer */ 1965184610Salfred sc->sc_transfer.data_rem = 0; 1966184610Salfred } 1967184610Salfred case USB_ST_SETUP: 1968184610Salfred DPRINTF(sc, UDMASS_BBB, "max_bulk=%d, data_rem=%d\n", 1969184610Salfred max_bulk, sc->sc_transfer.data_rem); 1970184610Salfred 1971184610Salfred if (sc->sc_transfer.data_rem == 0) { 1972184610Salfred umass_transfer_start(sc, UMASS_T_BBB_STATUS); 1973184610Salfred return; 1974184610Salfred } 1975184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 1976184610Salfred max_bulk = sc->sc_transfer.data_rem; 1977184610Salfred } 1978194677Sthompsa usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); 1979184610Salfred 1980194677Sthompsa#ifdef UMASS_EXT_BUFFER 1981194677Sthompsa usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, 1982194677Sthompsa max_bulk); 1983194677Sthompsa#else 1984194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, max_bulk); 1985194677Sthompsa#endif 1986194228Sthompsa usbd_transfer_submit(xfer); 1987184610Salfred return; 1988184610Salfred 1989184610Salfred default: /* Error */ 1990194677Sthompsa if (error == USB_ERR_CANCELLED) { 1991194677Sthompsa umass_tr_error(xfer, error); 1992184610Salfred } else { 1993184610Salfred umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS); 1994184610Salfred } 1995184610Salfred return; 1996184610Salfred 1997184610Salfred } 1998184610Salfred} 1999184610Salfred 2000184610Salfredstatic void 2001194677Sthompsaumass_t_bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error) 2002184610Salfred{ 2003184610Salfred umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS, 2004194677Sthompsa UMASS_T_BBB_DATA_READ, error); 2005184610Salfred} 2006184610Salfred 2007184610Salfredstatic void 2008194677Sthompsaumass_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error) 2009184610Salfred{ 2010194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 2011194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 2012194677Sthompsa#ifndef UMASS_EXT_BUFFER 2013194677Sthompsa struct usb_page_cache *pc; 2014194677Sthompsa#endif 2015194677Sthompsa int actlen, sumlen; 2016184610Salfred 2017194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 2018194677Sthompsa 2019184610Salfred switch (USB_GET_STATE(xfer)) { 2020184610Salfred case USB_ST_TRANSFERRED: 2021194677Sthompsa sc->sc_transfer.data_rem -= actlen; 2022194677Sthompsa sc->sc_transfer.data_ptr += actlen; 2023194677Sthompsa sc->sc_transfer.actlen += actlen; 2024184610Salfred 2025194677Sthompsa if (actlen < sumlen) { 2026184610Salfred /* short transfer */ 2027184610Salfred sc->sc_transfer.data_rem = 0; 2028184610Salfred } 2029184610Salfred case USB_ST_SETUP: 2030184610Salfred DPRINTF(sc, UDMASS_BBB, "max_bulk=%d, data_rem=%d\n", 2031184610Salfred max_bulk, sc->sc_transfer.data_rem); 2032184610Salfred 2033184610Salfred if (sc->sc_transfer.data_rem == 0) { 2034184610Salfred umass_transfer_start(sc, UMASS_T_BBB_STATUS); 2035184610Salfred return; 2036184610Salfred } 2037184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 2038184610Salfred max_bulk = sc->sc_transfer.data_rem; 2039184610Salfred } 2040194677Sthompsa usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); 2041184610Salfred 2042194677Sthompsa#ifdef UMASS_EXT_BUFFER 2043194677Sthompsa usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, 2044194677Sthompsa max_bulk); 2045194677Sthompsa#else 2046194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2047194677Sthompsa usbd_copy_in(pc, 0, sc->sc_transfer.data_ptr, max_bulk); 2048194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, max_bulk); 2049194677Sthompsa#endif 2050184610Salfred 2051194228Sthompsa usbd_transfer_submit(xfer); 2052184610Salfred return; 2053184610Salfred 2054184610Salfred default: /* Error */ 2055194677Sthompsa if (error == USB_ERR_CANCELLED) { 2056194677Sthompsa umass_tr_error(xfer, error); 2057184610Salfred } else { 2058184610Salfred umass_transfer_start(sc, UMASS_T_BBB_DATA_WR_CS); 2059184610Salfred } 2060184610Salfred return; 2061184610Salfred 2062184610Salfred } 2063184610Salfred} 2064184610Salfred 2065184610Salfredstatic void 2066194677Sthompsaumass_t_bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error) 2067184610Salfred{ 2068184610Salfred umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS, 2069194677Sthompsa UMASS_T_BBB_DATA_WRITE, error); 2070184610Salfred} 2071184610Salfred 2072184610Salfredstatic void 2073194677Sthompsaumass_t_bbb_status_callback(struct usb_xfer *xfer, usb_error_t error) 2074184610Salfred{ 2075194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 2076184610Salfred union ccb *ccb = sc->sc_transfer.ccb; 2077194677Sthompsa struct usb_page_cache *pc; 2078184610Salfred uint32_t residue; 2079194677Sthompsa int actlen; 2080184610Salfred 2081194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 2082194677Sthompsa 2083184610Salfred switch (USB_GET_STATE(xfer)) { 2084184610Salfred case USB_ST_TRANSFERRED: 2085184610Salfred 2086184610Salfred /* 2087184610Salfred * Do a full reset if there is something wrong with the CSW: 2088184610Salfred */ 2089184610Salfred sc->sc_status_try = 1; 2090184610Salfred 2091184610Salfred /* Zero missing parts of the CSW: */ 2092184610Salfred 2093194677Sthompsa if (actlen < sizeof(sc->csw)) { 2094184610Salfred bzero(&sc->csw, sizeof(sc->csw)); 2095184610Salfred } 2096194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2097194677Sthompsa usbd_copy_out(pc, 0, &sc->csw, actlen); 2098184610Salfred 2099184610Salfred DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw)); 2100184610Salfred 2101184610Salfred residue = UGETDW(sc->csw.dCSWDataResidue); 2102184610Salfred 2103189905Sthompsa if ((!residue) || (sc->sc_quirks & IGNORE_RESIDUE)) { 2104184610Salfred residue = (sc->sc_transfer.data_len - 2105184610Salfred sc->sc_transfer.actlen); 2106184610Salfred } 2107184610Salfred if (residue > sc->sc_transfer.data_len) { 2108184610Salfred DPRINTF(sc, UDMASS_BBB, "truncating residue from %d " 2109184610Salfred "to %d bytes\n", residue, sc->sc_transfer.data_len); 2110184610Salfred residue = sc->sc_transfer.data_len; 2111184610Salfred } 2112184610Salfred /* translate weird command-status signatures: */ 2113184610Salfred if (sc->sc_quirks & WRONG_CSWSIG) { 2114184610Salfred 2115184610Salfred uint32_t temp = UGETDW(sc->csw.dCSWSignature); 2116184610Salfred 2117184610Salfred if ((temp == CSWSIGNATURE_OLYMPUS_C1) || 2118184610Salfred (temp == CSWSIGNATURE_IMAGINATION_DBX1)) { 2119184610Salfred USETDW(sc->csw.dCSWSignature, CSWSIGNATURE); 2120184610Salfred } 2121184610Salfred } 2122184610Salfred /* check CSW and handle eventual error */ 2123184610Salfred if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) { 2124184610Salfred DPRINTF(sc, UDMASS_BBB, "bad CSW signature 0x%08x != 0x%08x\n", 2125184610Salfred UGETDW(sc->csw.dCSWSignature), CSWSIGNATURE); 2126184610Salfred /* 2127184610Salfred * Invalid CSW: Wrong signature or wrong tag might 2128184610Salfred * indicate that we lost synchronization. Reset the 2129184610Salfred * device. 2130184610Salfred */ 2131184610Salfred goto tr_error; 2132184610Salfred } else if (UGETDW(sc->csw.dCSWTag) != UGETDW(sc->cbw.dCBWTag)) { 2133184610Salfred DPRINTF(sc, UDMASS_BBB, "Invalid CSW: tag 0x%08x should be " 2134184610Salfred "0x%08x\n", UGETDW(sc->csw.dCSWTag), 2135184610Salfred UGETDW(sc->cbw.dCBWTag)); 2136184610Salfred goto tr_error; 2137184610Salfred } else if (sc->csw.bCSWStatus > CSWSTATUS_PHASE) { 2138184610Salfred DPRINTF(sc, UDMASS_BBB, "Invalid CSW: status %d > %d\n", 2139184610Salfred sc->csw.bCSWStatus, CSWSTATUS_PHASE); 2140184610Salfred goto tr_error; 2141184610Salfred } else if (sc->csw.bCSWStatus == CSWSTATUS_PHASE) { 2142184610Salfred DPRINTF(sc, UDMASS_BBB, "Phase error, residue = " 2143184610Salfred "%d\n", residue); 2144184610Salfred goto tr_error; 2145184610Salfred } else if (sc->sc_transfer.actlen > sc->sc_transfer.data_len) { 2146184610Salfred DPRINTF(sc, UDMASS_BBB, "Buffer overrun %d > %d\n", 2147184610Salfred sc->sc_transfer.actlen, sc->sc_transfer.data_len); 2148184610Salfred goto tr_error; 2149184610Salfred } else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) { 2150184610Salfred DPRINTF(sc, UDMASS_BBB, "Command failed, residue = " 2151184610Salfred "%d\n", residue); 2152184610Salfred 2153184610Salfred sc->sc_transfer.ccb = NULL; 2154184610Salfred 2155184610Salfred sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND; 2156184610Salfred 2157184610Salfred (sc->sc_transfer.callback) 2158184610Salfred (sc, ccb, residue, STATUS_CMD_FAILED); 2159184610Salfred } else { 2160184610Salfred sc->sc_transfer.ccb = NULL; 2161184610Salfred 2162184610Salfred sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND; 2163184610Salfred 2164184610Salfred (sc->sc_transfer.callback) 2165184610Salfred (sc, ccb, residue, STATUS_CMD_OK); 2166184610Salfred } 2167184610Salfred return; 2168184610Salfred 2169184610Salfred case USB_ST_SETUP: 2170194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 2171194228Sthompsa usbd_transfer_submit(xfer); 2172184610Salfred return; 2173184610Salfred 2174184610Salfred default: 2175184610Salfredtr_error: 2176184610Salfred DPRINTF(sc, UDMASS_BBB, "Failed to read CSW: %s, try %d\n", 2177194677Sthompsa usbd_errstr(error), sc->sc_status_try); 2178184610Salfred 2179194677Sthompsa if ((error == USB_ERR_CANCELLED) || 2180184610Salfred (sc->sc_status_try)) { 2181194677Sthompsa umass_tr_error(xfer, error); 2182184610Salfred } else { 2183184610Salfred sc->sc_status_try = 1; 2184184610Salfred umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS); 2185184610Salfred } 2186184610Salfred return; 2187184610Salfred 2188184610Salfred } 2189184610Salfred} 2190184610Salfred 2191184610Salfredstatic void 2192184610Salfredumass_command_start(struct umass_softc *sc, uint8_t dir, 2193184610Salfred void *data_ptr, uint32_t data_len, 2194184610Salfred uint32_t data_timeout, umass_callback_t *callback, 2195184610Salfred union ccb *ccb) 2196184610Salfred{ 2197184610Salfred sc->sc_transfer.lun = ccb->ccb_h.target_lun; 2198184610Salfred 2199184610Salfred /* 2200184610Salfred * NOTE: assumes that "sc->sc_transfer.cmd_data" and 2201184610Salfred * "sc->sc_transfer.cmd_len" has been properly 2202184610Salfred * initialized. 2203184610Salfred */ 2204184610Salfred 2205184610Salfred sc->sc_transfer.dir = data_len ? dir : DIR_NONE; 2206184610Salfred sc->sc_transfer.data_ptr = data_ptr; 2207184610Salfred sc->sc_transfer.data_len = data_len; 2208184610Salfred sc->sc_transfer.data_rem = data_len; 2209184610Salfred sc->sc_transfer.data_timeout = (data_timeout + UMASS_TIMEOUT); 2210184610Salfred 2211184610Salfred sc->sc_transfer.actlen = 0; 2212184610Salfred sc->sc_transfer.callback = callback; 2213184610Salfred sc->sc_transfer.ccb = ccb; 2214184610Salfred 2215184610Salfred if (sc->sc_xfer[sc->sc_last_xfer_index]) { 2216194228Sthompsa usbd_transfer_start(sc->sc_xfer[sc->sc_last_xfer_index]); 2217184610Salfred } else { 2218184610Salfred ccb->ccb_h.status = CAM_TID_INVALID; 2219184610Salfred xpt_done(ccb); 2220184610Salfred } 2221184610Salfred} 2222184610Salfred 2223184610Salfredstatic uint8_t 2224184610Salfredumass_bbb_get_max_lun(struct umass_softc *sc) 2225184610Salfred{ 2226192984Sthompsa struct usb_device_request req; 2227193045Sthompsa usb_error_t err; 2228184610Salfred uint8_t buf = 0; 2229184610Salfred 2230184610Salfred /* The Get Max Lun command is a class-specific request. */ 2231184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 2232184610Salfred req.bRequest = UR_BBB_GET_MAX_LUN; 2233184610Salfred USETW(req.wValue, 0); 2234184610Salfred req.wIndex[0] = sc->sc_iface_no; 2235184610Salfred req.wIndex[1] = 0; 2236184610Salfred USETW(req.wLength, 1); 2237184610Salfred 2238194228Sthompsa err = usbd_do_request(sc->sc_udev, NULL, &req, &buf); 2239184610Salfred if (err) { 2240184610Salfred buf = 0; 2241184610Salfred 2242184610Salfred /* Device doesn't support Get Max Lun request. */ 2243184610Salfred printf("%s: Get Max Lun not supported (%s)\n", 2244194228Sthompsa sc->sc_name, usbd_errstr(err)); 2245184610Salfred } 2246184610Salfred return (buf); 2247184610Salfred} 2248184610Salfred 2249184610Salfred/* 2250184610Salfred * Command/Bulk/Interrupt (CBI) specific functions 2251184610Salfred */ 2252184610Salfred 2253184610Salfredstatic void 2254184610Salfredumass_cbi_start_status(struct umass_softc *sc) 2255184610Salfred{ 2256184610Salfred if (sc->sc_xfer[UMASS_T_CBI_STATUS]) { 2257184610Salfred umass_transfer_start(sc, UMASS_T_CBI_STATUS); 2258184610Salfred } else { 2259184610Salfred union ccb *ccb = sc->sc_transfer.ccb; 2260184610Salfred 2261184610Salfred sc->sc_transfer.ccb = NULL; 2262184610Salfred 2263184610Salfred sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND; 2264184610Salfred 2265184610Salfred (sc->sc_transfer.callback) 2266184610Salfred (sc, ccb, (sc->sc_transfer.data_len - 2267184610Salfred sc->sc_transfer.actlen), STATUS_CMD_UNKNOWN); 2268184610Salfred } 2269184610Salfred} 2270184610Salfred 2271184610Salfredstatic void 2272194677Sthompsaumass_t_cbi_reset1_callback(struct usb_xfer *xfer, usb_error_t error) 2273184610Salfred{ 2274194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 2275192984Sthompsa struct usb_device_request req; 2276194677Sthompsa struct usb_page_cache *pc; 2277184610Salfred uint8_t buf[UMASS_CBI_DIAGNOSTIC_CMDLEN]; 2278184610Salfred 2279184610Salfred uint8_t i; 2280184610Salfred 2281184610Salfred switch (USB_GET_STATE(xfer)) { 2282184610Salfred case USB_ST_TRANSFERRED: 2283184610Salfred umass_transfer_start(sc, UMASS_T_CBI_RESET2); 2284184610Salfred return; 2285184610Salfred 2286184610Salfred case USB_ST_SETUP: 2287184610Salfred /* 2288184610Salfred * Command Block Reset Protocol 2289184610Salfred * 2290184610Salfred * First send a reset request to the device. Then clear 2291184610Salfred * any possibly stalled bulk endpoints. 2292184610Salfred * 2293184610Salfred * This is done in 3 steps, using 3 transfers: 2294184610Salfred * UMASS_T_CBI_RESET1 2295184610Salfred * UMASS_T_CBI_RESET2 2296184610Salfred * UMASS_T_CBI_RESET3 2297184610Salfred * UMASS_T_CBI_RESET4 (only if there is an interrupt endpoint) 2298184610Salfred */ 2299184610Salfred 2300184610Salfred DPRINTF(sc, UDMASS_CBI, "CBI reset!\n"); 2301184610Salfred 2302184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 2303184610Salfred req.bRequest = UR_CBI_ADSC; 2304184610Salfred USETW(req.wValue, 0); 2305184610Salfred req.wIndex[0] = sc->sc_iface_no; 2306184610Salfred req.wIndex[1] = 0; 2307184610Salfred USETW(req.wLength, UMASS_CBI_DIAGNOSTIC_CMDLEN); 2308184610Salfred 2309184610Salfred /* 2310184610Salfred * The 0x1d code is the SEND DIAGNOSTIC command. To 2311184610Salfred * distinguish between the two, the last 10 bytes of the CBL 2312184610Salfred * is filled with 0xff (section 2.2 of the CBI 2313184610Salfred * specification) 2314184610Salfred */ 2315184610Salfred buf[0] = 0x1d; /* Command Block Reset */ 2316184610Salfred buf[1] = 0x04; 2317184610Salfred 2318184610Salfred for (i = 2; i < UMASS_CBI_DIAGNOSTIC_CMDLEN; i++) { 2319184610Salfred buf[i] = 0xff; 2320184610Salfred } 2321184610Salfred 2322194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2323194677Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 2324194677Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 2325194677Sthompsa usbd_copy_in(pc, 0, buf, sizeof(buf)); 2326184610Salfred 2327194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 2328194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, sizeof(buf)); 2329194677Sthompsa usbd_xfer_set_frames(xfer, 2); 2330194228Sthompsa usbd_transfer_submit(xfer); 2331184610Salfred return; 2332184610Salfred 2333184610Salfred default: /* Error */ 2334194677Sthompsa umass_tr_error(xfer, error); 2335184610Salfred return; 2336184610Salfred 2337184610Salfred } 2338184610Salfred} 2339184610Salfred 2340184610Salfredstatic void 2341194677Sthompsaumass_t_cbi_reset2_callback(struct usb_xfer *xfer, usb_error_t error) 2342184610Salfred{ 2343184610Salfred umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_RESET3, 2344194677Sthompsa UMASS_T_CBI_DATA_READ, error); 2345184610Salfred} 2346184610Salfred 2347184610Salfredstatic void 2348194677Sthompsaumass_t_cbi_reset3_callback(struct usb_xfer *xfer, usb_error_t error) 2349184610Salfred{ 2350194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 2351184610Salfred 2352184610Salfred umass_t_cbi_data_clear_stall_callback 2353184610Salfred (xfer, (sc->sc_xfer[UMASS_T_CBI_RESET4] && 2354184610Salfred sc->sc_xfer[UMASS_T_CBI_STATUS]) ? 2355184610Salfred UMASS_T_CBI_RESET4 : UMASS_T_CBI_COMMAND, 2356194677Sthompsa UMASS_T_CBI_DATA_WRITE, error); 2357184610Salfred} 2358184610Salfred 2359184610Salfredstatic void 2360194677Sthompsaumass_t_cbi_reset4_callback(struct usb_xfer *xfer, usb_error_t error) 2361184610Salfred{ 2362184610Salfred umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_COMMAND, 2363194677Sthompsa UMASS_T_CBI_STATUS, error); 2364184610Salfred} 2365184610Salfred 2366184610Salfredstatic void 2367192984Sthompsaumass_t_cbi_data_clear_stall_callback(struct usb_xfer *xfer, 2368194677Sthompsa uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error) 2369184610Salfred{ 2370194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 2371184610Salfred 2372184610Salfred switch (USB_GET_STATE(xfer)) { 2373184610Salfred case USB_ST_TRANSFERRED: 2374184610Salfredtr_transferred: 2375184610Salfred if (next_xfer == UMASS_T_CBI_STATUS) { 2376184610Salfred umass_cbi_start_status(sc); 2377184610Salfred } else { 2378184610Salfred umass_transfer_start(sc, next_xfer); 2379184610Salfred } 2380184610Salfred return; 2381184610Salfred 2382184610Salfred case USB_ST_SETUP: 2383194228Sthompsa if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) { 2384184610Salfred goto tr_transferred; /* should not happen */ 2385184610Salfred } 2386184610Salfred return; 2387184610Salfred 2388184610Salfred default: /* Error */ 2389194677Sthompsa umass_tr_error(xfer, error); 2390184610Salfred return; 2391184610Salfred 2392184610Salfred } 2393184610Salfred} 2394184610Salfred 2395184610Salfredstatic void 2396194677Sthompsaumass_t_cbi_command_callback(struct usb_xfer *xfer, usb_error_t error) 2397184610Salfred{ 2398194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 2399184610Salfred union ccb *ccb = sc->sc_transfer.ccb; 2400192984Sthompsa struct usb_device_request req; 2401194677Sthompsa struct usb_page_cache *pc; 2402184610Salfred 2403184610Salfred switch (USB_GET_STATE(xfer)) { 2404184610Salfred case USB_ST_TRANSFERRED: 2405184610Salfred 2406184610Salfred if (sc->sc_transfer.dir == DIR_NONE) { 2407184610Salfred umass_cbi_start_status(sc); 2408184610Salfred } else { 2409184610Salfred umass_transfer_start 2410184610Salfred (sc, (sc->sc_transfer.dir == DIR_IN) ? 2411184610Salfred UMASS_T_CBI_DATA_READ : UMASS_T_CBI_DATA_WRITE); 2412184610Salfred } 2413184610Salfred return; 2414184610Salfred 2415184610Salfred case USB_ST_SETUP: 2416184610Salfred 2417184610Salfred if (ccb) { 2418184610Salfred 2419184610Salfred /* 2420184610Salfred * do a CBI transfer with cmd_len bytes from 2421184610Salfred * cmd_data, possibly a data phase of data_len 2422184610Salfred * bytes from/to the device and finally a status 2423184610Salfred * read phase. 2424184610Salfred */ 2425184610Salfred 2426184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 2427184610Salfred req.bRequest = UR_CBI_ADSC; 2428184610Salfred USETW(req.wValue, 0); 2429184610Salfred req.wIndex[0] = sc->sc_iface_no; 2430184610Salfred req.wIndex[1] = 0; 2431184610Salfred req.wLength[0] = sc->sc_transfer.cmd_len; 2432184610Salfred req.wLength[1] = 0; 2433184610Salfred 2434194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2435194677Sthompsa usbd_copy_in(pc, 0, &req, sizeof(req)); 2436194677Sthompsa pc = usbd_xfer_get_frame(xfer, 1); 2437194677Sthompsa usbd_copy_in(pc, 0, sc->sc_transfer.cmd_data, 2438184610Salfred sc->sc_transfer.cmd_len); 2439184610Salfred 2440194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 2441194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, sc->sc_transfer.cmd_len); 2442194677Sthompsa usbd_xfer_set_frames(xfer, 2443194677Sthompsa sc->sc_transfer.cmd_len ? 2 : 1); 2444184610Salfred 2445184610Salfred DIF(UDMASS_CBI, 2446184610Salfred umass_cbi_dump_cmd(sc, 2447184610Salfred sc->sc_transfer.cmd_data, 2448184610Salfred sc->sc_transfer.cmd_len)); 2449184610Salfred 2450194228Sthompsa usbd_transfer_submit(xfer); 2451184610Salfred } 2452184610Salfred return; 2453184610Salfred 2454184610Salfred default: /* Error */ 2455194677Sthompsa umass_tr_error(xfer, error); 2456184610Salfred return; 2457184610Salfred 2458184610Salfred } 2459184610Salfred} 2460184610Salfred 2461184610Salfredstatic void 2462194677Sthompsaumass_t_cbi_data_read_callback(struct usb_xfer *xfer, usb_error_t error) 2463184610Salfred{ 2464194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 2465194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 2466194677Sthompsa#ifndef UMASS_EXT_BUFFER 2467194677Sthompsa struct usb_page_cache *pc; 2468194677Sthompsa#endif 2469194677Sthompsa int actlen, sumlen; 2470184610Salfred 2471194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 2472194677Sthompsa 2473184610Salfred switch (USB_GET_STATE(xfer)) { 2474184610Salfred case USB_ST_TRANSFERRED: 2475194677Sthompsa#ifndef UMASS_EXT_BUFFER 2476194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2477194677Sthompsa usbd_copy_out(pc, 0, sc->sc_transfer.data_ptr, actlen); 2478194677Sthompsa#endif 2479194677Sthompsa sc->sc_transfer.data_rem -= actlen; 2480194677Sthompsa sc->sc_transfer.data_ptr += actlen; 2481194677Sthompsa sc->sc_transfer.actlen += actlen; 2482184610Salfred 2483194677Sthompsa if (actlen < sumlen) { 2484184610Salfred /* short transfer */ 2485184610Salfred sc->sc_transfer.data_rem = 0; 2486184610Salfred } 2487184610Salfred case USB_ST_SETUP: 2488184610Salfred DPRINTF(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n", 2489184610Salfred max_bulk, sc->sc_transfer.data_rem); 2490184610Salfred 2491184610Salfred if (sc->sc_transfer.data_rem == 0) { 2492184610Salfred umass_cbi_start_status(sc); 2493184610Salfred return; 2494184610Salfred } 2495184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 2496184610Salfred max_bulk = sc->sc_transfer.data_rem; 2497184610Salfred } 2498194677Sthompsa usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); 2499184610Salfred 2500194677Sthompsa#ifdef UMASS_EXT_BUFFER 2501194677Sthompsa usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, 2502194677Sthompsa max_bulk); 2503194677Sthompsa#else 2504194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, max_bulk); 2505194677Sthompsa#endif 2506194228Sthompsa usbd_transfer_submit(xfer); 2507184610Salfred return; 2508184610Salfred 2509184610Salfred default: /* Error */ 2510194677Sthompsa if ((error == USB_ERR_CANCELLED) || 2511184610Salfred (sc->sc_transfer.callback != &umass_cam_cb)) { 2512194677Sthompsa umass_tr_error(xfer, error); 2513184610Salfred } else { 2514184610Salfred umass_transfer_start(sc, UMASS_T_CBI_DATA_RD_CS); 2515184610Salfred } 2516184610Salfred return; 2517184610Salfred 2518184610Salfred } 2519184610Salfred} 2520184610Salfred 2521184610Salfredstatic void 2522194677Sthompsaumass_t_cbi_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error) 2523184610Salfred{ 2524184610Salfred umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS, 2525194677Sthompsa UMASS_T_CBI_DATA_READ, error); 2526184610Salfred} 2527184610Salfred 2528184610Salfredstatic void 2529194677Sthompsaumass_t_cbi_data_write_callback(struct usb_xfer *xfer, usb_error_t error) 2530184610Salfred{ 2531194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 2532194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 2533194677Sthompsa#ifndef UMASS_EXT_BUFFER 2534194677Sthompsa struct usb_page_cache *pc; 2535194677Sthompsa#endif 2536194677Sthompsa int actlen, sumlen; 2537184610Salfred 2538194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 2539194677Sthompsa 2540184610Salfred switch (USB_GET_STATE(xfer)) { 2541184610Salfred case USB_ST_TRANSFERRED: 2542194677Sthompsa sc->sc_transfer.data_rem -= actlen; 2543194677Sthompsa sc->sc_transfer.data_ptr += actlen; 2544194677Sthompsa sc->sc_transfer.actlen += actlen; 2545184610Salfred 2546194677Sthompsa if (actlen < sumlen) { 2547184610Salfred /* short transfer */ 2548184610Salfred sc->sc_transfer.data_rem = 0; 2549184610Salfred } 2550184610Salfred case USB_ST_SETUP: 2551184610Salfred DPRINTF(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n", 2552184610Salfred max_bulk, sc->sc_transfer.data_rem); 2553184610Salfred 2554184610Salfred if (sc->sc_transfer.data_rem == 0) { 2555184610Salfred umass_cbi_start_status(sc); 2556184610Salfred return; 2557184610Salfred } 2558184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 2559184610Salfred max_bulk = sc->sc_transfer.data_rem; 2560184610Salfred } 2561194677Sthompsa usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); 2562184610Salfred 2563194677Sthompsa#ifdef UMASS_EXT_BUFFER 2564194677Sthompsa usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, 2565194677Sthompsa max_bulk); 2566194677Sthompsa#else 2567194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2568194677Sthompsa usbd_copy_in(pc, 0, sc->sc_transfer.data_ptr, max_bulk); 2569194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, max_bulk); 2570194677Sthompsa#endif 2571184610Salfred 2572194228Sthompsa usbd_transfer_submit(xfer); 2573184610Salfred return; 2574184610Salfred 2575184610Salfred default: /* Error */ 2576194677Sthompsa if ((error == USB_ERR_CANCELLED) || 2577184610Salfred (sc->sc_transfer.callback != &umass_cam_cb)) { 2578194677Sthompsa umass_tr_error(xfer, error); 2579184610Salfred } else { 2580184610Salfred umass_transfer_start(sc, UMASS_T_CBI_DATA_WR_CS); 2581184610Salfred } 2582184610Salfred return; 2583184610Salfred 2584184610Salfred } 2585184610Salfred} 2586184610Salfred 2587184610Salfredstatic void 2588194677Sthompsaumass_t_cbi_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error) 2589184610Salfred{ 2590184610Salfred umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS, 2591194677Sthompsa UMASS_T_CBI_DATA_WRITE, error); 2592184610Salfred} 2593184610Salfred 2594184610Salfredstatic void 2595194677Sthompsaumass_t_cbi_status_callback(struct usb_xfer *xfer, usb_error_t error) 2596184610Salfred{ 2597194677Sthompsa struct umass_softc *sc = usbd_xfer_softc(xfer); 2598184610Salfred union ccb *ccb = sc->sc_transfer.ccb; 2599194677Sthompsa struct usb_page_cache *pc; 2600184610Salfred uint32_t residue; 2601184610Salfred uint8_t status; 2602194677Sthompsa int actlen; 2603184610Salfred 2604194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 2605194677Sthompsa 2606184610Salfred switch (USB_GET_STATE(xfer)) { 2607184610Salfred case USB_ST_TRANSFERRED: 2608184610Salfred 2609194677Sthompsa if (actlen < sizeof(sc->sbl)) { 2610184610Salfred goto tr_setup; 2611184610Salfred } 2612194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 2613194677Sthompsa usbd_copy_out(pc, 0, &sc->sbl, sizeof(sc->sbl)); 2614184610Salfred 2615184610Salfred residue = (sc->sc_transfer.data_len - 2616184610Salfred sc->sc_transfer.actlen); 2617184610Salfred 2618184610Salfred /* dissect the information in the buffer */ 2619184610Salfred 2620184610Salfred if (sc->sc_proto & UMASS_PROTO_UFI) { 2621184610Salfred 2622184610Salfred /* 2623184610Salfred * Section 3.4.3.1.3 specifies that the UFI command 2624184610Salfred * protocol returns an ASC and ASCQ in the interrupt 2625184610Salfred * data block. 2626184610Salfred */ 2627184610Salfred 2628184610Salfred DPRINTF(sc, UDMASS_CBI, "UFI CCI, ASC = 0x%02x, " 2629184610Salfred "ASCQ = 0x%02x\n", sc->sbl.ufi.asc, 2630184610Salfred sc->sbl.ufi.ascq); 2631184610Salfred 2632184610Salfred status = (((sc->sbl.ufi.asc == 0) && 2633184610Salfred (sc->sbl.ufi.ascq == 0)) ? 2634184610Salfred STATUS_CMD_OK : STATUS_CMD_FAILED); 2635184610Salfred 2636184610Salfred sc->sc_transfer.ccb = NULL; 2637184610Salfred 2638184610Salfred sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND; 2639184610Salfred 2640184610Salfred (sc->sc_transfer.callback) 2641184610Salfred (sc, ccb, residue, status); 2642184610Salfred 2643184610Salfred return; 2644184610Salfred 2645184610Salfred } else { 2646184610Salfred 2647184610Salfred /* Command Interrupt Data Block */ 2648184610Salfred 2649184610Salfred DPRINTF(sc, UDMASS_CBI, "type=0x%02x, value=0x%02x\n", 2650184610Salfred sc->sbl.common.type, sc->sbl.common.value); 2651184610Salfred 2652184610Salfred if (sc->sbl.common.type == IDB_TYPE_CCI) { 2653184610Salfred 2654184610Salfred status = (sc->sbl.common.value & IDB_VALUE_STATUS_MASK); 2655184610Salfred 2656184610Salfred status = ((status == IDB_VALUE_PASS) ? STATUS_CMD_OK : 2657184610Salfred (status == IDB_VALUE_FAIL) ? STATUS_CMD_FAILED : 2658184610Salfred (status == IDB_VALUE_PERSISTENT) ? STATUS_CMD_FAILED : 2659184610Salfred STATUS_WIRE_FAILED); 2660184610Salfred 2661184610Salfred sc->sc_transfer.ccb = NULL; 2662184610Salfred 2663184610Salfred sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND; 2664184610Salfred 2665184610Salfred (sc->sc_transfer.callback) 2666184610Salfred (sc, ccb, residue, status); 2667184610Salfred 2668184610Salfred return; 2669184610Salfred } 2670184610Salfred } 2671184610Salfred 2672184610Salfred /* fallthrough */ 2673184610Salfred 2674184610Salfred case USB_ST_SETUP: 2675184610Salfredtr_setup: 2676194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 2677194228Sthompsa usbd_transfer_submit(xfer); 2678184610Salfred return; 2679184610Salfred 2680184610Salfred default: /* Error */ 2681184610Salfred DPRINTF(sc, UDMASS_CBI, "Failed to read CSW: %s\n", 2682194677Sthompsa usbd_errstr(error)); 2683194677Sthompsa umass_tr_error(xfer, error); 2684184610Salfred return; 2685184610Salfred 2686184610Salfred } 2687184610Salfred} 2688184610Salfred 2689184610Salfred/* 2690184610Salfred * CAM specific functions (used by SCSI, UFI, 8070i (ATAPI)) 2691184610Salfred */ 2692184610Salfred 2693184610Salfredstatic int 2694184610Salfredumass_cam_attach_sim(struct umass_softc *sc) 2695184610Salfred{ 2696184610Salfred struct cam_devq *devq; /* Per device Queue */ 2697184610Salfred 2698184610Salfred /* 2699184610Salfred * A HBA is attached to the CAM layer. 2700184610Salfred * 2701184610Salfred * The CAM layer will then after a while start probing for devices on 2702184610Salfred * the bus. The number of SIMs is limited to one. 2703184610Salfred */ 2704184610Salfred 2705184610Salfred devq = cam_simq_alloc(1 /* maximum openings */ ); 2706184610Salfred if (devq == NULL) { 2707184610Salfred return (ENOMEM); 2708184610Salfred } 2709184610Salfred sc->sc_sim = cam_sim_alloc 2710184610Salfred (&umass_cam_action, &umass_cam_poll, 2711184610Salfred DEVNAME_SIM, 2712184610Salfred sc /* priv */ , 2713184610Salfred sc->sc_unit /* unit number */ , 2714184610Salfred#if (__FreeBSD_version >= 700037) 2715188415Sthompsa &sc->sc_mtx /* mutex */ , 2716184610Salfred#endif 2717184610Salfred 1 /* maximum device openings */ , 2718184610Salfred 0 /* maximum tagged device openings */ , 2719184610Salfred devq); 2720184610Salfred 2721184610Salfred if (sc->sc_sim == NULL) { 2722184610Salfred cam_simq_free(devq); 2723184610Salfred return (ENOMEM); 2724184610Salfred } 2725184610Salfred 2726184610Salfred#if (__FreeBSD_version >= 700037) 2727188415Sthompsa mtx_lock(&sc->sc_mtx); 2728184610Salfred#endif 2729184610Salfred 2730184610Salfred#if (__FreeBSD_version >= 700048) 2731184610Salfred if (xpt_bus_register(sc->sc_sim, sc->sc_dev, sc->sc_unit) != CAM_SUCCESS) { 2732188415Sthompsa mtx_unlock(&sc->sc_mtx); 2733184610Salfred return (ENOMEM); 2734184610Salfred } 2735184610Salfred#else 2736184610Salfred if (xpt_bus_register(sc->sc_sim, sc->sc_unit) != CAM_SUCCESS) { 2737184610Salfred#if (__FreeBSD_version >= 700037) 2738188415Sthompsa mtx_unlock(&sc->sc_mtx); 2739184610Salfred#endif 2740184610Salfred return (ENOMEM); 2741184610Salfred } 2742184610Salfred#endif 2743184610Salfred 2744184610Salfred#if (__FreeBSD_version >= 700037) 2745188415Sthompsa mtx_unlock(&sc->sc_mtx); 2746184610Salfred#endif 2747184610Salfred return (0); 2748184610Salfred} 2749184610Salfred 2750184610Salfredstatic void 2751184610Salfredumass_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) 2752184610Salfred{ 2753184610Salfred#if USB_DEBUG 2754184610Salfred struct umass_softc *sc = NULL; 2755184610Salfred 2756184610Salfred if (ccb->ccb_h.status != CAM_REQ_CMP) { 2757184610Salfred DPRINTF(sc, UDMASS_SCSI, "%s:%d Rescan failed, 0x%04x\n", 2758184610Salfred periph->periph_name, periph->unit_number, 2759184610Salfred ccb->ccb_h.status); 2760184610Salfred } else { 2761184610Salfred DPRINTF(sc, UDMASS_SCSI, "%s%d: Rescan succeeded\n", 2762184610Salfred periph->periph_name, periph->unit_number); 2763184610Salfred } 2764184610Salfred#endif 2765184610Salfred 2766184610Salfred xpt_free_path(ccb->ccb_h.path); 2767184610Salfred free(ccb, M_USBDEV); 2768184610Salfred} 2769184610Salfred 2770184610Salfredstatic void 2771184610Salfredumass_cam_rescan(struct umass_softc *sc) 2772184610Salfred{ 2773184610Salfred struct cam_path *path; 2774184610Salfred union ccb *ccb; 2775184610Salfred 2776184610Salfred DPRINTF(sc, UDMASS_SCSI, "scbus%d: scanning for %d:%d:%d\n", 2777184610Salfred cam_sim_path(sc->sc_sim), 2778184610Salfred cam_sim_path(sc->sc_sim), 2779184610Salfred sc->sc_unit, CAM_LUN_WILDCARD); 2780184610Salfred 2781184610Salfred ccb = malloc(sizeof(*ccb), M_USBDEV, M_WAITOK | M_ZERO); 2782184610Salfred 2783184610Salfred if (ccb == NULL) { 2784184610Salfred return; 2785184610Salfred } 2786184610Salfred#if (__FreeBSD_version >= 700037) 2787188415Sthompsa mtx_lock(&sc->sc_mtx); 2788184610Salfred#endif 2789184610Salfred 2790184610Salfred if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->sc_sim), 2791184610Salfred CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) 2792184610Salfred != CAM_REQ_CMP) { 2793184610Salfred#if (__FreeBSD_version >= 700037) 2794188415Sthompsa mtx_unlock(&sc->sc_mtx); 2795184610Salfred#endif 2796184610Salfred free(ccb, M_USBDEV); 2797184610Salfred return; 2798184610Salfred } 2799184610Salfred xpt_setup_ccb(&ccb->ccb_h, path, 5 /* priority (low) */ ); 2800184610Salfred ccb->ccb_h.func_code = XPT_SCAN_BUS; 2801184610Salfred ccb->ccb_h.cbfcnp = &umass_cam_rescan_callback; 2802184610Salfred ccb->crcn.flags = CAM_FLAG_NONE; 2803184610Salfred xpt_action(ccb); 2804184610Salfred 2805184610Salfred#if (__FreeBSD_version >= 700037) 2806188415Sthompsa mtx_unlock(&sc->sc_mtx); 2807184610Salfred#endif 2808184610Salfred 2809184610Salfred /* The scan is in progress now. */ 2810184610Salfred} 2811184610Salfred 2812184610Salfredstatic void 2813184610Salfredumass_cam_attach(struct umass_softc *sc) 2814184610Salfred{ 2815184610Salfred#ifndef USB_DEBUG 2816184610Salfred if (bootverbose) 2817184610Salfred#endif 2818184610Salfred printf("%s:%d:%d:%d: Attached to scbus%d\n", 2819184610Salfred sc->sc_name, cam_sim_path(sc->sc_sim), 2820184610Salfred sc->sc_unit, CAM_LUN_WILDCARD, 2821184610Salfred cam_sim_path(sc->sc_sim)); 2822184610Salfred 2823184610Salfred if (!cold) { 2824184610Salfred /* 2825184610Salfred * Notify CAM of the new device after a short delay. Any 2826184610Salfred * failure is benign, as the user can still do it by hand 2827184610Salfred * (camcontrol rescan <busno>). Only do this if we are not 2828184610Salfred * booting, because CAM does a scan after booting has 2829184610Salfred * completed, when interrupts have been enabled. 2830184610Salfred */ 2831184610Salfred 2832184610Salfred /* scan the new sim */ 2833184610Salfred umass_cam_rescan(sc); 2834184610Salfred } 2835184610Salfred} 2836184610Salfred 2837184610Salfred/* umass_cam_detach 2838184610Salfred * detach from the CAM layer 2839184610Salfred */ 2840184610Salfred 2841184610Salfredstatic void 2842184610Salfredumass_cam_detach_sim(struct umass_softc *sc) 2843184610Salfred{ 2844188415Sthompsa if (sc->sc_sim != NULL) { 2845184610Salfred if (xpt_bus_deregister(cam_sim_path(sc->sc_sim))) { 2846184610Salfred /* accessing the softc is not possible after this */ 2847184610Salfred sc->sc_sim->softc = UMASS_GONE; 2848188415Sthompsa cam_sim_free(sc->sc_sim, /* free_devq */ TRUE); 2849184610Salfred } else { 2850184610Salfred panic("%s: CAM layer is busy!\n", 2851184610Salfred sc->sc_name); 2852184610Salfred } 2853184610Salfred sc->sc_sim = NULL; 2854184610Salfred } 2855184610Salfred} 2856184610Salfred 2857184610Salfred/* umass_cam_action 2858184610Salfred * CAM requests for action come through here 2859184610Salfred */ 2860184610Salfred 2861184610Salfredstatic void 2862184610Salfredumass_cam_action(struct cam_sim *sim, union ccb *ccb) 2863184610Salfred{ 2864184610Salfred struct umass_softc *sc = (struct umass_softc *)sim->softc; 2865184610Salfred 2866198307Sthompsa if (sc == UMASS_GONE || 2867198307Sthompsa (sc != NULL && !usbd_device_attached(sc->sc_udev))) { 2868198307Sthompsa ccb->ccb_h.status = CAM_SEL_TIMEOUT; 2869184610Salfred xpt_done(ccb); 2870184610Salfred return; 2871184610Salfred } 2872184610Salfred if (sc) { 2873184610Salfred#if (__FreeBSD_version < 700037) 2874188415Sthompsa mtx_lock(&sc->sc_mtx); 2875184610Salfred#endif 2876184610Salfred } 2877184610Salfred /* 2878184610Salfred * Verify, depending on the operation to perform, that we either got 2879184610Salfred * a valid sc, because an existing target was referenced, or 2880184610Salfred * otherwise the SIM is addressed. 2881184610Salfred * 2882184610Salfred * This avoids bombing out at a printf and does give the CAM layer some 2883184610Salfred * sensible feedback on errors. 2884184610Salfred */ 2885184610Salfred switch (ccb->ccb_h.func_code) { 2886184610Salfred case XPT_SCSI_IO: 2887184610Salfred case XPT_RESET_DEV: 2888184610Salfred case XPT_GET_TRAN_SETTINGS: 2889184610Salfred case XPT_SET_TRAN_SETTINGS: 2890184610Salfred case XPT_CALC_GEOMETRY: 2891184610Salfred /* the opcodes requiring a target. These should never occur. */ 2892184610Salfred if (sc == NULL) { 2893184610Salfred DPRINTF(sc, UDMASS_GEN, "%s:%d:%d:%d:func_code 0x%04x: " 2894184610Salfred "Invalid target (target needed)\n", 2895184610Salfred DEVNAME_SIM, cam_sim_path(sc->sc_sim), 2896184610Salfred ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 2897184610Salfred ccb->ccb_h.func_code); 2898184610Salfred 2899184610Salfred ccb->ccb_h.status = CAM_TID_INVALID; 2900184610Salfred xpt_done(ccb); 2901184610Salfred goto done; 2902184610Salfred } 2903184610Salfred break; 2904184610Salfred case XPT_PATH_INQ: 2905184610Salfred case XPT_NOOP: 2906184610Salfred /* 2907184610Salfred * The opcodes sometimes aimed at a target (sc is valid), 2908184610Salfred * sometimes aimed at the SIM (sc is invalid and target is 2909184610Salfred * CAM_TARGET_WILDCARD) 2910184610Salfred */ 2911184610Salfred if ((sc == NULL) && 2912184610Salfred (ccb->ccb_h.target_id != CAM_TARGET_WILDCARD)) { 2913184610Salfred DPRINTF(sc, UDMASS_SCSI, "%s:%d:%d:%d:func_code 0x%04x: " 2914184610Salfred "Invalid target (no wildcard)\n", 2915184610Salfred DEVNAME_SIM, cam_sim_path(sc->sc_sim), 2916184610Salfred ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 2917184610Salfred ccb->ccb_h.func_code); 2918184610Salfred 2919184610Salfred ccb->ccb_h.status = CAM_TID_INVALID; 2920184610Salfred xpt_done(ccb); 2921184610Salfred goto done; 2922184610Salfred } 2923184610Salfred break; 2924184610Salfred default: 2925184610Salfred /* XXX Hm, we should check the input parameters */ 2926184610Salfred break; 2927184610Salfred } 2928184610Salfred 2929184610Salfred /* Perform the requested action */ 2930184610Salfred switch (ccb->ccb_h.func_code) { 2931184610Salfred case XPT_SCSI_IO: 2932184610Salfred { 2933184610Salfred uint8_t *cmd; 2934184610Salfred uint8_t dir; 2935184610Salfred 2936184610Salfred if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) { 2937184610Salfred cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr); 2938184610Salfred } else { 2939184610Salfred cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes); 2940184610Salfred } 2941184610Salfred 2942184610Salfred DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SCSI_IO: " 2943184610Salfred "cmd: 0x%02x, flags: 0x%02x, " 2944184610Salfred "%db cmd/%db data/%db sense\n", 2945184610Salfred cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id, 2946184610Salfred ccb->ccb_h.target_lun, cmd[0], 2947184610Salfred ccb->ccb_h.flags & CAM_DIR_MASK, ccb->csio.cdb_len, 2948184610Salfred ccb->csio.dxfer_len, ccb->csio.sense_len); 2949184610Salfred 2950184610Salfred if (sc->sc_transfer.ccb) { 2951184610Salfred DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SCSI_IO: " 2952184610Salfred "I/O in progress, deferring\n", 2953184610Salfred cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id, 2954184610Salfred ccb->ccb_h.target_lun); 2955184610Salfred ccb->ccb_h.status = CAM_SCSI_BUSY; 2956184610Salfred xpt_done(ccb); 2957184610Salfred goto done; 2958184610Salfred } 2959184610Salfred switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 2960184610Salfred case CAM_DIR_IN: 2961184610Salfred dir = DIR_IN; 2962184610Salfred break; 2963184610Salfred case CAM_DIR_OUT: 2964184610Salfred dir = DIR_OUT; 2965184610Salfred DIF(UDMASS_SCSI, 2966184610Salfred umass_dump_buffer(sc, ccb->csio.data_ptr, 2967184610Salfred ccb->csio.dxfer_len, 48)); 2968184610Salfred break; 2969184610Salfred default: 2970184610Salfred dir = DIR_NONE; 2971184610Salfred } 2972184610Salfred 2973184610Salfred ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED; 2974184610Salfred 2975184610Salfred /* 2976184610Salfred * sc->sc_transform will convert the command to the 2977184610Salfred * command format needed by the specific command set 2978184610Salfred * and return the converted command in 2979184610Salfred * "sc->sc_transfer.cmd_data" 2980184610Salfred */ 2981184610Salfred if (umass_std_transform(sc, ccb, cmd, ccb->csio.cdb_len)) { 2982184610Salfred 2983184610Salfred if (sc->sc_transfer.cmd_data[0] == INQUIRY) { 2984184610Salfred 2985184610Salfred /* 2986196826Strasz * Umass devices don't generally report their serial numbers 2987196826Strasz * in the usual SCSI way. Emulate it here. 2988196826Strasz */ 2989196826Strasz if ((sc->sc_transfer.cmd_data[1] & SI_EVPD) && 2990196826Strasz sc->sc_transfer.cmd_data[2] == SVPD_UNIT_SERIAL_NUMBER && 2991196826Strasz sc->sc_udev != NULL && 2992196826Strasz sc->sc_udev->serial != NULL && 2993196826Strasz sc->sc_udev->serial[0] != '\0') { 2994196826Strasz struct scsi_vpd_unit_serial_number *vpd_serial; 2995196826Strasz 2996196826Strasz vpd_serial = (struct scsi_vpd_unit_serial_number *)ccb->csio.data_ptr; 2997196826Strasz vpd_serial->length = strlen(sc->sc_udev->serial); 2998196826Strasz if (vpd_serial->length > sizeof(vpd_serial->serial_num)) 2999196826Strasz vpd_serial->length = sizeof(vpd_serial->serial_num); 3000196826Strasz memcpy(vpd_serial->serial_num, sc->sc_udev->serial, vpd_serial->length); 3001196826Strasz ccb->csio.scsi_status = SCSI_STATUS_OK; 3002196826Strasz ccb->ccb_h.status = CAM_REQ_CMP; 3003196826Strasz xpt_done(ccb); 3004196826Strasz goto done; 3005196826Strasz } 3006196826Strasz 3007196826Strasz /* 3008184610Salfred * Handle EVPD inquiry for broken devices first 3009184610Salfred * NO_INQUIRY also implies NO_INQUIRY_EVPD 3010184610Salfred */ 3011184610Salfred if ((sc->sc_quirks & (NO_INQUIRY_EVPD | NO_INQUIRY)) && 3012184610Salfred (sc->sc_transfer.cmd_data[1] & SI_EVPD)) { 3013184610Salfred struct scsi_sense_data *sense; 3014184610Salfred 3015184610Salfred sense = &ccb->csio.sense_data; 3016184610Salfred bzero(sense, sizeof(*sense)); 3017184610Salfred sense->error_code = SSD_CURRENT_ERROR; 3018184610Salfred sense->flags = SSD_KEY_ILLEGAL_REQUEST; 3019184610Salfred sense->add_sense_code = 0x24; 3020184610Salfred sense->extra_len = 10; 3021184610Salfred ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 3022184610Salfred ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | 3023184610Salfred CAM_AUTOSNS_VALID; 3024184610Salfred xpt_done(ccb); 3025184610Salfred goto done; 3026184610Salfred } 3027184610Salfred /* 3028184610Salfred * Return fake inquiry data for 3029184610Salfred * broken devices 3030184610Salfred */ 3031184610Salfred if (sc->sc_quirks & NO_INQUIRY) { 3032184610Salfred memcpy(ccb->csio.data_ptr, &fake_inq_data, 3033184610Salfred sizeof(fake_inq_data)); 3034184610Salfred ccb->csio.scsi_status = SCSI_STATUS_OK; 3035184610Salfred ccb->ccb_h.status = CAM_REQ_CMP; 3036184610Salfred xpt_done(ccb); 3037184610Salfred goto done; 3038184610Salfred } 3039184610Salfred if (sc->sc_quirks & FORCE_SHORT_INQUIRY) { 3040184610Salfred ccb->csio.dxfer_len = SHORT_INQUIRY_LENGTH; 3041184610Salfred } 3042184610Salfred } else if (sc->sc_transfer.cmd_data[0] == SYNCHRONIZE_CACHE) { 3043184610Salfred if (sc->sc_quirks & NO_SYNCHRONIZE_CACHE) { 3044184610Salfred ccb->csio.scsi_status = SCSI_STATUS_OK; 3045184610Salfred ccb->ccb_h.status = CAM_REQ_CMP; 3046184610Salfred xpt_done(ccb); 3047184610Salfred goto done; 3048184610Salfred } 3049184610Salfred } 3050184610Salfred umass_command_start(sc, dir, ccb->csio.data_ptr, 3051184610Salfred ccb->csio.dxfer_len, 3052184610Salfred ccb->ccb_h.timeout, 3053184610Salfred &umass_cam_cb, ccb); 3054184610Salfred } 3055184610Salfred break; 3056184610Salfred } 3057184610Salfred case XPT_PATH_INQ: 3058184610Salfred { 3059184610Salfred struct ccb_pathinq *cpi = &ccb->cpi; 3060184610Salfred 3061184610Salfred DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_PATH_INQ:.\n", 3062184610Salfred sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id, 3063184610Salfred ccb->ccb_h.target_lun); 3064184610Salfred 3065184610Salfred /* host specific information */ 3066184610Salfred cpi->version_num = 1; 3067184610Salfred cpi->hba_inquiry = 0; 3068184610Salfred cpi->target_sprt = 0; 3069184610Salfred cpi->hba_misc = PIM_NO_6_BYTE; 3070184610Salfred cpi->hba_eng_cnt = 0; 3071184610Salfred cpi->max_target = UMASS_SCSIID_MAX; /* one target */ 3072184610Salfred cpi->initiator_id = UMASS_SCSIID_HOST; 3073184610Salfred strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 3074184610Salfred strlcpy(cpi->hba_vid, "USB SCSI", HBA_IDLEN); 3075184610Salfred strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 3076184610Salfred cpi->unit_number = cam_sim_unit(sim); 3077184610Salfred cpi->bus_id = sc->sc_unit; 3078184610Salfred#if (__FreeBSD_version >= 700025) 3079184610Salfred cpi->protocol = PROTO_SCSI; 3080184610Salfred cpi->protocol_version = SCSI_REV_2; 3081184610Salfred cpi->transport = XPORT_USB; 3082184610Salfred cpi->transport_version = 0; 3083184610Salfred#endif 3084184610Salfred if (sc == NULL) { 3085184610Salfred cpi->base_transfer_speed = 0; 3086184610Salfred cpi->max_lun = 0; 3087184610Salfred } else { 3088184610Salfred if (sc->sc_quirks & FLOPPY_SPEED) { 3089184610Salfred cpi->base_transfer_speed = 3090184610Salfred UMASS_FLOPPY_TRANSFER_SPEED; 3091194228Sthompsa } else if (usbd_get_speed(sc->sc_udev) == 3092184610Salfred USB_SPEED_HIGH) { 3093184610Salfred cpi->base_transfer_speed = 3094184610Salfred UMASS_HIGH_TRANSFER_SPEED; 3095184610Salfred } else { 3096184610Salfred cpi->base_transfer_speed = 3097184610Salfred UMASS_FULL_TRANSFER_SPEED; 3098184610Salfred } 3099184610Salfred cpi->max_lun = sc->sc_maxlun; 3100184610Salfred } 3101184610Salfred 3102184610Salfred cpi->ccb_h.status = CAM_REQ_CMP; 3103184610Salfred xpt_done(ccb); 3104184610Salfred break; 3105184610Salfred } 3106184610Salfred case XPT_RESET_DEV: 3107184610Salfred { 3108184610Salfred DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_RESET_DEV:.\n", 3109184610Salfred cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id, 3110184610Salfred ccb->ccb_h.target_lun); 3111184610Salfred 3112184610Salfred umass_reset(sc); 3113184610Salfred 3114184610Salfred ccb->ccb_h.status = CAM_REQ_CMP; 3115184610Salfred xpt_done(ccb); 3116184610Salfred break; 3117184610Salfred } 3118184610Salfred case XPT_GET_TRAN_SETTINGS: 3119184610Salfred { 3120184610Salfred struct ccb_trans_settings *cts = &ccb->cts; 3121184610Salfred 3122184610Salfred DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_GET_TRAN_SETTINGS:.\n", 3123184610Salfred cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id, 3124184610Salfred ccb->ccb_h.target_lun); 3125184610Salfred 3126184610Salfred#if (__FreeBSD_version >= 700025) 3127184610Salfred cts->protocol = PROTO_SCSI; 3128184610Salfred cts->protocol_version = SCSI_REV_2; 3129184610Salfred cts->transport = XPORT_USB; 3130184610Salfred cts->transport_version = 0; 3131184610Salfred cts->xport_specific.valid = 0; 3132184610Salfred#else 3133184610Salfred cts->valid = 0; 3134184610Salfred cts->flags = 0; /* no disconnection, tagging */ 3135184610Salfred#endif 3136184610Salfred ccb->ccb_h.status = CAM_REQ_CMP; 3137184610Salfred xpt_done(ccb); 3138184610Salfred break; 3139184610Salfred } 3140184610Salfred case XPT_SET_TRAN_SETTINGS: 3141184610Salfred { 3142184610Salfred DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SET_TRAN_SETTINGS:.\n", 3143184610Salfred cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id, 3144184610Salfred ccb->ccb_h.target_lun); 3145184610Salfred 3146184610Salfred ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 3147184610Salfred xpt_done(ccb); 3148184610Salfred break; 3149184610Salfred } 3150184610Salfred case XPT_CALC_GEOMETRY: 3151184610Salfred { 3152184610Salfred cam_calc_geometry(&ccb->ccg, /* extended */ 1); 3153184610Salfred xpt_done(ccb); 3154184610Salfred break; 3155184610Salfred } 3156184610Salfred case XPT_NOOP: 3157184610Salfred { 3158184610Salfred DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_NOOP:.\n", 3159184610Salfred sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id, 3160184610Salfred ccb->ccb_h.target_lun); 3161184610Salfred 3162184610Salfred ccb->ccb_h.status = CAM_REQ_CMP; 3163184610Salfred xpt_done(ccb); 3164184610Salfred break; 3165184610Salfred } 3166184610Salfred default: 3167184610Salfred DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:func_code 0x%04x: " 3168184610Salfred "Not implemented\n", 3169184610Salfred sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id, 3170184610Salfred ccb->ccb_h.target_lun, ccb->ccb_h.func_code); 3171184610Salfred 3172184610Salfred ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 3173184610Salfred xpt_done(ccb); 3174184610Salfred break; 3175184610Salfred } 3176184610Salfred 3177184610Salfreddone: 3178184610Salfred#if (__FreeBSD_version < 700037) 3179184610Salfred if (sc) { 3180188415Sthompsa mtx_unlock(&sc->sc_mtx); 3181184610Salfred } 3182184610Salfred#endif 3183184610Salfred return; 3184184610Salfred} 3185184610Salfred 3186184610Salfredstatic void 3187184610Salfredumass_cam_poll(struct cam_sim *sim) 3188184610Salfred{ 3189184610Salfred struct umass_softc *sc = (struct umass_softc *)sim->softc; 3190184610Salfred 3191184610Salfred if (sc == UMASS_GONE) 3192184610Salfred return; 3193184610Salfred 3194184610Salfred DPRINTF(sc, UDMASS_SCSI, "CAM poll\n"); 3195184610Salfred 3196194677Sthompsa usbd_transfer_poll(sc->sc_xfer, UMASS_T_MAX); 3197184610Salfred} 3198184610Salfred 3199184610Salfred 3200184610Salfred/* umass_cam_cb 3201184610Salfred * finalise a completed CAM command 3202184610Salfred */ 3203184610Salfred 3204184610Salfredstatic void 3205184610Salfredumass_cam_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, 3206184610Salfred uint8_t status) 3207184610Salfred{ 3208184610Salfred ccb->csio.resid = residue; 3209184610Salfred 3210184610Salfred switch (status) { 3211184610Salfred case STATUS_CMD_OK: 3212184610Salfred ccb->ccb_h.status = CAM_REQ_CMP; 3213184610Salfred if ((sc->sc_quirks & READ_CAPACITY_OFFBY1) && 3214184610Salfred (ccb->ccb_h.func_code == XPT_SCSI_IO) && 3215184610Salfred (ccb->csio.cdb_io.cdb_bytes[0] == READ_CAPACITY)) { 3216184610Salfred struct scsi_read_capacity_data *rcap; 3217184610Salfred uint32_t maxsector; 3218184610Salfred 3219184610Salfred rcap = (void *)(ccb->csio.data_ptr); 3220184610Salfred maxsector = scsi_4btoul(rcap->addr) - 1; 3221184610Salfred scsi_ulto4b(maxsector, rcap->addr); 3222184610Salfred } 3223196826Strasz /* 3224196826Strasz * We have to add SVPD_UNIT_SERIAL_NUMBER to the list 3225196826Strasz * of pages supported by the device - otherwise, CAM 3226196826Strasz * will never ask us for the serial number if the 3227196826Strasz * device cannot handle that by itself. 3228196826Strasz */ 3229196826Strasz if (ccb->ccb_h.func_code == XPT_SCSI_IO && 3230196826Strasz sc->sc_transfer.cmd_data[0] == INQUIRY && 3231196826Strasz (sc->sc_transfer.cmd_data[1] & SI_EVPD) && 3232196826Strasz sc->sc_transfer.cmd_data[2] == SVPD_SUPPORTED_PAGE_LIST && 3233196826Strasz sc->sc_udev != NULL && 3234196826Strasz sc->sc_udev->serial != NULL && 3235196826Strasz sc->sc_udev->serial[0] != '\0') { 3236196826Strasz struct ccb_scsiio *csio; 3237196826Strasz struct scsi_vpd_supported_page_list *page_list; 3238196826Strasz 3239196826Strasz csio = &ccb->csio; 3240196826Strasz page_list = (struct scsi_vpd_supported_page_list *)csio->data_ptr; 3241196826Strasz if (page_list->length + 1 < SVPD_SUPPORTED_PAGES_SIZE) { 3242196826Strasz page_list->list[page_list->length] = SVPD_UNIT_SERIAL_NUMBER; 3243196826Strasz page_list->length++; 3244196826Strasz } 3245196826Strasz } 3246184610Salfred xpt_done(ccb); 3247184610Salfred break; 3248184610Salfred 3249184610Salfred case STATUS_CMD_UNKNOWN: 3250184610Salfred case STATUS_CMD_FAILED: 3251184610Salfred 3252184610Salfred /* fetch sense data */ 3253184610Salfred 3254184610Salfred /* the rest of the command was filled in at attach */ 3255184610Salfred sc->cam_scsi_sense.length = ccb->csio.sense_len; 3256184610Salfred 3257184610Salfred DPRINTF(sc, UDMASS_SCSI, "Fetching %d bytes of " 3258184610Salfred "sense data\n", ccb->csio.sense_len); 3259184610Salfred 3260184610Salfred if (umass_std_transform(sc, ccb, &sc->cam_scsi_sense.opcode, 3261184610Salfred sizeof(sc->cam_scsi_sense))) { 3262184610Salfred 3263184610Salfred if ((sc->sc_quirks & FORCE_SHORT_INQUIRY) && 3264184610Salfred (sc->sc_transfer.cmd_data[0] == INQUIRY)) { 3265184610Salfred ccb->csio.sense_len = SHORT_INQUIRY_LENGTH; 3266184610Salfred } 3267184610Salfred umass_command_start(sc, DIR_IN, &ccb->csio.sense_data.error_code, 3268184610Salfred ccb->csio.sense_len, ccb->ccb_h.timeout, 3269184610Salfred &umass_cam_sense_cb, ccb); 3270184610Salfred } 3271184610Salfred break; 3272184610Salfred 3273184610Salfred default: 3274184610Salfred /* 3275184610Salfred * the wire protocol failed and will have recovered 3276184610Salfred * (hopefully). We return an error to CAM and let CAM retry 3277184610Salfred * the command if necessary. 3278184610Salfred */ 3279184610Salfred ccb->ccb_h.status = CAM_REQ_CMP_ERR; 3280184610Salfred xpt_done(ccb); 3281184610Salfred break; 3282184610Salfred } 3283184610Salfred} 3284184610Salfred 3285184610Salfred/* 3286184610Salfred * Finalise a completed autosense operation 3287184610Salfred */ 3288184610Salfredstatic void 3289184610Salfredumass_cam_sense_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, 3290184610Salfred uint8_t status) 3291184610Salfred{ 3292184610Salfred uint8_t *cmd; 3293184610Salfred uint8_t key; 3294184610Salfred 3295184610Salfred switch (status) { 3296184610Salfred case STATUS_CMD_OK: 3297184610Salfred case STATUS_CMD_UNKNOWN: 3298184610Salfred case STATUS_CMD_FAILED: 3299184610Salfred 3300184610Salfred if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) { 3301184610Salfred cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr); 3302184610Salfred } else { 3303184610Salfred cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes); 3304184610Salfred } 3305184610Salfred 3306184610Salfred key = (ccb->csio.sense_data.flags & SSD_KEY); 3307184610Salfred 3308184610Salfred /* 3309184610Salfred * Getting sense data always succeeds (apart from wire 3310184610Salfred * failures): 3311184610Salfred */ 3312184610Salfred if ((sc->sc_quirks & RS_NO_CLEAR_UA) && 3313184610Salfred (cmd[0] == INQUIRY) && 3314184610Salfred (key == SSD_KEY_UNIT_ATTENTION)) { 3315184610Salfred /* 3316184610Salfred * Ignore unit attention errors in the case where 3317184610Salfred * the Unit Attention state is not cleared on 3318184610Salfred * REQUEST SENSE. They will appear again at the next 3319184610Salfred * command. 3320184610Salfred */ 3321184610Salfred ccb->ccb_h.status = CAM_REQ_CMP; 3322184610Salfred } else if (key == SSD_KEY_NO_SENSE) { 3323184610Salfred /* 3324184610Salfred * No problem after all (in the case of CBI without 3325184610Salfred * CCI) 3326184610Salfred */ 3327184610Salfred ccb->ccb_h.status = CAM_REQ_CMP; 3328184610Salfred } else if ((sc->sc_quirks & RS_NO_CLEAR_UA) && 3329184610Salfred (cmd[0] == READ_CAPACITY) && 3330184610Salfred (key == SSD_KEY_UNIT_ATTENTION)) { 3331184610Salfred /* 3332184610Salfred * Some devices do not clear the unit attention error 3333184610Salfred * on request sense. We insert a test unit ready 3334184610Salfred * command to make sure we clear the unit attention 3335184610Salfred * condition, then allow the retry to proceed as 3336184610Salfred * usual. 3337184610Salfred */ 3338184610Salfred 3339184610Salfred ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR 3340184610Salfred | CAM_AUTOSNS_VALID; 3341184610Salfred ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 3342184610Salfred 3343184610Salfred#if 0 3344184610Salfred DELAY(300000); 3345184610Salfred#endif 3346184610Salfred DPRINTF(sc, UDMASS_SCSI, "Doing a sneaky" 3347184610Salfred "TEST_UNIT_READY\n"); 3348184610Salfred 3349184610Salfred /* the rest of the command was filled in at attach */ 3350184610Salfred 3351184610Salfred if (umass_std_transform(sc, ccb, 3352184610Salfred &sc->cam_scsi_test_unit_ready.opcode, 3353184610Salfred sizeof(sc->cam_scsi_test_unit_ready))) { 3354184610Salfred umass_command_start(sc, DIR_NONE, NULL, 0, 3355184610Salfred ccb->ccb_h.timeout, 3356184610Salfred &umass_cam_quirk_cb, ccb); 3357184610Salfred } 3358184610Salfred break; 3359184610Salfred } else { 3360184610Salfred ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR 3361184610Salfred | CAM_AUTOSNS_VALID; 3362184610Salfred ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 3363184610Salfred } 3364184610Salfred xpt_done(ccb); 3365184610Salfred break; 3366184610Salfred 3367184610Salfred default: 3368184610Salfred DPRINTF(sc, UDMASS_SCSI, "Autosense failed, " 3369184610Salfred "status %d\n", status); 3370184610Salfred ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 3371184610Salfred xpt_done(ccb); 3372184610Salfred } 3373184610Salfred} 3374184610Salfred 3375184610Salfred/* 3376184610Salfred * This completion code just handles the fact that we sent a test-unit-ready 3377184610Salfred * after having previously failed a READ CAPACITY with CHECK_COND. Even 3378184610Salfred * though this command succeeded, we have to tell CAM to retry. 3379184610Salfred */ 3380184610Salfredstatic void 3381184610Salfredumass_cam_quirk_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, 3382184610Salfred uint8_t status) 3383184610Salfred{ 3384184610Salfred DPRINTF(sc, UDMASS_SCSI, "Test unit ready " 3385184610Salfred "returned status %d\n", status); 3386184610Salfred 3387184610Salfred ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR 3388184610Salfred | CAM_AUTOSNS_VALID; 3389184610Salfred ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 3390184610Salfred xpt_done(ccb); 3391184610Salfred} 3392184610Salfred 3393184610Salfred/* 3394184610Salfred * SCSI specific functions 3395184610Salfred */ 3396184610Salfred 3397184610Salfredstatic uint8_t 3398184610Salfredumass_scsi_transform(struct umass_softc *sc, uint8_t *cmd_ptr, 3399184610Salfred uint8_t cmd_len) 3400184610Salfred{ 3401184610Salfred if ((cmd_len == 0) || 3402184610Salfred (cmd_len > sizeof(sc->sc_transfer.cmd_data))) { 3403184610Salfred DPRINTF(sc, UDMASS_SCSI, "Invalid command " 3404184610Salfred "length: %d bytes\n", cmd_len); 3405184610Salfred return (0); /* failure */ 3406184610Salfred } 3407184610Salfred sc->sc_transfer.cmd_len = cmd_len; 3408184610Salfred 3409184610Salfred switch (cmd_ptr[0]) { 3410184610Salfred case TEST_UNIT_READY: 3411184610Salfred if (sc->sc_quirks & NO_TEST_UNIT_READY) { 3412184610Salfred DPRINTF(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY " 3413184610Salfred "to START_UNIT\n"); 3414184610Salfred bzero(sc->sc_transfer.cmd_data, cmd_len); 3415184610Salfred sc->sc_transfer.cmd_data[0] = START_STOP_UNIT; 3416184610Salfred sc->sc_transfer.cmd_data[4] = SSS_START; 3417184610Salfred return (1); 3418184610Salfred } 3419184610Salfred break; 3420184610Salfred 3421184610Salfred case INQUIRY: 3422184610Salfred /* 3423184610Salfred * some drives wedge when asked for full inquiry 3424184610Salfred * information. 3425184610Salfred */ 3426184610Salfred if (sc->sc_quirks & FORCE_SHORT_INQUIRY) { 3427184610Salfred bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len); 3428184610Salfred sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH; 3429184610Salfred return (1); 3430184610Salfred } 3431184610Salfred break; 3432184610Salfred } 3433184610Salfred 3434184610Salfred bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len); 3435184610Salfred return (1); 3436184610Salfred} 3437184610Salfred 3438184610Salfredstatic uint8_t 3439184610Salfredumass_rbc_transform(struct umass_softc *sc, uint8_t *cmd_ptr, uint8_t cmd_len) 3440184610Salfred{ 3441184610Salfred if ((cmd_len == 0) || 3442184610Salfred (cmd_len > sizeof(sc->sc_transfer.cmd_data))) { 3443184610Salfred DPRINTF(sc, UDMASS_SCSI, "Invalid command " 3444184610Salfred "length: %d bytes\n", cmd_len); 3445184610Salfred return (0); /* failure */ 3446184610Salfred } 3447184610Salfred switch (cmd_ptr[0]) { 3448184610Salfred /* these commands are defined in RBC: */ 3449184610Salfred case READ_10: 3450184610Salfred case READ_CAPACITY: 3451184610Salfred case START_STOP_UNIT: 3452184610Salfred case SYNCHRONIZE_CACHE: 3453184610Salfred case WRITE_10: 3454184610Salfred case 0x2f: /* VERIFY_10 is absent from 3455184610Salfred * scsi_all.h??? */ 3456184610Salfred case INQUIRY: 3457184610Salfred case MODE_SELECT_10: 3458184610Salfred case MODE_SENSE_10: 3459184610Salfred case TEST_UNIT_READY: 3460184610Salfred case WRITE_BUFFER: 3461184610Salfred /* 3462184610Salfred * The following commands are not listed in my copy of the 3463184610Salfred * RBC specs. CAM however seems to want those, and at least 3464184610Salfred * the Sony DSC device appears to support those as well 3465184610Salfred */ 3466184610Salfred case REQUEST_SENSE: 3467184610Salfred case PREVENT_ALLOW: 3468184610Salfred 3469184610Salfred bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len); 3470184610Salfred 3471184610Salfred if ((sc->sc_quirks & RBC_PAD_TO_12) && (cmd_len < 12)) { 3472184610Salfred bzero(sc->sc_transfer.cmd_data + cmd_len, 12 - cmd_len); 3473184610Salfred cmd_len = 12; 3474184610Salfred } 3475184610Salfred sc->sc_transfer.cmd_len = cmd_len; 3476184610Salfred return (1); /* sucess */ 3477184610Salfred 3478184610Salfred /* All other commands are not legal in RBC */ 3479184610Salfred default: 3480184610Salfred DPRINTF(sc, UDMASS_SCSI, "Unsupported RBC " 3481184610Salfred "command 0x%02x\n", cmd_ptr[0]); 3482184610Salfred return (0); /* failure */ 3483184610Salfred } 3484184610Salfred} 3485184610Salfred 3486184610Salfredstatic uint8_t 3487184610Salfredumass_ufi_transform(struct umass_softc *sc, uint8_t *cmd_ptr, 3488184610Salfred uint8_t cmd_len) 3489184610Salfred{ 3490184610Salfred if ((cmd_len == 0) || 3491184610Salfred (cmd_len > sizeof(sc->sc_transfer.cmd_data))) { 3492184610Salfred DPRINTF(sc, UDMASS_SCSI, "Invalid command " 3493184610Salfred "length: %d bytes\n", cmd_len); 3494184610Salfred return (0); /* failure */ 3495184610Salfred } 3496184610Salfred /* An UFI command is always 12 bytes in length */ 3497184610Salfred sc->sc_transfer.cmd_len = UFI_COMMAND_LENGTH; 3498184610Salfred 3499184610Salfred /* Zero the command data */ 3500184610Salfred bzero(sc->sc_transfer.cmd_data, UFI_COMMAND_LENGTH); 3501184610Salfred 3502184610Salfred switch (cmd_ptr[0]) { 3503184610Salfred /* 3504184610Salfred * Commands of which the format has been verified. They 3505184610Salfred * should work. Copy the command into the (zeroed out) 3506184610Salfred * destination buffer. 3507184610Salfred */ 3508184610Salfred case TEST_UNIT_READY: 3509184610Salfred if (sc->sc_quirks & NO_TEST_UNIT_READY) { 3510184610Salfred /* 3511184610Salfred * Some devices do not support this command. Start 3512184610Salfred * Stop Unit should give the same results 3513184610Salfred */ 3514184610Salfred DPRINTF(sc, UDMASS_UFI, "Converted TEST_UNIT_READY " 3515184610Salfred "to START_UNIT\n"); 3516184610Salfred 3517184610Salfred sc->sc_transfer.cmd_data[0] = START_STOP_UNIT; 3518184610Salfred sc->sc_transfer.cmd_data[4] = SSS_START; 3519184610Salfred return (1); 3520184610Salfred } 3521184610Salfred break; 3522184610Salfred 3523184610Salfred case REZERO_UNIT: 3524184610Salfred case REQUEST_SENSE: 3525184610Salfred case FORMAT_UNIT: 3526184610Salfred case INQUIRY: 3527184610Salfred case START_STOP_UNIT: 3528184610Salfred case SEND_DIAGNOSTIC: 3529184610Salfred case PREVENT_ALLOW: 3530184610Salfred case READ_CAPACITY: 3531184610Salfred case READ_10: 3532184610Salfred case WRITE_10: 3533184610Salfred case POSITION_TO_ELEMENT: /* SEEK_10 */ 3534184610Salfred case WRITE_AND_VERIFY: 3535184610Salfred case VERIFY: 3536184610Salfred case MODE_SELECT_10: 3537184610Salfred case MODE_SENSE_10: 3538184610Salfred case READ_12: 3539184610Salfred case WRITE_12: 3540184610Salfred case READ_FORMAT_CAPACITIES: 3541184610Salfred break; 3542184610Salfred 3543184610Salfred /* 3544184610Salfred * SYNCHRONIZE_CACHE isn't supported by UFI, nor should it be 3545184610Salfred * required for UFI devices, so it is appropriate to fake 3546184610Salfred * success. 3547184610Salfred */ 3548184610Salfred case SYNCHRONIZE_CACHE: 3549184610Salfred return (2); 3550184610Salfred 3551184610Salfred default: 3552184610Salfred DPRINTF(sc, UDMASS_SCSI, "Unsupported UFI " 3553184610Salfred "command 0x%02x\n", cmd_ptr[0]); 3554184610Salfred return (0); /* failure */ 3555184610Salfred } 3556184610Salfred 3557184610Salfred bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len); 3558184610Salfred return (1); /* success */ 3559184610Salfred} 3560184610Salfred 3561184610Salfred/* 3562184610Salfred * 8070i (ATAPI) specific functions 3563184610Salfred */ 3564184610Salfredstatic uint8_t 3565184610Salfredumass_atapi_transform(struct umass_softc *sc, uint8_t *cmd_ptr, 3566184610Salfred uint8_t cmd_len) 3567184610Salfred{ 3568184610Salfred if ((cmd_len == 0) || 3569184610Salfred (cmd_len > sizeof(sc->sc_transfer.cmd_data))) { 3570184610Salfred DPRINTF(sc, UDMASS_SCSI, "Invalid command " 3571184610Salfred "length: %d bytes\n", cmd_len); 3572184610Salfred return (0); /* failure */ 3573184610Salfred } 3574184610Salfred /* An ATAPI command is always 12 bytes in length. */ 3575184610Salfred sc->sc_transfer.cmd_len = ATAPI_COMMAND_LENGTH; 3576184610Salfred 3577184610Salfred /* Zero the command data */ 3578184610Salfred bzero(sc->sc_transfer.cmd_data, ATAPI_COMMAND_LENGTH); 3579184610Salfred 3580184610Salfred switch (cmd_ptr[0]) { 3581184610Salfred /* 3582184610Salfred * Commands of which the format has been verified. They 3583184610Salfred * should work. Copy the command into the destination 3584184610Salfred * buffer. 3585184610Salfred */ 3586184610Salfred case INQUIRY: 3587184610Salfred /* 3588184610Salfred * some drives wedge when asked for full inquiry 3589184610Salfred * information. 3590184610Salfred */ 3591184610Salfred if (sc->sc_quirks & FORCE_SHORT_INQUIRY) { 3592184610Salfred bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len); 3593184610Salfred 3594184610Salfred sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH; 3595184610Salfred return (1); 3596184610Salfred } 3597184610Salfred break; 3598184610Salfred 3599184610Salfred case TEST_UNIT_READY: 3600184610Salfred if (sc->sc_quirks & NO_TEST_UNIT_READY) { 3601184610Salfred DPRINTF(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY " 3602184610Salfred "to START_UNIT\n"); 3603184610Salfred sc->sc_transfer.cmd_data[0] = START_STOP_UNIT; 3604184610Salfred sc->sc_transfer.cmd_data[4] = SSS_START; 3605184610Salfred return (1); 3606184610Salfred } 3607184610Salfred break; 3608184610Salfred 3609184610Salfred case REZERO_UNIT: 3610184610Salfred case REQUEST_SENSE: 3611184610Salfred case START_STOP_UNIT: 3612184610Salfred case SEND_DIAGNOSTIC: 3613184610Salfred case PREVENT_ALLOW: 3614184610Salfred case READ_CAPACITY: 3615184610Salfred case READ_10: 3616184610Salfred case WRITE_10: 3617184610Salfred case POSITION_TO_ELEMENT: /* SEEK_10 */ 3618184610Salfred case SYNCHRONIZE_CACHE: 3619184610Salfred case MODE_SELECT_10: 3620184610Salfred case MODE_SENSE_10: 3621184610Salfred case READ_BUFFER: 3622184610Salfred case 0x42: /* READ_SUBCHANNEL */ 3623184610Salfred case 0x43: /* READ_TOC */ 3624184610Salfred case 0x44: /* READ_HEADER */ 3625184610Salfred case 0x47: /* PLAY_MSF (Play Minute/Second/Frame) */ 3626184610Salfred case 0x48: /* PLAY_TRACK */ 3627184610Salfred case 0x49: /* PLAY_TRACK_REL */ 3628184610Salfred case 0x4b: /* PAUSE */ 3629184610Salfred case 0x51: /* READ_DISK_INFO */ 3630184610Salfred case 0x52: /* READ_TRACK_INFO */ 3631184610Salfred case 0x54: /* SEND_OPC */ 3632184610Salfred case 0x59: /* READ_MASTER_CUE */ 3633184610Salfred case 0x5b: /* CLOSE_TR_SESSION */ 3634184610Salfred case 0x5c: /* READ_BUFFER_CAP */ 3635184610Salfred case 0x5d: /* SEND_CUE_SHEET */ 3636184610Salfred case 0xa1: /* BLANK */ 3637184610Salfred case 0xa5: /* PLAY_12 */ 3638184610Salfred case 0xa6: /* EXCHANGE_MEDIUM */ 3639184610Salfred case 0xad: /* READ_DVD_STRUCTURE */ 3640184610Salfred case 0xbb: /* SET_CD_SPEED */ 3641184610Salfred case 0xe5: /* READ_TRACK_INFO_PHILIPS */ 3642184610Salfred break;; 3643184610Salfred 3644184610Salfred case READ_12: 3645184610Salfred case WRITE_12: 3646184610Salfred default: 3647184610Salfred DPRINTF(sc, UDMASS_SCSI, "Unsupported ATAPI " 3648184610Salfred "command 0x%02x - trying anyway\n", 3649184610Salfred cmd_ptr[0]); 3650184610Salfred break;; 3651184610Salfred } 3652184610Salfred 3653184610Salfred bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len); 3654184610Salfred return (1); /* success */ 3655184610Salfred} 3656184610Salfred 3657184610Salfredstatic uint8_t 3658184610Salfredumass_no_transform(struct umass_softc *sc, uint8_t *cmd, 3659184610Salfred uint8_t cmdlen) 3660184610Salfred{ 3661184610Salfred return (0); /* failure */ 3662184610Salfred} 3663184610Salfred 3664184610Salfredstatic uint8_t 3665184610Salfredumass_std_transform(struct umass_softc *sc, union ccb *ccb, 3666184610Salfred uint8_t *cmd, uint8_t cmdlen) 3667184610Salfred{ 3668184610Salfred uint8_t retval; 3669184610Salfred 3670184610Salfred retval = (sc->sc_transform) (sc, cmd, cmdlen); 3671184610Salfred 3672184610Salfred if (retval == 2) { 3673184610Salfred ccb->ccb_h.status = CAM_REQ_CMP; 3674184610Salfred xpt_done(ccb); 3675184610Salfred return (0); 3676184610Salfred } else if (retval == 0) { 3677184610Salfred ccb->ccb_h.status = CAM_REQ_INVALID; 3678184610Salfred xpt_done(ccb); 3679184610Salfred return (0); 3680184610Salfred } 3681184610Salfred /* Command should be executed */ 3682184610Salfred return (1); 3683184610Salfred} 3684184610Salfred 3685184610Salfred#if USB_DEBUG 3686184610Salfredstatic void 3687184610Salfredumass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw) 3688184610Salfred{ 3689184610Salfred uint8_t *c = cbw->CBWCDB; 3690184610Salfred 3691184610Salfred uint32_t dlen = UGETDW(cbw->dCBWDataTransferLength); 3692184610Salfred uint32_t tag = UGETDW(cbw->dCBWTag); 3693184610Salfred 3694184610Salfred uint8_t clen = cbw->bCDBLength; 3695184610Salfred uint8_t flags = cbw->bCBWFlags; 3696184610Salfred uint8_t lun = cbw->bCBWLUN; 3697184610Salfred 3698184610Salfred DPRINTF(sc, UDMASS_BBB, "CBW %d: cmd = %db " 3699184610Salfred "(0x%02x%02x%02x%02x%02x%02x%s), " 3700184610Salfred "data = %db, lun = %d, dir = %s\n", 3701184610Salfred tag, clen, 3702184610Salfred c[0], c[1], c[2], c[3], c[4], c[5], (clen > 6 ? "..." : ""), 3703184610Salfred dlen, lun, (flags == CBWFLAGS_IN ? "in" : 3704184610Salfred (flags == CBWFLAGS_OUT ? "out" : "<invalid>"))); 3705184610Salfred} 3706184610Salfred 3707184610Salfredstatic void 3708184610Salfredumass_bbb_dump_csw(struct umass_softc *sc, umass_bbb_csw_t *csw) 3709184610Salfred{ 3710184610Salfred uint32_t sig = UGETDW(csw->dCSWSignature); 3711184610Salfred uint32_t tag = UGETDW(csw->dCSWTag); 3712184610Salfred uint32_t res = UGETDW(csw->dCSWDataResidue); 3713184610Salfred uint8_t status = csw->bCSWStatus; 3714184610Salfred 3715184610Salfred DPRINTF(sc, UDMASS_BBB, "CSW %d: sig = 0x%08x (%s), tag = 0x%08x, " 3716184610Salfred "res = %d, status = 0x%02x (%s)\n", 3717184610Salfred tag, sig, (sig == CSWSIGNATURE ? "valid" : "invalid"), 3718184610Salfred tag, res, 3719184610Salfred status, (status == CSWSTATUS_GOOD ? "good" : 3720184610Salfred (status == CSWSTATUS_FAILED ? "failed" : 3721184610Salfred (status == CSWSTATUS_PHASE ? "phase" : "<invalid>")))); 3722184610Salfred} 3723184610Salfred 3724184610Salfredstatic void 3725184610Salfredumass_cbi_dump_cmd(struct umass_softc *sc, void *cmd, uint8_t cmdlen) 3726184610Salfred{ 3727184610Salfred uint8_t *c = cmd; 3728184610Salfred uint8_t dir = sc->sc_transfer.dir; 3729184610Salfred 3730184610Salfred DPRINTF(sc, UDMASS_BBB, "cmd = %db " 3731184610Salfred "(0x%02x%02x%02x%02x%02x%02x%s), " 3732184610Salfred "data = %db, dir = %s\n", 3733184610Salfred cmdlen, 3734184610Salfred c[0], c[1], c[2], c[3], c[4], c[5], (cmdlen > 6 ? "..." : ""), 3735184610Salfred sc->sc_transfer.data_len, 3736184610Salfred (dir == DIR_IN ? "in" : 3737184610Salfred (dir == DIR_OUT ? "out" : 3738184610Salfred (dir == DIR_NONE ? "no data phase" : "<invalid>")))); 3739184610Salfred} 3740184610Salfred 3741184610Salfredstatic void 3742184610Salfredumass_dump_buffer(struct umass_softc *sc, uint8_t *buffer, uint32_t buflen, 3743184610Salfred uint32_t printlen) 3744184610Salfred{ 3745184610Salfred uint32_t i, j; 3746184610Salfred char s1[40]; 3747184610Salfred char s2[40]; 3748184610Salfred char s3[5]; 3749184610Salfred 3750184610Salfred s1[0] = '\0'; 3751184610Salfred s3[0] = '\0'; 3752184610Salfred 3753184610Salfred sprintf(s2, " buffer=%p, buflen=%d", buffer, buflen); 3754184610Salfred for (i = 0; (i < buflen) && (i < printlen); i++) { 3755184610Salfred j = i % 16; 3756184610Salfred if (j == 0 && i != 0) { 3757184610Salfred DPRINTF(sc, UDMASS_GEN, "0x %s%s\n", 3758184610Salfred s1, s2); 3759184610Salfred s2[0] = '\0'; 3760184610Salfred } 3761184610Salfred sprintf(&s1[j * 2], "%02x", buffer[i] & 0xff); 3762184610Salfred } 3763184610Salfred if (buflen > printlen) 3764184610Salfred sprintf(s3, " ..."); 3765184610Salfred DPRINTF(sc, UDMASS_GEN, "0x %s%s%s\n", 3766184610Salfred s1, s2, s3); 3767184610Salfred} 3768184610Salfred 3769184610Salfred#endif 3770