diff options
-rw-r--r-- | sys/dev/usb/FILES | 9 | ||||
-rw-r--r-- | sys/dev/usb/TODO | 2 | ||||
-rw-r--r-- | sys/dev/usb/files.usb | 6 | ||||
-rw-r--r-- | sys/dev/usb/umass.c | 2595 | ||||
-rw-r--r-- | sys/dev/usb/umass_quirks.c | 484 | ||||
-rw-r--r-- | sys/dev/usb/umass_quirks.h | 62 | ||||
-rw-r--r-- | sys/dev/usb/umass_scsi.c | 464 | ||||
-rw-r--r-- | sys/dev/usb/umass_scsi.h | 42 | ||||
-rw-r--r-- | sys/dev/usb/umassvar.h | 272 | ||||
-rw-r--r-- | sys/dev/usb/usb.h | 6 | ||||
-rw-r--r-- | sys/dev/usb/usb_port.h | 33 | ||||
-rw-r--r-- | sys/dev/usb/usscanner.c | 18 |
12 files changed, 1760 insertions, 2233 deletions
diff --git a/sys/dev/usb/FILES b/sys/dev/usb/FILES index a7138531869..4b3398b0ad6 100644 --- a/sys/dev/usb/FILES +++ b/sys/dev/usb/FILES @@ -39,7 +39,14 @@ ukbd.c USB keyboard driver ukbdmap.c wscons key mapping for ukbd ukbdvar.h API for ukbd.c ulpt.c USB printer class driver -umass.c USB mass storage driver (bulk only for now) +umass.c USB mass storage wire protocol driver +umass_isdata.c In-System Design ATA over bulk-only driver +umass_isdata.h and definitions for it +umass_quirks.c Table of strange umass devices +umass_quirks.h and definitions for it +umass_scsi.c umass command protocol driver +umass_scsi.h and definitions for it +umassvar.h definitions for umass.c umidi.c USB MIDI driver umidi_quirks.c Strange MIDI devices umidi_quirks.h and definitions for it diff --git a/sys/dev/usb/TODO b/sys/dev/usb/TODO index 28088a69fb3..2bc3497628a 100644 --- a/sys/dev/usb/TODO +++ b/sys/dev/usb/TODO @@ -85,6 +85,8 @@ Get rid of hcpriv. Keyspan serial driver +Clean up umass driver + Documentation: -------------- diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index e95b5efd221..c3bbcfa5697 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -1,4 +1,4 @@ -# $OpenBSD: files.usb,v 1.31 2002/11/30 19:29:29 nate Exp $ +# $OpenBSD: files.usb,v 1.32 2003/05/17 06:07:57 nate Exp $ # $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $ # # Config file and device description for machine-independent USB code. @@ -89,9 +89,11 @@ file dev/usb/ulpt.c ulpt needs-flag # Mass storage -device umass: scsi, atapi +device umass: scsi, atapi, ata attach umass at uhub file dev/usb/umass.c umass +file dev/usb/umass_quirks.c umass +file dev/usb/umass_scsi.c umass & (scsibus | atapiscsi) # Misc diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c index ae7dc941aa6..c01a43d1d89 100644 --- a/sys/dev/usb/umass.c +++ b/sys/dev/usb/umass.c @@ -1,5 +1,5 @@ -/* $OpenBSD: umass.c,v 1.23 2003/05/07 04:33:33 deraadt Exp $ */ -/* $NetBSD: umass.c,v 1.49 2001/01/21 18:56:38 augustss Exp $ */ +/* $OpenBSD: umass.c,v 1.24 2003/05/17 06:07:57 nate Exp $ */ +/* $NetBSD: umass.c,v 1.96 2003/04/26 12:46:59 dsainty Exp $ */ /*- * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>, * Nick Hibma <n_hibma@freebsd.org> @@ -30,7 +30,7 @@ */ /* - * Universal Serial Bus Mass Storage Class Bulk-Only Transport + * Universal Serial Bus Mass Storage Class specs: * http://www.usb.org/developers/data/devclass/usbmassover_11.pdf * http://www.usb.org/developers/data/devclass/usbmassbulk_10.pdf * http://www.usb.org/developers/data/devclass/usbmass-cbi10.pdf @@ -39,7 +39,7 @@ /* * Ported to NetBSD by Lennart Augustsson <augustss@netbsd.org>. - * Parts of the code written my Jason R. Thorpe <thorpej@shagadelic.org>. + * Parts of the code written by Jason R. Thorpe <thorpej@shagadelic.org>. */ /* @@ -51,13 +51,14 @@ * * Over these wire protocols it handles the following command protocols * - SCSI - * - UFI (floppy command set) - * - 8070 (ATA/ATAPI) + * - 8070 (ATA/ATAPI for rewritable removable media) + * - UFI (USB Floppy Interface) * - * UFI and 8070i are transformed versions of the SCSI command set. The - * sc->transform method is used to convert the commands into the appropriate - * format (if at all necessary). For example, UFI requires all commands to be - * 12 bytes in length amongst other things. + * 8070i is a transformed version of the SCSI command set. UFI is a transformed + * version of the 8070i command set. The sc->transform method is used to + * convert the commands into the appropriate format (if at all necessary). + * For example, ATAPI requires all commands to be 12 bytes in length amongst + * other things. * * The source code below is marked and can be split into a number of pieces * (in this order): @@ -93,15 +94,15 @@ * umass_cam_cb again to complete the CAM command. */ -/* XXX Should we split the driver into a number of files? umass.c, - * umass_scsi.c, umass_8070.c, umass_ufi.c, umass_bbb.c, umass_cbi.c or - * something similar? - */ - -#if !defined(__OpenBSD__) +#if defined(__NetBSD__) #include "atapibus.h" +#include "scsibus.h" +#elif defined(__OpenBSD__) +#include "atapiscsi.h" #endif +#include "wd.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -109,7 +110,6 @@ #if defined(__NetBSD__) || defined(__OpenBSD__) #include <sys/buf.h> #include <sys/device.h> -#include <sys/ioctl.h> #include <sys/malloc.h> #undef KASSERT #define KASSERT(cond, msg) @@ -124,396 +124,14 @@ #include <dev/usb/usbdi_util.h> #include <dev/usb/usbdevs.h> -#if defined(__FreeBSD__) -#include <cam/cam.h> -#include <cam/cam_ccb.h> -#include <cam/cam_sim.h> -#include <cam/cam_xpt_sim.h> -#include <cam/scsi/scsi_all.h> -#include <cam/scsi/scsi_da.h> - -#ifdef UMASS_DO_CAM_RESCAN -#include <sys/devicestat.h> -#include <cam/cam_periph.h> -#endif +#include <dev/usb/umassvar.h> +#include <dev/usb/umass_quirks.h> +#include <dev/usb/umass_scsi.h> -#elif defined(__NetBSD__) -#include <sys/scsiio.h> -#include <dev/scsipi/scsi_all.h> -#include <dev/scsipi/scsipi_all.h> -#include <dev/scsipi/scsiconf.h> - -#include <dev/scsipi/atapiconf.h> - -#include <dev/scsipi/scsipi_disk.h> -#include <dev/scsipi/scsi_disk.h> -#include <dev/scsipi/scsi_changer.h> - -#include <dev/ata/atavar.h> /* XXX */ - -#define SCSI_LINK_TARGET(sc) ((sc)->scsipi_scsi.target) -#define SCSI_LINK_LUN(sc) ((sc)->scsipi_scsi.lun) -#elif defined(__OpenBSD__) -#include <scsi/scsi_all.h> -#include <scsi/scsiconf.h> -#include <scsi/scsi_disk.h> -#include <machine/bus.h> - -#define SCSI_LINK_TARGET(sc) ((sc)->target) -#define SCSI_LINK_LUN(sc) ((sc)->lun) -#define scsipi_generic scsi_generic - -#endif - -#define SHORT_INQUIRY_LENGTH 36 /* XXX */ #ifdef UMASS_DEBUG -#define DIF(m, x) if (umassdebug & (m)) do { x ; } while (0) -#define DPRINTF(m, x) if (umassdebug & (m)) logprintf x -#define UDMASS_UPPER 0x00008000 /* upper layer */ -#define UDMASS_GEN 0x00010000 /* general */ -#define UDMASS_SCSI 0x00020000 /* scsi */ -#define UDMASS_UFI 0x00040000 /* ufi command set */ -#define UDMASS_8070 0x00080000 /* 8070i command set */ -#define UDMASS_USB 0x00100000 /* USB general */ -#define UDMASS_BBB 0x00200000 /* Bulk-Only transfers */ -#define UDMASS_CBI 0x00400000 /* CBI transfers */ -#define UDMASS_ALL 0xffff0000 /* all of the above */ - -#define UDMASS_XFER 0x40000000 /* all transfers */ -#define UDMASS_CMD 0x80000000 - int umassdebug = 0; -#else -#define DIF(m, x) /* nop */ -#define DPRINTF(m, x) /* nop */ -#endif - - -/* Generic definitions */ - -#define UFI_COMMAND_LENGTH 12 -#define ATAPI_COMMAND_LENGTH 12 - -/* Direction for umass_*_transfer */ -#define DIR_NONE 0 -#define DIR_IN 1 -#define DIR_OUT 2 - -/* The transfer speed determines the timeout value */ -#define UMASS_DEFAULT_TRANSFER_SPEED 150 /* in kb/s, conservative est. */ -#define UMASS_FLOPPY_TRANSFER_SPEED 20 -#define UMASS_ZIP100_TRANSFER_SPEED 650 - -#define UMASS_SPINUP_TIME 10000 /* ms */ - -#ifdef __FreeBSD__ -/* device name */ -#define DEVNAME "umass" -#define DEVNAME_SIM "umass-" - -#define UMASS_MAX_TRANSFER_SIZE 65536 - -/* CAM specific definitions */ - -/* The bus id, whatever that is */ -#define UMASS_SCSI_BUS 0 - -/* All USB drives are 'connected' to one SIM (SCSI controller). umass3 - * ends up being target 3 on that SIM. When a request for target 3 - * comes in we fetch the softc with devclass_get_softc(target_id). - * - * The SIM is the highest target number. This makes sure that umass0 corresponds - * to target 0 on the USB SCSI bus. - */ -#ifndef UMASS_DEBUG -#define UMASS_SCSIID_MAX 32 /* maximum number of drives expected */ -#else -/* while debugging avoid unnecessary clutter in the output at umass_cam_rescan - * (XPT_PATH_INQ) - */ -#define UMASS_SCSIID_MAX 3 /* maximum number of drives expected */ -#endif -#define UMASS_SCSIID_HOST UMASS_SCSIID_MAX -#endif - -#define MS_TO_TICKS(ms) ((ms) * hz / 1000) - - -/* Bulk-Only features */ - -#define UR_BBB_RESET 0xff /* Bulk-Only reset */ -#define UR_BBB_GET_MAX_LUN 0xfe - -/* Command Block Wrapper */ -typedef struct { - uDWord dCBWSignature; -# define CBWSIGNATURE 0x43425355 - uDWord dCBWTag; - uDWord dCBWDataTransferLength; - uByte bCBWFlags; -# define CBWFLAGS_OUT 0x00 -# define CBWFLAGS_IN 0x80 - uByte bCBWLUN; - uByte bCDBLength; -# define CBWCDBLENGTH 16 - uByte CBWCDB[CBWCDBLENGTH]; -} umass_bbb_cbw_t; -#define UMASS_BBB_CBW_SIZE 31 - -/* Command Status Wrapper */ -typedef struct { - uDWord dCSWSignature; -# define CSWSIGNATURE 0x53425355 - uDWord dCSWTag; - uDWord dCSWDataResidue; - uByte bCSWStatus; -# define CSWSTATUS_GOOD 0x0 -# define CSWSTATUS_FAILED 0x1 -# define CSWSTATUS_PHASE 0x2 -} umass_bbb_csw_t; -#define UMASS_BBB_CSW_SIZE 13 - -/* CBI features */ - -#define UR_CBI_ADSC 0x00 - -typedef unsigned char umass_cbi_cbl_t[16]; /* Command block */ - -typedef union { - struct { - unsigned char type; - #define IDB_TYPE_CCI 0x00 - unsigned char value; - #define IDB_VALUE_PASS 0x00 - #define IDB_VALUE_FAIL 0x01 - #define IDB_VALUE_PHASE 0x02 - #define IDB_VALUE_PERSISTENT 0x03 - #define IDB_VALUE_STATUS_MASK 0x03 - } common; - - struct { - unsigned char asc; - unsigned char ascq; - } ufi; -} umass_cbi_sbl_t; - - - -struct umass_softc; /* see below */ - -typedef void (*transfer_cb_f)(struct umass_softc *sc, void *priv, - int residue, int status); -#define STATUS_CMD_OK 0 /* everything ok */ -#define STATUS_CMD_UNKNOWN 1 /* will have to fetch sense */ -#define STATUS_CMD_FAILED 2 /* transfer was ok, command failed */ -#define STATUS_WIRE_FAILED 3 /* couldn't even get command across */ - -typedef void (*wire_reset_f)(struct umass_softc *sc, int status); -typedef void (*wire_transfer_f)(struct umass_softc *sc, int lun, - void *cmd, int cmdlen, void *data, int datalen, - int dir, transfer_cb_f cb, void *priv); -typedef void (*wire_state_f)(usbd_xfer_handle xfer, - usbd_private_handle priv, usbd_status err); - -#if defined(__FreeBSD__) -typedef int (*command_transform_f)(struct umass_softc *sc, - unsigned char *cmd, int cmdlen, - unsigned char **rcmd, int *rcmdlen); -#endif - - -/* the per device structure */ -struct umass_softc { - USBBASEDEVICE sc_dev; /* base device */ - usbd_device_handle sc_udev; /* device */ - - unsigned char drive; -# define DRIVE_GENERIC 0 /* use defaults for this one */ -# define ZIP_100 1 /* to be used for quirks */ -# define ZIP_250 2 -# define SHUTTLE_EUSB 3 -# define INSYSTEM_USBCABLE 4 - unsigned char quirks; - /* The drive does not support Test Unit Ready. Convert to - * Start Unit. - * Y-E Data - * ZIP 100 - */ -# define NO_TEST_UNIT_READY 0x01 - /* The drive does not reset the Unit Attention state after - * REQUEST SENSE has been sent. The INQUIRY command does not reset - * the UA either, and so CAM runs in circles trying to retrieve the - * initial INQUIRY data. - * Y-E Data - */ -# define RS_NO_CLEAR_UA 0x02 /* no REQUEST SENSE on INQUIRY*/ - /* The drive does not support START_STOP. - * Shuttle E-USB - */ -# define NO_START_STOP 0x04 - /* Don't ask for full inquiry data (255 bytes). - * Yano ATAPI-USB - */ -# define FORCE_SHORT_INQUIRY 0x08 - - unsigned int proto; -# define PROTO_UNKNOWN 0x0000 /* unknown protocol */ -# define PROTO_BBB 0x0001 /* USB wire protocol */ -# define PROTO_CBI 0x0002 -# define PROTO_CBI_I 0x0004 -# define PROTO_WIRE 0x00ff /* USB wire protocol mask */ -# define PROTO_SCSI 0x0100 /* command protocol */ -# define PROTO_ATAPI 0x0200 -# define PROTO_UFI 0x0400 -# define PROTO_RBC 0x0800 -# define PROTO_COMMAND 0xff00 /* command protocol mask */ - - u_char subclass; /* interface subclass */ - u_char protocol; /* interface protocol */ - - usbd_interface_handle iface; /* Mass Storage interface */ - int ifaceno; /* MS iface number */ - - u_int8_t bulkin; /* bulk-in Endpoint Address */ - u_int8_t bulkout; /* bulk-out Endpoint Address */ - u_int8_t intrin; /* intr-in Endp. (CBI) */ - usbd_pipe_handle bulkin_pipe; - usbd_pipe_handle bulkout_pipe; - usbd_pipe_handle intrin_pipe; - - /* Reset the device in a wire protocol specific way */ - wire_reset_f reset; - - /* The start of a wire transfer. It prepares the whole transfer (cmd, - * data, and status stage) and initiates it. It is up to the state - * machine (below) to handle the various stages and errors in these - */ - wire_transfer_f transfer; - - /* The state machine, handling the various states during a transfer */ - wire_state_f state; - -#if defined(__FreeBSD__) - /* The command transform function is used to conver the SCSI commands - * into their derivatives, like UFI, ATAPI, and friends. - */ - command_transform_f transform; /* command transform */ -#endif - - /* Bulk specific variables for transfers in progress */ - umass_bbb_cbw_t cbw; /* command block wrapper */ - umass_bbb_csw_t csw; /* command status wrapper*/ - /* CBI specific variables for transfers in progress */ - umass_cbi_cbl_t cbl; /* command block */ - umass_cbi_sbl_t sbl; /* status block */ - - /* generic variables for transfers in progress */ - /* ctrl transfer requests */ - usb_device_request_t request; - - /* xfer handles - * Most of our operations are initiated from interrupt context, so - * we need to avoid using the one that is in use. We want to avoid - * allocating them in the interrupt context as well. - */ - /* indices into array below */ -# define XFER_BBB_CBW 0 /* Bulk-Only */ -# define XFER_BBB_DATA 1 -# define XFER_BBB_DCLEAR 2 -# define XFER_BBB_CSW1 3 -# define XFER_BBB_CSW2 4 -# define XFER_BBB_SCLEAR 5 -# define XFER_BBB_RESET1 6 -# define XFER_BBB_RESET2 7 -# define XFER_BBB_RESET3 8 - -# define XFER_CBI_CB 0 /* CBI */ -# define XFER_CBI_DATA 1 -# define XFER_CBI_STATUS 2 -# define XFER_CBI_DCLEAR 3 -# define XFER_CBI_SCLEAR 4 -# define XFER_CBI_RESET1 5 -# define XFER_CBI_RESET2 6 -# define XFER_CBI_RESET3 7 - -# define XFER_NR 9 /* maximum number */ - - usbd_xfer_handle transfer_xfer[XFER_NR]; /* for ctrl xfers */ - - void *data_buffer; - - int transfer_dir; /* data direction */ - void *transfer_data; /* data buffer */ - int transfer_datalen; /* (maximum) length */ - int transfer_actlen; /* actual length */ - transfer_cb_f transfer_cb; /* callback */ - void *transfer_priv; /* for callback */ - int transfer_status; - - int transfer_state; -# define TSTATE_IDLE 0 -# define TSTATE_BBB_COMMAND 1 /* CBW transfer */ -# define TSTATE_BBB_DATA 2 /* Data transfer */ -# define TSTATE_BBB_DCLEAR 3 /* clear endpt stall */ -# define TSTATE_BBB_STATUS1 4 /* clear endpt stall */ -# define TSTATE_BBB_SCLEAR 5 /* clear endpt stall */ -# define TSTATE_BBB_STATUS2 6 /* CSW transfer */ -# define TSTATE_BBB_RESET1 7 /* reset command */ -# define TSTATE_BBB_RESET2 8 /* in clear stall */ -# define TSTATE_BBB_RESET3 9 /* out clear stall */ -# define TSTATE_CBI_COMMAND 10 /* command transfer */ -# define TSTATE_CBI_DATA 11 /* data transfer */ -# define TSTATE_CBI_STATUS 12 /* status transfer */ -# define TSTATE_CBI_DCLEAR 13 /* clear ep stall */ -# define TSTATE_CBI_SCLEAR 14 /* clear ep stall */ -# define TSTATE_CBI_RESET1 15 /* reset command */ -# define TSTATE_CBI_RESET2 16 /* in clear stall */ -# define TSTATE_CBI_RESET3 17 /* out clear stall */ -# define TSTATE_STATES 18 /* # of states above */ - - - int transfer_speed; /* in kb/s */ - int timeout; /* in msecs */ - - u_int8_t maxlun; /* max lun supported */ - -#ifdef UMASS_DEBUG - struct timeval tv; -#endif - -#if defined(__FreeBSD__) - /* SCSI/CAM specific variables */ - struct scsi_sense cam_scsi_sense; - -#elif defined(__NetBSD__) || defined(__OpenBSD__) - union { - struct scsipi_link sc_link; -#if defined(__NetBSD__) - struct { - struct ata_atapi_attach sc_aa; - struct ata_drive_datas sc_aa_drive; - } aa; -#endif - } u; -#if defined(__NetBSD__) - struct atapi_adapter sc_atapi_adapter; -#define sc_adapter sc_atapi_adapter._generic -#else - struct scsi_adapter sc_atapi_adapter; -#define sc_adapter sc_atapi_adapter -#endif - int sc_xfer_flags; - usbd_status sc_sync_status; - struct scsipi_sense sc_sense_cmd; - - device_ptr_t sc_child; /* child device, for detach */ - char sc_dying; - -#endif -}; -#ifdef UMASS_DEBUG char *states[TSTATE_STATES+1] = { /* should be kept in sync with the list at transfer_state */ "Idle", @@ -538,17 +156,9 @@ char *states[TSTATE_STATES+1] = { }; #endif -struct cam_sim *umass_sim; /* SCSI Interface Module */ -struct cam_path *umass_path; /* and its path */ - - /* USB device probe/attach/detach functions */ USB_DECLARE_DRIVER(umass); Static void umass_disco(struct umass_softc *sc); -Static int umass_match_proto(struct umass_softc *sc, - usbd_interface_handle iface, - usbd_device_handle dev); -Static void umass_init_shuttle(struct umass_softc *sc); /* generic transfer functions */ Static usbd_status umass_setup_transfer(struct umass_softc *sc, @@ -556,113 +166,42 @@ Static usbd_status umass_setup_transfer(struct umass_softc *sc, void *buffer, int buflen, int flags, usbd_xfer_handle xfer); Static usbd_status umass_setup_ctrl_transfer(struct umass_softc *sc, - usbd_device_handle dev, usb_device_request_t *req, void *buffer, int buflen, int flags, usbd_xfer_handle xfer); -Static void umass_clear_endpoint_stall(struct umass_softc *sc, - u_int8_t endpt, usbd_pipe_handle pipe, - int state, usbd_xfer_handle xfer); +Static void umass_clear_endpoint_stall(struct umass_softc *sc, int endpt, + usbd_xfer_handle xfer); #if 0 -Static void umass_reset(struct umass_softc *sc, - transfer_cb_f cb, void *priv); +Static void umass_reset(struct umass_softc *sc, transfer_cb_f cb, void *priv); #endif /* Bulk-Only related functions */ -Static void umass_bbb_reset(struct umass_softc *sc, int status); -Static void umass_bbb_transfer(struct umass_softc *sc, int lun, - void *cmd, int cmdlen, - void *data, int datalen, int dir, - transfer_cb_f cb, void *priv); -Static void umass_bbb_state(usbd_xfer_handle xfer, - usbd_private_handle priv, - usbd_status err); -usbd_status umass_bbb_get_max_lun(struct umass_softc *sc, - u_int8_t *maxlun); +Static void umass_bbb_transfer(struct umass_softc *, int, void *, int, void *, + int, int, u_int, umass_callback, void *); +Static void umass_bbb_reset(struct umass_softc *, int); +Static void umass_bbb_state(usbd_xfer_handle, usbd_private_handle, usbd_status); +usbd_status umass_bbb_get_max_lun(struct umass_softc *, u_int8_t *); /* CBI related functions */ -Static int umass_cbi_adsc(struct umass_softc *sc, char *buffer,int buflen, - usbd_xfer_handle xfer); -Static void umass_cbi_reset(struct umass_softc *sc, int status); -Static void umass_cbi_transfer(struct umass_softc *sc, int lun, - void *cmd, int cmdlen, - void *data, int datalen, int dir, - transfer_cb_f cb, void *priv); -Static void umass_cbi_state(usbd_xfer_handle xfer, - usbd_private_handle priv, usbd_status err); - -#if defined(__FreeBSD__) -/* CAM related functions */ -Static void umass_cam_action(struct cam_sim *sim, union ccb *ccb); -Static void umass_cam_poll(struct cam_sim *sim); - -Static void umass_cam_cb(struct umass_softc *sc, void *priv, - int residue, int status); -Static void umass_cam_sense_cb(struct umass_softc *sc, void *priv, - int residue, int status); - -#ifdef UMASS_DO_CAM_RESCAN -Static void umass_cam_rescan(struct umass_softc *sc); -#endif - -Static int umass_cam_attach_sim(void); -Static int umass_cam_attach(struct umass_softc *sc); -Static int umass_cam_detach_sim(void); -Static int umass_cam_detach(struct umass_softc *sc); - -#elif defined(__NetBSD__) || defined(__OpenBSD__) - -#define UMASS_SCSIID_HOST 0x00 -#define UMASS_SCSIID_DEVICE 0x01 - -#define UMASS_ATAPI_DRIVE 0 +Static void umass_cbi_transfer(struct umass_softc *, int, void *, int, void *, + int, int, u_int, umass_callback, void *); +Static void umass_cbi_reset(struct umass_softc *, int); +Static void umass_cbi_state(usbd_xfer_handle, usbd_private_handle, usbd_status); -#define UMASS_MAX_TRANSFER_SIZE MAXBSIZE +Static int umass_cbi_adsc(struct umass_softc *, char *, int, usbd_xfer_handle); -struct scsipi_device umass_dev = -{ - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ +const struct umass_wire_methods umass_bbb_methods = { + umass_bbb_transfer, + umass_bbb_reset, + umass_bbb_state }; -Static int umass_scsipi_cmd(struct scsipi_xfer *xs); -Static void umass_scsipi_minphys(struct buf *bp); -Static int umass_scsipi_ioctl(struct scsipi_link *, u_long, - caddr_t, int, struct proc *); -Static void umass_scsipi_cb(struct umass_softc *sc, void *priv, - int residue, int status); -Static void umass_scsipi_sense_cb(struct umass_softc *sc, void *priv, - int residue, int status); - -Static int scsipiprint(void *aux, const char *pnp); -Static int umass_ufi_transform(struct umass_softc *sc, - struct scsipi_generic *cmd, int cmdlen, - struct scsipi_generic *rcmd, int *rcmdlen); - -#if NATAPIBUS > 0 -Static void umass_atapi_probedev(struct atapibus_softc *, int); -#endif -#endif - -#if defined(__FreeBSD__) -/* SCSI specific functions */ -Static int umass_scsi_transform(struct umass_softc *sc, - unsigned char *cmd, int cmdlen, - unsigned char **rcmd, int *rcmdlen); - -/* UFI specific functions */ -Static int umass_ufi_transform(struct umass_softc *sc, - unsigned char *cmd, int cmdlen, - unsigned char **rcmd, int *rcmdlen); - -/* 8070 specific functions */ -Static int umass_8070_transform(struct umass_softc *sc, - unsigned char *cmd, int cmdlen, - unsigned char **rcmd, int *rcmdlen); -#endif +const struct umass_wire_methods umass_cbi_methods = { + umass_cbi_transfer, + umass_cbi_reset, + umass_cbi_state +}; #ifdef UMASS_DEBUG /* General debugging functions */ @@ -675,298 +214,180 @@ Static void umass_dump_buffer(struct umass_softc *sc, u_int8_t *buffer, #endif -void usbd_clear_endpoint_toggle(usbd_pipe_handle pipe); /* XXXXX */ - /* * USB device probe/attach/detach */ -/* - * Match the device we are seeing with the devices supported. Fill in the - * proto and drive fields in the softc accordingly. - * This function is called from both probe and attach. - */ - -Static int -umass_match_proto(sc, iface, dev) - struct umass_softc *sc; - usbd_interface_handle iface; - usbd_device_handle dev; +USB_MATCH(umass) { - usb_device_descriptor_t *dd; + USB_MATCH_START(umass, uaa); + const struct umass_quirk *quirk; usb_interface_descriptor_t *id; - u_int vendor, product; - - /* - * Fill in sc->drive and sc->proto and return a match - * value if both are determined and 0 otherwise. - */ - - sc->drive = DRIVE_GENERIC; - sc->proto = PROTO_UNKNOWN; - sc->transfer_speed = UMASS_DEFAULT_TRANSFER_SPEED; - - sc->sc_udev = dev; - dd = usbd_get_device_descriptor(dev); - vendor = UGETW(dd->idVendor); - product = UGETW(dd->idProduct); - - if (vendor == USB_VENDOR_SHUTTLE && - product == USB_PRODUCT_SHUTTLE_EUSB) { - sc->drive = SHUTTLE_EUSB; -#if CBI_I - sc->proto = PROTO_ATAPI | PROTO_CBI_I; -#else - sc->proto = PROTO_ATAPI | PROTO_CBI; -#endif - sc->subclass = UISUBCLASS_SFF8020I; - sc->protocol = UIPROTO_MASS_CBI; - sc->quirks |= NO_TEST_UNIT_READY | NO_START_STOP; - return (UMATCH_VENDOR_PRODUCT); - } - - if (vendor == USB_VENDOR_TRUMPION && - product == USB_PRODUCT_TRUMPION_XXX1100) { - sc->proto = PROTO_ATAPI | PROTO_CBI; - return (UMATCH_VENDOR_PRODUCT); - } - - if (vendor == USB_VENDOR_YANO && - product == USB_PRODUCT_YANO_U640MO) { - sc->proto = PROTO_ATAPI | PROTO_CBI_I; - sc->quirks |= FORCE_SHORT_INQUIRY; - return (UMATCH_VENDOR_PRODUCT); - } - - if (vendor == USB_VENDOR_SONY && - product == USB_PRODUCT_SONY_MSC) { - printf ("XXX Sony MSC\n"); - sc->quirks |= FORCE_SHORT_INQUIRY; - } - - if (vendor == USB_VENDOR_YEDATA && - product == USB_PRODUCT_YEDATA_FLASHBUSTERU) { - - /* Revisions < 1.28 do not handle the interrupt endpoint - * very well. - */ - if (UGETW(dd->bcdDevice) < 0x128) - sc->proto = PROTO_UFI | PROTO_CBI; - else -#if CBI_I - sc->proto = PROTO_UFI | PROTO_CBI_I; -#else - sc->proto = PROTO_UFI | PROTO_CBI; -#endif - /* - * Revisions < 1.28 do not have the TEST UNIT READY command - * Revisions == 1.28 have a broken TEST UNIT READY - */ - if (UGETW(dd->bcdDevice) <= 0x128) - sc->quirks |= NO_TEST_UNIT_READY; - - sc->subclass = UISUBCLASS_UFI; - sc->protocol = UIPROTO_MASS_CBI; - sc->quirks |= RS_NO_CLEAR_UA; - sc->transfer_speed = UMASS_FLOPPY_TRANSFER_SPEED; - return (UMATCH_VENDOR_PRODUCT_REV); - } + if (uaa->iface == NULL) + return (UMATCH_NONE); - if (vendor == USB_VENDOR_INSYSTEM && - product == USB_PRODUCT_INSYSTEM_USBCABLE) { - sc->drive = INSYSTEM_USBCABLE; - sc->proto = PROTO_ATAPI | PROTO_CBI; - sc->quirks |= NO_TEST_UNIT_READY | NO_START_STOP; - return (UMATCH_VENDOR_PRODUCT); - } + quirk = umass_lookup(uaa->vendor, uaa->product); + if (quirk != NULL) + return (quirk->uq_match); - id = usbd_get_interface_descriptor(iface); + id = usbd_get_interface_descriptor(uaa->iface); if (id == NULL || id->bInterfaceClass != UICLASS_MASS) return (UMATCH_NONE); - if (vendor == USB_VENDOR_SONY && id->bInterfaceSubClass == 0xff) { - /* - * Sony DSC devices set the sub class to 0xff - * instead of 1 (RBC). Fix that here. - */ - id->bInterfaceSubClass = UISUBCLASS_RBC; - /* They also should be able to do higher speed. */ - sc->transfer_speed = 500; - } - - if (vendor == USB_VENDOR_FUJIPHOTO && - product == USB_PRODUCT_FUJIPHOTO_MASS0100) - sc->quirks |= NO_TEST_UNIT_READY | NO_START_STOP; - - sc->subclass = id->bInterfaceSubClass; - sc->protocol = id->bInterfaceProtocol; - - switch (sc->subclass) { - case UISUBCLASS_SCSI: - sc->proto |= PROTO_SCSI; - break; - case UISUBCLASS_UFI: - sc->transfer_speed = UMASS_FLOPPY_TRANSFER_SPEED; - sc->proto |= PROTO_UFI; - break; + switch (id->bInterfaceSubClass) { + case UISUBCLASS_RBC: case UISUBCLASS_SFF8020I: - case UISUBCLASS_SFF8070I: case UISUBCLASS_QIC157: - sc->proto |= PROTO_ATAPI; - break; - case UISUBCLASS_RBC: - sc->proto |= PROTO_RBC; + case UISUBCLASS_UFI: + case UISUBCLASS_SFF8070I: + case UISUBCLASS_SCSI: break; default: - /* Assume that unsupported devices are ATAPI */ - DPRINTF(UDMASS_GEN, ("%s: Unsupported command protocol %d\n", - USBDEVNAME(sc->sc_dev), id->bInterfaceSubClass)); - - sc->proto |= PROTO_ATAPI; - break; + return (UMATCH_IFACECLASS); } - switch (sc->protocol) { - case UIPROTO_MASS_CBI: - sc->proto |= PROTO_CBI; - break; + switch (id->bInterfaceProtocol) { case UIPROTO_MASS_CBI_I: -#if CBI_I - sc->proto |= PROTO_CBI_I; -#else - sc->proto |= PROTO_CBI; -#endif - break; + case UIPROTO_MASS_CBI: + case UIPROTO_MASS_BBB_OLD: case UIPROTO_MASS_BBB: - sc->proto |= PROTO_BBB; - break; - case UIPROTO_MASS_BBB_P: - sc->drive = ZIP_100; - sc->proto |= PROTO_BBB; - sc->transfer_speed = UMASS_ZIP100_TRANSFER_SPEED; - sc->quirks |= NO_TEST_UNIT_READY; break; default: - DPRINTF(UDMASS_GEN, ("%s: Unsupported wire protocol %d\n", - USBDEVNAME(sc->sc_dev), id->bInterfaceProtocol)); - return (UMATCH_NONE); + return (UMATCH_IFACECLASS_IFACESUBCLASS); } - return (UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO); -} - -USB_MATCH(umass) -{ - USB_MATCH_START(umass, uaa); -#if defined(__FreeBSD__) - struct umass_softc *sc = device_get_softc(self); -#elif defined(__NetBSD__) || defined(__OpenBSD__) - struct umass_softc scs, *sc = &scs; - memset(sc, 0, sizeof *sc); - strlcpy(sc->sc_dev.dv_xname, "umass", sizeof sc->sc_dev.dv_xname); -#endif - - if (uaa->iface == NULL) - return(UMATCH_NONE); - - return (umass_match_proto(sc, uaa->iface, uaa->device)); + return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); } -void umass_delayed_attach(struct umass_softc *sc); - USB_ATTACH(umass) { USB_ATTACH_START(umass, sc, uaa); + const struct umass_quirk *quirk; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; - const char *sSubclass, *sProto; + const char *sWire, *sCommand; char devinfo[1024]; - int i, bno; - int err; - - /* - * the softc struct is bzero-ed in device_set_driver. We can safely - * call umass_detach without specifically initialising the struct. - */ + usbd_status err; + int i, bno, error; usbd_devinfo(uaa->device, 0, devinfo, sizeof devinfo); USB_ATTACH_SETUP; - sc->iface = uaa->iface; - sc->ifaceno = uaa->ifaceno; + sc->sc_udev = uaa->device; + sc->sc_iface = uaa->iface; + sc->sc_ifaceno = uaa->ifaceno; + + quirk = umass_lookup(uaa->vendor, uaa->product); + if (quirk != NULL) { + sc->sc_wire = quirk->uq_wire; + sc->sc_cmd = quirk->uq_cmd; + sc->sc_quirks = quirk->uq_flags; + sc->sc_busquirks = quirk->uq_busquirks; - /* initialise the proto and drive values in the umass_softc (again) */ - if (umass_match_proto(sc, sc->iface, uaa->device) == 0) { - printf("%s: match failed\n", USBDEVNAME(sc->sc_dev)); + if (quirk->uq_fixup != NULL) + (*quirk->uq_fixup)(sc); + } else { + sc->sc_wire = UMASS_WPROTO_UNSPEC; + sc->sc_cmd = UMASS_CPROTO_UNSPEC; + sc->sc_quirks = 0; + sc->sc_busquirks = 0; + } + + id = usbd_get_interface_descriptor(sc->sc_iface); + if (id == NULL) USB_ATTACH_ERROR_RETURN; + + if (sc->sc_wire == UMASS_WPROTO_UNSPEC) { + switch (id->bInterfaceProtocol) { + case UIPROTO_MASS_CBI: + sc->sc_wire = UMASS_WPROTO_CBI; + break; + case UIPROTO_MASS_CBI_I: + sc->sc_wire = UMASS_WPROTO_CBI_I; + break; + case UIPROTO_MASS_BBB: + case UIPROTO_MASS_BBB_OLD: + sc->sc_wire = UMASS_WPROTO_BBB; + break; + default: + DPRINTF(UDMASS_GEN, + ("%s: Unsupported wire protocol %u\n", + USBDEVNAME(sc->sc_dev), + id->bInterfaceProtocol)); + USB_ATTACH_ERROR_RETURN; + } } - /* - * The timeout is based on the maximum expected transfer size - * divided by the expected transfer speed. - * We multiply by 4 to make sure a busy system doesn't make things - * fail. - */ - sc->timeout = 4 * UMASS_MAX_TRANSFER_SIZE / sc->transfer_speed; - sc->timeout += UMASS_SPINUP_TIME; /* allow for spinning up */ + /* XXX - Now unsupported CBI with CCI */ + if (sc->sc_wire == UMASS_WPROTO_CBI_I) + sc->sc_wire = UMASS_WPROTO_CBI; + + if (sc->sc_cmd == UMASS_CPROTO_UNSPEC) { + switch (id->bInterfaceSubClass) { + case UISUBCLASS_SCSI: + sc->sc_cmd = UMASS_CPROTO_SCSI; + break; + case UISUBCLASS_UFI: + sc->sc_cmd = UMASS_CPROTO_UFI; + break; + case UISUBCLASS_SFF8020I: + case UISUBCLASS_SFF8070I: + case UISUBCLASS_QIC157: + sc->sc_cmd = UMASS_CPROTO_ATAPI; + break; + case UISUBCLASS_RBC: + sc->sc_cmd = UMASS_CPROTO_RBC; + break; + default: + DPRINTF(UDMASS_GEN, + ("%s: Unsupported command protocol %u\n", + USBDEVNAME(sc->sc_dev), + id->bInterfaceSubClass)); + USB_ATTACH_ERROR_RETURN; + } + } - id = usbd_get_interface_descriptor(sc->iface); printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); - switch (sc->subclass) { - case UISUBCLASS_RBC: - sSubclass = "RBC"; - break; - case UISUBCLASS_SCSI: - sSubclass = "SCSI"; - break; - case UISUBCLASS_UFI: - sSubclass = "UFI"; + switch (sc->sc_wire) { + case UMASS_WPROTO_CBI: + sWire = "CBI"; break; - case UISUBCLASS_SFF8020I: - sSubclass = "SFF8020i"; + case UMASS_WPROTO_CBI_I: + sWire = "CBI with CCI"; break; - case UISUBCLASS_SFF8070I: - sSubclass = "SFF8070i"; - break; - case UISUBCLASS_QIC157: - sSubclass = "QIC157"; + case UMASS_WPROTO_BBB: + sWire = "Bulk-Only"; break; default: - sSubclass = "unknown"; + sWire = "unknown"; break; } - switch (sc->protocol) { - case UIPROTO_MASS_CBI: - sProto = "CBI"; + + switch (sc->sc_cmd) { + case UMASS_CPROTO_RBC: + sCommand = "RBC"; break; - case UIPROTO_MASS_CBI_I: - sProto = "CBI-I"; + case UMASS_CPROTO_SCSI: + sCommand = "SCSI"; break; - case UIPROTO_MASS_BBB: - sProto = "BBB"; + case UMASS_CPROTO_UFI: + sCommand = "UFI"; break; - case UIPROTO_MASS_BBB_P: - sProto = "BBB-P"; + case UMASS_CPROTO_ATAPI: + sCommand = "ATAPI"; + break; + case UMASS_CPROTO_ISD_ATA: + sCommand = "ISD-ATA"; break; default: - sProto = "unknown"; + sCommand = "unknown"; break; } - printf("%s: using %s over %s\n", USBDEVNAME(sc->sc_dev), sSubclass, - sProto); - if (sc->drive == INSYSTEM_USBCABLE) { - err = usbd_set_interface(0, 1); - if (err) { - DPRINTF(UDMASS_USB, ("%s: could not switch to " - "Alt Interface %d\n", - USBDEVNAME(sc->sc_dev), 1)); - umass_disco(sc); - USB_ATTACH_ERROR_RETURN; - } - } + printf("%s: using %s over %s\n", USBDEVNAME(sc->sc_dev), sCommand, + sWire); /* * In addition to the Control endpoint the following endpoints @@ -980,22 +401,22 @@ USB_ATTACH(umass) * from the device descriptors of the current interface. */ for (i = 0 ; i < id->bNumEndpoints ; i++) { - ed = usbd_interface2endpoint_descriptor(sc->iface, i); - if (!ed) { + ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); + if (ed == NULL) { printf("%s: could not read endpoint descriptor\n", USBDEVNAME(sc->sc_dev)); USB_ATTACH_ERROR_RETURN; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { - sc->bulkin = ed->bEndpointAddress; + sc->sc_epaddr[UMASS_BULKIN] = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { - sc->bulkout = ed->bEndpointAddress; - } else if (sc->proto & PROTO_CBI_I + sc->sc_epaddr[UMASS_BULKOUT] = ed->bEndpointAddress; + } else if (sc->sc_wire == UMASS_WPROTO_CBI_I && UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { - sc->intrin = ed->bEndpointAddress; + sc->sc_epaddr[UMASS_INTRIN] = ed->bEndpointAddress; #ifdef UMASS_DEBUG if (UGETW(ed->wMaxPacketSize) > 2) { DPRINTF(UDMASS_CBI, ("%s: intr size is %d\n", @@ -1007,19 +428,21 @@ USB_ATTACH(umass) } /* check whether we found all the endpoints we need */ - if (!sc->bulkin || !sc->bulkout - || (sc->proto & PROTO_CBI_I && !sc->intrin) ) { - DPRINTF(UDMASS_USB, ("%s: endpoint not found %d/%d/%d\n", - USBDEVNAME(sc->sc_dev), - sc->bulkin, sc->bulkout, sc->intrin)); - umass_disco(sc); + if (!sc->sc_epaddr[UMASS_BULKIN] || !sc->sc_epaddr[UMASS_BULKOUT] || + (sc->sc_wire == UMASS_WPROTO_CBI_I && + !sc->sc_epaddr[UMASS_INTRIN])) { + DPRINTF(UDMASS_USB, ("%s: endpoint not found %u/%u/%u\n", + USBDEVNAME(sc->sc_dev), sc->sc_epaddr[UMASS_BULKIN], + sc->sc_epaddr[UMASS_BULKOUT], + sc->sc_epaddr[UMASS_INTRIN])); USB_ATTACH_ERROR_RETURN; } /* * Get the maximum LUN supported by the device. */ - if ((sc->proto & PROTO_WIRE) == PROTO_BBB) { + if (sc->sc_wire == UMASS_WPROTO_BBB && + !(sc->sc_quirks & UMASS_QUIRK_NO_MAX_LUN)) { err = umass_bbb_get_max_lun(sc, &sc->maxlun); if (err) { printf("%s: unable to get Max Lun: %s\n", @@ -1031,19 +454,20 @@ USB_ATTACH(umass) } /* Open the bulk-in and -out pipe */ - err = usbd_open_pipe(sc->iface, sc->bulkout, - USBD_EXCLUSIVE_USE, &sc->bulkout_pipe); + err = usbd_open_pipe(sc->sc_iface, sc->sc_epaddr[UMASS_BULKOUT], + USBD_EXCLUSIVE_USE, + &sc->sc_pipe[UMASS_BULKOUT]); if (err) { - DPRINTF(UDMASS_USB, ("%s: cannot open %d-out pipe (bulk)\n", - USBDEVNAME(sc->sc_dev), sc->bulkout)); + DPRINTF(UDMASS_USB, ("%s: cannot open %u-out pipe (bulk)\n", + USBDEVNAME(sc->sc_dev), sc->sc_epaddr[UMASS_BULKOUT])); umass_disco(sc); USB_ATTACH_ERROR_RETURN; } - err = usbd_open_pipe(sc->iface, sc->bulkin, - USBD_EXCLUSIVE_USE, &sc->bulkin_pipe); + err = usbd_open_pipe(sc->sc_iface, sc->sc_epaddr[UMASS_BULKIN], + USBD_EXCLUSIVE_USE, &sc->sc_pipe[UMASS_BULKIN]); if (err) { - DPRINTF(UDMASS_USB, ("%s: could not open %d-in pipe (bulk)\n", - USBDEVNAME(sc->sc_dev), sc->bulkin)); + DPRINTF(UDMASS_USB, ("%s: could not open %u-in pipe (bulk)\n", + USBDEVNAME(sc->sc_dev), sc->sc_epaddr[UMASS_BULKIN])); umass_disco(sc); USB_ATTACH_ERROR_RETURN; } @@ -1059,12 +483,13 @@ USB_ATTACH(umass) * code for handling the data on that endpoint simpler. No data * arriving concurrently. */ - if (sc->proto & PROTO_CBI_I) { - err = usbd_open_pipe(sc->iface, sc->intrin, - USBD_EXCLUSIVE_USE, &sc->intrin_pipe); + if (sc->sc_wire == UMASS_WPROTO_CBI_I) { + err = usbd_open_pipe(sc->sc_iface, sc->sc_epaddr[UMASS_INTRIN], + USBD_EXCLUSIVE_USE, &sc->sc_pipe[UMASS_INTRIN]); if (err) { - DPRINTF(UDMASS_USB, ("%s: couldn't open %d-in (intr)\n", - USBDEVNAME(sc->sc_dev), sc->intrin)); + DPRINTF(UDMASS_USB, ("%s: couldn't open %u-in (intr)\n", + USBDEVNAME(sc->sc_dev), + sc->sc_epaddr[UMASS_INTRIN])); umass_disco(sc); USB_ATTACH_ERROR_RETURN; } @@ -1076,7 +501,7 @@ USB_ATTACH(umass) /* request a sufficient number of xfer handles */ for (i = 0; i < XFER_NR; i++) { sc->transfer_xfer[i] = usbd_alloc_xfer(uaa->device); - if (sc->transfer_xfer[i] == 0) { + if (sc->transfer_xfer[i] == NULL) { DPRINTF(UDMASS_USB, ("%s: Out of memory\n", USBDEVNAME(sc->sc_dev))); umass_disco(sc); @@ -1084,14 +509,14 @@ USB_ATTACH(umass) } } /* Allocate buffer for data transfer (it's huge). */ - switch (sc->proto & PROTO_WIRE) { - case PROTO_BBB: + switch (sc->sc_wire) { + case UMASS_WPROTO_BBB: bno = XFER_BBB_DATA; goto dalloc; - case PROTO_CBI: + case UMASS_WPROTO_CBI: bno = XFER_CBI_DATA; goto dalloc; - case PROTO_CBI_I: + case UMASS_WPROTO_CBI_I: bno = XFER_CBI_DATA; dalloc: sc->data_buffer = usbd_alloc_buffer(sc->transfer_xfer[bno], @@ -1106,144 +531,108 @@ USB_ATTACH(umass) } /* Initialise the wire protocol specific methods */ - if (sc->proto & PROTO_BBB) { - sc->reset = umass_bbb_reset; - sc->transfer = umass_bbb_transfer; - sc->state = umass_bbb_state; - } else if ((sc->proto & PROTO_CBI) || (sc->proto & PROTO_CBI_I)) { - sc->reset = umass_cbi_reset; - sc->transfer = umass_cbi_transfer; - sc->state = umass_cbi_state; -#ifdef UMASS_DEBUG - } else { - panic("%s:%d: Unknown proto 0x%02x", - __FILE__, __LINE__, sc->proto); -#endif + switch (sc->sc_wire) { + case UMASS_WPROTO_BBB: + sc->sc_methods = &umass_bbb_methods; + break; + case UMASS_WPROTO_CBI: + case UMASS_WPROTO_CBI_I: + sc->sc_methods = &umass_cbi_methods; + break; + default: + umass_disco(sc); + USB_ATTACH_ERROR_RETURN; } - if (sc->drive == SHUTTLE_EUSB) - umass_init_shuttle(sc); + if (quirk != NULL && quirk->uq_init != NULL) { + err = (*quirk->uq_init)(sc); + if (err) { + umass_disco(sc); + USB_ATTACH_ERROR_RETURN; + } + } - /* - * Fill in the adapter. - */ - sc->sc_adapter.scsipi_cmd = umass_scsipi_cmd; - sc->sc_adapter.scsipi_minphys = umass_scsipi_minphys; + error = 0; + switch (sc->sc_cmd) { + case UMASS_CPROTO_RBC: + case UMASS_CPROTO_SCSI: +#if defined(__OpenBSD__) || NSCSIBUS > 0 + error = umass_scsi_attach(sc); +#else + printf("%s: scsibus not configured\n", USBDEVNAME(sc->sc_dev)); +#endif + break; - /* - * fill in the prototype scsipi_link. - */ - switch (sc->proto & PROTO_COMMAND) { - case PROTO_SCSI: - case PROTO_UFI: - case PROTO_ATAPI: - case PROTO_RBC: - if ((sc->proto & PROTO_COMMAND) != PROTO_SCSI) - sc->u.sc_link.flags |= SDEV_ATAPI; - else - sc->u.sc_link.flags &= ~SDEV_ATAPI; - - sc->u.sc_link.adapter_buswidth = 2; - sc->u.sc_link.adapter_target = UMASS_SCSIID_HOST; - sc->u.sc_link.luns = sc->maxlun + 1; - - sc->u.sc_link.adapter_softc = sc; - sc->u.sc_link.adapter = &sc->sc_adapter; - sc->u.sc_link.device = &umass_dev; - sc->u.sc_link.openings = 1; - - if(sc->quirks & NO_TEST_UNIT_READY) - sc->u.sc_link.quirks |= ADEV_NOTUR; + case UMASS_CPROTO_UFI: + case UMASS_CPROTO_ATAPI: +#if (NATAPIBUS > 0) || (NATAPISCSI > 0) + error = umass_atapi_attach(sc); +#else + printf("%s: "UMASS_ATAPISTR" not configured\n", + USBDEVNAME(sc->sc_dev)); +#endif break; + case UMASS_CPROTO_ISD_ATA: +#if defined (__NetBSD__) && NWD > 0 + error = umass_isdata_attach(sc); +#else + printf("%s: isdata not configured\n", USBDEVNAME(sc->sc_dev)); +#endif + break; default: - printf("%s: proto=0x%x not supported yet\n", - USBDEVNAME(sc->sc_dev), sc->proto); + printf("%s: command protocol=0x%x not supported\n", + USBDEVNAME(sc->sc_dev), sc->sc_cmd); umass_disco(sc); USB_ATTACH_ERROR_RETURN; } - - if (cold) { - startuphook_establish((void (*)(void *))umass_delayed_attach, - sc); - } else { - /* hot plug, do it now */ - umass_delayed_attach(sc); - } - - DPRINTF(UDMASS_GEN, ("%s: Attach finished\n", USBDEVNAME(sc->sc_dev))); - - USB_ATTACH_SUCCESS_RETURN; -} - -void -umass_delayed_attach(struct umass_softc *sc) -{ - sc->sc_child = config_found(&sc->sc_dev, &sc->u, scsipiprint); - if (sc->sc_child == NULL) { + if (error) { + printf("%s: bus attach failed\n", USBDEVNAME(sc->sc_dev)); umass_disco(sc); - /* Not an error, just not a complete success. */ - USB_ATTACH_SUCCESS_RETURN; + USB_ATTACH_ERROR_RETURN; } usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, USBDEV(sc->sc_dev)); -} -Static int -scsipiprint(aux, pnp) - void *aux; - const char *pnp; -{ -#if !defined(__OpenBSD__) - extern int atapi_print(void *aux, const char *pnp); - struct scsipi_link *l = aux; - - if (l->type == BUS_SCSI) - return (scsiprint(aux, pnp)); - else - return (atapi_print(aux, pnp)); -#else - return (scsiprint(aux, pnp)); -#endif + DPRINTF(UDMASS_GEN, ("%s: Attach finished\n", USBDEVNAME(sc->sc_dev))); + + USB_ATTACH_SUCCESS_RETURN; } USB_DETACH(umass) { USB_DETACH_START(umass, sc); - int rv = 0; + struct umassbus_softc *scbus = sc->bus; + int rv = 0, i, s; DPRINTF(UDMASS_USB, ("%s: detached\n", USBDEVNAME(sc->sc_dev))); /* Abort the pipes to wake up any waiting processes. */ - if (sc->bulkout_pipe != NULL) - usbd_abort_pipe(sc->bulkout_pipe); - if (sc->bulkin_pipe != NULL) - usbd_abort_pipe(sc->bulkin_pipe); - if (sc->intrin_pipe != NULL) - usbd_abort_pipe(sc->intrin_pipe); + for (i = 0 ; i < UMASS_NEP ; i++) { + if (sc->sc_pipe[i] != NULL) + usbd_abort_pipe(sc->sc_pipe[i]); + } -#if 0 /* Do we really need reference counting? Perhaps in ioctl() */ s = splusb(); if (--sc->sc_refcnt >= 0) { +#ifdef DIAGNOSTIC + printf("%s: waiting for refcnt\n", USBDEVNAME(sc->sc_dev)); +#endif /* Wait for processes to go away. */ usb_detach_wait(USBDEV(sc->sc_dev)); } splx(s); -#endif -#if defined(__FreeBSD__) - if ((sc->proto & PROTO_SCSI) || - (sc->proto & PROTO_ATAPI) || - (sc->proto & PROTO_UFI)) - /* detach the device from the SCSI host controller (SIM) */ - rv = umass_cam_detach(sc); -#elif defined(__NetBSD__) || defined(__OpenBSD__) - if (sc->sc_child != NULL) - rv = config_detach(sc->sc_child, flags); -#endif + if (scbus != NULL) { + if (scbus->sc_child != NULL) + rv = config_detach(scbus->sc_child, flags); + free(scbus, M_DEVBUF); + sc->bus = NULL; + } + if (rv != 0) return (rv); @@ -1252,16 +641,14 @@ USB_DETACH(umass) usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, USBDEV(sc->sc_dev)); - return (0); + return (rv); } -#if defined(__NetBSD__) || defined(__OpenBSD__) int -umass_activate(self, act) - struct device *self; - enum devact act; +umass_activate(struct device *dev, enum devact act) { - struct umass_softc *sc = (struct umass_softc *) self; + struct umass_softc *sc = (struct umass_softc *)dev; + struct umassbus_softc *scbus = sc->bus; int rv = 0; DPRINTF(UDMASS_USB, ("%s: umass_activate: %d\n", @@ -1273,22 +660,19 @@ umass_activate(self, act) break; case DVACT_DEACTIVATE: - if (sc->sc_child == NULL) + sc->sc_dying = 1; + if (scbus == NULL || scbus->sc_child == NULL) break; - rv = config_deactivate(sc->sc_child); + rv = config_deactivate(scbus->sc_child); DPRINTF(UDMASS_USB, ("%s: umass_activate: child " "returned %d\n", USBDEVNAME(sc->sc_dev), rv)); - if (rv == 0) - sc->sc_dying = 1; break; } return (rv); } -#endif Static void -umass_disco(sc) - struct umass_softc *sc; +umass_disco(struct umass_softc *sc) { int i; @@ -1302,27 +686,12 @@ umass_disco(sc) } /* Remove all the pipes. */ - if (sc->bulkout_pipe != NULL) - usbd_close_pipe(sc->bulkout_pipe); - if (sc->bulkin_pipe != NULL) - usbd_close_pipe(sc->bulkin_pipe); - if (sc->intrin_pipe != NULL) - usbd_close_pipe(sc->intrin_pipe); -} - -Static void -umass_init_shuttle(struct umass_softc *sc) -{ - usb_device_request_t req; - u_char status[2]; - - /* The Linux driver does this */ - req.bmRequestType = UT_READ_VENDOR_DEVICE; - req.bRequest = 1; - USETW(req.wValue, 0); - USETW(req.wIndex, sc->ifaceno); - USETW(req.wLength, sizeof status); - (void)usbd_do_request(sc->sc_udev, &req, &status); + for (i = 0 ; i < UMASS_NEP ; i++) { + if (sc->sc_pipe[i] != NULL) { + usbd_close_pipe(sc->sc_pipe[i]); + sc->sc_pipe[i] = NULL; + } + } } /* @@ -1342,7 +711,7 @@ umass_setup_transfer(struct umass_softc *sc, usbd_pipe_handle pipe, /* Initialiase a USB transfer and then schedule it */ usbd_setup_xfer(xfer, pipe, (void *)sc, buffer, buflen, - flags | sc->sc_xfer_flags, sc->timeout, sc->state); + flags | sc->sc_xfer_flags, sc->timeout, sc->sc_methods->wire_state); err = usbd_transfer(xfer); DPRINTF(UDMASS_XFER,("%s: start xfer buffer=%p buflen=%d flags=0x%x " @@ -1359,10 +728,8 @@ umass_setup_transfer(struct umass_softc *sc, usbd_pipe_handle pipe, Static usbd_status -umass_setup_ctrl_transfer(struct umass_softc *sc, usbd_device_handle dev, - usb_device_request_t *req, - void *buffer, int buflen, int flags, - usbd_xfer_handle xfer) +umass_setup_ctrl_transfer(struct umass_softc *sc, usb_device_request_t *req, + void *buffer, int buflen, int flags, usbd_xfer_handle xfer) { usbd_status err; @@ -1371,8 +738,8 @@ umass_setup_ctrl_transfer(struct umass_softc *sc, usbd_device_handle dev, /* Initialiase a USB control transfer and then schedule it */ - usbd_setup_default_xfer(xfer, dev, (void *) sc, - sc->timeout, req, buffer, buflen, flags, sc->state); + usbd_setup_default_xfer(xfer, sc->sc_udev, (void *) sc, sc->timeout, + req, buffer, buflen, flags, sc->sc_methods->wire_state); err = usbd_transfer(xfer); if (err && err != USBD_IN_PROGRESS) { @@ -1387,30 +754,23 @@ umass_setup_ctrl_transfer(struct umass_softc *sc, usbd_device_handle dev, } Static void -umass_clear_endpoint_stall(struct umass_softc *sc, - u_int8_t endpt, usbd_pipe_handle pipe, - int state, usbd_xfer_handle xfer) +umass_clear_endpoint_stall(struct umass_softc *sc, int endpt, + usbd_xfer_handle xfer) { - usbd_device_handle dev; - if (sc->sc_dying) return; DPRINTF(UDMASS_BBB, ("%s: Clear endpoint 0x%02x stall\n", - USBDEVNAME(sc->sc_dev), endpt)); - - usbd_interface2device_handle(sc->iface, &dev); + USBDEVNAME(sc->sc_dev), sc->sc_epaddr[endpt])); - sc->transfer_state = state; + usbd_clear_endpoint_toggle(sc->sc_pipe[endpt]); - usbd_clear_endpoint_toggle(pipe); - - sc->request.bmRequestType = UT_WRITE_ENDPOINT; - sc->request.bRequest = UR_CLEAR_FEATURE; - USETW(sc->request.wValue, UF_ENDPOINT_HALT); - USETW(sc->request.wIndex, endpt); - USETW(sc->request.wLength, 0); - umass_setup_ctrl_transfer(sc, dev, &sc->request, NULL, 0, 0, xfer); + sc->sc_req.bmRequestType = UT_WRITE_ENDPOINT; + sc->sc_req.bRequest = UR_CLEAR_FEATURE; + USETW(sc->sc_req.wValue, UF_ENDPOINT_HALT); + USETW(sc->sc_req.wIndex, sc->sc_epaddr[endpt]); + USETW(sc->sc_req.wLength, 0); + umass_setup_ctrl_transfer(sc, &sc->sc_req, NULL, 0, 0, xfer); } #if 0 @@ -1432,10 +792,9 @@ umass_reset(struct umass_softc *sc, transfer_cb_f cb, void *priv) Static void umass_bbb_reset(struct umass_softc *sc, int status) { - usbd_device_handle dev; - - KASSERT(sc->proto & PROTO_BBB, - ("sc->proto == 0x%02x wrong for umass_bbb_reset\n", sc->proto)); + KASSERT(sc->sc_wire & UMASS_WPROTO_BBB, + ("sc->sc_wire == 0x%02x wrong for umass_bbb_reset\n", + sc->sc_wire)); if (sc->sc_dying) return; @@ -1462,31 +821,32 @@ umass_bbb_reset(struct umass_softc *sc, int status) sc->transfer_state = TSTATE_BBB_RESET1; sc->transfer_status = status; - usbd_interface2device_handle(sc->iface, &dev); - /* reset is a class specific interface write */ - sc->request.bmRequestType = UT_WRITE_CLASS_INTERFACE; - sc->request.bRequest = UR_BBB_RESET; - USETW(sc->request.wValue, 0); - USETW(sc->request.wIndex, sc->ifaceno); - USETW(sc->request.wLength, 0); - umass_setup_ctrl_transfer(sc, dev, &sc->request, NULL, 0, 0, + sc->sc_req.bmRequestType = UT_WRITE_CLASS_INTERFACE; + sc->sc_req.bRequest = UR_BBB_RESET; + USETW(sc->sc_req.wValue, 0); + USETW(sc->sc_req.wIndex, sc->sc_ifaceno); + USETW(sc->sc_req.wLength, 0); + umass_setup_ctrl_transfer(sc, &sc->sc_req, NULL, 0, 0, sc->transfer_xfer[XFER_BBB_RESET1]); } Static void umass_bbb_transfer(struct umass_softc *sc, int lun, void *cmd, int cmdlen, - void *data, int datalen, int dir, - transfer_cb_f cb, void *priv) + void *data, int datalen, int dir, u_int timeout, + umass_callback cb, void *priv) { static int dCBWtag = 42; /* unique for CBW of transfer */ DPRINTF(UDMASS_BBB,("%s: umass_bbb_transfer cmd=0x%02x\n", USBDEVNAME(sc->sc_dev), *(u_char *)cmd)); - KASSERT(sc->proto & PROTO_BBB, - ("sc->proto == 0x%02x wrong for umass_bbb_transfer\n", - sc->proto)); + KASSERT(sc->sc_wire & UMASS_WPROTO_BBB, + ("sc->sc_wire == 0x%02x wrong for umass_bbb_transfer\n", + sc->sc_wire)); + + /* Be a little generous. */ + sc->timeout = timeout + USBD_DEFAULT_TIMEOUT; /* * Do a Bulk-Only transfer with cmdlen bytes from cmd, possibly @@ -1558,7 +918,7 @@ umass_bbb_transfer(struct umass_softc *sc, int lun, void *cmd, int cmdlen, sc->cbw.bCBWFlags = (dir == DIR_IN? CBWFLAGS_IN:CBWFLAGS_OUT); sc->cbw.bCBWLUN = lun; sc->cbw.bCDBLength = cmdlen; - bcopy(cmd, sc->cbw.CBWCDB, cmdlen); + memcpy(sc->cbw.CBWCDB, cmd, cmdlen); DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw)); @@ -1575,7 +935,7 @@ umass_bbb_transfer(struct umass_softc *sc, int lun, void *cmd, int cmdlen, sc->transfer_state = TSTATE_BBB_COMMAND; /* Send the CBW from host to device via bulk-out endpoint. */ - if (umass_setup_transfer(sc, sc->bulkout_pipe, + if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT], &sc->cbw, UMASS_BBB_CBW_SIZE, 0, sc->transfer_xfer[XFER_BBB_CBW])) { umass_bbb_reset(sc, STATUS_WIRE_FAILED); @@ -1590,8 +950,9 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, struct umass_softc *sc = (struct umass_softc *) priv; usbd_xfer_handle next_xfer; - KASSERT(sc->proto & PROTO_BBB, - ("sc->proto == 0x%02x wrong for umass_bbb_state\n",sc->proto)); + KASSERT(sc->sc_wire & UMASS_WPROTO_BBB, + ("sc->sc_wire == 0x%02x wrong for umass_bbb_state\n", + sc->sc_wire)); if (sc->sc_dying) return; @@ -1630,7 +991,7 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, /* Data transport phase, setup transfer */ sc->transfer_state = TSTATE_BBB_DATA; if (sc->transfer_dir == DIR_IN) { - if (umass_setup_transfer(sc, sc->bulkin_pipe, + if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKIN], sc->data_buffer, sc->transfer_datalen, USBD_SHORT_XFER_OK | USBD_NO_COPY, sc->transfer_xfer[XFER_BBB_DATA])) @@ -1640,7 +1001,7 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, } else if (sc->transfer_dir == DIR_OUT) { memcpy(sc->data_buffer, sc->transfer_data, sc->transfer_datalen); - if (umass_setup_transfer(sc, sc->bulkout_pipe, + if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT], sc->data_buffer, sc->transfer_datalen, USBD_NO_COPY,/* fixed length transfer */ sc->transfer_xfer[XFER_BBB_DATA])) @@ -1662,18 +1023,16 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, &sc->transfer_actlen, NULL); if (err) { - DPRINTF(UDMASS_BBB, ("%s: Data-%s %db failed, " + DPRINTF(UDMASS_BBB, ("%s: Data-%s %d failed, " "%s\n", USBDEVNAME(sc->sc_dev), (sc->transfer_dir == DIR_IN?"in":"out"), sc->transfer_datalen,usbd_errstr(err))); if (err == USBD_STALLED) { + sc->transfer_state = TSTATE_BBB_DCLEAR; umass_clear_endpoint_stall(sc, (sc->transfer_dir == DIR_IN? - sc->bulkin:sc->bulkout), - (sc->transfer_dir == DIR_IN? - sc->bulkin_pipe:sc->bulkout_pipe), - TSTATE_BBB_DCLEAR, + UMASS_BULKIN:UMASS_BULKOUT), sc->transfer_xfer[XFER_BBB_DCLEAR]); return; } else { @@ -1729,9 +1088,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, } /* Read the Command Status Wrapper via bulk-in endpoint. */ - if (umass_setup_transfer(sc, sc->bulkin_pipe, - &sc->csw, UMASS_BBB_CSW_SIZE, 0, - next_xfer)) { + if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKIN], + &sc->csw, UMASS_BBB_CSW_SIZE, 0, next_xfer)) { umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } @@ -1750,10 +1108,9 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, * retry it, otherwise fail. */ if (sc->transfer_state == TSTATE_BBB_STATUS1) { - umass_clear_endpoint_stall(sc, - sc->bulkin, sc->bulkin_pipe, - TSTATE_BBB_SCLEAR, - sc->transfer_xfer[XFER_BBB_SCLEAR]); + sc->transfer_state = TSTATE_BBB_SCLEAR; + umass_clear_endpoint_stall(sc, UMASS_BULKIN, + sc->transfer_xfer[XFER_BBB_SCLEAR]); return; } else { umass_bbb_reset(sc, STATUS_WIRE_FAILED); @@ -1763,6 +1120,15 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw)); + /* Translate weird command-status signatures. */ + if ((sc->sc_quirks & UMASS_QUIRK_WRONG_CSWSIG) && + UGETDW(sc->csw.dCSWSignature) == CSWSIGNATURE_OLYMPUS_C1) + USETDW(sc->csw.dCSWSignature, CSWSIGNATURE); + + /* Translate invalid command-status tags */ + if (sc->sc_quirks & UMASS_QUIRK_WRONG_CSWTAG) + USETDW(sc->csw.dCSWTag, UGETDW(sc->cbw.dCBWTag)); + /* Check CSW and handle any error */ if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) { /* Invalid CSW: Wrong signature or wrong tag might @@ -1807,9 +1173,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, panic("%s: transferred %d bytes instead of %d bytes", USBDEVNAME(sc->sc_dev), sc->transfer_actlen, sc->transfer_datalen); - } #if 0 - else if (sc->transfer_datalen - sc->transfer_actlen + } else if (sc->transfer_datalen - sc->transfer_actlen != UGETDW(sc->csw.dCSWDataResidue)) { DPRINTF(UDMASS_BBB, ("%s: actlen=%d != residue=%d\n", USBDEVNAME(sc->sc_dev), @@ -1818,10 +1183,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; - - } #endif - else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) { + } else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) { DPRINTF(UDMASS_BBB, ("%s: Command Failed, res = %d\n", USBDEVNAME(sc->sc_dev), UGETDW(sc->csw.dCSWDataResidue))); @@ -1849,8 +1212,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, printf("%s: BBB reset failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); - umass_clear_endpoint_stall(sc, - sc->bulkin, sc->bulkin_pipe, TSTATE_BBB_RESET2, + sc->transfer_state = TSTATE_BBB_RESET2; + umass_clear_endpoint_stall(sc, UMASS_BULKIN, sc->transfer_xfer[XFER_BBB_RESET2]); return; @@ -1860,8 +1223,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, USBDEVNAME(sc->sc_dev), usbd_errstr(err)); /* no error recovery, otherwise we end up in a loop */ - umass_clear_endpoint_stall(sc, - sc->bulkout, sc->bulkout_pipe, TSTATE_BBB_RESET3, + sc->transfer_state = TSTATE_BBB_RESET3; + umass_clear_endpoint_stall(sc, UMASS_BULKOUT, sc->transfer_xfer[XFER_BBB_RESET3]); return; @@ -1895,19 +1258,16 @@ Static int umass_cbi_adsc(struct umass_softc *sc, char *buffer, int buflen, usbd_xfer_handle xfer) { - usbd_device_handle dev; - - KASSERT(sc->proto & (PROTO_CBI|PROTO_CBI_I), - ("sc->proto == 0x%02x wrong for umass_cbi_adsc\n",sc->proto)); - - usbd_interface2device_handle(sc->iface, &dev); - - sc->request.bmRequestType = UT_WRITE_CLASS_INTERFACE; - sc->request.bRequest = UR_CBI_ADSC; - USETW(sc->request.wValue, 0); - USETW(sc->request.wIndex, sc->ifaceno); - USETW(sc->request.wLength, buflen); - return umass_setup_ctrl_transfer(sc, dev, &sc->request, buffer, + KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I), + ("sc->sc_wire == 0x%02x wrong for umass_cbi_adsc\n", + sc->sc_wire)); + + sc->sc_req.bmRequestType = UT_WRITE_CLASS_INTERFACE; + sc->sc_req.bRequest = UR_CBI_ADSC; + USETW(sc->sc_req.wValue, 0); + USETW(sc->sc_req.wIndex, sc->sc_ifaceno); + USETW(sc->sc_req.wLength, buflen); + return umass_setup_ctrl_transfer(sc, &sc->sc_req, buffer, buflen, 0, xfer); } @@ -1918,8 +1278,9 @@ umass_cbi_reset(struct umass_softc *sc, int status) int i; # define SEND_DIAGNOSTIC_CMDLEN 12 - KASSERT(sc->proto & (PROTO_CBI|PROTO_CBI_I), - ("sc->proto == 0x%02x wrong for umass_cbi_reset\n",sc->proto)); + KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I), + ("sc->sc_wire == 0x%02x wrong for umass_cbi_reset\n", + sc->sc_wire)); if (sc->sc_dying) return; @@ -1965,19 +1326,22 @@ umass_cbi_reset(struct umass_softc *sc, int status) Static void umass_cbi_transfer(struct umass_softc *sc, int lun, - void *cmd, int cmdlen, void *data, int datalen, int dir, - transfer_cb_f cb, void *priv) + void *cmd, int cmdlen, void *data, int datalen, int dir, + u_int timeout, umass_callback cb, void *priv) { DPRINTF(UDMASS_CBI,("%s: umass_cbi_transfer cmd=0x%02x, len=%d\n", USBDEVNAME(sc->sc_dev), *(u_char *)cmd, datalen)); - KASSERT(sc->proto & (PROTO_CBI|PROTO_CBI_I), - ("sc->proto == 0x%02x wrong for umass_cbi_transfer\n", - sc->proto)); + KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I), + ("sc->sc_wire == 0x%02x wrong for umass_cbi_transfer\n", + sc->sc_wire)); if (sc->sc_dying) return; + /* Be a little generous. */ + sc->timeout = timeout + USBD_DEFAULT_TIMEOUT; + /* * Do a CBI transfer with cmdlen bytes from cmd, possibly * a data phase of datalen bytes from/to the device and finally a @@ -2025,8 +1389,9 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, { struct umass_softc *sc = (struct umass_softc *) priv; - KASSERT(sc->proto & (PROTO_CBI|PROTO_CBI_I), - ("sc->proto == 0x%02x wrong for umass_cbi_state\n", sc->proto)); + KASSERT(sc->sc_wire & (UMASS_WPROTO_CBI|UMASS_WPROTO_CBI_I), + ("sc->sc_wire == 0x%02x wrong for umass_cbi_state\n", + sc->sc_wire)); if (sc->sc_dying) return; @@ -2049,10 +1414,10 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, /* Status transport by control pipe (section 2.3.2.1). * The command contained in the command block failed. * - * The control pipe has already been unstalled by the - * USB stack. - * Section 2.4.3.1.1 states that the bulk in endpoints - * should not stalled at this point. + * The control pipe has already been unstalled by the + * USB stack. + * Section 2.4.3.1.1 states that the bulk in endpoints + * should not stalled at this point. */ sc->transfer_state = TSTATE_IDLE; @@ -2071,7 +1436,7 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, sc->transfer_state = TSTATE_CBI_DATA; if (sc->transfer_dir == DIR_IN) { - if (umass_setup_transfer(sc, sc->bulkin_pipe, + if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKIN], sc->transfer_data, sc->transfer_datalen, USBD_SHORT_XFER_OK | USBD_NO_COPY, sc->transfer_xfer[XFER_CBI_DATA])) @@ -2080,17 +1445,17 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, } else if (sc->transfer_dir == DIR_OUT) { memcpy(sc->data_buffer, sc->transfer_data, sc->transfer_datalen); - if (umass_setup_transfer(sc, sc->bulkout_pipe, + if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT], sc->transfer_data, sc->transfer_datalen, USBD_NO_COPY,/* fixed length transfer */ sc->transfer_xfer[XFER_CBI_DATA])) umass_cbi_reset(sc, STATUS_WIRE_FAILED); - } else if (sc->proto & PROTO_CBI_I) { + } else if (sc->sc_wire == UMASS_WPROTO_CBI_I) { DPRINTF(UDMASS_CBI, ("%s: no data phase\n", USBDEVNAME(sc->sc_dev))); sc->transfer_state = TSTATE_CBI_STATUS; - if (umass_setup_transfer(sc, sc->intrin_pipe, + if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_INTRIN], &sc->sbl, sizeof(sc->sbl), 0, /* fixed length transfer */ sc->transfer_xfer[XFER_CBI_STATUS])){ @@ -2116,15 +1481,14 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, USBDEVNAME(sc->sc_dev), sc->transfer_actlen)); if (err) { - DPRINTF(UDMASS_CBI, ("%s: Data-%s %db failed, " + DPRINTF(UDMASS_CBI, ("%s: Data-%s %d failed, " "%s\n", USBDEVNAME(sc->sc_dev), (sc->transfer_dir == DIR_IN?"in":"out"), sc->transfer_datalen,usbd_errstr(err))); if (err == USBD_STALLED) { - umass_clear_endpoint_stall(sc, - sc->bulkin, sc->bulkin_pipe, - TSTATE_CBI_DCLEAR, + sc->transfer_state = TSTATE_CBI_DCLEAR; + umass_clear_endpoint_stall(sc, UMASS_BULKIN, sc->transfer_xfer[XFER_CBI_DCLEAR]); } else { umass_cbi_reset(sc, STATUS_WIRE_FAILED); @@ -2140,10 +1504,10 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, umass_dump_buffer(sc, sc->transfer_data, sc->transfer_actlen, 48)); - if (sc->proto & PROTO_CBI_I) { + if (sc->sc_wire == UMASS_WPROTO_CBI_I) { sc->transfer_state = TSTATE_CBI_STATUS; memset(&sc->sbl, 0, sizeof(sc->sbl)); - if (umass_setup_transfer(sc, sc->intrin_pipe, + if (umass_setup_transfer(sc, sc->sc_pipe[UMASS_INTRIN], &sc->sbl, sizeof(sc->sbl), 0, /* fixed length transfer */ sc->transfer_xfer[XFER_CBI_STATUS])){ @@ -2168,9 +1532,8 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, */ if (err == USBD_STALLED) { - umass_clear_endpoint_stall(sc, - sc->intrin, sc->intrin_pipe, - TSTATE_CBI_SCLEAR, + sc->transfer_state = TSTATE_CBI_SCLEAR; + umass_clear_endpoint_stall(sc, UMASS_INTRIN, sc->transfer_xfer[XFER_CBI_SCLEAR]); } else { umass_cbi_reset(sc, STATUS_WIRE_FAILED); @@ -2180,7 +1543,7 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, /* Dissect the information in the buffer */ - if (sc->proto & PROTO_UFI) { + if (sc->sc_cmd == UMASS_CPROTO_UFI) { int status; /* Section 3.4.3.1.3 specifies that the UFI command @@ -2256,8 +1619,8 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, printf("%s: CBI reset failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); - umass_clear_endpoint_stall(sc, - sc->bulkin, sc->bulkin_pipe, TSTATE_CBI_RESET2, + sc->transfer_state = TSTATE_CBI_RESET2; + umass_clear_endpoint_stall(sc, UMASS_BULKIN, sc->transfer_xfer[XFER_CBI_RESET2]); return; @@ -2267,8 +1630,8 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, USBDEVNAME(sc->sc_dev), usbd_errstr(err)); /* no error recovery, otherwise we end up in a loop */ - umass_clear_endpoint_stall(sc, - sc->bulkout, sc->bulkout_pipe, TSTATE_CBI_RESET3, + sc->transfer_state = TSTATE_CBI_RESET3; + umass_clear_endpoint_stall(sc, UMASS_BULKOUT, sc->transfer_xfer[XFER_CBI_RESET3]); return; @@ -2298,26 +1661,21 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status umass_bbb_get_max_lun(struct umass_softc *sc, u_int8_t *maxlun) { - usbd_device_handle dev; usb_device_request_t req; usbd_status err; - usb_interface_descriptor_t *id; *maxlun = 0; /* Default to 0. */ DPRINTF(UDMASS_BBB, ("%s: Get Max Lun\n", USBDEVNAME(sc->sc_dev))); - usbd_interface2device_handle(sc->iface, &dev); - id = usbd_get_interface_descriptor(sc->iface); - /* The Get Max Lun command is a class-specific request. */ req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UR_BBB_GET_MAX_LUN; USETW(req.wValue, 0); - USETW(req.wIndex, id->bInterfaceNumber); + USETW(req.wIndex, sc->sc_ifaceno); USETW(req.wLength, 1); - err = usbd_do_request(dev, &req, maxlun); + err = usbd_do_request(sc->sc_udev, &req, maxlun); switch (err) { case USBD_NORMAL_COMPLETION: DPRINTF(UDMASS_BBB, ("%s: Max Lun %d\n", @@ -2354,706 +1712,6 @@ umass_bbb_get_max_lun(struct umass_softc *sc, u_int8_t *maxlun) -#if defined(__FreeBSD__) -/* - * CAM specific functions (used by SCSI, UFI, 8070) - */ - -Static int -umass_cam_attach_sim() -{ - struct cam_devq *devq; /* Per device Queue */ - - /* A HBA is attached to the CAM layer. - * - * The CAM layer will then after a while start probing for - * devices on the bus. The number of devices is limitted to one. - */ - - /* SCSI transparent command set */ - - devq = cam_simq_alloc(1 /*maximum openings*/); - if (devq == NULL) - return(ENOMEM); - - umass_sim = cam_sim_alloc(umass_cam_action, umass_cam_poll, DEVNAME, - NULL /*priv*/, 0 /*unit number*/, - 1 /*maximum device openings*/, - 0 /*maximum tagged device openings*/, - devq); - if (umass_sim == NULL) { - cam_simq_free(devq); - return(ENOMEM); - } - - if(xpt_bus_register(umass_sim, 0) != CAM_SUCCESS) - return(ENOMEM); - - if (xpt_create_path(&umass_path, NULL, cam_sim_path(umass_sim), - UMASS_SCSIID_HOST, 0) - != CAM_REQ_CMP) - return(ENOMEM); - - return(0); -} - -#ifdef UMASS_DO_CAM_RESCAN -/* this function is only used from umass_cam_rescan, so mention - * prototype down here. - */ -Static void umass_cam_rescan_callback(struct cam_periph *periph,union ccb *ccb); - -Static void -umass_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) -{ -#ifdef UMASS_DEBUG - struct umass_softc *sc = devclass_get_softc(umass_devclass, - ccb->ccb_h.target_id); - - if (ccb->ccb_h.status != CAM_REQ_CMP) { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: Rescan failed, 0x%04x\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun, - ccb->ccb_h.status)); - } else { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: Rescan succeeded, freeing resources.\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); - } -#endif - - xpt_free_path(ccb->ccb_h.path); - free(ccb, M_USBDEV); -} - -Static void -umass_cam_rescan(struct umass_softc *sc) -{ - struct cam_path *path; - union ccb *ccb = malloc(sizeof(union ccb), M_USBDEV, M_WAITOK); - - memset(ccb, 0, sizeof(union ccb)); - - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: scanning bus for new device %d\n", - USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), - device_get_unit(sc->sc_dev), 0, - device_get_unit(sc->sc_dev))); - - if (xpt_create_path(&path, xpt_periph, cam_sim_path(umass_sim), - device_get_unit(sc->sc_dev), 0) - != CAM_REQ_CMP) - return; - - xpt_setup_ccb(&ccb->ccb_h, path, 5/*priority (low)*/); - ccb->ccb_h.func_code = XPT_SCAN_BUS; - ccb->ccb_h.cbfcnp = umass_cam_rescan_callback; - ccb->crcn.flags = CAM_FLAG_NONE; - xpt_action(ccb); - - /* The scan is in progress now. */ -} -#endif - -Static int -umass_cam_attach(struct umass_softc *sc) -{ - /* SIM already attached at module load. The device is a target on the - * one SIM we registered: target device_get_unit(self). - */ - - /* The artificial limit UMASS_SCSIID_MAX is there because CAM expects - * a limit to the number of targets that are present on a SIM. - */ - if (device_get_unit(sc->sc_dev) > UMASS_SCSIID_MAX) { - printf("%s: Increase UMASS_SCSIID_MAX (currently %d) in %s " - "and try again.\n", USBDEVNAME(sc->sc_dev), - UMASS_SCSIID_MAX, __FILE__); - return(1); - } - -#ifdef UMASS_DO_CAM_RESCAN - if (!cold) { - /* Notify CAM of the new device. Any failure is benign, as the - * user can still do it by hand (camcontrol rescan <busno>). - * Only do this if we are not booting, because CAM does a scan - * after booting has completed, when interrupts have been - * enabled. - */ - umass_cam_rescan(sc); - } -#endif - - return(0); /* always succesful */ -} - -/* umass_cam_detach - * detach from the CAM layer - */ - -Static int -umass_cam_detach_sim() -{ - if (umass_sim) - return(EBUSY); /* XXX CAM can't handle disappearing SIMs yet */ - - if (umass_path) { - /* XXX do we need to send an asynchroneous event for the SIM? - xpt_async(AC_LOST_DEVICE, umass_path, NULL); - */ - xpt_free_path(umass_path); - umass_path = NULL; - } - - if (umass_sim) { - if (xpt_bus_deregister(cam_sim_path(umass_sim))) - cam_sim_free(umass_sim, /*free_devq*/TRUE); - else - return(EBUSY); - - umass_sim = NULL; - } - - return(0); -} - -Static int -umass_cam_detach(struct umass_softc *sc) -{ - struct cam_path *path; - - /* detach of sim not done until module unload */ - DPRINTF(UDMASS_SCSI, ("%s: losing CAM device entry\n", - USBDEVNAME(sc->sc_dev))); - - if (xpt_create_path(&path, NULL, cam_sim_path(umass_sim), - device_get_unit(sc->sc_dev), CAM_LUN_WILDCARD) - != CAM_REQ_CMP) - return(ENOMEM); - xpt_async(AC_LOST_DEVICE, path, NULL); - xpt_free_path(path); - - return(0); -} - - - -/* umass_cam_action - * CAM requests for action come through here - */ - -Static void -umass_cam_action(struct cam_sim *sim, union ccb *ccb) -{ - struct umass_softc *sc = devclass_get_softc(umass_devclass, - ccb->ccb_h.target_id); - - /* The softc is still there, but marked as going away. umass_cam_detach - * has not yet notified CAM of the lost device however. - */ - if (sc && sc->sc_dying) { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: " - "Invalid target (gone)\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun, - ccb->ccb_h.func_code)); - ccb->ccb_h.status = CAM_TID_INVALID; - xpt_done(ccb); - return; - } - - /* Verify, depending on the operation to perform, that we either got a - * valid sc, because an existing target was referenced, or otherwise - * the SIM is addressed. - * - * This avoids bombing out at a printf and does give the CAM layer some - * sensible feedback on errors. - */ - switch (ccb->ccb_h.func_code) { - case XPT_SCSI_IO: - case XPT_RESET_DEV: - case XPT_GET_TRAN_SETTINGS: - case XPT_SET_TRAN_SETTINGS: - case XPT_CALC_GEOMETRY: - /* the opcodes requiring a target. These should never occur. */ - if (sc == NULL) { - printf("%s:%d:%d:%d:func_code 0x%04x: " - "Invalid target\n", - DEVNAME_SIM, UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun, - ccb->ccb_h.func_code); - - ccb->ccb_h.status = CAM_TID_INVALID; - xpt_done(ccb); - return; - } - break; - case XPT_PATH_INQ: - case XPT_NOOP: - /* The opcodes sometimes aimed at a target (sc is valid), - * sometimes aimed at the SIM (sc is invalid and target is - * CAM_TARGET_WILDCARD) - */ - if (sc == NULL && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: " - "Invalid target\n", - DEVNAME_SIM, UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun, - ccb->ccb_h.func_code)); - - ccb->ccb_h.status = CAM_TID_INVALID; - xpt_done(ccb); - return; - } - break; - default: - /* XXX Hm, we should check the input parameters */ - } - - /* Perform the requested action */ - switch (ccb->ccb_h.func_code) { - case XPT_SCSI_IO: - { - struct ccb_scsiio *csio = &ccb->csio; /* deref union */ - int dir; - unsigned char *cmd; - int cmdlen; - - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SCSI_IO: " - "cmd: 0x%02x, flags: 0x%02x, " - "%db cmd/%db data/%db sense\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun, - csio->cdb_io.cdb_bytes[0], - ccb->ccb_h.flags & CAM_DIR_MASK, - csio->cdb_len, csio->dxfer_len, - csio->sense_len)); - - /* clear the end of the buffer to make sure we don't send out - * garbage. - */ - DIF(UDMASS_SCSI, if ((ccb->ccb_h.flags & CAM_DIR_MASK) - == CAM_DIR_OUT) - umass_dump_buffer(sc, csio->data_ptr, - csio->dxfer_len, 48)); - - if (sc->transfer_state != TSTATE_IDLE) { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SCSI_IO: " - "I/O requested while busy (state %d, %s)\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun, - sc->transfer_state,states[sc->transfer_state])); - ccb->ccb_h.status = CAM_SCSI_BUSY; - xpt_done(ccb); - return; - } - - switch(ccb->ccb_h.flags&CAM_DIR_MASK) { - case CAM_DIR_IN: - dir = DIR_IN; - break; - case CAM_DIR_OUT: - dir = DIR_OUT; - break; - default: - dir = DIR_NONE; - } - - ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED; - if (sc->transform(sc, csio->cdb_io.cdb_bytes, csio->cdb_len, - &cmd, &cmdlen)) { - sc->transfer(sc, ccb->ccb_h.target_lun, cmd, cmdlen, - csio->data_ptr, - csio->dxfer_len, dir, - umass_cam_cb, (void *) ccb); - } else { - ccb->ccb_h.status = CAM_REQ_INVALID; - xpt_done(ccb); - } - - break; - } - case XPT_PATH_INQ: - { - struct ccb_pathinq *cpi = &ccb->cpi; - - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_PATH_INQ:.\n", - (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)), - UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); - - /* host specific information */ - cpi->version_num = 1; - cpi->hba_inquiry = 0; - cpi->target_sprt = 0; - cpi->hba_misc = 0; - cpi->hba_eng_cnt = 0; - cpi->max_target = UMASS_SCSIID_MAX; /* one target */ - cpi->max_lun = 0; /* no LUN's supported */ - cpi->initiator_id = UMASS_SCSIID_HOST; - strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); - strncpy(cpi->hba_vid, "USB SCSI", HBA_IDLEN); - strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); - cpi->unit_number = cam_sim_unit(sim); - cpi->bus_id = UMASS_SCSI_BUS; - if (sc) { - cpi->base_transfer_speed = sc->transfer_speed; - cpi->max_lun = sc->maxlun; - } - - cpi->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - break; - } - case XPT_RESET_DEV: - { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_RESET_DEV:.\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); - - ccb->ccb_h.status = CAM_REQ_INPROG; - umass_reset(sc, umass_cam_cb, (void *) ccb); - break; - } - case XPT_GET_TRAN_SETTINGS: - { - struct ccb_trans_settings *cts = &ccb->cts; - - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_GET_TRAN_SETTINGS:.\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); - - cts->valid = 0; - cts->flags = 0; /* no disconnection, tagging */ - - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - break; - } - case XPT_SET_TRAN_SETTINGS: - { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SET_TRAN_SETTINGS:.\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); - - ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - xpt_done(ccb); - break; - } - case XPT_CALC_GEOMETRY: - { - struct ccb_calc_geometry *ccg = &ccb->ccg; - - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_CALC_GEOMETRY: " - "Volume size = %d\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun, - ccg->volume_size)); - - /* XXX We should probably ask the drive for the details - * instead of cluching them up ourselves - */ - if (sc->drive == ZIP_100) { - ccg->heads = 64; - ccg->secs_per_track = 32; - ccg->cylinders = ccg->volume_size / ccg->heads - / ccg->secs_per_track; - ccb->ccb_h.status = CAM_REQ_CMP; - break; - } else if (sc->proto & PROTO_UFI) { - ccg->heads = 2; - if (ccg->volume_size == 2880) - ccg->secs_per_track = 18; - else - ccg->secs_per_track = 9; - ccg->cylinders = 80; - break; - } else { - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - } - - xpt_done(ccb); - break; - } - case XPT_NOOP: - { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_NOOP:.\n", - (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)), - UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); - - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - break; - } - default: - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: " - "Not implemented\n", - (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)), - UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun, - ccb->ccb_h.func_code)); - - ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - xpt_done(ccb); - break; - } -} - -/* umass_cam_poll - * all requests are handled through umass_cam_action, requests - * are never pending. So, nothing to do here. - */ -Static void -umass_cam_poll(struct cam_sim *sim) -{ -#ifdef UMASS_DEBUG - struct umass_softc *sc = (struct umass_softc *) sim->softc; - - DPRINTF(UDMASS_SCSI, ("%s: CAM poll\n", - USBDEVNAME(sc->sc_dev))); -#endif - - /* nop */ -} - - -/* umass_cam_cb - * finalise a completed CAM command - */ - -Static void -umass_cam_cb(struct umass_softc *sc, void *priv, int residue, int status) -{ - union ccb *ccb = (union ccb *) priv; - struct ccb_scsiio *csio = &ccb->csio; /* deref union */ - - csio->resid = residue; - - switch (status) { - case STATUS_CMD_OK: - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - break; - - case STATUS_CMD_UNKNOWN: - case STATUS_CMD_FAILED: - switch (ccb->ccb_h.func_code) { - case XPT_SCSI_IO: - { - unsigned char *cmd; - int cmdlen; - - /* fetch sense data */ - DPRINTF(UDMASS_SCSI,("%s: Fetching %db sense data\n", - USBDEVNAME(sc->sc_dev), - sc->cam_scsi_sense.length)); - - sc->cam_scsi_sense.length = csio->sense_len; - - if (sc->transform(sc, (char *) &sc->cam_scsi_sense, - sizeof(sc->cam_scsi_sense), - &cmd, &cmdlen)) { - sc->transfer(sc, ccb->ccb_h.target_lun, - cmd, cmdlen, - &csio->sense_data, - csio->sense_len, DIR_IN, - umass_cam_sense_cb, (void *) ccb); - } else { -#ifdef UMASS_DEBUG - panic("transform(REQUEST_SENSE) failed"); -#else - csio->resid = sc->transfer_datalen; - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - xpt_done(ccb); -#endif - } - break; - } - case XPT_RESET_DEV: /* Reset failed */ - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - xpt_done(ccb); - break; - default: - panic("umass_cam_cb called for func_code %d", - ccb->ccb_h.func_code); - } - break; - - case STATUS_WIRE_FAILED: - /* the wire protocol failed and will have recovered - * (hopefully). We return an error to CAM and let CAM retry - * the command if necessary. - */ - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - xpt_done(ccb); - break; - - default: - panic("%s: Unknown status %d in umass_cam_cb", - USBDEVNAME(sc->sc_dev), status); - } -} - -/* Finalise a completed autosense operation - */ -Static void -umass_cam_sense_cb(struct umass_softc *sc, void *priv, int residue, int status) -{ - union ccb *ccb = (union ccb *) priv; - struct ccb_scsiio *csio = &ccb->csio; /* deref union */ - - switch (status) { - case STATUS_CMD_OK: - case STATUS_CMD_UNKNOWN: - /* Getting sense data succeeded. The length of the sense data - * is not returned in any way. The sense data itself contains - * the length of the sense data that is valid. - */ - if (sc->quirks & RS_NO_CLEAR_UA - && csio->cdb_io.cdb_bytes[0] == INQUIRY - && (csio->sense_data.flags & SSD_KEY) - == SSD_KEY_UNIT_ATTENTION) { - /* Ignore unit attention errors in the case where - * the Unit Attention state is not cleared on - * REQUEST SENSE. They will appear again at the next - * command. - */ - ccb->ccb_h.status = CAM_REQ_CMP; - } else if ((csio->sense_data.flags & SSD_KEY) - == SSD_KEY_NO_SENSE) { - /* No problem after all (in the case of CBI without - * CCI) - */ - ccb->ccb_h.status = CAM_REQ_CMP; - } else { - ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR - | CAM_AUTOSNS_VALID; - csio->scsi_status = SCSI_STATUS_CHECK_COND; - } - xpt_done(ccb); - break; - - default: - DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n", - USBDEVNAME(sc->sc_dev), status)); - ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; - xpt_done(ccb); - } -} - - -Static int -umass_driver_load(module_t mod, int what, void *arg) -{ - int err; - - switch (what) { - case MOD_UNLOAD: - err = umass_cam_detach_sim(); - if (err) - return(err); - return(usbd_driver_load(mod, what, arg)); - case MOD_LOAD: - /* We don't attach to CAM at this point, because it will try - * and malloc memory for it. This is not possible when the - * boot loader loads umass as a module before the kernel - * has been bootstrapped. - */ - default: - return(usbd_driver_load(mod, what, arg)); - } -} - - - -/* (even the comment is missing) */ - -DRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, umass_driver_load, 0); - - -/* - * SCSI specific functions - */ - -Static int -umass_scsi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, - unsigned char **rcmd, int *rcmdlen) -{ - *rcmd = cmd; /* trivial copy */ - *rcmdlen = cmdlen; - - switch (cmd[0]) { - case TEST_UNIT_READY: - if (sc->quirks & NO_TEST_UNIT_READY) { - DPRINTF(UDMASS_SCSI, ("%s: Converted TEST_UNIT_READY " - "to START_UNIT\n", USBDEVNAME(sc->sc_dev))); - cmd[0] = START_STOP_UNIT; - cmd[4] = SSS_START; - } - break; - } - - return 1; /* success */ -} - -/* - * UFI specific functions - */ - -Static int -umass_ufi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, - unsigned char **rcmd, int *rcmdlen) -{ - *rcmd = cmd; - /* A UFI command is always 12 bytes in length */ - /* XXX cmd[(cmdlen+1)..12] contains garbage */ - *rcmdlen = 12; - - switch (cmd[0]) { - case TEST_UNIT_READY: - if (sc->quirks & NO_TEST_UNIT_READY) { - DPRINTF(UDMASS_UFI, ("%s: Converted TEST_UNIT_READY " - "to START_UNIT\n", USBDEVNAME(sc->sc_dev))); - cmd[0] = START_STOP_UNIT; - cmd[4] = SSS_START; - } - return 1; - case INQUIRY: - case START_STOP_UNIT: - case MODE_SENSE: - case PREVENT_ALLOW: - case READ_10: - case READ_12: - case READ_CAPACITY: - case REQUEST_SENSE: - case REZERO_UNIT: - case POSITION_TO_ELEMENT: /* SEEK_10 */ - case SEND_DIAGNOSTIC: - case WRITE_10: - case WRITE_12: - /* FORMAT_UNIT */ - /* MODE_SELECT */ - /* READ_FORMAT_CAPACITY */ - /* VERIFY */ - /* WRITE_AND_VERIFY */ - return 1; /* success */ - default: - return 0; /* success */ - } -} - -/* - * 8070 specific functions - */ -Static int -umass_8070_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, - unsigned char **rcmd, int *rcmdlen) -{ - return 0; /* failure */ -} - -#endif /* __FreeBSD__ */ - #ifdef UMASS_DEBUG Static void @@ -3065,11 +1723,13 @@ umass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw) int tag = UGETDW(cbw->dCBWTag); int flags = cbw->bCBWFlags; - DPRINTF(UDMASS_BBB, ("%s: CBW %d: cmd = %db " - "(0x%02x%02x%02x%02x%02x%02x%s), " + DPRINTF(UDMASS_BBB, ("%s: CBW %d: cmdlen=%d " + "(0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%s), " "data = %d bytes, dir = %s\n", USBDEVNAME(sc->sc_dev), tag, clen, - c[0], c[1], c[2], c[3], c[4], c[5], (clen > 6? "...":""), + c[0], c[1], c[2], c[3], c[4], c[5], + c[6], c[7], c[8], c[9], + (clen > 10? "...":""), dlen, (flags == CBWFLAGS_IN? "in": (flags == CBWFLAGS_OUT? "out":"<invalid>")))); } @@ -3119,482 +1779,3 @@ umass_dump_buffer(struct umass_softc *sc, u_int8_t *buffer, int buflen, USBDEVNAME(sc->sc_dev), s1, s2, s3)); } #endif - - - - - - - - -#if defined(__NetBSD__) || defined(__OpenBSD__) -Static int -umass_scsipi_cmd(xs) - struct scsipi_xfer *xs; -{ - struct scsipi_link *sc_link = xs->sc_link; - struct umass_softc *sc = sc_link->adapter_softc; - struct scsipi_generic *cmd, trcmd; - int cmdlen; - int dir; -#ifdef UMASS_DEBUG - microtime(&sc->tv); -#endif - - memset(&trcmd, 0, sizeof(trcmd)); - -#if defined(__NetBSD__) - DIF(UDMASS_UPPER, sc_link->flags |= DEBUGLEVEL); -#endif -#if defined(__OpenBSD__) - DIF(UDMASS_UPPER, sc_link->flags |= SCSIDEBUG_LEVEL); -#endif - -#if defined(__NetBSD__) || defined(__OpenBSD__) - DPRINTF(UDMASS_CMD, ("%s: umass_scsi_cmd: %d:%d xs=%p cmd=0x%02x " - "(quirks=0x%x, poll=%d)\n", USBDEVNAME(sc->sc_dev), - SCSI_LINK_TARGET(sc_link), SCSI_LINK_LUN(sc_link), - xs, xs->cmd->opcode, sc_link->quirks, - xs->xs_control & XS_CTL_POLL)); -#endif - -#if defined(USB_DEBUG) && defined(SCSIDEBUG) - if (umassdebug & UDMASS_SCSI) - show_scsipi_xs(xs); - else if (umassdebug & ~UDMASS_CMD) - show_scsipi_cmd(xs); -#endif - - if (sc->sc_dying) { - xs->error = XS_DRIVER_STUFFUP; - goto done; - } - -#ifdef UMASS_DEBUG -#if defined(__NetBSD__) - if ((sc_link->type == BUS_ATAPI ? - sc_link->scsipi_atapi.drive : SCSI_LINK_TARGET(sc_link)) - != UMASS_SCSIID_DEVICE) { - DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n", - USBDEVNAME(sc->sc_dev), - SCSI_LINK_TARGET(sc_link))); - xs->error = XS_DRIVER_STUFFUP; - goto done; - } -#endif -#if defined(__OpenBSD__) - if (sc_link->target != UMASS_SCSIID_DEVICE) { - DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n", - USBDEVNAME(sc->sc_dev), - sc_link->target)); - xs->error = XS_DRIVER_STUFFUP; - goto done; - } -#endif -#endif - - cmd = xs->cmd; - - if (xs->cmd->opcode == MODE_SENSE && - (sc_link->quirks & SDEV_NOMODESENSE)) { - /*printf("%s: MODE_SENSE\n", USBDEVNAME(sc->sc_dev));*/ - xs->error = XS_TIMEOUT; - goto done; - } - - if (xs->cmd->opcode == START_STOP && - (sc->quirks & NO_START_STOP)) { - /*printf("%s: START_STOP\n", USBDEVNAME(sc->sc_dev));*/ - xs->error = XS_NOERROR; - goto done; - } - - if (xs->cmd->opcode == INQUIRY && - (sc->quirks & FORCE_SHORT_INQUIRY)) { - memcpy(&trcmd, cmd, sizeof trcmd); - trcmd.bytes[4] = SHORT_INQUIRY_LENGTH; - cmd = &trcmd; - } - - dir = DIR_NONE; - if (xs->datalen) { - switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { - case XS_CTL_DATA_IN: - dir = DIR_IN; - break; - case XS_CTL_DATA_OUT: - dir = DIR_OUT; - break; - } - } - - if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) { - printf("umass_cmd: large datalen, %d\n", xs->datalen); - xs->error = XS_DRIVER_STUFFUP; - goto done; - } - - cmdlen = xs->cmdlen; - if (sc->proto & PROTO_UFI) { - if (!umass_ufi_transform(sc, cmd, cmdlen, &trcmd, &cmdlen)) { - xs->error = XS_DRIVER_STUFFUP; - goto done; - } - cmd= &trcmd; - } - - if (sc->proto & PROTO_ATAPI) { - bcopy(cmd, &trcmd, cmdlen); - cmd = &trcmd; - cmdlen = ATAPI_COMMAND_LENGTH; - } - - if (xs->xs_control & XS_CTL_POLL) { - /* Use sync transfer. XXX Broken! */ - DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: sync dir=%d\n", dir)); - sc->sc_xfer_flags = USBD_SYNCHRONOUS; - sc->sc_sync_status = USBD_INVAL; - sc->transfer(sc, SCSI_LINK_LUN(sc_link), cmd, cmdlen, - xs->data, xs->datalen, dir, 0, xs); - sc->sc_xfer_flags = 0; - DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n", - sc->sc_sync_status)); - switch (sc->sc_sync_status) { - case USBD_NORMAL_COMPLETION: - xs->error = XS_NOERROR; - break; - case USBD_TIMEOUT: - xs->error = XS_TIMEOUT; - break; - default: - xs->error = XS_DRIVER_STUFFUP; - break; - } - goto done; - } else { - DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: async dir=%d, cmdlen=%d" - " datalen=%d\n", - dir, cmdlen, xs->datalen)); - sc->transfer(sc, SCSI_LINK_LUN(sc_link), cmd, cmdlen, - xs->data, xs->datalen, dir, umass_scsipi_cb, xs); - return (SUCCESSFULLY_QUEUED); - } - - /* Return if command finishes early. */ - done: -#if defined(__NetBSD__) - xs->xs_status |= XS_STS_DONE; -#endif -#if defined(__OpenBSD__) - xs->flags |= ITSDONE; -#endif - - scsipi_done(xs); - if (xs->xs_control & XS_CTL_POLL) - return (COMPLETE); - else - return (SUCCESSFULLY_QUEUED); -} - -Static void -umass_scsipi_minphys(bp) - struct buf *bp; -{ - if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE) - bp->b_bcount = UMASS_MAX_TRANSFER_SIZE; - minphys(bp); -} - -int -umass_scsipi_ioctl(link, cmd, arg, flag, p) - struct scsipi_link *link; - u_long cmd; - caddr_t arg; - int flag; - struct proc *p; -{ - /*struct umass_softc *sc = link->adapter_softc;*/ - - switch (cmd) { -#if 0 - case SCBUSIORESET: - ccb->ccb_h.status = CAM_REQ_INPROG; - umass_reset(sc, umass_cam_cb, (void *) ccb); - return (0); -#endif - default: - return (ENOTTY); - } -} - -Static void -umass_scsipi_cb(struct umass_softc *sc, void *priv, int residue, int status) -{ - struct scsipi_xfer *xs = priv; - struct scsipi_link *sc_link = xs->sc_link; - int cmdlen; - int s; -#ifdef UMASS_DEBUG - struct timeval tv; - u_int delta; - microtime(&tv); - delta = (tv.tv_sec - sc->tv.tv_sec) * 1000000 + tv.tv_usec - sc->tv.tv_usec; -#endif - - DPRINTF(UDMASS_CMD,("umass_scsipi_cb: at %lu.%06lu, delta=%u: xs=%p residue=%d" - " status=%d\n", tv.tv_sec, tv.tv_usec, delta, xs, residue, status)); - xs->resid = residue; - - switch (status) { - case STATUS_CMD_OK: - xs->error = XS_NOERROR; - break; - - case STATUS_CMD_UNKNOWN: - case STATUS_CMD_FAILED: - /* fetch sense data */ - memset(&sc->sc_sense_cmd, 0, sizeof(sc->sc_sense_cmd)); - sc->sc_sense_cmd.opcode = REQUEST_SENSE; - sc->sc_sense_cmd.byte2 = SCSI_LINK_LUN(sc_link) << - SCSI_CMD_LUN_SHIFT; - sc->sc_sense_cmd.length = sizeof(xs->sense); - - cmdlen = sizeof(sc->sc_sense_cmd); - if (sc->proto & PROTO_UFI) - cmdlen = UFI_COMMAND_LENGTH; - else if (sc->proto & PROTO_ATAPI) - cmdlen = ATAPI_COMMAND_LENGTH; - - sc->transfer(sc, SCSI_LINK_LUN(sc_link), - &sc->sc_sense_cmd, cmdlen, - &xs->sense, sizeof(xs->sense), DIR_IN, - umass_scsipi_sense_cb, xs); - return; - - case STATUS_WIRE_FAILED: - xs->error = XS_RESET; - break; - - default: - panic("%s: Unknown status %d in umass_scsipi_cb", - USBDEVNAME(sc->sc_dev), status); - } - -#if defined(__NetBSD__) - xs->xs_status |= XS_STS_DONE; -#endif -#if defined(__OpenBSD__) - xs->flags |= ITSDONE; -#endif - - DPRINTF(UDMASS_CMD,("umass_scsipi_cb: at %lu.%06lu: return xs->error=" - "%d, xs->xs_status=0x%x xs->resid=%d\n", - tv.tv_sec, tv.tv_usec, - xs->error, xs->xs_status, xs->resid)); - - s = splbio(); - scsipi_done(xs); - splx(s); -} - -/* - * Finalise a completed autosense operation - */ -Static void -umass_scsipi_sense_cb(struct umass_softc *sc, void *priv, int residue, - int status) -{ - struct scsipi_xfer *xs = priv; - int s; - int bytes_received; - - DPRINTF(UDMASS_CMD,("umass_scsipi_sense_cb: xs=%p residue=%d " - "status=%d\n", xs, residue, status)); - - switch (status) { - case STATUS_CMD_OK: - case STATUS_CMD_UNKNOWN: - /* getting sense data succeeded */ - if ((xs->cmd->opcode == INQUIRY) - && (xs->resid < xs->datalen)) { - /* Some drivers return SENSE errors even after INQUIRY - * The upper layer doesn't like that. - */ - xs->error = XS_NOERROR; - break; - } - - bytes_received = sizeof(xs->sense) - residue; - - if (bytes_received < 8 || - (bytes_received < xs->sense.extra_len + 8)) - xs->error = XS_SHORTSENSE; - else - xs->error = XS_SENSE; - -#if defined(__OpenBSD__) - /* Note that this test may need to be revised - with QIC-157a/SCSI tape drives that return - ILI, EOM in the high bits of flags. - */ - if ((xs->sense.error_code & SSD_ERRCODE) == 0x70 && - (xs->sense.flags == 0)) - xs->error = XS_NOERROR; -#endif - - break; - default: - DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n", - USBDEVNAME(sc->sc_dev), status)); - xs->error = XS_DRIVER_STUFFUP; - break; - } - -#if defined(__NetBSD__) - xs->xs_status |= XS_STS_DONE; -#endif -#if defined(__OpenBSD__) - xs->flags |= ITSDONE; -#endif - - DPRINTF(UDMASS_CMD,("umass_scsipi_sense_cb: return xs->error=%d, " - "xs->xs_status=0x%x xs->resid=%d\n", xs->error, xs->xs_status, - xs->resid)); - - s = splbio(); - scsipi_done(xs); - splx(s); -} - -/* - * UFI specific functions - */ - -Static int -umass_ufi_transform(struct umass_softc *sc, struct scsipi_generic *cmd, - int cmdlen, struct scsipi_generic *rcmd, int *rcmdlen) -{ - *rcmdlen = UFI_COMMAND_LENGTH; - memset(rcmd, 0, sizeof *rcmd); - - /* Handle any quirks */ - if (cmd->opcode == TEST_UNIT_READY - && (sc->quirks & NO_TEST_UNIT_READY)) { - /* - * Some devices do not support this command. - * Start Stop Unit should give the same results - */ - DPRINTF(UDMASS_UFI, ("%s: Converted TEST_UNIT_READY " - "to START_UNIT\n", USBDEVNAME(sc->sc_dev))); - rcmd->opcode = START_STOP; - rcmd->bytes[3] = SSS_START; - return 1; - } - - switch (cmd->opcode) { - /* Commands of which the format has been verified. They should work. */ - case TEST_UNIT_READY: - case REZERO_UNIT: - case REQUEST_SENSE: - case INQUIRY: - case START_STOP: - /*case SEND_DIAGNOSTIC: ??*/ - case PREVENT_ALLOW: - case READ_CAPACITY: - case READ_BIG: - case WRITE_BIG: - case POSITION_TO_ELEMENT: /* SEEK_10 */ - case MODE_SELECT_BIG: - case MODE_SENSE_BIG: - default: - /* Copy the command into the (zeroed out) destination buffer */ - memcpy(rcmd, cmd, cmdlen); - return (1); /* success */ - - /* - * Other UFI commands: FORMAT_UNIT, MODE_SELECT, READ_FORMAT_CAPACITY, - * VERIFY, WRITE_AND_VERIFY. - * These should be checked whether they somehow can be made to fit. - */ - - /* These commands are known _not_ to work. They should be converted. */ - case READ_COMMAND: - case WRITE_COMMAND: - case MODE_SENSE: - case MODE_SELECT: - printf("%s: Unsupported UFI command 0x%02x", - USBDEVNAME(sc->sc_dev), cmd->opcode); - if (cmdlen == 6) - printf(", 6 byte command should have been converted"); - printf("\n"); - return (0); /* failure */ - } -} - - -#if NATAPIBUS > 0 -Static void -umass_atapi_probedev(atapi, target) - struct atapibus_softc *atapi; - int target; -{ - struct scsipi_link *sc_link; - struct scsipibus_attach_args sa; - struct ata_drive_datas *drvp = &atapi->sc_drvs[target]; - char vendor[33], product[65], revision[17]; - struct scsipi_inquiry_data inqbuf; - - DPRINTF(UDMASS_SCSI,("umass_atapi_probedev: atapi=%p target=%d\n", - atapi, target)); - - if (atapi->sc_link[target]) - return; - - sc_link = malloc(sizeof(*sc_link), M_DEVBUF, M_NOWAIT); - if (sc_link == NULL) { - printf("%s: can't allocate link for drive %d\n", - atapi->sc_dev.dv_xname, target); - return; - } - *sc_link = *atapi->adapter_link; - - DIF(UDMASS_UPPER, sc_link->flags |= DEBUGLEVEL); - - /* Fill generic parts of the link. */ - sc_link->active = 0; - sc_link->scsipi_atapi.drive = target; - sc_link->device = &umass_dev; - TAILQ_INIT(&sc_link->pending_xfers); - - DPRINTF(UDMASS_SCSI, ("umass_atapi_probedev: doing inquiry\n")); - /* Now go ask the device all about itself. */ - memset(&inqbuf, 0, sizeof(inqbuf)); - if (scsipi_inquire(sc_link, &inqbuf, XS_CTL_DISCOVERY) != 0) - goto bad; - - scsipi_strvis(vendor, 33, inqbuf.vendor, 8); - scsipi_strvis(product, 65, inqbuf.product, 16); - scsipi_strvis(revision, 17, inqbuf.revision, 4); - - sa.sa_sc_link = sc_link; - sa.sa_inqbuf.type = inqbuf.device; - sa.sa_inqbuf.removable = inqbuf.dev_qual2 & SID_REMOVABLE ? - T_REMOV : T_FIXED; - if (sa.sa_inqbuf.removable) - sc_link->flags |= SDEV_REMOVABLE; - /* XXX how? sc_link->scsipi_atapi.cap |= ACAP_LEN;*/ - sa.sa_inqbuf.vendor = vendor; - sa.sa_inqbuf.product = product; - sa.sa_inqbuf.revision = revision; - sa.sa_inqptr = NULL; - - drvp->drv_softc = atapi_probedev(atapi, target, sc_link, &sa); - /* atapi_probedev() frees the scsipi_link when there is no device. */ - return; - -bad: - free(sc_link, M_DEVBUF); - return; -} -#endif -#endif diff --git a/sys/dev/usb/umass_quirks.c b/sys/dev/usb/umass_quirks.c new file mode 100644 index 00000000000..95f07084eda --- /dev/null +++ b/sys/dev/usb/umass_quirks.c @@ -0,0 +1,484 @@ +/* $OpenBSD: umass_quirks.c,v 1.3 2003/05/17 06:07:57 nate Exp $ */ +/* $NetBSD: umass_quirks.c,v 1.39 2003/05/08 15:19:47 augustss Exp $ */ + +/* + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by MAEKAWA Masahide (gehenna@NetBSD.org). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/buf.h> + +#if defined(__NetBSD__) +#include <dev/scsipi/scsipi_all.h> /* for scsiconf.h below */ +#include <dev/scsipi/scsiconf.h> /* for quirks defines */ +#elif defined(__OpenBSD__) +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#endif + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdevs.h> + +#include <dev/usb/umassvar.h> +#include <dev/usb/umass_quirks.h> + +Static usbd_status umass_init_insystem(struct umass_softc *); +Static usbd_status umass_init_shuttle(struct umass_softc *); + +Static void umass_fixup_sony(struct umass_softc *); +Static void umass_fixup_yedata(struct umass_softc *); + +Static const struct umass_quirk umass_quirks[] = { + { { USB_VENDOR_ATI, USB_PRODUCT_ATI2_205 }, + UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA, + 0, + 0, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_DMI, USB_PRODUCT_DMI_SA2_0 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_EASYDISK, USB_PRODUCT_EASYDISK_EASYDISK }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_FUJIPHOTO, USB_PRODUCT_FUJIPHOTO_MASS0100 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_NO_START_STOP, + PQUIRK_NOTUR | PQUIRK_NOSENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_FORCE_SHORT_INQUIRY | UMASS_QUIRK_NO_START_STOP, + PQUIRK_NOMODESENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_HP, USB_PRODUCT_HP_CDWRITERPLUS }, + UMASS_WPROTO_CBI, UMASS_CPROTO_ATAPI, + 0, + PQUIRK_NOSENSE | PQUIRK_NOMODESENSE, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_ADAPTERV2 }, + UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA, + 0, + 0, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_ATAPI }, + UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA, + 0, + 0, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_DRIVEV2_5 }, + UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA, + 0, + 0, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_IDEUSB2 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_USBCABLE }, + UMASS_WPROTO_CBI, UMASS_CPROTO_ATAPI, + UMASS_QUIRK_NO_START_STOP, + PQUIRK_NOTUR, + UMATCH_VENDOR_PRODUCT, + umass_init_insystem, NULL + }, + + { { USB_VENDOR_IODATA2, USB_PRODUCT_IODATA2_USB2SC }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + 0, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_IOMEGA, USB_PRODUCT_IOMEGA_ZIP100 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOTUR, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_IOMEGA, USB_PRODUCT_IOMEGA_ZIP250 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOTUR, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_DUBPXXG }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_FORCE_SHORT_INQUIRY | UMASS_QUIRK_NO_START_STOP, + PQUIRK_NOMODESENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_DPCM }, + UMASS_WPROTO_CBI, UMASS_CPROTO_ATAPI, + 0, + PQUIRK_NOTUR, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_MINOLTA, USB_PRODUCT_MINOLTA_S304 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_NO_MAX_LUN | UMASS_QUIRK_NO_START_STOP, + 0, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_MINOLTA, USB_PRODUCT_MINOLTA_X }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_NO_MAX_LUN | UMASS_QUIRK_NO_START_STOP, + 0, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_NO_MAX_LUN, + PQUIRK_NOMODESENSE | PQUIRK_NODOORLOCK | PQUIRK_NOBIGMODESENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY2 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_NO_MAX_LUN, + PQUIRK_NOMODESENSE | PQUIRK_NODOORLOCK | PQUIRK_NOBIGMODESENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_NEODIO, USB_PRODUCT_NEODIO_ND3050 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE | PQUIRK_FORCELUNS, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_NEODIO, USB_PRODUCT_NEODIO_ND5010 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE | PQUIRK_FORCELUNS, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_OLYMPUS, USB_PRODUCT_OLYMPUS_C1 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_WRONG_CSWSIG, + 0, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_OLYMPUS, USB_PRODUCT_OLYMPUS_C700 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_ONLYBIG | SDEV_NOSYNCCACHE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_MD1II }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_NO_MAX_LUN | UMASS_QUIRK_NO_START_STOP, + PQUIRK_NOMODESENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_MD2 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_OTI, USB_PRODUCT_OTI_SOLID }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE | PQUIRK_NOBIGMODESENSE, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_PEN, USB_PRODUCT_PEN_MOBILEDRIVE }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE | PQUIRK_NODOORLOCK | PQUIRK_FORCELUNS, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_PEN, USB_PRODUCT_PEN_USBDISK }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_NO_MAX_LUN | UMASS_QUIRK_NO_START_STOP, + 0, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_PEN, USB_PRODUCT_PEN_USBREADER }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_PILOTECH, USB_PRODUCT_PILOTECH_CRW600 }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE | PQUIRK_FORCELUNS, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_PQI, USB_PRODUCT_PQI_TRAVELFLASH }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE | PQUIRK_NODOORLOCK, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_SL11R }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UFI, + UMASS_QUIRK_WRONG_CSWTAG, + 0, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSB }, + UMASS_WPROTO_CBI_I, UMASS_CPROTO_ATAPI, + UMASS_QUIRK_NO_START_STOP, + PQUIRK_NOTUR, + UMATCH_VENDOR_PRODUCT, + umass_init_shuttle, NULL + }, + + { { USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_ZIOMMC }, + UMASS_WPROTO_CBI_I, UMASS_CPROTO_ATAPI, + UMASS_QUIRK_NO_START_STOP, + PQUIRK_NOTUR, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_SIIG, USB_PRODUCT_SIIG_MULTICARDREADER }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + UMASS_QUIRK_NO_START_STOP, + 0, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL,NULL + }, + + { { USB_VENDOR_SONY, USB_PRODUCT_SONY_DRIVEV2 }, + UMASS_WPROTO_BBB, UMASS_CPROTO_ISD_ATA, + 0, + 0, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + 0, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, umass_fixup_sony + }, + + { { USB_VENDOR_SONY, USB_PRODUCT_SONY_MSC }, + UMASS_WPROTO_CBI, UMASS_CPROTO_UFI, + UMASS_QUIRK_FORCE_SHORT_INQUIRY | UMASS_QUIRK_RS_NO_CLEAR_UA, + PQUIRK_NOMODESENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_TEAC, USB_PRODUCT_TEAC_FD05PUB }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UNSPEC, + 0, + PQUIRK_NOMODESENSE, + UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO, + NULL, NULL + }, + + { { USB_VENDOR_TRUMPION, USB_PRODUCT_TRUMPION_XXX1100 }, + UMASS_WPROTO_CBI, UMASS_CPROTO_ATAPI, + 0, + 0, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_YANO, USB_PRODUCT_YANO_U640MO }, + UMASS_WPROTO_CBI_I, UMASS_CPROTO_ATAPI, + UMASS_QUIRK_FORCE_SHORT_INQUIRY, + 0, + UMATCH_VENDOR_PRODUCT, + NULL, NULL + }, + + { { USB_VENDOR_YEDATA, USB_PRODUCT_YEDATA_FLASHBUSTERU }, + UMASS_WPROTO_UNSPEC, UMASS_CPROTO_UFI, + UMASS_QUIRK_RS_NO_CLEAR_UA, + PQUIRK_NOMODESENSE, + UMATCH_VENDOR_PRODUCT_REV, + NULL, umass_fixup_yedata + }, + +}; + +const struct umass_quirk * +umass_lookup(u_int16_t vendor, u_int16_t product) +{ + return ((const struct umass_quirk *) + usb_lookup(umass_quirks, vendor, product)); +} + +Static usbd_status +umass_init_insystem(struct umass_softc *sc) +{ + usbd_status err; + + err = usbd_set_interface(sc->sc_iface, 1); + if (err) { + DPRINTF(UDMASS_USB, + ("%s: could not switch to Alt Interface 1\n", + USBDEVNAME(sc->sc_dev))); + return (err); + } + + return (USBD_NORMAL_COMPLETION); +} + +Static usbd_status +umass_init_shuttle(struct umass_softc *sc) +{ + usb_device_request_t req; + u_int8_t status[2]; + + /* The Linux driver does this */ + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = 1; + USETW(req.wValue, 0); + USETW(req.wIndex, sc->sc_ifaceno); + USETW(req.wLength, sizeof(status)); + + return (usbd_do_request(sc->sc_udev, &req, &status)); +} + +Static void +umass_fixup_sony(struct umass_softc *sc) +{ + usb_interface_descriptor_t *id; + + id = usbd_get_interface_descriptor(sc->sc_iface); + if (id->bInterfaceSubClass == 0xff) { + sc->sc_cmd = UMASS_CPROTO_RBC; + } +} + +Static void +umass_fixup_yedata(struct umass_softc *sc) +{ + usb_device_descriptor_t *dd; + + dd = usbd_get_device_descriptor(sc->sc_udev); + + /* + * Revisions < 1.28 do not handle the interrupt endpoint very well. + */ + if (UGETW(dd->bcdDevice) < 0x128) + sc->sc_wire = UMASS_WPROTO_CBI; + else + sc->sc_wire = UMASS_WPROTO_CBI_I; + + /* + * Revisions < 1.28 do not have the TEST UNIT READY command + * Revisions == 1.28 have a broken TEST UNIT READY + */ + if (UGETW(dd->bcdDevice) <= 0x128) + sc->sc_busquirks |= PQUIRK_NOTUR; +} diff --git a/sys/dev/usb/umass_quirks.h b/sys/dev/usb/umass_quirks.h new file mode 100644 index 00000000000..f8fb586b3c3 --- /dev/null +++ b/sys/dev/usb/umass_quirks.h @@ -0,0 +1,62 @@ +/* $OpenBSD: umass_quirks.h,v 1.3 2003/05/17 06:07:57 nate Exp $ */ +/* $NetBSD: umass_quirks.h,v 1.3 2001/12/29 13:46:23 augustss Exp $ */ + +/* + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by MAEKAWA Masahide (gehenna@NetBSD.org). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef _DEV_USB_UMASS_QUIRKS_H_ +#define _DEV_USB_UMASS_QUIRKS_H_ + +typedef usbd_status (*umass_init_quirk)(struct umass_softc *); +typedef void (*umass_fixup_quirk)(struct umass_softc *); + +struct umass_quirk { + struct usb_devno uq_dev; + + u_int8_t uq_wire; + u_int8_t uq_cmd; + u_int32_t uq_flags; + u_int32_t uq_busquirks; + int uq_match; + + umass_init_quirk uq_init; + umass_fixup_quirk uq_fixup; +}; + +const struct umass_quirk *umass_lookup(u_int16_t, u_int16_t); + +#endif /* _DEV_USB_UMASS_QUIRKS_H_ */ diff --git a/sys/dev/usb/umass_scsi.c b/sys/dev/usb/umass_scsi.c new file mode 100644 index 00000000000..0c7f4b91f5c --- /dev/null +++ b/sys/dev/usb/umass_scsi.c @@ -0,0 +1,464 @@ +/* $OpenBSD: umass_scsi.c,v 1.3 2003/05/17 06:07:57 nate Exp $ */ +/* $NetBSD: umass_scsipi.c,v 1.9 2003/02/16 23:14:08 augustss Exp $ */ +/* + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "atapiscsi.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/buf.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/malloc.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> +#include <dev/usb/usbdevs.h> + +#include <dev/usb/umassvar.h> +#include <dev/usb/umass_scsi.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#include <scsi/scsi_disk.h> +#include <machine/bus.h> + +struct umass_scsi_softc { + struct umassbus_softc base; + struct scsi_link sc_link; + struct scsi_adapter sc_adapter; + + usbd_status sc_sync_status; + struct scsi_sense sc_sense_cmd; +}; + + +#define SHORT_INQUIRY_LENGTH 36 /* XXX */ + +#define UMASS_SCSIID_HOST 0x00 +#define UMASS_SCSIID_DEVICE 0x01 + +#define UMASS_ATAPI_DRIVE 0 + +int umass_scsi_cmd(struct scsi_xfer *); +void umass_scsi_minphys(struct buf *); + +void umass_scsi_cb(struct umass_softc *sc, void *priv, int residue, + int status); +void umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue, + int status); +struct umass_scsi_softc *umass_scsi_setup(struct umass_softc *); + +struct scsi_device umass_scsi_dev = { NULL, NULL, NULL, NULL, }; + +#if NATAPISCSI > 0 +struct scsi_device umass_atapiscsi_dev = { NULL, NULL, NULL, NULL, }; +#endif + +int +umass_scsi_attach(struct umass_softc *sc) +{ + struct umass_scsi_softc *scbus; + + scbus = umass_scsi_setup(sc); + scbus->sc_link.adapter_target = UMASS_SCSIID_HOST; + scbus->sc_link.luns = sc->maxlun + 1; + scbus->sc_link.flags &= ~SDEV_ATAPI; + scbus->sc_link.device = &umass_scsi_dev; + + DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: SCSI\n" + "sc = 0x%x, scbus = 0x%x\n", + USBDEVNAME(sc->sc_dev), sc, scbus)); + + sc->sc_refcnt++; + scbus->base.sc_child = + config_found((struct device *)sc, &scbus->sc_link, scsiprint); + if (--sc->sc_refcnt < 0) + usb_detach_wakeup(USBDEV(sc->sc_dev)); + + return (0); +} + +#if NATAPISCSI > 0 +int +umass_atapi_attach(struct umass_softc *sc) +{ + struct umass_scsi_softc *scbus; + + scbus = umass_scsi_setup(sc); + scbus->sc_link.adapter_target = UMASS_SCSIID_HOST; + scbus->sc_link.luns = 1; + scbus->sc_link.flags |= SDEV_ATAPI; + scbus->sc_link.quirks |= SDEV_NOLUNS; + scbus->sc_link.device = &umass_atapiscsi_dev; + + DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: ATAPI\n" + "sc = 0x%x, scbus = 0x%x\n", + USBDEVNAME(sc->sc_dev), sc, scbus)); + + sc->sc_refcnt++; + scbus->base.sc_child = + config_found((struct device *)sc, &scbus->sc_link, scsiprint); + if (--sc->sc_refcnt < 0) + usb_detach_wakeup(USBDEV(sc->sc_dev)); + + return (0); +} +#endif + +struct umass_scsi_softc * +umass_scsi_setup(struct umass_softc *sc) +{ + struct umass_scsi_softc *scbus; + + scbus = malloc(sizeof(struct umass_scsi_softc), M_DEVBUF, M_WAITOK); + memset(&scbus->sc_link, 0, sizeof(struct scsi_link)); + memset(&scbus->sc_adapter, 0, sizeof(struct scsi_adapter)); + + sc->bus = (struct umassbus_softc *)scbus; + + /* Fill in the adapter. */ + scbus->sc_adapter.scsi_cmd = umass_scsi_cmd; + scbus->sc_adapter.scsi_minphys = umass_scsi_minphys; + + /* Fill in the link. */ + scbus->sc_link.adapter_buswidth = 2; + scbus->sc_link.openings = 1; + scbus->sc_link.adapter = &scbus->sc_adapter; + scbus->sc_link.adapter_softc = sc; + scbus->sc_link.openings = 1; + scbus->sc_link.quirks |= PQUIRK_ONLYBIG | PQUIRK_NOMODESENSE | + sc->sc_busquirks; + + return (scbus); +} + +int +umass_scsi_cmd(struct scsi_xfer *xs) +{ + struct scsi_link *sc_link = xs->sc_link; + struct umass_softc *sc = sc_link->adapter_softc; + struct umass_scsi_softc *scbus = (struct umass_scsi_softc *)sc->bus; + + struct scsi_generic *cmd, trcmd; + int cmdlen, dir, s; + +#ifdef UMASS_DEBUG + microtime(&sc->tv); +#endif + + memset(&trcmd, 0, sizeof(trcmd)); + + DIF(UDMASS_UPPER, sc_link->flags |= SCSIDEBUG_LEVEL); + + DPRINTF(UDMASS_CMD, ("%s: umass_scsi_cmd: at %lu.%06lu: %d:%d " + "xs=%p cmd=0x%02x datalen=%d (quirks=0x%x, poll=%d)\n", + USBDEVNAME(sc->sc_dev), sc->tv.tv_sec, sc->tv.tv_usec, + sc_link->target, sc_link->lun, xs, xs->cmd->opcode, + xs->datalen, sc_link->quirks, xs->flags & SCSI_POLL)); + +#if defined(USB_DEBUG) && defined(SCSIDEBUG) + if (umassdebug & UDMASS_SCSI) + show_scsi_xs(xs); + else if (umassdebug & ~UDMASS_CMD) + show_scsi_cmd(xs); +#endif + + if (sc->sc_dying) { + xs->error = XS_DRIVER_STUFFUP; + goto done; + } + +#if defined(UMASS_DEBUG) + if (sc_link->target != UMASS_SCSIID_DEVICE) { + DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n", + USBDEVNAME(sc->sc_dev), sc_link->target)); + xs->error = XS_DRIVER_STUFFUP; + goto done; + } +#endif + + cmd = xs->cmd; + cmdlen = xs->cmdlen; + + if (cmd->opcode == MODE_SENSE && + (sc_link->quirks & SDEV_NOMODESENSE)) { + xs->error = XS_TIMEOUT; + goto done; + } + + if (cmd->opcode == START_STOP && + (sc->sc_quirks & UMASS_QUIRK_NO_START_STOP)) { + xs->error = XS_NOERROR; + goto done; + } + + if (cmd->opcode == INQUIRY && + (sc->sc_quirks & UMASS_QUIRK_FORCE_SHORT_INQUIRY)) { + /* + * Some drives wedge when asked for full inquiry + * information. + */ + memcpy(&trcmd, cmd, sizeof(trcmd)); + trcmd.bytes[4] = SHORT_INQUIRY_LENGTH; + cmd = &trcmd; + xs->datalen = SHORT_INQUIRY_LENGTH; + } + + dir = DIR_NONE; + if (xs->datalen) { + switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { + case SCSI_DATA_IN: + dir = DIR_IN; + break; + case SCSI_DATA_OUT: + dir = DIR_OUT; + break; + } + } + + if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) { + printf("umass_cmd: large datalen, %d\n", xs->datalen); + xs->error = XS_DRIVER_STUFFUP; + goto done; + } + + if (xs->flags & SCSI_POLL) { + /* Use sync transfer. XXX Broken! */ + DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: sync dir=%d\n", dir)); + sc->sc_xfer_flags = USBD_SYNCHRONOUS; + scbus->sc_sync_status = USBD_INVAL; + sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen, + xs->data, xs->datalen, dir, + xs->timeout, 0, xs); + sc->sc_xfer_flags = 0; + DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n", + scbus->sc_sync_status)); + switch (scbus->sc_sync_status) { + case USBD_NORMAL_COMPLETION: + xs->error = XS_NOERROR; + break; + case USBD_TIMEOUT: + xs->error = XS_TIMEOUT; + break; + default: + xs->error = XS_DRIVER_STUFFUP; + break; + } + goto done; + } else { + DPRINTF(UDMASS_SCSI, + ("umass_scsi_cmd: async dir=%d, cmdlen=%d" + " datalen=%d\n", + dir, cmdlen, xs->datalen)); + sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen, + xs->data, xs->datalen, dir, + xs->timeout, umass_scsi_cb, xs); + return (SUCCESSFULLY_QUEUED); + } + + /* Return if command finishes early. */ + done: + xs->flags |= ITSDONE; + + s = splbio(); + scsi_done(xs); + splx(s); + if (xs->flags & SCSI_POLL) + return (COMPLETE); + else + return (SUCCESSFULLY_QUEUED); +} + +void +umass_scsi_minphys(struct buf *bp) +{ + if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE) + bp->b_bcount = UMASS_MAX_TRANSFER_SIZE; + + minphys(bp); +} + +void +umass_scsi_cb(struct umass_softc *sc, void *priv, int residue, int status) +{ + struct umass_scsi_softc *scbus = (struct umass_scsi_softc *)sc->bus; + struct scsi_xfer *xs = priv; + struct scsi_link *link = xs->sc_link; + int cmdlen; + int s; +#ifdef UMASS_DEBUG + struct timeval tv; + u_int delta; + microtime(&tv); + delta = (tv.tv_sec - sc->tv.tv_sec) * 1000000 + + tv.tv_usec - sc->tv.tv_usec; +#endif + + DPRINTF(UDMASS_CMD, + ("umass_scsi_cb: at %lu.%06lu, delta=%u: xs=%p residue=%d" + " status=%d\n", tv.tv_sec, tv.tv_usec, delta, xs, residue, + status)); + + xs->resid = residue; + + switch (status) { + case STATUS_CMD_OK: + xs->error = XS_NOERROR; + break; + + case STATUS_CMD_UNKNOWN: + DPRINTF(UDMASS_CMD, ("umass_scsi_cb: status cmd unknown\n")); + /* we can't issue REQUEST SENSE */ + if (xs->sc_link->quirks & PQUIRK_NOSENSE) { + /* + * If no residue and no other USB error, + * command succeeded. + */ + if (residue == 0) { + xs->error = XS_NOERROR; + break; + } + + /* + * Some devices return a short INQUIRY + * response, omitting response data from the + * "vendor specific data" on... + */ + if (xs->cmd->opcode == INQUIRY && + residue < xs->datalen) { + xs->error = XS_NOERROR; + break; + } + + xs->error = XS_DRIVER_STUFFUP; + break; + } + /* FALLTHROUGH */ + case STATUS_CMD_FAILED: + printf("umass_scsi_cb: status cmd failed\n"); + /* fetch sense data */ + memset(&scbus->sc_sense_cmd, 0, sizeof(scbus->sc_sense_cmd)); + scbus->sc_sense_cmd.opcode = REQUEST_SENSE; + scbus->sc_sense_cmd.byte2 = link->lun << SCSI_CMD_LUN_SHIFT; + scbus->sc_sense_cmd.length = sizeof(xs->sense); + + cmdlen = sizeof(scbus->sc_sense_cmd); + if (sc->sc_cmd == UMASS_CPROTO_UFI) /* XXX */ + cmdlen = UFI_COMMAND_LENGTH; + sc->sc_methods->wire_xfer(sc, link->lun, + &scbus->sc_sense_cmd, cmdlen, + &xs->sense, sizeof(xs->sense), + DIR_IN, xs->timeout, + umass_scsi_sense_cb, xs); + return; + + case STATUS_WIRE_FAILED: + xs->error = XS_RESET; + break; + + default: + panic("%s: Unknown status %d in umass_scsi_cb", + USBDEVNAME(sc->sc_dev), status); + } + + xs->flags |= ITSDONE; + + DPRINTF(UDMASS_CMD,("umass_scsi_cb: at %lu.%06lu: return error=%d, " + "status=0x%x resid=%d\n", + tv.tv_sec, tv.tv_usec, + xs->error, xs->status, xs->resid)); + + s = splbio(); + scsi_done(xs); + splx(s); +} + +/* + * Finalise a completed autosense operation + */ +void +umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue, + int status) +{ + struct scsi_xfer *xs = priv; + int s; + + DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: xs=%p residue=%d " + "status=%d\n", xs, residue, status)); + + switch (status) { + case STATUS_CMD_OK: + case STATUS_CMD_UNKNOWN: + /* getting sense data succeeded */ + if (xs->cmd->opcode == INQUIRY && (xs->resid < xs->datalen || + (sc->sc_quirks & UMASS_QUIRK_RS_NO_CLEAR_UA /* XXX */))) { + /* + * Some drivers return SENSE errors even after INQUIRY. + * The upper layer doesn't like that. + */ + xs->error = XS_NOERROR; + break; + } + /* XXX look at residue */ + if (residue == 0 || residue == 14)/* XXX */ + xs->error = XS_SENSE; + else + xs->error = XS_SHORTSENSE; + break; + default: + DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n", + USBDEVNAME(sc->sc_dev), status)); + xs->error = XS_DRIVER_STUFFUP; + break; + } + + xs->flags |= ITSDONE; + + DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: return xs->error=%d, " + "xs->flags=0x%x xs->resid=%d\n", xs->error, xs->status, + xs->resid)); + + s = splbio(); + scsi_done(xs); + splx(s); +} + diff --git a/sys/dev/usb/umass_scsi.h b/sys/dev/usb/umass_scsi.h new file mode 100644 index 00000000000..73961b59454 --- /dev/null +++ b/sys/dev/usb/umass_scsi.h @@ -0,0 +1,42 @@ +/* $OpenBSD: umass_scsi.h,v 1.3 2003/05/17 06:07:57 nate Exp $ */ +/* $NetBSD: umass_scsipi.h,v 1.1 2001/12/24 13:25:53 augustss Exp $ */ + +/* + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +int umass_scsi_attach(struct umass_softc *sc); +int umass_atapi_attach(struct umass_softc *sc); diff --git a/sys/dev/usb/umassvar.h b/sys/dev/usb/umassvar.h new file mode 100644 index 00000000000..e7636bfc4f3 --- /dev/null +++ b/sys/dev/usb/umassvar.h @@ -0,0 +1,272 @@ +/* $OpenBSD: umassvar.h,v 1.3 2003/05/17 06:07:57 nate Exp $ */ +/* $NetBSD: umassvar.h,v 1.19 2003/02/22 05:18:50 tsutsui Exp $ */ +/*- + * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>, + * Nick Hibma <n_hibma@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/usb/umass.c,v 1.13 2000/03/26 01:39:12 n_hibma Exp $ + */ + +#ifdef UMASS_DEBUG +#define DIF(m, x) if (umassdebug & (m)) do { x ; } while (0) +#define DPRINTF(m, x) if (umassdebug & (m)) logprintf x +#define UDMASS_UPPER 0x00008000 /* upper layer */ +#define UDMASS_GEN 0x00010000 /* general */ +#define UDMASS_SCSI 0x00020000 /* scsi */ +#define UDMASS_UFI 0x00040000 /* ufi command set */ +#define UDMASS_8070 0x00080000 /* 8070i command set */ +#define UDMASS_USB 0x00100000 /* USB general */ +#define UDMASS_BBB 0x00200000 /* Bulk-Only transfers */ +#define UDMASS_CBI 0x00400000 /* CBI transfers */ +#define UDMASS_ALL 0xffff0000 /* all of the above */ + +#define UDMASS_XFER 0x40000000 /* all transfers */ +#define UDMASS_CMD 0x80000000 + +extern int umassdebug; +#else +#define DIF(m, x) /* nop */ +#define DPRINTF(m, x) /* nop */ +#endif + +/* Generic definitions */ + +#define UFI_COMMAND_LENGTH 12 + +/* Direction for umass_*_transfer */ +#define DIR_NONE 0 +#define DIR_IN 1 +#define DIR_OUT 2 + +/* Endpoints for umass */ +#define UMASS_BULKIN 0 +#define UMASS_BULKOUT 1 +#define UMASS_INTRIN 2 +#define UMASS_NEP 3 + +/* Bulk-Only features */ + +#define UR_BBB_RESET 0xff /* Bulk-Only reset */ +#define UR_BBB_GET_MAX_LUN 0xfe + +/* Command Block Wrapper */ +typedef struct { + uDWord dCBWSignature; +#define CBWSIGNATURE 0x43425355 + uDWord dCBWTag; + uDWord dCBWDataTransferLength; + uByte bCBWFlags; +#define CBWFLAGS_OUT 0x00 +#define CBWFLAGS_IN 0x80 + uByte bCBWLUN; + uByte bCDBLength; +#define CBWCDBLENGTH 16 + uByte CBWCDB[CBWCDBLENGTH]; +} umass_bbb_cbw_t; +#define UMASS_BBB_CBW_SIZE 31 + +/* Command Status Wrapper */ +typedef struct { + uDWord dCSWSignature; +#define CSWSIGNATURE 0x53425355 +#define CSWSIGNATURE_OLYMPUS_C1 0x55425355 + uDWord dCSWTag; + uDWord dCSWDataResidue; + uByte bCSWStatus; +#define CSWSTATUS_GOOD 0x0 +#define CSWSTATUS_FAILED 0x1 +#define CSWSTATUS_PHASE 0x2 +} umass_bbb_csw_t; +#define UMASS_BBB_CSW_SIZE 13 + +/* CBI features */ + +#define UR_CBI_ADSC 0x00 + +typedef unsigned char umass_cbi_cbl_t[16]; /* Command block */ + +typedef union { + struct { + uByte type; +#define IDB_TYPE_CCI 0x00 + uByte value; +#define IDB_VALUE_PASS 0x00 +#define IDB_VALUE_FAIL 0x01 +#define IDB_VALUE_PHASE 0x02 +#define IDB_VALUE_PERSISTENT 0x03 +#define IDB_VALUE_STATUS_MASK 0x03 + } common; + + struct { + uByte asc; + uByte ascq; + } ufi; +} umass_cbi_sbl_t; + +struct umass_softc; /* see below */ + +typedef void (*umass_callback)(struct umass_softc *, void *, int, int); +#define STATUS_CMD_OK 0 /* everything ok */ +#define STATUS_CMD_UNKNOWN 1 /* will have to fetch sense */ +#define STATUS_CMD_FAILED 2 /* transfer was ok, command failed */ +#define STATUS_WIRE_FAILED 3 /* couldn't even get command across */ + +typedef void (*umass_wire_xfer)(struct umass_softc *, int, void *, int, void *, + int, int, u_int, umass_callback, void *); +typedef void (*umass_wire_reset)(struct umass_softc *, int); +typedef void (*umass_wire_state)(usbd_xfer_handle, usbd_private_handle, + usbd_status); + +struct umass_wire_methods { + umass_wire_xfer wire_xfer; + umass_wire_reset wire_reset; + umass_wire_state wire_state; +}; + +struct umassbus_softc { + device_ptr_t sc_child; /* child device, for detach */ +}; + +/* the per device structure */ +struct umass_softc { + USBBASEDEVICE sc_dev; /* base device */ + usbd_device_handle sc_udev; /* device */ + usbd_interface_handle sc_iface; /* interface */ + int sc_ifaceno; /* interface number */ + + u_int8_t sc_epaddr[UMASS_NEP]; + usbd_pipe_handle sc_pipe[UMASS_NEP]; + usb_device_request_t sc_req; + + const struct umass_wire_methods *sc_methods; + + u_int8_t sc_wire; /* wire protocol */ +#define UMASS_WPROTO_UNSPEC 0 +#define UMASS_WPROTO_BBB 1 +#define UMASS_WPROTO_CBI 2 +#define UMASS_WPROTO_CBI_I 3 + + u_int8_t sc_cmd; /* command protocol */ +#define UMASS_CPROTO_UNSPEC 0 +#define UMASS_CPROTO_SCSI 1 +#define UMASS_CPROTO_ATAPI 2 +#define UMASS_CPROTO_UFI 3 +#define UMASS_CPROTO_RBC 4 +#define UMASS_CPROTO_ISD_ATA 5 + + u_int32_t sc_quirks; +#define UMASS_QUIRK_RS_NO_CLEAR_UA 0x00000002 +#define UMASS_QUIRK_NO_START_STOP 0x00000004 +#define UMASS_QUIRK_FORCE_SHORT_INQUIRY 0x00000008 +#define UMASS_QUIRK_WRONG_CSWSIG 0x00000010 +#define UMASS_QUIRK_NO_MAX_LUN 0x00000020 +#define UMASS_QUIRK_WRONG_CSWTAG 0x00000040 + + u_int32_t sc_busquirks; + + /* Bulk specific variables for transfers in progress */ + umass_bbb_cbw_t cbw; /* command block wrapper */ + umass_bbb_csw_t csw; /* command status wrapper*/ + /* CBI specific variables for transfers in progress */ + umass_cbi_cbl_t cbl; /* command block */ + umass_cbi_sbl_t sbl; /* status block */ + + /* xfer handles + * Most of our operations are initiated from interrupt context, so + * we need to avoid using the one that is in use. We want to avoid + * allocating them in the interrupt context as well. + */ + /* indices into array below */ +#define XFER_BBB_CBW 0 /* Bulk-Only */ +#define XFER_BBB_DATA 1 +#define XFER_BBB_DCLEAR 2 +#define XFER_BBB_CSW1 3 +#define XFER_BBB_CSW2 4 +#define XFER_BBB_SCLEAR 5 +#define XFER_BBB_RESET1 6 +#define XFER_BBB_RESET2 7 +#define XFER_BBB_RESET3 8 + +#define XFER_CBI_CB 0 /* CBI */ +#define XFER_CBI_DATA 1 +#define XFER_CBI_STATUS 2 +#define XFER_CBI_DCLEAR 3 +#define XFER_CBI_SCLEAR 4 +#define XFER_CBI_RESET1 5 +#define XFER_CBI_RESET2 6 +#define XFER_CBI_RESET3 7 + +#define XFER_NR 9 /* maximum number */ + + usbd_xfer_handle transfer_xfer[XFER_NR]; /* for ctrl xfers */ + + void *data_buffer; + + int transfer_dir; /* data direction */ + void *transfer_data; /* data buffer */ + int transfer_datalen; /* (maximum) length */ + int transfer_actlen; /* actual length */ + umass_callback transfer_cb; /* callback */ + void *transfer_priv; /* for callback */ + int transfer_status; + + int transfer_state; +#define TSTATE_IDLE 0 +#define TSTATE_BBB_COMMAND 1 /* CBW transfer */ +#define TSTATE_BBB_DATA 2 /* Data transfer */ +#define TSTATE_BBB_DCLEAR 3 /* clear endpt stall */ +#define TSTATE_BBB_STATUS1 4 /* clear endpt stall */ +#define TSTATE_BBB_SCLEAR 5 /* clear endpt stall */ +#define TSTATE_BBB_STATUS2 6 /* CSW transfer */ +#define TSTATE_BBB_RESET1 7 /* reset command */ +#define TSTATE_BBB_RESET2 8 /* in clear stall */ +#define TSTATE_BBB_RESET3 9 /* out clear stall */ +#define TSTATE_CBI_COMMAND 10 /* command transfer */ +#define TSTATE_CBI_DATA 11 /* data transfer */ +#define TSTATE_CBI_STATUS 12 /* status transfer */ +#define TSTATE_CBI_DCLEAR 13 /* clear ep stall */ +#define TSTATE_CBI_SCLEAR 14 /* clear ep stall */ +#define TSTATE_CBI_RESET1 15 /* reset command */ +#define TSTATE_CBI_RESET2 16 /* in clear stall */ +#define TSTATE_CBI_RESET3 17 /* out clear stall */ +#define TSTATE_STATES 18 /* # of states above */ + + + int timeout; /* in msecs */ + + u_int8_t maxlun; /* max lun supported */ + +#ifdef UMASS_DEBUG + struct timeval tv; +#endif + + int sc_xfer_flags; + char sc_dying; + int sc_refcnt; + + struct umassbus_softc *bus; /* bus dependent data */ +}; + +#define UMASS_MAX_TRANSFER_SIZE MAXBSIZE diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h index 38764f82edb..79786cc37a1 100644 --- a/sys/dev/usb/usb.h +++ b/sys/dev/usb/usb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usb.h,v 1.20 2002/07/25 02:18:11 nate Exp $ */ +/* $OpenBSD: usb.h,v 1.21 2003/05/17 06:07:57 nate Exp $ */ /* $NetBSD: usb.h,v 1.52 2001/07/23 15:17:50 nathanw Exp $ */ /* $FreeBSD: src/sys/dev/usb/usb.h,v 1.14 1999/11/17 22:33:46 n_hibma Exp $ */ @@ -392,8 +392,8 @@ typedef struct { #define UISUBCLASS_SCSI 6 #define UIPROTO_MASS_CBI_I 0 #define UIPROTO_MASS_CBI 1 -#define UIPROTO_MASS_BBB 2 -#define UIPROTO_MASS_BBB_P 80 /* 'P' for the Iomega Zip drive */ +#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */ +#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */ #define UICLASS_HUB 0x09 #define UISUBCLASS_HUB 0 diff --git a/sys/dev/usb/usb_port.h b/sys/dev/usb/usb_port.h index 4b4d3004cc0..2bdd1ef61e4 100644 --- a/sys/dev/usb/usb_port.h +++ b/sys/dev/usb/usb_port.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usb_port.h,v 1.40 2002/07/25 02:18:11 nate Exp $ */ +/* $OpenBSD: usb_port.h,v 1.41 2003/05/17 06:07:57 nate Exp $ */ /* $NetBSD: usb_port.h,v 1.44 2001/05/14 20:35:29 bouyer Exp $ */ /* $FreeBSD: src/sys/dev/usb/usb_port.h,v 1.21 1999/11/17 22:33:47 n_hibma Exp $ */ @@ -216,26 +216,21 @@ __CONCAT(dname,_detach)(self, flags) \ #define Static +#define UMASS_ATAPISTR "atapiscsi" + +/* periph_quirks */ +#define PQUIRK_FORCELUNS SDEV_FORCELUNS /* prehistoric device groks + LUNs */ +#define PQUIRK_NOMODESENSE SDEV_NOMODESENSE/* device doesn't do MODE SENSE + properly */ +#define PQUIRK_NOTUR ADEV_NOTUR /* no TEST UNIT READY */ +#define PQUIRK_NODOORLOCK ADEV_NODOORLOCK /* can't lock door */ +#define PQUIRK_NOSENSE ADEV_NOSENSE /* can't REQUEST SENSE */ +#define PQUIRK_ONLYBIG SDEV_ONLYBIG +#define PQUIRK_NOBIGMODESENSE 0 + #define UCOMBUSCF_PORTNO -1 #define UCOMBUSCF_PORTNO_DEFAULT -1 - -#define SCSI_MODE_SENSE MODE_SENSE -#define XS_STS_DONE ITSDONE -#define XS_CTL_POLL SCSI_POLL -#define XS_CTL_DATA_IN SCSI_DATA_IN -#define XS_CTL_DATA_OUT SCSI_DATA_OUT -#define scsipi_adapter scsi_adapter -#define scsipi_cmd scsi_cmd -#define scsipi_device scsi_device -#define scsipi_done scsi_done -#define scsipi_link scsi_link -#define scsipi_minphys scsi_minphys -#define scsipi_sense scsi_sense -#define scsipi_xfer scsi_xfer -#define show_scsipi_xs show_scsi_xs -#define show_scsipi_cmd show_scsi_cmd -#define xs_control flags -#define xs_status status #define UHIDBUSCF_REPORTID -1 #define UHIDBUSCF_REPORTID_DEFAULT -1 diff --git a/sys/dev/usb/usscanner.c b/sys/dev/usb/usscanner.c index 7479f6c72b6..3ab9f622ebb 100644 --- a/sys/dev/usb/usscanner.c +++ b/sys/dev/usb/usscanner.c @@ -1,4 +1,4 @@ -/* $OpenBSD: usscanner.c,v 1.7 2003/05/07 04:33:33 deraadt Exp $ */ +/* $OpenBSD: usscanner.c,v 1.8 2003/05/17 06:07:57 nate Exp $ */ /* $NetBSD: usscanner.c,v 1.6 2001/01/23 14:04:14 augustss Exp $ */ /* @@ -89,6 +89,22 @@ int usscannerdebug = 0; #define DPRINTFN(n,x) #endif +#define XS_CTL_DATA_IN SCSI_DATA_IN +#define XS_CTL_DATA_OUT SCSI_DATA_OUT +#define scsipi_adapter scsi_adapter +#define scsipi_cmd scsi_cmd +#define scsipi_device scsi_device +#define scsipi_done scsi_done +#define scsipi_link scsi_link +#define scsipi_minphys scsi_minphys +#define scsipi_sense scsi_sense +#define scsipi_xfer scsi_xfer +#define show_scsipi_xs show_scsi_xs +#define show_scsipi_cmd show_scsi_cmd +#define xs_control flags +#define xs_status status +#define XS_STS_DONE ITSDONE +#define XS_CTL_POLL SCSI_POLL #define USSCANNER_CONFIG_NO 1 #define USSCANNER_IFACE_IDX 0 |