usb/160299: MicroSDHC-to-USB adapters do not work in FreeBSD 8.x
Hans Petter Selasky
hselasky at c2i.net
Tue Aug 30 11:30:15 UTC 2011
The following reply was made to PR usb/160299; it has been noted by GNATS.
From: Hans Petter Selasky <hselasky at c2i.net>
To: freebsd-usb at freebsd.org
Cc: Brett Glass <freebsd-prs at brettglass.com>,
freebsd-gnats-submit at freebsd.org
Subject: Re: usb/160299: MicroSDHC-to-USB adapters do not work in FreeBSD 8.x
Date: Tue, 30 Aug 2011 13:26:58 +0200
--Boundary-00=_CkMXOqbZCgU0ukV
Content-Type: text/plain;
charset="iso-8859-15"
Content-Transfer-Encoding: 7bit
> >Fix:
> This behavior is so common that it should not be characterized as a quirk
> but as a general property of USB flash devices. All USB flash storage
> devices should have SYNCHRONIZE CACHE and similar SCSI commands disabled
> by default. These commands should, of course, be enabled for USB-attached
> ATAPI rotating media, which supports them.
>
> >Release-Note:
> >Audit-Trail:
>
> >Unformatted:
Hi,
Can everyone using 8-stable or 9-current try this patch and see if it breaks
your mass storage device or not:
1) Get latest 8-stable or 9-current sources in /usr/src
2) Apply patch:
cd /usr/src
cat msc_auto_quirk.patch | patch
3) Build and install new kernel
4) Report back.
--HPS
--Boundary-00=_CkMXOqbZCgU0ukV
Content-Type: text/x-patch;
charset="iso-8859-15";
name="msc_auto_quirk.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="msc_auto_quirk.patch"
=== sys/dev/usb/quirk/usb_quirk.c
==================================================================
--- sys/dev/usb/quirk/usb_quirk.c (revision 225095)
+++ sys/dev/usb/quirk/usb_quirk.c (local)
@@ -148,12 +148,10 @@
UQ_MSC_FORCE_PROTO_SCSI),
USB_QUIRK(AIPTEK, POCKETCAM3M, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI),
- USB_QUIRK(AIPTEK2, SUNPLUS_TECH, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(ALCOR, SDCR_6335, 0x0000, 0xffff, UQ_MSC_NO_TEST_UNIT_READY,
UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(ALCOR, SDCR_6362, 0x0000, 0xffff, UQ_MSC_NO_TEST_UNIT_READY,
UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(ALCOR, AU6390, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(ALCOR, UMCR_9361, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN),
USB_QUIRK(ALCOR, TRANSCEND, 0x0000, 0xffff, UQ_MSC_NO_GETMAXLUN,
@@ -173,14 +171,12 @@
USB_QUIRK(CENTURY, EX35QUAT, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_FORCE_SHORT_INQ,
UQ_MSC_NO_START_STOP, UQ_MSC_IGNORE_RESIDUE),
- USB_QUIRK(CENTURY, EX35SW4_SB4, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(CYPRESS, XX6830XX, 0x0000, 0xffff, UQ_MSC_NO_GETMAXLUN,
UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(DESKNOTE, UCR_61S2B, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI),
USB_QUIRK(DMI, CFSM_RW, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI,
UQ_MSC_NO_GETMAXLUN),
- USB_QUIRK(DMI, DISK, 0x000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(EPSON, STYLUS_875DC, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY),
USB_QUIRK(EPSON, STYLUS_895, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -188,7 +184,6 @@
USB_QUIRK(FEIYA, 5IN1, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI),
USB_QUIRK(FREECOM, DVD, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI),
- USB_QUIRK(FREECOM, HDD, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(FUJIPHOTO, MASS0100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI_I,
UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_RS_CLEAR_UA, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(GENESYS, GL641USB2IDE, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -232,7 +227,6 @@
USB_QUIRK(IOMEGA, ZIP100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI,
UQ_MSC_NO_TEST_UNIT_READY), /* XXX ZIP drives can also use ATAPI */
- USB_QUIRK(JMICRON, JM20336, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(JMICRON, JM20337, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI,
UQ_MSC_NO_SYNC_CACHE),
@@ -279,8 +273,6 @@
UQ_MSC_FORCE_PROTO_ATAPI),
USB_QUIRK(MYSON, HEDEN, 0x0000, 0xffff, UQ_MSC_IGNORE_RESIDUE,
UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(MYSON, HEDEN_8813, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(MYSON, STARREADER, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(NEODIO, ND3260, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_FORCE_SHORT_INQ),
USB_QUIRK(NETAC, CF_CARD, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -317,7 +309,6 @@
USB_QUIRK(PANASONIC, KXLCB35AN, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI),
USB_QUIRK(PANASONIC, LS120CAM, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_UFI),
- USB_QUIRK(PHILIPS, SPE3030CC, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(PLEXTOR, 40_12_40U, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_TEST_UNIT_READY),
USB_QUIRK(PNY, ATTACHE2, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
@@ -328,7 +319,6 @@
USB_QUIRK_VP(USB_VENDOR_SAMSUNG_TECHWIN,
USB_PRODUCT_SAMSUNG_TECHWIN_DIGIMAX_410, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY),
- USB_QUIRK(SAMSUNG, YP_U4, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
USB_QUIRK(SANDISK, SDDR05A, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_READ_CAP_OFFBY1,
UQ_MSC_NO_GETMAXLUN),
@@ -448,12 +438,6 @@
UQ_MSC_FORCE_PROTO_ATAPI),
USB_QUIRK(MEIZU, M6_SL, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(ACTIONS, MP4, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
- UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(ASUS, GMSC, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(CHIPSBANK, USBMEMSTICK, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(CHIPSBANK, USBMEMSTICK1, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
- USB_QUIRK(NEWLINK, USB2IDEBRIDGE, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE),
/* Non-standard USB MIDI devices */
USB_QUIRK(ROLAND, UM1, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
@@ -567,9 +551,9 @@
uint16_t x;
uint16_t y;
- if (quirk == UQ_NONE) {
- return (0);
- }
+ if (quirk == UQ_NONE)
+ goto done;
+
mtx_lock(&usb_quirk_mtx);
for (x = 0; x != USB_DEV_QUIRKS_MAX; x++) {
@@ -603,7 +587,8 @@
break;
}
mtx_unlock(&usb_quirk_mtx);
- return (0);
+done:
+ return (usb_test_quirk_w(info, quirk));
}
static struct usb_quirk_entry *
=== sys/dev/usb/storage/umass.c
==================================================================
--- sys/dev/usb/storage/umass.c (revision 225095)
+++ sys/dev/usb/storage/umass.c (local)
@@ -1025,12 +1025,6 @@
sc->cam_scsi_sense.opcode = REQUEST_SENSE;
sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY;
- /*
- * some devices need a delay after that the configuration value is
- * set to function properly:
- */
- usb_pause_mtx(NULL, hz);
-
/* register the SIM */
err = umass_cam_attach_sim(sc);
if (err) {
=== sys/dev/usb/usb_device.c
==================================================================
--- sys/dev/usb/usb_device.c (revision 225095)
+++ sys/dev/usb/usb_device.c (local)
@@ -1239,8 +1239,10 @@
usb_init_attach_arg(struct usb_device *udev,
struct usb_attach_arg *uaa)
{
- bzero(uaa, sizeof(*uaa));
+ uint8_t x;
+ memset(uaa, 0, sizeof(*uaa));
+
uaa->device = udev;
uaa->usb_mode = udev->flags.usb_mode;
uaa->port = udev->port_no;
@@ -1254,6 +1256,9 @@
uaa->info.bDeviceProtocol = udev->ddesc.bDeviceProtocol;
uaa->info.bConfigIndex = udev->curr_config_index;
uaa->info.bConfigNum = udev->curr_config_no;
+
+ for (x = 0; x != USB_MAX_AUTO_QUIRK; x++)
+ uaa->info.autoQuirk[x] = udev->autoQuirk[x];
}
/*------------------------------------------------------------------------*
@@ -1850,7 +1855,21 @@
}
}
}
+ if (set_config_failed == 0 && config_index == 0 &&
+ usb_test_quirk(&uaa, UQ_MSC_NO_SYNC_CACHE) == 0) {
+ /*
+ * Try to figure out if there are any MSC quirks we
+ * should apply automatically:
+ */
+ err = usb_msc_auto_quirk(udev, 0);
+
+ if (err != 0) {
+ set_config_failed = 1;
+ goto repeat_set_config;
+ }
+ }
+
config_done:
DPRINTF("new dev (addr %d), udev=%p, parent_hub=%p\n",
udev->address, udev, udev->parent_hub);
@@ -2698,3 +2717,16 @@
return (0); /* success */
}
+usb_error_t
+usbd_add_dynamic_quirk(struct usb_device *udev, uint16_t quirk)
+{
+ uint8_t x;
+
+ for (x = 0; x != USB_MAX_AUTO_QUIRK; x++) {
+ if (udev->autoQuirk[x] == 0) {
+ udev->autoQuirk[x] = quirk;
+ return (0); /* success */
+ }
+ }
+ return (USB_ERR_NOMEM);
+}
=== sys/dev/usb/usb_device.h
==================================================================
--- sys/dev/usb/usb_device.h (revision 225095)
+++ sys/dev/usb/usb_device.h (local)
@@ -149,6 +149,7 @@
uint16_t power; /* mA the device uses */
uint16_t langid; /* language for strings */
+ uint16_t autoQuirk[USB_MAX_AUTO_QUIRK]; /* dynamic quirks */
uint8_t address; /* device addess */
uint8_t device_index; /* device index in "bus->devices" */
=== sys/dev/usb/usb_dynamic.c
==================================================================
--- sys/dev/usb/usb_dynamic.c (revision 225095)
+++ sys/dev/usb/usb_dynamic.c (local)
@@ -50,12 +50,12 @@
#include <dev/usb/usb_process.h>
#include <dev/usb/usb_device.h>
#include <dev/usb/usb_dynamic.h>
+#include <dev/usb/quirk/usb_quirk.h>
/* function prototypes */
static usb_handle_req_t usb_temp_get_desc_w;
static usb_temp_setup_by_index_t usb_temp_setup_by_index_w;
static usb_temp_unsetup_t usb_temp_unsetup_w;
-static usb_test_quirk_t usb_test_quirk_w;
static usb_quirk_ioctl_t usb_quirk_ioctl_w;
/* global variables */
@@ -72,9 +72,19 @@
return (USB_ERR_INVAL);
}
-static uint8_t
+uint8_t
usb_test_quirk_w(const struct usbd_lookup_info *info, uint16_t quirk)
{
+ uint8_t x;
+
+ if (quirk == UQ_NONE)
+ return (0); /* no match */
+
+ for (x = 0; x != USB_MAX_AUTO_QUIRK; x++) {
+ if (info->autoQuirk[x] == quirk)
+ return (1); /* match */
+ }
+
return (0); /* no match */
}
=== sys/dev/usb/usb_dynamic.h
==================================================================
--- sys/dev/usb/usb_dynamic.h (revision 225095)
+++ sys/dev/usb/usb_dynamic.h (local)
@@ -57,5 +57,6 @@
void usb_temp_unload(void *);
void usb_quirk_unload(void *);
void usb_bus_unload(void *);
+usb_test_quirk_t usb_test_quirk_w;
#endif /* _USB_DYNAMIC_H_ */
=== sys/dev/usb/usb_freebsd.h
==================================================================
--- sys/dev/usb/usb_freebsd.h (revision 225095)
+++ sys/dev/usb/usb_freebsd.h (local)
@@ -68,6 +68,8 @@
#define USB_EP0_BUFSIZE 1024 /* bytes */
#define USB_CS_RESET_LIMIT 20 /* failures = 20 * 50 ms = 1sec */
+#define USB_MAX_AUTO_QUIRK 4 /* maximum number of dynamic quirks */
+
typedef uint32_t usb_timeout_t; /* milliseconds */
typedef uint32_t usb_frlength_t; /* bytes */
typedef uint32_t usb_frcount_t; /* units */
=== sys/dev/usb/usb_msctest.c
==================================================================
--- sys/dev/usb/usb_msctest.c (revision 225095)
+++ sys/dev/usb/usb_msctest.c (local)
@@ -96,6 +96,8 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
static uint8_t scsi_tct_eject[] = { 0x06, 0xf5, 0x04, 0x02, 0x52, 0x70 };
+static uint8_t scsi_sync_cache[] = { 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
#define BULK_SIZE 64 /* dummy */
#define ERR_CSW_FAILED -1
@@ -163,7 +165,7 @@
static void bbb_transfer_start(struct bbb_transfer *, uint8_t);
static void bbb_data_clear_stall_callback(struct usb_xfer *, uint8_t,
uint8_t);
-static uint8_t bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t,
+static int bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t,
void *, size_t, void *, size_t, usb_timeout_t);
static struct bbb_transfer *bbb_attach(struct usb_device *, uint8_t);
static void bbb_detach(struct bbb_transfer *);
@@ -454,7 +456,7 @@
* 0: Success
* Else: Failure
*------------------------------------------------------------------------*/
-static uint8_t
+static int
bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun,
void *data_ptr, size_t data_len, void *cmd_ptr, size_t cmd_len,
usb_timeout_t data_timeout)
@@ -566,9 +568,10 @@
usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index)
{
struct bbb_transfer *sc;
- usb_error_t err;
- uint8_t timeout, is_cdrom;
+ uint8_t timeout;
+ uint8_t is_cdrom;
uint8_t sid_type;
+ int err;
sc = bbb_attach(udev, iface_index);
if (sc == NULL)
@@ -595,6 +598,88 @@
}
usb_error_t
+usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index)
+{
+ struct bbb_transfer *sc;
+ uint8_t timeout;
+ uint8_t is_no_direct;
+ uint8_t sid_type;
+ int err;
+
+ sc = bbb_attach(udev, iface_index);
+ if (sc == NULL)
+ return (0);
+
+ /*
+ * Some devices need a delay after that the configuration
+ * value is set to function properly:
+ */
+ usb_pause_mtx(NULL, hz);
+
+ is_no_direct = 1;
+ for (timeout = 4; timeout; timeout--) {
+ err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
+ SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
+ USB_MS_HZ);
+
+ if (err == 0 && sc->actlen > 0) {
+ sid_type = sc->buffer[0] & 0x1F;
+ if (sid_type == 0x00)
+ is_no_direct = 0;
+ break;
+ } else if (err != ERR_CSW_FAILED)
+ break; /* non retryable error */
+ usb_pause_mtx(NULL, hz);
+ }
+
+ if (is_no_direct) {
+ DPRINTF("Device is not direct access.\n");
+ goto done;
+ }
+
+ err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
+ &scsi_test_unit_ready, sizeof(scsi_test_unit_ready),
+ USB_MS_HZ);
+
+ if (err != 0) {
+
+ if (err != ERR_CSW_FAILED)
+ goto error;
+ }
+
+ err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
+ &scsi_sync_cache, sizeof(scsi_sync_cache),
+ USB_MS_HZ);
+
+ if (err != 0) {
+
+ if (err != ERR_CSW_FAILED)
+ goto error;
+
+ DPRINTF("Device doesn't handle synchronize cache\n");
+
+ usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
+ }
+
+done:
+ bbb_detach(sc);
+ return (0);
+
+error:
+ bbb_detach(sc);
+
+ DPRINTF("Device did not respond, enabling all quirks\n");
+
+ usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
+ usbd_add_dynamic_quirk(udev, UQ_MSC_NO_TEST_UNIT_READY);
+
+ /* Need to re-enumerate the device */
+ usbd_req_re_enumerate(udev, NULL);
+
+ return (USB_ERR_STALLED);
+}
+
+usb_error_t
usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
{
struct bbb_transfer *sc;
=== sys/dev/usb/usb_msctest.h
==================================================================
--- sys/dev/usb/usb_msctest.h (revision 225095)
+++ sys/dev/usb/usb_msctest.h (local)
@@ -40,5 +40,7 @@
uint8_t iface_index);
usb_error_t usb_msc_eject(struct usb_device *udev,
uint8_t iface_index, int method);
+usb_error_t usb_msc_auto_quirk(struct usb_device *udev,
+ uint8_t iface_index);
#endif /* _USB_MSCTEST_H_ */
=== sys/dev/usb/usbdi.h
==================================================================
--- sys/dev/usb/usbdi.h (revision 225095)
+++ sys/dev/usb/usbdi.h (local)
@@ -353,6 +353,7 @@
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
+ uint16_t autoQuirk[USB_MAX_AUTO_QUIRK];
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
@@ -475,6 +476,8 @@
void usb_pause_mtx(struct mtx *mtx, int _ticks);
usb_error_t usbd_set_pnpinfo(struct usb_device *udev,
uint8_t iface_index, const char *pnpinfo);
+usb_error_t usbd_add_dynamic_quirk(struct usb_device *udev,
+ uint16_t quirk);
const struct usb_device_id *usbd_lookup_id_by_info(
const struct usb_device_id *id, usb_size_t sizeof_id,
--Boundary-00=_CkMXOqbZCgU0ukV--
More information about the freebsd-usb
mailing list