diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2005-05-14 23:36:27 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2005-05-14 23:36:27 +0000 |
commit | 66ced9bada92fa1376dfd55073b763f781d4764f (patch) | |
tree | 9dfc9add08e6e90114c3d5bc822fbec4f015581d | |
parent | 5e017dfcaee3abb57aab4fdf622aa4c9ccf67bda (diff) |
Try to ensure that UFI/ATAPI USB umass devices always get the zero
padded 12 byte commands mandated by the standard. Adapt the Linux data
length twiddling on certain commands. We used to have some of this in
a different form, curtesy of csapuntz@, but it got lost in subsequent
merges.
Fixes the USB card reader of Quentin Barnes who provided much testing
and feedback for over a year!
Tested by drahn@, ok marco@, 'this is good stuff' deraadt@.
-rw-r--r-- | sys/dev/usb/umass.c | 56 | ||||
-rw-r--r-- | sys/dev/usb/umass_scsi.c | 4 |
2 files changed, 46 insertions, 14 deletions
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c index ab2a7ea7c67..736aa574850 100644 --- a/sys/dev/usb/umass.c +++ b/sys/dev/usb/umass.c @@ -1,4 +1,4 @@ -/* $OpenBSD: umass.c,v 1.39 2005/04/01 06:41:13 pascoe Exp $ */ +/* $OpenBSD: umass.c,v 1.40 2005/05/14 23:36:26 krw Exp $ */ /* $NetBSD: umass.c,v 1.116 2004/06/30 05:53:46 mycroft Exp $ */ /* @@ -131,15 +131,6 @@ * umass_cam_cb again to complete the CAM command. */ -#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> @@ -157,6 +148,8 @@ #endif #include <machine/bus.h> +#include <scsi/scsi_all.h> + #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> #include <dev/usb/usbdi_util.h> @@ -212,6 +205,7 @@ Static usbd_status umass_setup_ctrl_transfer(struct umass_softc *sc, usbd_xfer_handle xfer); Static void umass_clear_endpoint_stall(struct umass_softc *sc, int endpt, usbd_xfer_handle xfer); +Static void umass_adjust_transfer(struct umass_softc *); #if 0 Static void umass_reset(struct umass_softc *sc, transfer_cb_f cb, void *priv); #endif @@ -879,6 +873,41 @@ umass_setup_ctrl_transfer(struct umass_softc *sc, usb_device_request_t *req, } Static void +umass_adjust_transfer(struct umass_softc *sc) +{ + switch (sc->sc_cmd) { + case UMASS_CPROTO_UFI: + sc->cbw.bCDBLength = UFI_COMMAND_LENGTH; + /* Adjust the length field in certain scsi commands. */ + switch (sc->cbw.CBWCDB[0]) { + case INQUIRY: + if (sc->transfer_datalen > 36) { + sc->transfer_datalen = 36; + sc->cbw.CBWCDB[4] = 36; + } + break; + case MODE_SENSE_BIG: + if (sc->transfer_datalen > 8) { + sc->transfer_datalen = 8; + sc->cbw.CBWCDB[7] = 0; + sc->cbw.CBWCDB[8] = 8; + } + break; + case REQUEST_SENSE: + if (sc->transfer_datalen > 18) { + sc->transfer_datalen = 18; + sc->cbw.CBWCDB[4] = 18; + } + break; + } + break; + case UMASS_CPROTO_ATAPI: + sc->cbw.bCDBLength = UFI_COMMAND_LENGTH; + break; + } +} + +Static void umass_clear_endpoint_stall(struct umass_softc *sc, int endpt, usbd_xfer_handle xfer) { @@ -1049,6 +1078,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; + bzero(sc->cbw.CBWCDB, sizeof(sc->cbw.CBWCDB)); memcpy(sc->cbw.CBWCDB, cmd, cmdlen); DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw)); @@ -1066,6 +1096,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. */ + umass_adjust_transfer(sc); if ((err = umass_setup_transfer(sc, sc->sc_pipe[UMASS_BULKOUT], &sc->cbw, UMASS_BBB_CBW_SIZE, 0, sc->transfer_xfer[XFER_BBB_CBW]))) @@ -1516,7 +1547,10 @@ umass_cbi_transfer(struct umass_softc *sc, int lun, sc->transfer_state = TSTATE_CBI_COMMAND; /* Send the Command Block from host to device via control endpoint. */ - if ((err = umass_cbi_adsc(sc, cmd, cmdlen, + bzero(sc->cbw.CBWCDB, sizeof(sc->cbw.CBWCDB)); + memcpy(sc->cbw.CBWCDB, cmd, cmdlen); + umass_adjust_transfer(sc); + if ((err = umass_cbi_adsc(sc, (void *)sc->cbw.CBWCDB, sc->cbw.bCDBLength, sc->transfer_xfer[XFER_CBI_CB]))) umass_cbi_reset(sc, STATUS_WIRE_FAILED); diff --git a/sys/dev/usb/umass_scsi.c b/sys/dev/usb/umass_scsi.c index 435ae278d59..537c17f5ed8 100644 --- a/sys/dev/usb/umass_scsi.c +++ b/sys/dev/usb/umass_scsi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: umass_scsi.c,v 1.11 2005/04/27 23:54:44 krw Exp $ */ +/* $OpenBSD: umass_scsi.c,v 1.12 2005/05/14 23:36:26 krw Exp $ */ /* $NetBSD: umass_scsipi.c,v 1.9 2003/02/16 23:14:08 augustss Exp $ */ /* * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -364,8 +364,6 @@ umass_scsi_cb(struct umass_softc *sc, void *priv, int residue, int status) scbus->sc_sense_cmd.length = sizeof(xs->sense); cmdlen = sizeof(scbus->sc_sense_cmd); - if (sc->sc_cmd == UMASS_CPROTO_UFI) /* XXX */ - cmdlen = UFI_COMMAND_LENGTH; sc->sc_methods->wire_xfer(sc, link->lun, &scbus->sc_sense_cmd, cmdlen, &xs->sense, sizeof(xs->sense), |