From 29301d8cd54eca6a042ad48dd540c2afae08c30e Mon Sep 17 00:00:00 2001 From: Bob Beck Date: Thu, 1 Jun 2006 00:30:31 +0000 Subject: Move mtio drive prep to a function, and makes the changer check it's notion of access, avoiding problems on more tightly coupled changers if the tape is already ejected - currently these stupid devices return "Initialization Command Required" sense codes but there is (as yet) no way to tell userland that. checking the ACCESS changer flag appears safe in both cases. Adds support for "voltag" type for the source for a move, so you can do "chio move voltag 0003B72 drive 0" to move a tape with the corresponding bar code. Documents the above, as well as status -vVa in the man page. partly from freebsd, man page tweaks by jmc@ ok krw@ --- bin/chio/chio.1 | 34 ++++++++-- bin/chio/chio.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 196 insertions(+), 40 deletions(-) diff --git a/bin/chio/chio.1 b/bin/chio/chio.1 index 78e5dc0a994..09aca48fd3b 100644 --- a/bin/chio/chio.1 +++ b/bin/chio/chio.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: chio.1,v 1.25 2006/05/29 10:49:07 jmc Exp $ +.\" $OpenBSD: chio.1,v 1.26 2006/06/01 00:30:30 beck Exp $ .\" $NetBSD: chio.1,v 1.1.1.1 1996/04/03 00:34:38 thorpej Exp $ .\" .\" Copyright (c) 1996 Jason R. Thorpe @@ -59,15 +59,21 @@ rather than the default device .Pp A medium changer apparatus is made up of .Em elements . -There are four element types: +There are five element types: .Em picker (medium transport), .Em slot (storage), .Em portal -(import/export), and +(import/export), .Em drive -(data transfer). +(data transfer), and +.Em voltag +(select by volume identifier). +The +.Em voltag +pseudo-element type allows the selection of tapes by their volume code, +which is typically a barcode on the tape. In this command description, the shorthand .Sq ET will be used to represent an element type, and @@ -165,12 +171,26 @@ Note that not all changers behave as expected in response to this command. .It Cm setpicker Ar unit Configure the changer to use picker .Ar unit . -.It Cm status Op Ar ET +.It Cm status +.Op Fl vVa +.Op Ar ET Report the status of all elements in the changer. If .Ar ET is specified, report the status of all elements of type .Ar ET . +.Bl -tag -width Ds +.It Fl v +Print the primary volume tag for each loaded medium, if any. +The volume +tag is printed as +.Dq \*(LtLABEL:SERIAL\*(Gt . +.It Fl V +Print the alternate volume tag for each loaded medium, if any. +.It Fl a +Print all additional information (as in +.Fl vV ) . +.El .Pp The status bits output are defined as follows: .Bl -tag -width indent @@ -208,6 +228,10 @@ Move the media in slot 3 (fourth slot) to drive 0 (first drive): .Pp .Dl # chio move slot 3 drive 0 .Pp +Move the media with volume tag 000007L2 to drive 1 (second drive): +.Pp +.Dl # chio move voltag 00007L2 drive 0 +.Pp Configure the changer to use picker 2 (third picker) for operations: .Pp .Dl # chio setpicker 2 diff --git a/bin/chio/chio.c b/bin/chio/chio.c index 1f8b1fea3ec..ea91338712a 100644 --- a/bin/chio/chio.c +++ b/bin/chio/chio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: chio.c,v 1.17 2006/05/31 05:01:59 deraadt Exp $ */ +/* $OpenBSD: chio.c,v 1.18 2006/06/01 00:30:30 beck Exp $ */ /* $NetBSD: chio.c,v 1.1.1.1 1996/04/03 00:34:38 thorpej Exp $ */ /* @@ -60,6 +60,8 @@ static int parse_element_unit(char *); static int parse_special(char *); static int is_special(char *); static char *bits_to_string(int, const char *); +static void find_voltag(char *, int *, int *); +static void check_source_drive(int); static int do_move(char *, int, char **); static int do_exchange(char *, int, char **); @@ -182,44 +184,30 @@ do_move(char *cname, int argc, char *argv[]) } bzero(&cmd, sizeof(cmd)); - /* */ - cmd.cm_fromtype = parse_element_type(*argv); - ++argv; --argc; - - /* */ - cmd.cm_fromunit = parse_element_unit(*argv); - ++argv; --argc; - - if (cmd.cm_fromtype == CHET_DT) { - /* - * from unit is a drive - make sure the tape - * in it is unmounted before we attempt to move - * it to avoid errors in "disconnected" type - * pickers where the drive is on a seperate target - * from the changer. - */ - struct mtop mtoffl = { MTOFFL, 1 }; - char *tapedev; - int mtfd; - - tapedev = parse_tapedev(_PATH_CH_CONF, changer_name, - cmd.cm_fromunit); - mtfd = opendev(tapedev, O_RDONLY, OPENDEV_PART | OPENDEV_DRCT, - NULL); - if (mtfd == -1) - err(1, "%s drive %d (%s): open", changer_name, - cmd.cm_fromunit, tapedev); - if (ioctl(mtfd, MTIOCTOP, &mtoffl) == -1) - err(1, "%s drive %d (%s): rewoffl", changer_name, - cmd.cm_fromunit, tapedev); - close(mtfd); + /* + * Get the from ET and EU - we search for it if the ET is + * "voltag", otherwise, we just use the ET and EU given to us. + */ + if (strcmp(*argv, "voltag") == 0) { + ++argv; --argc; + find_voltag(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit); + ++argv; --argc; + } else { + cmd.cm_fromtype = parse_element_type(*argv); + ++argv; --argc; + cmd.cm_fromunit = parse_element_unit(*argv); + ++argv; --argc; } - /* */ + if (cmd.cm_fromtype == CHET_DT) + check_source_drive(cmd.cm_fromunit); + + /* + * Don't allow voltag on the to ET, using a volume + * as a destination makes no sense on a move + */ cmd.cm_totype = parse_element_type(*argv); ++argv; --argc; - - /* */ cmd.cm_tounit = parse_element_unit(*argv); ++argv; --argc; @@ -601,6 +589,150 @@ do_status(char *cname, int argc, char *argv[]) return (1); } +/* + * Check a drive unit as the source for a move or exchange + * operation. If the drive is not accessible, we attempt + * to unmount the tape in it before moving to avoid + * errors in "disconnected" type pickers where the drive + * is on a seperate target from the changer. + */ +static void +check_source_drive(int unit) { + struct mtop mtoffl = { MTOFFL, 1 }; + struct changer_element_status_request cmd; + struct changer_element_status *ces; + struct changer_params data; + size_t count = 0; + int mtfd; + char *tapedev; + + /* + * Get params from changer. Specifically, we need the element + * counts. + */ + bzero(&data, sizeof(data)); + if (ioctl(changer_fd, CHIOGPARAMS, &data)) + err(1, "%s: CHIOGPARAMS", changer_name); + + count = data.cp_ndrives; + if (unit < 0 || unit >= count) + err(1, "%s: invalid drive: drive %d", changer_name, unit); + + bzero(&cmd, sizeof(cmd)); + cmd.cesr_type = CHET_DT; + /* Allocate storage for the status info. */ + cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data)); + if ((cmd.cesr_data) == NULL) + errx(1, "can't allocate status storage"); + + if (ioctl(changer_fd, CHIOGSTATUS, &cmd)) { + free(cmd.cesr_data); + err(1, "%s: CHIOGSTATUS", changer_name); + } + ces = &(cmd.cesr_data[unit]); + + if ((ces->ces_flags & CESTATUS_FULL) != CESTATUS_FULL) + err(1, "%s: drive %d is empty!", changer_name, unit); + + if ((ces->ces_flags & CESTATUS_ACCESS) == CESTATUS_ACCESS) + return; /* changer thinks all is well - trust it */ + + /* + * Otherwise, drive is FULL, but not accessible. + * Try to make it accessible by doing an mt offline. + */ + + tapedev = parse_tapedev(_PATH_CH_CONF, changer_name, unit); + mtfd = opendev(tapedev, O_RDONLY, OPENDEV_PART | OPENDEV_DRCT, + NULL); + if (mtfd == -1) + err(1, "%s drive %d (%s): open", changer_name, unit, tapedev); + if (ioctl(mtfd, MTIOCTOP, &mtoffl) == -1) + err(1, "%s drive %d (%s): rewoffl", changer_name, unit, + tapedev); + close(mtfd); +} + +void +find_voltag(char *voltag, int *type, int *unit) +{ + struct changer_element_status_request cmd; + struct changer_params data; + int i, chet, schet, echet, found; + size_t count = 0; + + /* + * Get params from changer. Specifically, we need the element + * counts. + */ + bzero(&data, sizeof(data)); + if (ioctl(changer_fd, CHIOGPARAMS, &data)) + err(1, "%s: CHIOGPARAMS", changer_name); + + found = 0; + schet = CHET_MT; + echet = CHET_DT; + + /* + * For each type of element, iterate through each one until + * we find the correct volume id. + */ + + for (chet = schet; chet <= echet; ++chet) { + switch (chet) { + case CHET_MT: + count = data.cp_npickers; + break; + case CHET_ST: + count = data.cp_nslots; + break; + case CHET_IE: + count = data.cp_nportals; + break; + case CHET_DT: + count = data.cp_ndrives; + break; + } + if (count == 0 || found) + continue; + + bzero(&cmd, sizeof(cmd)); + cmd.cesr_type = chet; + /* Allocate storage for the status info. */ + cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data)); + if ((cmd.cesr_data) == NULL) + errx(1, "can't allocate status storage"); + cmd.cesr_flags |= CESR_VOLTAGS; + + if (ioctl(changer_fd, CHIOGSTATUS, &cmd)) { + free(cmd.cesr_data); + err(1, "%s: CHIOGSTATUS", changer_name); + } + + /* + * look through each element to see if it has our desired + * volume tag. + */ + for (i = 0; i < count; ++i) { + struct changer_element_status *ces = + &(cmd.cesr_data[i]); + if ((ces->ces_flags & CESTATUS_FULL) != CESTATUS_FULL) + continue; /* no tape in drive */ + if (strcasecmp(voltag, ces->ces_pvoltag.cv_volid) + == 0) { + *type = chet; + *unit = i; + found = 1; + free(cmd.cesr_data); + return; + } + } + free(cmd.cesr_data); + } + errx(1, "%s: unable to locate voltag: %s", changer_name, voltag); +} + + static int parse_element_type(char *cp) { -- cgit v1.2.3