diff options
author | joerg <joerg@FreeBSD.org> | 2001-04-22 20:13:28 +0000 |
---|---|---|
committer | joerg <joerg@FreeBSD.org> | 2001-04-22 20:13:28 +0000 |
commit | ec7938a91df0a860785f3bd531cd22ba1ebb8ae2 (patch) | |
tree | 2a5256bec9cfd9b12d6af1978d016a6d80846a61 /sys/cam | |
parent | f6f0d430cc4156c3b3bfec6b23d1cc7ae53f9848 (diff) | |
download | FreeBSD-src-ec7938a91df0a860785f3bd531cd22ba1ebb8ae2.zip FreeBSD-src-ec7938a91df0a860785f3bd531cd22ba1ebb8ae2.tar.gz |
Fix the `tape drive spinning indefinately upon mt stat' problem.
With the recent changes in the CAM error handling, some problems in
the error handling of sa(4) have been uncovered. Basically, a number
of conditions that are not actually errors have been mistreated as
genuine errors. In particular:
. Trying to read in variable length mode with a mismatched blocksize
between the on-tape (virtual) blocks and the read(2) supplied buffer
size, causing an ILI SCSI condition, have caused an attempt to retry
the supposedly `errored' transfer, causing the tape to be read
continuously until it eventually hit EOM. Since by default any
simple mt(1) operation does an initial test read, an `mt stat' was
sufficient to trigger this bug.
Note that it's Justin's opinion that treating a NO SENSE as an EIO
is another bug in CAM. I feel not authorized to fix cam_periph.c
without another confirmation that i'm on the right track, however.
. Hitting a filemark caused the read(2) syscall to return EIO, instead
of returning a `short read'. Note that the current fix only solves
this problem in variable length mode. Fixed length mode uses a
different code path, and since i didn't grok all the intentions behind
that handling, i did not touch it (IOW: it's still broken, and you get
an EIO upon hitting a filemark).
The solution is to keep track of those conditions inside saerror(),
and upon completion to not call cam_periph_error() in that case. We
need to make sure that the device gets unfrozen if needed though (in
case of actual errors, cam_periph_error() does this on our behalf).
Not objected by: mjacob (who currently doesn't have the time to
review the patch)
Diffstat (limited to 'sys/cam')
-rw-r--r-- | sys/cam/scsi/scsi_sa.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/sys/cam/scsi/scsi_sa.c b/sys/cam/scsi/scsi_sa.c index adfbbb0..318534e 100644 --- a/sys/cam/scsi/scsi_sa.c +++ b/sys/cam/scsi/scsi_sa.c @@ -2286,7 +2286,7 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs) u_int32_t resid = 0; int32_t info = 0; int error_code, sense_key, asc, ascq; - int error, defer_action; + int error, defer_action, no_actual_error = FALSE; periph = xpt_path_periph(ccb->ccb_h.path); softc = (struct sa_softc *)periph->softc; @@ -2396,6 +2396,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs) if (defer_action) { error = -1; softc->flags |= SA_FLAG_EOF_PENDING; + } else { + no_actual_error = TRUE; } /* * Unconditionally, if we detected a filemark on a read, @@ -2424,6 +2426,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs) softc->flags |= SA_FLAG_EIO_PENDING; else error = EIO; + } else { + no_actual_error = TRUE; } /* * Bump the block number if we hadn't seen a filemark. @@ -2438,8 +2442,17 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs) } } } - if (error == 0) + if (error == 0 && !no_actual_error) return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb)); + if (no_actual_error) { + if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(ccb->ccb_h.path, + /* relsim_flags */0, + /* openings */0, + /* timeout */0, + /* getcount_only */ FALSE); + return (0); + } if (error == -1) return (0); |