From dillon@flea.best.net Thu Dec 11 11:31:00 1997 Received: from flea.best.net (root@flea.best.net [206.184.139.131]) by hub.freebsd.org (8.8.7/8.8.7) with ESMTP id LAA07598 for ; Thu, 11 Dec 1997 11:30:59 -0800 (PST) (envelope-from dillon@flea.best.net) Received: (from dillon@localhost) by flea.best.net (8.8.8/8.7.3) id LAA07999; Thu, 11 Dec 1997 11:30:26 -0800 (PST) Message-Id: <199712111930.LAA07999@flea.best.net> Date: Thu, 11 Dec 1997 11:30:26 -0800 (PST) From: Matt Dillon Reply-To: dillon@best.net To: FreeBSD-gnats-submit@freebsd.org Subject: tape changer device volume support added X-Send-Pr-Version: 3.2 >Number: 5275 >Category: kern >Synopsis: [PATCH] Added volume (barcode) support to tape changer device (ch) >Confidential: no >Severity: non-critical >Priority: low >Responsible: dillon >State: closed >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Thu Dec 11 11:40:01 PST 1997 >Closed-Date: Mon Dec 10 14:35:29 PST 2001 >Last-Modified: Mon Dec 10 14:38:04 PST 2001 >Originator: Matt Dillon >Release: FreeBSD 2.2.5-STABLE i386 >Organization: Best Internet Communications >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 #include #include + #include #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 []\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; + } + } + >Release-Note: >Audit-Trail: State-Changed-From-To: open->suspended State-Changed-By: phk State-Changed-When: Wed May 27 02:42:05 PDT 1998 State-Changed-Why: awaiting committer Responsible-Changed-From-To: freebsd-bugs->dillon Responsible-Changed-By: johan Responsible-Changed-When: Thu Aug 10 23:41:12 PDT 2000 Responsible-Changed-Why: Let Matt handle his own PRs. http://www.freebsd.org/cgi/query-pr.cgi?pr=5275 State-Changed-From-To: suspended->closed State-Changed-By: dillon State-Changed-When: Mon Dec 10 14:35:29 PST 2001 State-Changed-Why: support added long ago ('voltag' command to chio) http://www.FreeBSD.org/cgi/query-pr.cgi?pr=5275 >Unformatted: