More specifically, make handling of resid consistant and at least
superficially correct. Triggered by the hack I had to commit to fix
a problem with a large un-tar from my ahci DAT drive.
A cookie for those who can show any semantic change I made outside
of the calculation and usage of resid's.
Any big tape users out there want to give it a whirl and ensure I
didn't break anything while trying to make the code easier to read?
OK's also accepted. :-).
.... Ken
Index: st.c
===================================================================
RCS file: /cvs/src/sys/scsi/st.c,v
retrieving revision 1.109
diff -u -p -r1.109 st.c
--- st.c 1 Sep 2010 23:24:03 -0000 1.109
+++ st.c 7 Sep 2010 01:23:34 -0000
@@ -1952,7 +1952,8 @@ st_interpret_sense(struct scsi_xfer *xs)
struct st_softc *st = sc_link->device_softc;
u_int8_t serr = sense->error_code & SSD_ERRCODE;
u_int8_t skey = sense->flags & SSD_KEY;
- int32_t info;
+ int32_t resid;
+ int datalen;
if (((sc_link->flags & SDEV_OPEN) == 0) ||
(serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED))
@@ -1996,88 +1997,76 @@ st_interpret_sense(struct scsi_xfer *xs)
}
/*
- * Get the sense fields and work out what code
+ * 'resid' can be in units of st->blksize or bytes. xs->resid and
+ * xs->datalen are always in units of bytes. So we need a variable
+ * to store datalen in the same units as resid and to adjust
+ * xs->resid to be in bytes.
*/
- if (sense->error_code & SSD_ERRCODE_VALID)
- info = _4btol(sense->info);
- else
- info = xs->datalen; /* bad choice if fixed blocks */
- if (st->flags & ST_FIXEDBLOCKS) {
- xs->resid = info * st->blksize;
- if (sense->flags & SSD_EOM) {
- st->flags |= ST_EIO_PENDING;
+ datalen = xs->datalen;
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ xs->resid = resid = (int32_t)_4btol(sense->info);
+ if (st->flags & ST_FIXEDBLOCKS) {
+ xs->resid *= st->blksize;
+ datalen /= st->blksize;
}
- if (sense->flags & SSD_FILEMARK) {
- st->flags |= ST_AT_FILEMARK;
- if (st->media_fileno != -1) {
- st->media_fileno++;
- st->media_blkno = 0;
- }
+ if (xs->resid < 0 || xs->resid > xs->datalen)
+ xs->resid = xs->datalen;
+ } else {
+ xs->resid = resid = xs->datalen;
+ if (st->flags & ST_FIXEDBLOCKS) {
+ resid /= st->blksize;
+ datalen /= st->blksize;
}
- if (sense->flags & SSD_ILI) {
- st->flags |= ST_EIO_PENDING;
- if (sense->error_code & SSD_ERRCODE_VALID &&
- (xs->flags & SCSI_SILENT) == 0)
- printf("%s: block wrong size, %d blocks
residual\n",
- st->sc_dev.dv_xname, info);
-
- /*
- * This quirk code helps the drive read
- * the first tape block, regardless of
- * format. That is required for these
- * drives to return proper MODE SENSE
- * information.
- */
- if ((st->quirks & ST_Q_SENSE_HELP) &&
- !(sc_link->flags & SDEV_MEDIA_LOADED))
- st->blksize -= 512;
+ }
+
+ if (sense->flags & SSD_FILEMARK) {
+ if (st->media_fileno != -1) {
+ st->media_fileno++;
+ st->media_blkno = 0;
}
+ if ((st->flags & ST_FIXEDBLOCKS) == 0)
+ return 0;
+ st->flags |= ST_AT_FILEMARK;
+ }
+
+ if (sense->flags & SSD_EOM) {
+ if ((st->flags & ST_FIXEDBLOCKS) == 0)
+ return EIO;
+ st->flags |= ST_EIO_PENDING;
+ }
+
+ if (sense->flags & SSD_ILI) {
+ if ((st->flags & ST_FIXEDBLOCKS) == 0) {
+ if (resid >= 0 && resid <= datalen)
+ return (0);
+ if ((xs->flags & SCSI_SILENT) == 0)
+ printf( "%s: bad residual %d out of "
+ "%d\n", st->sc_dev.dv_xname, resid,
+ datalen);
+ return (EIO);
+ }
+
+ /* Fixed size blocks. */
+ if (sense->error_code & SSD_ERRCODE_VALID)
+ if ((xs->flags & SCSI_SILENT) == 0)
+ printf("%s: block wrong size, %d blocks "
+ "residual\n", st->sc_dev.dv_xname, resid);
+ st->flags |= ST_EIO_PENDING;
/*
- * If no data was transferred, return immediately
+ * This quirk code helps the drive read the first tape block,
+ * regardless of format. That is required for these drives to
+ * return proper MODE SENSE information.
*/
- if (xs->resid >= xs->datalen) {
- xs->resid = xs->datalen;
- if (st->flags & ST_EIO_PENDING)
- return EIO;
- if (st->flags & ST_AT_FILEMARK) {
- return 0;
- }
- }
- } else { /* must be variable mode */
- xs->resid = xs->datalen; /* to be sure */
- if (sense->flags & SSD_EOM)
+ if ((st->quirks & ST_Q_SENSE_HELP) &&
+ !(sc_link->flags & SDEV_MEDIA_LOADED))
+ st->blksize -= 512;
+ }
+
+ if ((st->flags & ST_FIXEDBLOCKS) && xs->resid == xs->datalen) {
+ if (st->flags & ST_EIO_PENDING)
return EIO;
- if (sense->flags & SSD_FILEMARK) {
- if (st->media_fileno != -1) {
- st->media_fileno++;
- st->media_blkno = 0;
- }
+ if (st->flags & ST_AT_FILEMARK)
return 0;
- }
- if (sense->flags & SSD_ILI) {
- if (info < 0) {
- /*
- * the record was bigger than the read
- */
- if ((xs->flags & SCSI_SILENT) == 0)
- printf("%s: %d-byte record too big\n",
- st->sc_dev.dv_xname,
- xs->datalen - info);
- return (EIO);
- } else if (info > xs->datalen) {
- /*
- * huh? the residual is bigger than the request
- */
- if ((xs->flags & SCSI_SILENT) == 0)
- printf(
- "%s: bad residual %d out of %d\n",
- st->sc_dev.dv_xname, info,
- xs->datalen);
- return (EIO);
- }
- xs->resid = info;
- return (0);
- }
}
if (skey == SKEY_BLANK_CHECK) {