diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/scsi/ch.c | 84 |
1 files changed, 73 insertions, 11 deletions
diff --git a/sys/scsi/ch.c b/sys/scsi/ch.c index 0889cab23bc..46651b7acd0 100644 --- a/sys/scsi/ch.c +++ b/sys/scsi/ch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ch.c,v 1.24 2006/05/11 00:45:59 krw Exp $ */ +/* $OpenBSD: ch.c,v 1.25 2006/05/28 17:24:43 beck Exp $ */ /* $NetBSD: ch.c,v 1.26 1997/02/21 22:06:52 thorpej Exp $ */ /* @@ -110,19 +110,23 @@ const struct scsi_inquiry_pattern ch_patterns[] = { "", "", ""}, }; -/* SCSI glue */ -struct scsi_device ch_switch = { - NULL, NULL, NULL, NULL -}; - int ch_move(struct ch_softc *, struct changer_move *); int ch_exchange(struct ch_softc *, struct changer_exchange *); int ch_position(struct ch_softc *, struct changer_position *); int ch_usergetelemstatus(struct ch_softc *, int, u_int8_t *); int ch_getelemstatus(struct ch_softc *, int, int, caddr_t, size_t); int ch_get_params(struct ch_softc *, int); +int ch_interpret_sense(struct scsi_xfer *xs); void ch_get_quirks(struct ch_softc *, struct scsi_inquiry_data *); +/* SCSI glue */ +struct scsi_device ch_switch = { + ch_interpret_sense, + NULL, + NULL, + NULL +}; + /* * SCSI changer quirks. */ @@ -200,13 +204,14 @@ chopen(dev, flags, fmt, p) sc->sc_link->flags |= SDEV_OPEN; /* - * Absorb any unit attention errors. Ignore "not ready" - * since this might occur if e.g. a tape isn't actually - * loaded in the drive. + * Absorb any unit attention errors. We must notice + * "Not ready" errors as a changer will report "In the + * process of getting ready" any time it must rescan + * itself to determine the state of the changer. */ error = scsi_test_unit_ready(sc->sc_link, - TEST_READY_RETRIES_DEFAULT, - SCSI_IGNORE_NOT_READY|SCSI_IGNORE_MEDIA_CHANGE); + TEST_READY_RETRIES_TAPE, + SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE); if (error) goto bad; @@ -694,3 +699,60 @@ ch_get_quirks(sc, inqbuf) sc->sc_settledelay = match->cq_settledelay; } } + +/* + * Look at the returned sense and act on the error and detirmine + * The unix error number to pass back... (0 = report no error) + * (-1 = continue processing) + */ +int +ch_interpret_sense(xs) + struct scsi_xfer *xs; +{ + struct scsi_sense_data *sense = &xs->sense; + struct scsi_link *sc_link = xs->sc_link; + u_int8_t serr = sense->error_code & SSD_ERRCODE; + u_int8_t skey = sense->flags & SSD_KEY; + + if (((sc_link->flags & SDEV_OPEN) == 0) || + (serr != 0x70 && serr != 0x71)) + return (EJUSTRETURN); /* let the generic code handle it */ + + switch (skey) { + + /* + * We do custom processing in ch for the unit becoming ready case. + * in this case we do not allow xs->retries to be decremented + * only on the "Unit Becoming Ready" case. This is because tape + * changers report "Unit Becoming Ready" when they rescan their + * state (i.e. when the door got opened) and can take a long time + * for large units. Rather than having a massive timeout for + * all operations (which would cause other problems) we allow + * changers to wait (but be interruptable with Ctrl-C) forever + * as long as they are reporting that they are becoming ready. + * all other cases are handled as per the default. + */ + case SKEY_NOT_READY: + if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0) + return (0); + switch (sense->add_sense_code) { + case 0x04: /* LUN not ready */ + switch (sense->add_sense_code_qual) { + case 0x01: /* Becoming Ready */ + SC_DEBUG(sc_link, SDEV_DB1, + ("not ready: busy (%#x)\n", + sense->add_sense_code_qual)); + /* don't count this as a retry */ + xs->retries++; + return (scsi_delay(xs, 1)); + default: + return (EJUSTRETURN); + } + break; + default: + return (EJUSTRETURN); + } + default: + return (EJUSTRETURN); + } +} |