Date: Thu, 11 Dec 1997 11:30:26 -0800 (PST) From: Matt Dillon <dillon@best.net> To: FreeBSD-gnats-submit@FreeBSD.ORG Subject: kern/5275: tape changer device volume support added Message-ID: <199712111930.LAA07999@flea.best.net> Resent-Message-ID: <199712111940.LAA08420@hub.freebsd.org>
index | next in thread | raw e-mail
>Number: 5275
>Category: kern
>Synopsis: Added volume (barcode) support to tape changer device (ch)
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Thu Dec 11 11:40:01 PST 1997
>Last-Modified:
>Originator: Matt Dillon
>Organization:
Best Internet Communications
>Release: FreeBSD 2.2.5-STABLE i386
>Environment:
FreeBSD 2.2.5, large SCSI-II tape library / exabyte drives
>Description:
The 'ch' command does not extract volume label information. Volume
label information is an essential part of a large tape library because
it allows software to manipulate tapes by their bar-code label rather
then having to remember what tape is in what slot.
>How-To-Repeat:
chio status does not return volume labels :-)
>Fix:
My fix consists of three context diffs. I have added additional
commands to the chio do-everything ioctl to allow for future status
extensions and implemented volume-label retrieval with the current
extension.
sys/sys/chio.h: added an extended information structure and record
size specification.
sys/scsi/ch.c: added an extended command to the do-every ioctl.
bin/chio/chio.c: chio now uses the extended command to retrieve
volume label information, and I added a 'locate'
command to allow one to locate a tape volume
by name.
Also, the device works wonderfully, you can remove the comment in
the manual page for ch/chio with regards to it being untested. Kudos
to Jason Thorpe!
*** sys/sys/LINK/chio.h Tue Mar 11 11:39:07 1997
--- sys/sys/chio.h Tue Dec 2 12:48:24 1997
***************
*** 126,131 ****
--- 126,143 ----
u_int8_t *ces_data; /* pre-allocated data storage */
};
+ struct changer_element_info {
+ u_int8_t cei_flags;
+ char cei_volume[37];
+ char cei_pad[2];
+ };
+
+ struct changer_element_vstatus {
+ int ces_type;
+ int ces_recSize; /* ces_info object size */
+ struct changer_element_info *ces_info; /* array */
+ };
+
/*
* Data returned by CHIOGSTATUS is an array of flags bytes.
* Not all flags have meaning for all element types.
***************
*** 152,156 ****
--- 164,170 ----
#define CHIOSPICKER _IOW('c', 0x05, int)
#define CHIOGPARAMS _IOR('c', 0x06, struct changer_params)
#define CHIOGSTATUS _IOW('c', 0x08, struct changer_element_status)
+ #define CHIOGSTATUSVOL _IOW('c', 0x09, struct changer_element_vstatus)
+ #define CHIOGLOCATEVOL _IOW('c', 0x0A, struct changer_element_vstatus)
#endif /* !_SYS_CHIO_H_ */
*** sys/scsi/LINK/ch.c Fri Mar 7 01:34:26 1997
--- sys/scsi/ch.c Mon Dec 1 14:00:12 1997
***************
*** 54,59 ****
--- 54,60 ----
#include <scsi/scsi_all.h>
#include <scsi/scsi_changer.h>
#include <scsi/scsiconf.h>
+ #include <stddef.h>
#include "ch.h"
***************
*** 161,168 ****
static int ch_move __P((struct ch_softc *, struct changer_move *));
static int ch_exchange __P((struct ch_softc *, struct changer_exchange *));
static int ch_position __P((struct ch_softc *, struct changer_position *));
! static int ch_usergetelemstatus __P((struct ch_softc *, int, u_int8_t *));
! static int ch_getelemstatus __P((struct ch_softc *, int, int, caddr_t, size_t));
static int ch_get_params __P((struct ch_softc *, int));
static errval
--- 162,169 ----
static int ch_move __P((struct ch_softc *, struct changer_move *));
static int ch_exchange __P((struct ch_softc *, struct changer_exchange *));
static int ch_position __P((struct ch_softc *, struct changer_position *));
! static int ch_usergetelemstatus __P((struct ch_softc *, int, u_int8_t *, int));
! static int ch_getelemstatus __P((struct ch_softc *, int, int, caddr_t, size_t, int));
static int ch_get_params __P((struct ch_softc *, int));
static errval
***************
*** 342,348 ****
struct changer_element_status *ces =
(struct changer_element_status *)data;
! error = ch_usergetelemstatus(sc, ces->ces_type, ces->ces_data);
break; }
/* Implement prevent/allow? */
--- 343,360 ----
struct changer_element_status *ces =
(struct changer_element_status *)data;
! error = ch_usergetelemstatus(sc, ces->ces_type, ces->ces_data, 1);
! break; }
!
! case CHIOGSTATUSVOL: {
! struct changer_element_vstatus *ces =
! (struct changer_element_vstatus *)data;
!
! error = ch_usergetelemstatus(sc, ces->ces_type, (u_int8_t *)ces->ces_info, ces->ces_recSize);
! break; }
!
! case CHIOGLOCATEVOL: {
! error = EINVAL;
break; }
/* Implement prevent/allow? */
***************
*** 499,511 ****
/*
* 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).
*/
static int
! ch_usergetelemstatus(sc, chet, uptr)
struct ch_softc *sc;
int chet;
u_int8_t *uptr;
{
struct read_element_status_header *st_hdr;
struct read_element_status_page_header *pg_hdr;
--- 511,525 ----
/*
* 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). If the user requested an extended status, we return
! * additional information formatted into a struct changer_element_info
*/
static int
! ch_usergetelemstatus(sc, chet, uptr, recSize)
struct ch_softc *sc;
int chet;
u_int8_t *uptr;
+ int recSize;
{
struct read_element_status_header *st_hdr;
struct read_element_status_page_header *pg_hdr;
***************
*** 513,518 ****
--- 527,533 ----
caddr_t data = NULL;
size_t size, desclen;
int avail, i, error = 0;
+ int pgflags;
u_int8_t *user_data = NULL;
/*
***************
*** 523,535 ****
return (EINVAL);
/*
* Request one descriptor for the given element type. This
* is used to determine the size of the descriptor so that
* we can allocate enough storage for all of them. We assume
* that the first one can fit into 1k.
*/
data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
! if (error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024))
goto done;
st_hdr = (struct read_element_status_header *)data;
--- 538,556 ----
return (EINVAL);
/*
+ * allow unaligned sizes (e.g. 1 is valid)
+ */
+ if (recSize < 1 || recSize > 256)
+ return (EINVAL);
+
+ /*
* Request one descriptor for the given element type. This
* is used to determine the size of the descriptor so that
* we can allocate enough storage for all of them. We assume
* that the first one can fit into 1k.
*/
data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
! if (error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024, (recSize > 1)))
goto done;
st_hdr = (struct read_element_status_header *)data;
***************
*** 537,542 ****
--- 558,565 ----
sizeof(struct read_element_status_header));
desclen = scsi_2btou(pg_hdr->edl);
+ pgflags = pg_hdr->flags;
+
size = sizeof(struct read_element_status_header) +
sizeof(struct read_element_status_page_header) +
(desclen * sc->sc_counts[chet]);
***************
*** 548,554 ****
free(data, M_DEVBUF);
data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
if (error = ch_getelemstatus(sc, sc->sc_firsts[chet],
! sc->sc_counts[chet], data, size))
goto done;
/*
--- 571,577 ----
free(data, M_DEVBUF);
data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
if (error = ch_getelemstatus(sc, sc->sc_firsts[chet],
! sc->sc_counts[chet], data, size, (recSize > 1)))
goto done;
/*
***************
*** 560,577 ****
printf("%s: warning, READ ELEMENT STATUS avail != count\n",
sc->sc_dev.dv_xname);
! user_data = (u_int8_t *)malloc(avail, M_DEVBUF, M_WAITOK);
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;
(u_long)desc += desclen;
}
/* Copy flags array out to userspace. */
! error = copyout(user_data, uptr, avail);
done:
if (data != NULL)
--- 583,608 ----
printf("%s: warning, READ ELEMENT STATUS avail != count\n",
sc->sc_dev.dv_xname);
! user_data = (u_int8_t *)malloc(avail * recSize, M_DEVBUF, M_WAITOK);
desc = (struct read_element_status_descriptor *)((u_long)data +
sizeof(struct read_element_status_header) +
sizeof(struct read_element_status_page_header));
+ bzero(user_data, avail * recSize);
for (i = 0; i < avail; ++i) {
! struct changer_element_info *cei = (struct changer_element_info *)&user_data[i * recSize];
!
! cei->cei_flags = desc->flags1;
! if (recSize >= offsetof(struct changer_element_info, cei_pad[0]) &&
! (pgflags & READ_ELEMENT_STATUS_PVOLTAG)
! ) {
! bcopy((char *)desc + 12, cei->cei_volume, 36);
! }
(u_long)desc += desclen;
}
/* Copy flags array out to userspace. */
! error = copyout(user_data, uptr, avail * recSize);
done:
if (data != NULL)
***************
*** 582,592 ****
}
static int
! ch_getelemstatus(sc, first, count, data, datalen)
struct ch_softc *sc;
int first, count;
caddr_t data;
size_t datalen;
{
struct scsi_read_element_status cmd;
--- 613,624 ----
}
static int
! ch_getelemstatus(sc, first, count, data, datalen, voltag)
struct ch_softc *sc;
int first, count;
caddr_t data;
size_t datalen;
+ int voltag;
{
struct scsi_read_element_status cmd;
***************
*** 595,600 ****
--- 627,633 ----
*/
bzero(&cmd, sizeof(cmd));
cmd.opcode = READ_ELEMENT_STATUS;
+ cmd.byte2 = (voltag) ? READ_ELEMENT_STATUS_VOLTAG : 0;
scsi_uto2b(first, cmd.sea);
scsi_uto2b(count, cmd.count);
scsi_uto3b(datalen, cmd.len);
*** bin/chio/LINK/chio.c Wed Sep 17 13:17:23 1997
--- bin/chio/chio.c Mon Dec 1 18:40:09 1997
***************
*** 54,59 ****
--- 54,60 ----
static int parse_special __P((char *));
static int is_special __P((char *));
static char *bits_to_string __P((int, const char *));
+ void sstrip(char *s);
static int do_move __P((char *, int, char **));
static int do_exchange __P((char *, int, char **));
***************
*** 62,67 ****
--- 63,69 ----
static int do_getpicker __P((char *, int, char **));
static int do_setpicker __P((char *, int, char **));
static int do_status __P((char *, int, char **));
+ static int do_locate __P((char *, int, char **));
/* Valid changer element types. */
const struct element_type elements[] = {
***************
*** 81,86 ****
--- 83,89 ----
{ "getpicker", do_getpicker },
{ "setpicker", do_setpicker },
{ "status", do_status },
+ { "locate", do_locate },
{ NULL, 0 },
};
***************
*** 462,470 ****
int argc;
char **argv;
{
! struct changer_element_status cmd;
struct changer_params data;
! u_int8_t *statusp;
int i, count, chet, schet, echet;
char *description;
--- 465,473 ----
int argc;
char **argv;
{
! struct changer_element_vstatus cmd;
struct changer_params data;
! struct changer_element_info *statusp;
int i, count, chet, schet, echet;
char *description;
***************
*** 535,558 ****
}
/* Allocate storage for the status bytes. */
! if ((statusp = (u_int8_t *)malloc(count)) == NULL)
errx(1, "can't allocate status storage");
! bzero(statusp, count);
bzero(&cmd, sizeof(cmd));
cmd.ces_type = chet;
! cmd.ces_data = statusp;
! if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cmd)) {
free(statusp);
! err(1, "%s: CHIOGSTATUS", changer_name);
}
/* Dump the status for each element of this type. */
for (i = 0; i < count; ++i) {
! printf("%s %d: %s\n", description, i,
! bits_to_string(statusp[i], CESTATUS_BITS));
}
free(statusp);
--- 538,564 ----
}
/* Allocate storage for the status bytes. */
! if ((statusp = (void *)malloc(count * sizeof(struct changer_element_info))) == NULL)
errx(1, "can't allocate status storage");
! bzero(statusp, count * sizeof(struct changer_element_info));
bzero(&cmd, sizeof(cmd));
cmd.ces_type = chet;
! cmd.ces_info = statusp;
! cmd.ces_recSize = sizeof(struct changer_element_info);
! if (ioctl(changer_fd, CHIOGSTATUSVOL, (char *)&cmd)) {
free(statusp);
! err(1, "%s: CHIOGSTATUSVOL", changer_name);
}
/* Dump the status for each element of this type. */
for (i = 0; i < count; ++i) {
! printf("%s %d: %s %s\n", description, i,
! bits_to_string(statusp[i].cei_flags, CESTATUS_BITS),
! statusp[i].cei_volume
! );
}
free(statusp);
***************
*** 566,571 ****
--- 572,677 ----
}
static int
+ do_locate(cname, argc, argv)
+ char *cname;
+ int argc;
+ char **argv;
+ {
+ struct changer_element_vstatus cmd;
+ struct changer_params data;
+ struct changer_element_info *statusp;
+ int i, count, chet;
+ int r = 1;
+ char *description;
+
+ count = 0;
+ description = NULL;
+
+ /*
+ * On a status command, we expect the following:
+ *
+ * VOLTAG
+ *
+ * If we get no arguments, an error occurs
+ */
+ if (argc != 1) {
+ warnx("%s: expected one volume tag", cname);
+ goto usage;
+ }
+
+ /*
+ * Get params from changer. Specifically, we need the element
+ * counts.
+ */
+ bzero(&data, sizeof(data));
+ if (ioctl(changer_fd, CHIOGPARAMS, (char *)&data))
+ err(1, "%s: CHIOGPARAMS", changer_name);
+
+ for (chet = CHET_MT; chet <= CHET_DT; ++chet) {
+ switch (chet) {
+ case CHET_MT:
+ count = data.cp_npickers;
+ description = "picker";
+ break;
+
+ case CHET_ST:
+ count = data.cp_nslots;
+ description = "slot";
+ break;
+
+ case CHET_IE:
+ count = data.cp_nportals;
+ description = "portal";
+ break;
+
+ case CHET_DT:
+ count = data.cp_ndrives;
+ description = "drive";
+ break;
+ }
+
+ if (count == 0)
+ continue;
+
+ /* Allocate storage for the status bytes. */
+ if ((statusp = (void *)malloc(count * sizeof(struct changer_element_info))) == NULL)
+ errx(1, "can't allocate status storage");
+
+ bzero(statusp, count * sizeof(struct changer_element_info));
+ bzero(&cmd, sizeof(cmd));
+
+ cmd.ces_type = chet;
+ cmd.ces_info = statusp;
+ cmd.ces_recSize = sizeof(struct changer_element_info);
+
+ if (ioctl(changer_fd, CHIOGSTATUSVOL, (char *)&cmd)) {
+ free(statusp);
+ err(1, "%s: CHIOGSTATUSVOL", changer_name);
+ }
+
+ /* Dump the status for each element of this type. */
+ for (i = 0; i < count; ++i) {
+ sstrip(statusp[i].cei_volume);
+
+ if (strcmp(*argv, statusp[i].cei_volume) == 0) {
+ printf("%s %d\n", description, i);
+ r = 0;
+ break;
+ }
+ }
+ free(statusp);
+ if (i != count)
+ break;
+ }
+
+ return (r);
+
+ usage:
+ fprintf(stderr, "usage: chio %s [<element type>]\n", cname);
+ return (1);
+ }
+
+ static int
parse_element_type(cp)
char *cp;
{
***************
*** 665,667 ****
--- 771,785 ----
fprintf(stderr, "\n");
exit(1);
}
+
+ void
+ sstrip(char *s)
+ {
+ char *p = s + strlen(s);
+ while (p >= s) {
+ if (*p == ' ')
+ *p = 0;
+ --p;
+ }
+ }
+
>Audit-Trail:
>Unformatted:
home |
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199712111930.LAA07999>
