diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2006-05-31 03:01:45 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2006-05-31 03:01:45 +0000 |
commit | e5386b7b2a08769532ed49309f46c540a9063742 (patch) | |
tree | 3c5415dcfcbd0ffd88cd7b175e5a2a3fd8f6f308 /sys | |
parent | 05464d11f08ccea6b5f871c2916fbd513b6c0200 (diff) |
Add support for primary and alternate volume tags to ch(4) - borrowed
and adapted from FreeBSD. This adds the ability for status requests to ask
for the volume tags (usually bar codes, on changers with a bar code reader)
on media inthe library.
ok deraadt@, krw@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/scsi/ch.c | 96 | ||||
-rw-r--r-- | sys/scsi/scsi_changer.h | 21 | ||||
-rw-r--r-- | sys/sys/chio.h | 30 |
3 files changed, 117 insertions, 30 deletions
diff --git a/sys/scsi/ch.c b/sys/scsi/ch.c index 46651b7acd0..104e99672d4 100644 --- a/sys/scsi/ch.c +++ b/sys/scsi/ch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ch.c,v 1.25 2006/05/28 17:24:43 beck Exp $ */ +/* $OpenBSD: ch.c,v 1.26 2006/05/31 03:01:44 beck Exp $ */ /* $NetBSD: ch.c,v 1.26 1997/02/21 22:06:52 thorpej Exp $ */ /* @@ -113,8 +113,9 @@ const struct scsi_inquiry_pattern ch_patterns[] = { 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_usergetelemstatus(struct ch_softc *, + struct changer_element_status_request *); +int ch_getelemstatus(struct ch_softc *, int, int, caddr_t, size_t, int); 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 *); @@ -206,7 +207,7 @@ chopen(dev, flags, fmt, p) /* * 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 + * 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, @@ -338,10 +339,10 @@ chioctl(dev, cmd, data, flags, p) break; } case CHIOGSTATUS: { - struct changer_element_status *ces = - (struct changer_element_status *)data; + struct changer_element_status_request *cesr = + (struct changer_element_status_request *)data; - error = ch_usergetelemstatus(sc, ces->ces_type, ces->ces_data); + error = ch_usergetelemstatus(sc, cesr); break; } /* Implement prevent/allow? */ @@ -497,23 +498,63 @@ ch_position(sc, cp) } /* + * Copy a volume tag to a volume_tag struct, converting SCSI byte order + * to host native byte order in the volume serial number. The volume + * label as returned by the changer is transferred to user mode as + * nul-terminated string. Volume labels are truncated at the first + * space, as suggested by SCSI-2. + */ +static void +copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag) +{ + int i; + + for (i=0; i<CH_VOLTAG_MAXLEN; i++) { + char c = voltag->vif[i]; + if (c && c != ' ') + uvoltag->cv_volid[i] = c; + else + break; + } + uvoltag->cv_volid[i] = '\0'; + uvoltag->cv_serial = _2btol(voltag->vsn); +} + +/* + * Copy an an element status descriptor to a user-mode + * changer_element_status structure. + */ +static void +copy_element_status(int flags, struct read_element_status_descriptor *desc, + struct changer_element_status *ces) +{ + ces->ces_flags = desc->flags1; + + if (flags & READ_ELEMENT_STATUS_PVOLTAG) + copy_voltag(&ces->ces_pvoltag, &desc->pvoltag); + if (flags & READ_ELEMENT_STATUS_AVOLTAG) + copy_voltag(&ces->ces_avoltag, &desc->avoltag); +} + +/* * Perform a READ ELEMENT STATUS on behalf of the user, and return to * the user only the data the user is interested in (i.e. an array of - * flags bytes). + * changer_element_status structures) */ int -ch_usergetelemstatus(sc, chet, uptr) +ch_usergetelemstatus(sc, cesr) struct ch_softc *sc; - int chet; - u_int8_t *uptr; + struct changer_element_status_request *cesr; { + struct changer_element_status *user_data = NULL; struct read_element_status_header *st_hdr; struct read_element_status_page_header *pg_hdr; struct read_element_status_descriptor *desc; caddr_t data = NULL; - size_t size, desclen; + size_t size, desclen, udsize; + int chet = cesr->cesr_type; int avail, i, error = 0; - u_int8_t *user_data = NULL; + int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0; /* * If there are no elements of the requested type in the changer, @@ -529,7 +570,8 @@ ch_usergetelemstatus(sc, chet, uptr) * that the first one can fit into 1k. */ data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK); - error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024); + error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, + want_voltags); if (error) goto done; @@ -549,7 +591,7 @@ ch_usergetelemstatus(sc, chet, uptr) free(data, M_DEVBUF); data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK); error = ch_getelemstatus(sc, sc->sc_firsts[chet], - sc->sc_counts[chet], data, size); + sc->sc_counts[chet], data, size, want_voltags); if (error) goto done; @@ -557,23 +599,29 @@ ch_usergetelemstatus(sc, chet, uptr) * Fill in the user status array. */ st_hdr = (struct read_element_status_header *)data; + pg_hdr = (struct read_element_status_page_header *)((u_long)data + + sizeof(struct read_element_status_header)); + avail = _2btol(st_hdr->count); if (avail != sc->sc_counts[chet]) printf("%s: warning, READ ELEMENT STATUS avail != count\n", sc->sc_dev.dv_xname); + udsize = avail * sizeof(struct changer_element_status); - user_data = (u_int8_t *)malloc(avail, M_DEVBUF, M_WAITOK); + user_data = malloc(udsize, M_DEVBUF, M_WAITOK); + bzero(user_data, udsize); desc = (struct read_element_status_descriptor *)((u_long)data + sizeof(struct read_element_status_header) + sizeof(struct read_element_status_page_header)); for (i = 0; i < avail; ++i) { - user_data[i] = desc->flags1; + struct changer_element_status *ces = &(user_data[i]); + copy_element_status(pg_hdr->flags, desc, ces); (u_long)desc += desclen; } - /* Copy flags array out to userspace. */ - error = copyout(user_data, uptr, avail); + /* Copy array out to userspace. */ + error = copyout(user_data, cesr->cesr_data, udsize); done: if (data != NULL) @@ -584,11 +632,13 @@ ch_usergetelemstatus(sc, chet, uptr) } int -ch_getelemstatus(sc, first, count, data, datalen) +ch_getelemstatus(sc, first, count, data, datalen, voltag) struct ch_softc *sc; - int first, count; + int first; + int count; caddr_t data; size_t datalen; + int voltag; { struct scsi_read_element_status cmd; @@ -600,6 +650,8 @@ ch_getelemstatus(sc, first, count, data, datalen) _lto2b(first, cmd.sea); _lto2b(count, cmd.count); _lto3b(datalen, cmd.len); + if (voltag) + cmd.byte2 |= READ_ELEMENT_STATUS_VOLTAG; /* * Send command to changer. @@ -726,7 +778,7 @@ ch_interpret_sense(xs) * 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 + * 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. diff --git a/sys/scsi/scsi_changer.h b/sys/scsi/scsi_changer.h index e4ca108285f..e20f2a0714f 100644 --- a/sys/scsi/scsi_changer.h +++ b/sys/scsi/scsi_changer.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_changer.h,v 1.3 1996/10/31 01:09:22 niklas Exp $ */ +/* $OpenBSD: scsi_changer.h,v 1.4 2006/05/31 03:01:44 beck Exp $ */ /* $NetBSD: scsi_changer.h,v 1.7 1996/04/03 00:25:48 thorpej Exp $ */ /* @@ -49,7 +49,7 @@ * * TRW Financial Systems, in accordance with their agreement with Carnegie * Mellon University, makes this software available to CMU to distribute - * or use in any manner that they see fit as long as this message is kept with + * or use in any manner that they see fit as long as this message is kept with * the software. For this reason TFS also grants any other persons or * organisations permission to use or modify this software. * @@ -184,6 +184,16 @@ struct read_element_status_page_header { u_int8_t nbytes[3]; /* byte count of all descriptors */ }; +/* + * Format of a volume tag + */ + +struct volume_tag { + u_int8_t vif[32]; /* volume identification field */ + u_int8_t reserved[2]; + u_int8_t vsn[2]; /* volume sequence number */ +}; + struct read_element_status_descriptor { u_int8_t eaddr[2]; /* element address */ u_int8_t flags1; @@ -230,7 +240,12 @@ struct read_element_status_descriptor { * * bytes 48-83: Alternate volume tag information. * (field omitted if AVOLTAG = 0) - * + */ + + struct volume_tag pvoltag; /* omitted if PVOLTAG == 0 */ + struct volume_tag avoltag; /* omitted if AVOLTAG == 0 */ + + /* * bytes 84-87: Reserved (moved up if either of the above fields * are omitted) * diff --git a/sys/sys/chio.h b/sys/sys/chio.h index 6a64ed50263..88afaa92e7a 100644 --- a/sys/sys/chio.h +++ b/sys/sys/chio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: chio.h,v 1.6 2003/03/28 11:42:28 mickey Exp $ */ +/* $OpenBSD: chio.h,v 1.7 2006/05/31 03:01:44 beck Exp $ */ /* $NetBSD: chio.h,v 1.8 1996/04/03 00:25:21 thorpej Exp $ */ /* @@ -50,6 +50,11 @@ #define CHET_DT 3 /* data transfer (drive) */ /* + * Maximum length of a volume identification string + */ +#define CH_VOLTAG_MAXLEN 32 + +/* * Structure used to execute a MOVE MEDIUM command. */ struct changer_move { @@ -114,12 +119,27 @@ struct changer_params { int cp_ndrives; /* number of drives */ }; +struct changer_voltag { + u_char cv_volid[CH_VOLTAG_MAXLEN + 1]; + u_int16_t cv_serial; +}; + +struct changer_element_status { + int ces_type; /* element type */ + u_int8_t ces_flags; /* flags */ + struct changer_voltag ces_pvoltag; /* primary voltag */ + struct changer_voltag ces_avoltag; /* alternate voltag */ +}; + /* * Command used to get element status. */ -struct changer_element_status { - int ces_type; /* element type */ - u_int8_t *ces_data; /* pre-allocated data storage */ +struct changer_element_status_request { + int cesr_type; /* element type */ + int cesr_flags; +#define CESR_VOLTAGS 0x01 + + struct changer_element_status *cesr_data; /* pre-allocated data storage */ }; /* @@ -151,6 +171,6 @@ struct changer_element_status { #define CHIOGPICKER _IOR('c', 0x44, int) #define CHIOSPICKER _IOW('c', 0x45, int) #define CHIOGPARAMS _IOR('c', 0x46, struct changer_params) -#define CHIOGSTATUS _IOW('c', 0x48, struct changer_element_status) +#define CHIOGSTATUS _IOW('c', 0x48, struct changer_element_status_request) #endif /* _SYS_CHIO_H_ */ |