Fix breakage introduced by r256843: removing the SA_CCB_WAITING bit

left some of the decisions based on its counterpart, SA_CCB_BUFFER_IO
being random.  As a result, propagation of the residual information
for the SPACE command was broken, so the number of filemarks
encountered during a SPACE operation was miscalculated.  Consequently,
systems relying on properly tracked filemark counters (like Bacula)
fell apart.

The change also removes a switch/case in sadone() which r256843
degraded to a single remaining case label.

PR:		192285
Approved by:	ken
MFC after:	2 weeks
This commit is contained in:
Joerg Wunsch 2014-07-31 22:09:50 +00:00
parent 13243ba9b2
commit 8d92719522
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=269353

View File

@ -113,16 +113,8 @@ typedef enum {
#define ccb_pflags ppriv_field0
#define ccb_bp ppriv_ptr1
#define SA_CCB_BUFFER_IO 0x0
#define SA_CCB_TYPEMASK 0x1
#define SA_POSITION_UPDATED 0x2
#define Set_CCB_Type(x, type) \
x->ccb_h.ccb_pflags &= ~SA_CCB_TYPEMASK; \
x->ccb_h.ccb_pflags |= type
#define CCB_Type(x) (x->ccb_h.ccb_pflags & SA_CCB_TYPEMASK)
/* bits in ccb_pflags */
#define SA_POSITION_UPDATED 0x1
typedef enum {
@ -1835,7 +1827,6 @@ sastart(struct cam_periph *periph, union ccb *start_ccb)
bp->bio_data, bp->bio_bcount, SSD_FULL_SIZE,
IO_TIMEOUT);
start_ccb->ccb_h.ccb_pflags &= ~SA_POSITION_UPDATED;
Set_CCB_Type(start_ccb, SA_CCB_BUFFER_IO);
start_ccb->ccb_h.ccb_bp = bp;
bp = bioq_first(&softc->bio_queue);
xpt_action(start_ccb);
@ -1860,92 +1851,86 @@ sadone(struct cam_periph *periph, union ccb *done_ccb)
{
struct sa_softc *softc;
struct ccb_scsiio *csio;
struct bio *bp;
int error;
softc = (struct sa_softc *)periph->softc;
csio = &done_ccb->csio;
switch (CCB_Type(csio)) {
case SA_CCB_BUFFER_IO:
{
struct bio *bp;
int error;
softc->dsreg = MTIO_DSREG_REST;
bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
error = 0;
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
if ((error = saerror(done_ccb, 0, 0)) == ERESTART) {
/*
* A retry was scheduled, so just return.
*/
return;
}
}
if (error == EIO) {
softc->dsreg = MTIO_DSREG_REST;
bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
error = 0;
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
if ((error = saerror(done_ccb, 0, 0)) == ERESTART) {
/*
* Catastrophic error. Mark the tape as frozen
* (we no longer know tape position).
*
* Return all queued I/O with EIO, and unfreeze
* our queue so that future transactions that
* attempt to fix this problem can get to the
* device.
*
* A retry was scheduled, so just return.
*/
return;
}
}
if (error == EIO) {
softc->flags |= SA_FLAG_TAPE_FROZEN;
bioq_flush(&softc->bio_queue, NULL, EIO);
}
if (error != 0) {
bp->bio_resid = bp->bio_bcount;
bp->bio_error = error;
bp->bio_flags |= BIO_ERROR;
/*
* In the error case, position is updated in saerror.
*/
} else {
bp->bio_resid = csio->resid;
bp->bio_error = 0;
if (csio->resid != 0) {
bp->bio_flags |= BIO_ERROR;
}
if (bp->bio_cmd == BIO_WRITE) {
softc->flags |= SA_FLAG_TAPE_WRITTEN;
softc->filemarks = 0;
}
if (!(csio->ccb_h.ccb_pflags & SA_POSITION_UPDATED) &&
(softc->blkno != (daddr_t) -1)) {
if ((softc->flags & SA_FLAG_FIXED) != 0) {
u_int32_t l;
if (softc->blk_shift != 0) {
l = bp->bio_bcount >>
softc->blk_shift;
} else {
l = bp->bio_bcount /
softc->media_blksize;
}
softc->blkno += (daddr_t) l;
} else {
softc->blkno++;
}
}
}
/*
* If we had an error (immediate or pending),
* release the device queue now.
* Catastrophic error. Mark the tape as frozen
* (we no longer know tape position).
*
* Return all queued I/O with EIO, and unfreeze
* our queue so that future transactions that
* attempt to fix this problem can get to the
* device.
*
*/
if (error || (softc->flags & SA_FLAG_ERR_PENDING))
cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0);
if (error || bp->bio_resid) {
CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
("error %d resid %ld count %ld\n", error,
bp->bio_resid, bp->bio_bcount));
softc->flags |= SA_FLAG_TAPE_FROZEN;
bioq_flush(&softc->bio_queue, NULL, EIO);
}
if (error != 0) {
bp->bio_resid = bp->bio_bcount;
bp->bio_error = error;
bp->bio_flags |= BIO_ERROR;
/*
* In the error case, position is updated in saerror.
*/
} else {
bp->bio_resid = csio->resid;
bp->bio_error = 0;
if (csio->resid != 0) {
bp->bio_flags |= BIO_ERROR;
}
if (bp->bio_cmd == BIO_WRITE) {
softc->flags |= SA_FLAG_TAPE_WRITTEN;
softc->filemarks = 0;
}
if (!(csio->ccb_h.ccb_pflags & SA_POSITION_UPDATED) &&
(softc->blkno != (daddr_t) -1)) {
if ((softc->flags & SA_FLAG_FIXED) != 0) {
u_int32_t l;
if (softc->blk_shift != 0) {
l = bp->bio_bcount >>
softc->blk_shift;
} else {
l = bp->bio_bcount /
softc->media_blksize;
}
softc->blkno += (daddr_t) l;
} else {
softc->blkno++;
}
}
biofinish(bp, softc->device_stats, 0);
break;
}
/*
* If we had an error (immediate or pending),
* release the device queue now.
*/
if (error || (softc->flags & SA_FLAG_ERR_PENDING))
cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0);
if (error || bp->bio_resid) {
CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
("error %d resid %ld count %ld\n", error,
bp->bio_resid, bp->bio_bcount));
}
biofinish(bp, softc->device_stats, 0);
xpt_release_ccb(done_ccb);
}
@ -2498,7 +2483,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
info /= softc->media_blksize;
}
}
if (CCB_Type(csio) == SA_CCB_BUFFER_IO) {
if (csio->cdb_io.cdb_bytes[0] == SA_READ ||
csio->cdb_io.cdb_bytes[0] == SA_WRITE) {
bcopy((caddr_t) sense, (caddr_t) &softc->last_io_sense,
sizeof (struct scsi_sense_data));
bcopy(csio->cdb_io.cdb_bytes, softc->last_io_cdb,