summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2003-03-25 16:21:09 +0000
committernjl <njl@FreeBSD.org>2003-03-25 16:21:09 +0000
commite17741e782047ccd0e4a4ae2ab7a45f2074ae4ae (patch)
tree699de5e4db0ba3dccef9d7e04e44575be4fa25af
parentf92a704df5ac95408d63dc8819ef62397b52a960 (diff)
downloadFreeBSD-src-e17741e782047ccd0e4a4ae2ab7a45f2074ae4ae.zip
FreeBSD-src-e17741e782047ccd0e4a4ae2ab7a45f2074ae4ae.tar.gz
Add code to implement two new USB quirk types: NO_INQUIRY and NO_INQUIRY_EVPD
The former fakes a valid response to an inquiry command. (I am completely blown away that there are devices which hang upon receiving inquiry). The latter returns "invalid request" to any inquiry commands with EVPD set. NO_INQUIRY implies NO_INQUIRY_EVPD but not vice versa. Both quirks have been tested separately on my USB key although it didn't require either of them. While I'm here, fix wildcarding so that any/all of vendor, product, revision can be wildcarded. Idea from: Linux MFC after: 2 weeks
-rw-r--r--sys/dev/usb/umass.c71
1 files changed, 60 insertions, 11 deletions
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c
index 9cd3897..9decb8c 100644
--- a/sys/dev/usb/umass.c
+++ b/sys/dev/usb/umass.c
@@ -319,6 +319,10 @@ struct umass_devdescr_t {
# define NO_GETMAXLUN 0x0100
/* The device uses a weird CSWSIGNATURE. */
# define WRONG_CSWSIG 0x0200
+ /* Device cannot handle INQUIRY so fake a generic response */
+# define NO_INQUIRY 0x0400
+ /* Device cannot handle INQUIRY EVPD, return CHECK CONDITION */
+# define NO_INQUIRY_EVPD 0x0800
};
Static struct umass_devdescr_t umass_devdescrs[] = {
@@ -542,7 +546,11 @@ char *states[TSTATE_STATES+1] = {
#endif
Static struct cam_sim *umass_sim; /* SCSI Interface Module */
-
+/* If device cannot return valid inquiry data, fake it */
+Static uint8_t fake_inq_data[SHORT_INQUIRY_LENGTH] = {
+ 0, /*removable*/ 0x80, SCSI_REV_2, SCSI_REV_2,
+ /*additional_length*/ 31, 0, 0, 0
+};
/* USB device probe/attach/detach functions */
USB_DECLARE_DRIVER(umass);
@@ -708,16 +716,25 @@ umass_match_proto(struct umass_softc *sc, usbd_interface_handle iface,
* check for wildcarded and fully matched. First match wins.
*/
for (i = 0; umass_devdescrs[i].vid != VID_EOT && !found; i++) {
- if (umass_devdescrs[i].vid == UGETW(dd->idVendor)
- && umass_devdescrs[i].pid == UGETW(dd->idProduct)) {
+ if (umass_devdescrs[i].vid == VID_WILDCARD &&
+ umass_devdescrs[i].pid == PID_WILDCARD &&
+ umass_devdescrs[i].rid == RID_WILDCARD) {
+ printf("umass: ignoring invalid wildcard quirk\n");
+ continue;
+ }
+ if ((umass_devdescrs[i].vid == UGETW(dd->idVendor) ||
+ umass_devdescrs[i].vid == VID_WILDCARD)
+ && (umass_devdescrs[i].pid == UGETW(dd->idProduct) ||
+ umass_devdescrs[i].pid == PID_WILDCARD)) {
if (umass_devdescrs[i].rid == RID_WILDCARD) {
- sc->proto = umass_devdescrs[i].proto;
- sc->quirks = umass_devdescrs[i].quirks;
- return UMATCH_VENDOR_PRODUCT;
- } else if (umass_devdescrs[i].rid == UGETW(dd->bcdDevice)) {
- sc->proto = umass_devdescrs[i].proto;
- sc->quirks = umass_devdescrs[i].quirks;
- return UMATCH_VENDOR_PRODUCT_REV;
+ sc->proto = umass_devdescrs[i].proto;
+ sc->quirks = umass_devdescrs[i].quirks;
+ return (UMATCH_VENDOR_PRODUCT);
+ } else if (umass_devdescrs[i].rid ==
+ UGETW(dd->bcdDevice)) {
+ sc->proto = umass_devdescrs[i].proto;
+ sc->quirks = umass_devdescrs[i].quirks;
+ return (UMATCH_VENDOR_PRODUCT_REV);
} /* else RID does not match */
}
}
@@ -2386,7 +2403,39 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb)
*/
if (sc->transform(sc, cmd, cmdlen, &rcmd, &rcmdlen)) {
- if ((sc->quirks & FORCE_SHORT_INQUIRY) && (rcmd[0] == INQUIRY)) {
+ /*
+ * Handle EVPD inquiry for broken devices first
+ * NO_INQUIRY also implies NO_INQUIRY_EVPD
+ */
+ if ((sc->quirks & (NO_INQUIRY_EVPD | NO_INQUIRY)) &&
+ rcmd[0] == INQUIRY && (rcmd[1] & SI_EVPD)) {
+ struct scsi_sense_data *sense;
+
+ sense = &ccb->csio.sense_data;
+ bzero(sense, sizeof(*sense));
+ sense->error_code = SSD_CURRENT_ERROR;
+ sense->flags = SSD_KEY_ILLEGAL_REQUEST;
+ sense->add_sense_code = 0x24;
+ sense->extra_len = 10;
+ ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
+ ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
+ CAM_AUTOSNS_VALID;
+ xpt_done(ccb);
+ return;
+ }
+ /* Return fake inquiry data for broken devices */
+ if ((sc->quirks & NO_INQUIRY) && rcmd[0] == INQUIRY) {
+ struct ccb_scsiio *csio = &ccb->csio;
+
+ memcpy(csio->data_ptr, &fake_inq_data,
+ sizeof(fake_inq_data));
+ csio->scsi_status = SCSI_STATUS_OK;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ return;
+ }
+ if ((sc->quirks & FORCE_SHORT_INQUIRY) &&
+ rcmd[0] == INQUIRY) {
csio->dxfer_len = SHORT_INQUIRY_LENGTH;
}
sc->transfer(sc, ccb->ccb_h.target_lun, rcmd, rcmdlen,
OpenPOWER on IntegriCloud