Some USB mass storage devices return the number of sectors in response

to a READ_CAPACITY request rather than the maximum sector (off by one
problem).  This causes a huge cascade of errors as the geom tasting
code tries to read the last sector (which isn't really there in the
face of this error).  automated tools that manipulate disk labels and
such also have issues.

Create a new quirk READ_CAPACITY_OFFBY1 and add a quirk for the
SanDISK ImageMate that I have that suffers from this problem (the
SDDR-31).  It intercepts the READ_CAPACITY response and adjusts it
from number of sectors to max sector for devices with this quirk.

Reading the Linux source suggests that there are a host of
other devices with this issue, including iPods and some popular
cameras.  I've not added quirks for them, since I don't have the
devices in front of me to test.
This commit is contained in:
imp 2007-02-27 22:33:50 +00:00
parent 0bd2af4cfe
commit b8fed42140

View File

@ -317,6 +317,10 @@ struct umass_devdescr_t {
# define NO_INQUIRY_EVPD 0x0800
/* Pad all RBC requests to 12 bytes. */
# define RBC_PAD_TO_12 0x1000
/* Device reports number of sectors from READ_CAPACITY, not max
* sector number.
*/
# define READ_CAPACITY_OFFBY1 0x2000
};
static struct umass_devdescr_t umass_devdescrs[] = {
@ -446,6 +450,10 @@ static struct umass_devdescr_t umass_devdescrs[] = {
UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
IGNORE_RESIDUE | NO_START_STOP
},
{ USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR31, RID_WILDCARD,
UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
READ_CAPACITY_OFFBY1
},
{ USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ2_256, RID_WILDCARD,
UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
IGNORE_RESIDUE
@ -2698,6 +2706,16 @@ umass_cam_cb(struct umass_softc *sc, void *priv, int residue, int status)
switch (status) {
case STATUS_CMD_OK:
ccb->ccb_h.status = CAM_REQ_CMP;
if ((sc->quirks & READ_CAPACITY_OFFBY1) &&
(ccb->ccb_h.func_code == XPT_SCSI_IO) &&
(csio->cdb_io.cdb_bytes[0] == READ_CAPACITY)) {
struct scsi_read_capacity_data *rcap;
uint32_t maxsector;
rcap = (struct scsi_read_capacity_data *)csio->data_ptr;
maxsector = scsi_4btoul(rcap->addr) - 1;
scsi_ulto4b(maxsector, rcap->addr);
}
xpt_done(ccb);
break;