diff options
author | Nathan Binkert <nate@cvs.openbsd.org> | 2002-05-07 18:08:06 +0000 |
---|---|---|
committer | Nathan Binkert <nate@cvs.openbsd.org> | 2002-05-07 18:08:06 +0000 |
commit | 98e3a0a3b6a5b0271467c9f199a555d22161f072 (patch) | |
tree | 04221a5a893956a1fe82881463802b2e507063b3 /sys/dev/usb/umass.c | |
parent | 3a7a8acd4f0393073cd00591e53b1b8a4eb1bd60 (diff) |
Sync ulpt driver with NetBSD
Diffstat (limited to 'sys/dev/usb/umass.c')
-rw-r--r-- | sys/dev/usb/umass.c | 2576 |
1 files changed, 379 insertions, 2197 deletions
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c index 17e1d1bf45f..a47e31a0d27 100644 --- a/sys/dev/usb/umass.c +++ b/sys/dev/usb/umass.c @@ -1,5 +1,5 @@ -/* $OpenBSD: umass.c,v 1.14 2002/03/14 03:16:08 millert Exp $ */ -/* $NetBSD: umass.c,v 1.49 2001/01/21 18:56:38 augustss Exp $ */ +/* $OpenBSD: umass.c,v 1.15 2002/05/07 18:08:04 nate Exp $ */ +/* $NetBSD: umass.c,v 1.87 2002/03/17 18:02:53 augustss 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 @@ -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> @@ -124,396 +125,15 @@ #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_scsipi.h> +#include <dev/usb/umass_isdata.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 +158,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 +168,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__) +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_SCSIID_HOST 0x00 -#define UMASS_SCSIID_DEVICE 0x01 +Static int umass_cbi_adsc(struct umass_softc *, char *, int, usbd_xfer_handle); -#define UMASS_ATAPI_DRIVE 0 - -#define UMASS_MAX_TRANSFER_SIZE MAXBSIZE - -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,292 +216,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_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); + return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); } -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); - strcpy(sc->sc_dev.dv_xname, "umass"); -#endif - - if (uaa->iface == NULL) - return(UMATCH_NONE); - - return (umass_match_proto(sc, uaa->iface, uaa->device)); -} - -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); 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; + + 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; + } - /* 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)); + 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 UMASS_CPROTO_ATAPI: + sCommand = "ATAPI"; break; - case UIPROTO_MASS_BBB_P: - sProto = "BBB-P"; + 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 @@ -974,22 +403,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", @@ -1001,19 +430,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", @@ -1025,19 +456,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; } @@ -1053,12 +485,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; } @@ -1078,14 +511,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], @@ -1100,123 +533,89 @@ 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\n", - __FILE__, __LINE__, sc->proto); -#endif - } - - if (sc->drive == SHUTTLE_EUSB) - umass_init_shuttle(sc); - - /* - * Fill in the adapter. - */ - sc->sc_adapter.scsipi_cmd = umass_scsipi_cmd; - sc->sc_adapter.scsipi_minphys = umass_scsipi_minphys; - - /* - * 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; + 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: - printf("%s: proto=0x%x not supported yet\n", - USBDEVNAME(sc->sc_dev), sc->proto); 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); + if (quirk != NULL && quirk->uq_init != NULL) { + err = (*quirk->uq_init)(sc); + if (err) { + umass_disco(sc); + USB_ATTACH_ERROR_RETURN; + } } - DPRINTF(UDMASS_GEN, ("%s: Attach finished\n", USBDEVNAME(sc->sc_dev))); + 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; - USB_ATTACH_SUCCESS_RETURN; -} + 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; -void -umass_delayed_attach(struct umass_softc *sc) -{ - sc->sc_child = config_found(&sc->sc_dev, &sc->u, scsipiprint); - if (sc->sc_child == NULL) { + 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: command protocol=0x%x not supported\n", + USBDEVNAME(sc->sc_dev), sc->sc_cmd); + umass_disco(sc); + USB_ATTACH_ERROR_RETURN; + } + 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; 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() */ @@ -1228,16 +627,13 @@ USB_DETACH(umass) 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); @@ -1246,16 +642,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", @@ -1267,22 +661,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; @@ -1296,27 +687,10 @@ 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]); + } } /* @@ -1336,7 +710,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 " @@ -1353,10 +727,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; @@ -1365,8 +737,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) { @@ -1381,30 +753,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 @@ -1426,10 +791,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; @@ -1456,31 +820,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 @@ -1552,7 +917,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)); @@ -1569,7 +934,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); @@ -1584,8 +949,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; @@ -1624,7 +990,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])) @@ -1634,7 +1000,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])) @@ -1656,18 +1022,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 { @@ -1723,9 +1087,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; } @@ -1744,10 +1107,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); @@ -1757,6 +1119,11 @@ 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); + /* Check CSW and handle any error */ if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) { /* Invalid CSW: Wrong signature or wrong tag might @@ -1801,9 +1168,8 @@ umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, panic("%s: transferred %d bytes instead of %d bytes\n", 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), @@ -1812,10 +1178,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))); @@ -1843,8 +1207,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; @@ -1854,8 +1218,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; @@ -1889,19 +1253,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); } @@ -1912,8 +1273,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; @@ -1959,19 +1321,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 @@ -2019,8 +1384,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; @@ -2043,10 +1409,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; @@ -2065,7 +1431,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])) @@ -2074,17 +1440,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])){ @@ -2110,15 +1476,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); @@ -2134,10 +1499,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])){ @@ -2162,9 +1527,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); @@ -2174,7 +1538,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 @@ -2250,8 +1614,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; @@ -2261,8 +1625,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; @@ -2292,26 +1656,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", @@ -2348,706 +1707,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\n"); -#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\n", - 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\n", - 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 @@ -3059,11 +1718,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>")))); } @@ -3113,482 +1774,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 == SCSI_MODE_SENSE && - (sc_link->quirks & SDEV_NOMODESENSE)) { - /*printf("%s: SCSI_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\n", - 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 SCSI_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 SCSI_MODE_SELECT_BIG: - case SCSI_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 SCSI_READ_COMMAND: - case SCSI_WRITE_COMMAND: - case SCSI_MODE_SENSE: - case SCSI_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 |