summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorBob Beck <beck@cvs.openbsd.org>2006-05-31 03:01:45 +0000
committerBob Beck <beck@cvs.openbsd.org>2006-05-31 03:01:45 +0000
commite5386b7b2a08769532ed49309f46c540a9063742 (patch)
tree3c5415dcfcbd0ffd88cd7b175e5a2a3fd8f6f308 /sys
parent05464d11f08ccea6b5f871c2916fbd513b6c0200 (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.c96
-rw-r--r--sys/scsi/scsi_changer.h21
-rw-r--r--sys/sys/chio.h30
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_ */