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)
This commit is contained in:
parent
bcc11eec02
commit
fc89704c57
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user