summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Jacob <mjacob@FreeBSD.org>2001-08-30 16:25:24 +0000
committerMatt Jacob <mjacob@FreeBSD.org>2001-08-30 16:25:24 +0000
commit83e9f270b36335087328fb0898190674fe6548c7 (patch)
tree960cb6fc59f73828e42da7eaf5568a9d153d67c1
parent7e59bf67650ca375b1ea234935910f77011ad205 (diff)
Notes
-rw-r--r--sys/cam/scsi/scsi_sa.c197
1 files changed, 112 insertions, 85 deletions
diff --git a/sys/cam/scsi/scsi_sa.c b/sys/cam/scsi/scsi_sa.c
index ae1ed5757ea8..d22cf0c5ba4f 100644
--- a/sys/cam/scsi/scsi_sa.c
+++ b/sys/cam/scsi/scsi_sa.c
@@ -928,8 +928,6 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
}
}
}
- if (g->mt_resid) {
- }
error = 0;
break;
}
@@ -1063,17 +1061,20 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
/* see above */
softc->flags &=
~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
+ softc->flags &= ~SA_FLAG_ERR_PENDING;
softc->filemarks = 0;
break;
case MTERASE: /* erase */
error = saerase(periph, count);
softc->flags &=
~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
+ softc->flags &= ~SA_FLAG_ERR_PENDING;
break;
case MTRETENS: /* re-tension tape */
error = saretension(periph);
softc->flags &=
~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
+ softc->flags &= ~SA_FLAG_ERR_PENDING;
break;
case MTOFFL: /* rewind and put the drive offline */
@@ -1555,23 +1556,33 @@ sastart(struct cam_periph *periph, union ccb *start_ccb)
xpt_release_ccb(start_ccb);
} else if ((softc->flags & SA_FLAG_ERR_PENDING) != 0) {
struct bio *done_bp;
+again:
softc->queue_count--;
bioq_remove(&softc->bio_queue, bp);
bp->bio_resid = bp->bio_bcount;
- bp->bio_flags |= BIO_ERROR;
+ done_bp = bp;
if ((softc->flags & SA_FLAG_EOM_PENDING) != 0) {
- if (bp->bio_cmd == BIO_WRITE)
- bp->bio_error = ENOSPC;
- else
- bp->bio_error = EIO;
- }
- if ((softc->flags & SA_FLAG_EOF_PENDING) != 0) {
- bp->bio_error = EIO;
- }
- if ((softc->flags & SA_FLAG_EIO_PENDING) != 0) {
+ /*
+ * We now just clear errors in this case
+ * and let the residual be the notifier.
+ */
+ bp->bio_error = 0;
+ } else if ((softc->flags & SA_FLAG_EOF_PENDING) != 0) {
+ /*
+ * This can only happen if we're reading
+ * in fixed length mode. In this case,
+ * we dump the rest of the list the
+ * same way.
+ */
+ bp->bio_error = 0;
+ if (bioq_first(&softc->bio_queue) != NULL) {
+ biodone(done_bp);
+ goto again;
+ }
+ } else if ((softc->flags & SA_FLAG_EIO_PENDING) != 0) {
bp->bio_error = EIO;
+ bp->bio_flags |= BIO_ERROR;
}
- done_bp = bp;
bp = bioq_first(&softc->bio_queue);
/*
* Only if we have no other buffers queued up
@@ -2231,6 +2242,12 @@ exit:
*/
if (error != 0) {
(void) sareservereleaseunit(periph, FALSE);
+ } else {
+ /*
+ * Clear I/O residual.
+ */
+ softc->last_io_resid = 0;
+ softc->last_ctl_resid = 0;
}
return (error);
}
@@ -2286,20 +2303,25 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
struct scsi_sense_data *sense;
u_int32_t resid = 0;
int32_t info = 0;
- int error_code, sense_key, asc, ascq;
- int error, defer_action, no_actual_error = FALSE;
+ cam_status status;
+ int error_code, sense_key, asc, ascq, error, aqvalid;
periph = xpt_path_periph(ccb->ccb_h.path);
softc = (struct sa_softc *)periph->softc;
csio = &ccb->csio;
sense = &csio->sense_data;
scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq);
+ aqvalid = sense->extra_len >= 6;
error = 0;
+ status = csio->ccb_h.status & CAM_STATUS_MASK;
+
/*
- * Calculate/latch up, any residuals...
+ * Calculate/latch up, any residuals... We do this in a funny 2-step
+ * so we can print stuff here if we have CAM_DEBUG enabled for this
+ * unit.
*/
- if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) {
+ if (status == CAM_SCSI_STATUS_ERROR) {
if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
info = (int32_t) scsi_4btoul(sense->info);
resid = info;
@@ -2328,33 +2350,56 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
softc->last_ctl_resid = resid;
softc->last_resid_was_io = 0;
}
- CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Key 0x%x ASC/ASCQ "
- "0x%x 0x%x flags 0x%x resid %d dxfer_len %d\n", sense_key,
- asc, ascq, sense->flags & ~SSD_KEY_RESERVED, resid,
- csio->dxfer_len));
+ CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("CDB[0]=0x%x Key 0x%x "
+ "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %d "
+ "dxfer_len %d\n", csio->cdb_io.cdb_bytes[0] & 0xff,
+ sense_key, asc, ascq, status,
+ sense->flags & ~SSD_KEY_RESERVED, resid, csio->dxfer_len));
} else {
- CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Cam Status 0x%x\n",
- csio->ccb_h.status & CAM_STATUS_MASK));
+ CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+ ("Cam Status 0x%x\n", status));
}
- /*
- * If it's neither a SCSI Check Condition Error nor a non-read/write
- * command, let the common code deal with it the error setting.
- */
- if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR ||
- (CCB_Type(csio) == SA_CCB_WAITING)) {
+ switch (status) {
+ case CAM_REQ_CMP:
+ return (0);
+ case CAM_SCSI_STATUS_ERROR:
+ /*
+ * If a read/write command, we handle it here.
+ */
+ if (CCB_Type(csio) != SA_CCB_WAITING) {
+ break;
+ }
+ /*
+ * If this was just EOM/EOP, Filemark, Setmark or ILI detected
+ * on a non read/write command, we assume it's not an error
+ * and propagate the residule and return.
+ */
+ if ((aqvalid && asc == 0 && ascq > 0 && ascq <= 5) ||
+ (aqvalid == 0 && sense_key == SSD_KEY_NO_SENSE)) {
+ csio->resid = resid;
+ QFRLS(ccb);
+ return (0);
+ }
+ /*
+ * Otherwise, we let the common code handle this.
+ */
return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb));
- }
/*
- * Calculate whether we'll defer action.
+ * XXX: To Be Fixed
+ * We cannot depend upon CAM honoring retry counts for these.
*/
-
- if (resid > 0 && resid < csio->dxfer_len &&
- (softc->flags & SA_FLAG_FIXED) != 0) {
- defer_action = TRUE;
- } else {
- defer_action = FALSE;
+ case CAM_SCSI_BUS_RESET:
+ case CAM_BDR_SENT:
+ case CAM_REQUEUE_REQ:
+ if (ccb->ccb_h.retry_count <= 0) {
+ return (EIO);
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb));
}
/*
@@ -2362,43 +2407,34 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
* From this point out, we're only handling read/write cases.
* Handle writes && reads differently.
*/
-
+
if (csio->cdb_io.cdb_bytes[0] == SA_WRITE) {
- if (sense->flags & SSD_FILEMARK) {
- xpt_print_path(csio->ccb_h.path);
- printf("filemark detected on write?\n");
- if (softc->fileno != (daddr_t) -1) {
- softc->fileno++;
- softc->blkno = 0;
- csio->ccb_h.ccb_pflags |= SA_POSITION_UPDATED;
- }
- }
- if (sense->flags & SSD_EOM) {
+ if (sense_key == SSD_KEY_VOLUME_OVERFLOW) {
csio->resid = resid;
- if (defer_action) {
- error = -1;
- softc->flags |= SA_FLAG_EOM_PENDING;
- } else {
- error = ENOSPC;
- }
+ error = ENOSPC;
+ } else if (sense->flags & SSD_EOM) {
+ softc->flags |= SA_FLAG_EOM_PENDING;
+ /*
+ * Grotesque as it seems, the few times
+ * I've actually seen a non-zero resid,
+ * the tape drive actually lied and had
+ * writtent all the data!.
+ */
+ csio->resid = 0;
}
} else {
+ csio->resid = resid;
if (sense_key == SSD_KEY_BLANK_CHECK) {
- csio->resid = resid;
- if (defer_action) {
- error = -1;
+ if (softc->quirks & SA_QUIRK_1FM) {
+ error = 0;
softc->flags |= SA_FLAG_EOM_PENDING;
} else {
error = EIO;
}
- }
- if (sense->flags & SSD_FILEMARK) {
- csio->resid = resid;
- if (defer_action) {
+ } else if (sense->flags & SSD_FILEMARK) {
+ if (softc->flags & SA_FLAG_FIXED) {
error = -1;
softc->flags |= SA_FLAG_EOF_PENDING;
- } else {
- no_actual_error = TRUE;
}
/*
* Unconditionally, if we detected a filemark on a read,
@@ -2411,6 +2447,7 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
}
}
}
+
/*
* Incorrect Length usually applies to read, but can apply to writes.
*/
@@ -2422,13 +2459,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
error = EIO;
} else {
csio->resid = resid;
- if ((softc->flags & SA_FLAG_FIXED) != 0) {
- if (defer_action)
- softc->flags |= SA_FLAG_EIO_PENDING;
- else
- error = EIO;
- } else {
- no_actual_error = TRUE;
+ if (softc->flags & SA_FLAG_FIXED) {
+ softc->flags |= SA_FLAG_EIO_PENDING;
}
/*
* Bump the block number if we hadn't seen a filemark.
@@ -2443,22 +2475,17 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
}
}
}
- 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);
- else
- return (error);
+ if (error <= 0) {
+ /*
+ * Unfreeze the queue if frozen as we're not returning anything
+ * to our waiters that would indicate an I/O error has occurred
+ * (yet).
+ */
+ QFRLS(ccb);
+ error = 0;
+ }
+ return (error);
}
static int