diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2006-05-28 17:24:44 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2006-05-28 17:24:44 +0000 |
commit | 4d7e39ac1a71def26ae9e6a35bbd5c9cf678ad51 (patch) | |
tree | 6288d195288e3a66286817eb159399d705f1b947 | |
parent | 63117f6b5a2b5f44674fa3ecb781353da57e1297 (diff) |
Fix open(2) semantics for ch(4) to not be completely on fresh minty crack:
1) Don't use SCSI_IGNORE_NOT_READY when doing test_unit ready to wait for
the device to come up.
2) use SCSI_IGNORE_ILLEGAL_REQUEST when doing test_unit_ready to wait for
the device to come up (just as is done in st(4))
3) add a ch_interpret_sense routing to perform special handling of
the case where the unit is in the process of becoming ready. Hope springs
eternal, that if the device tells us it is trying to become ready, then
we should wait for it to do so, however long it takes (and on tape library
scans this can take a while - i.e. a few minutes for large libraries).
The custom handler ensures that the retry count is not decremented in
this case and this case only.
ok krw@
-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); + } +} |