From 91f91457a7cc308612accc12b3d87ddeb05c41bf Mon Sep 17 00:00:00 2001 From: ken Date: Mon, 18 Sep 2000 06:09:11 +0000 Subject: Add two new features to chio(1): - The ability to specify elements by volume tag instead of their actual physical location. e.g., instead of: chio move slot 3 slot 4 you would now use: chio move voltag FOO slot 4 - The ability to return an element to its previous location, as specified by the source element. e.g., instead of: chio move drive 0 slot 4 you would now use: chio return drive 0 or chio return voltag FOO These features will obviously only work with changers that support volume tags and/or source element IDs. chio(1) should fail gracefully if the user attempts to use these new features and the source element ID or volume tag are not found. PR: bin/21178 Submitted by: "C. Stephen Gunn" Reviewed by: ken --- bin/chio/chio.1 | 36 +++++-- bin/chio/chio.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 304 insertions(+), 15 deletions(-) (limited to 'bin/chio') diff --git a/bin/chio/chio.1 b/bin/chio/chio.1 index 34f913f..4697c9b 100644 --- a/bin/chio/chio.1 +++ b/bin/chio/chio.1 @@ -69,20 +69,27 @@ to the desired changer 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). In this command description, the shorthand +(data transfer), and +.Em voltag +(select by volume identifier). The +.Em voltag +pseudo-element type allows the selection of tapes by their volume tag +(typically a barcode on the tape). +.Pp +In this command description, the shorthand .Em ET will be used to represent an element type, and .Em EU -will be used to represent an element unit. For example, to represent -the first robotic arm in the changer, the +will be used to represent an element unit. +For example, to represent the first robotic arm in the changer, the .Em ET would be .Dq picker @@ -137,6 +144,15 @@ Note that not all medium changers support the .Ic exchange operation; the changer must have multiple free pickers or emulate multiple free pickers with transient storage. +.It Xo Nm return +.Ar +.Xc +Return the media unit to its source element. +This command will query the status of the specified media unit, and +will move it to the element specified in its source attribute. +This is a convenient way to return media from a drive or portal +to its previous element in the changer. +.Pp .It Xo Nm position .Ar .Op Ar inv @@ -246,6 +262,11 @@ Element supports receiving media (importing) from an outside human operator. .Bl -tag -width indent .It Nm chio move slot 3 drive 0 Move the media in slot 3 (fourth slot) to drive 0 (first drive). +.It Nm chio move voltag VOLUME01 drive 0 +Move the media with the barcode VOLUME01 to drive 0 (first drive). +.It Nm chio return drive 0 +Remove the tape from drive 0 (first drive) and return it to its original +location in the rack. .It Nm chio setpicker 2 Configure the changer to use picker 2 (third picker) for operations. .El @@ -265,4 +286,7 @@ program and SCSI changer driver were written by for And Communications, http://www.and.com/. .br Additional work by -.An Hans Huebner Aq hans@artcom.de +.An Hans Huebner +.Aq hans@artcom.de +and Steve Gunn +.Aq csg@waterspout.com diff --git a/bin/chio/chio.c b/bin/chio/chio.c index e3f6551..31b69d4 100644 --- a/bin/chio/chio.c +++ b/bin/chio/chio.c @@ -32,6 +32,7 @@ */ /* * Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr. + * Addidional Copyright (c) 2000, by C. Stephen Gunn, Waterspout Communications */ #ifndef lint @@ -64,6 +65,9 @@ static int parse_special __P((char *)); static int is_special __P((char *)); static const char *bits_to_string __P((int, const char *)); +static void find_element __P((char *, u_int16_t *, u_int16_t *)); +static struct changer_element_status *get_element_status __P((u_int16_t, u_int16_t)); + static int do_move __P((char *, int, char **)); static int do_exchange __P((char *, int, char **)); static int do_position __P((char *, int, char **)); @@ -72,14 +76,20 @@ 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_ielem __P((char *, int, char **)); +static int do_return __P((char *, int, char **)); static int do_voltag __P((char *, int, char **)); +#ifndef CHET_VT +#define CHET_VT 10 /* Completely Arbitrary */ +#endif + /* Valid changer element types. */ const struct element_type elements[] = { { "drive", CHET_DT }, { "picker", CHET_MT }, { "portal", CHET_IE }, { "slot", CHET_ST }, + { "voltag", CHET_VT }, /* Select tapes by barcode */ { NULL, 0 }, }; @@ -93,6 +103,7 @@ const struct changer_command commands[] = { { "position", do_position }, { "setpicker", do_setpicker }, { "status", do_status }, + { "return", do_return }, { "voltag", do_voltag }, { NULL, 0 }, }; @@ -195,14 +206,24 @@ do_move(cname, argc, argv) cmd.cm_fromtype = parse_element_type(*argv); ++argv; --argc; - /* */ - cmd.cm_fromunit = parse_element_unit(*argv); + /* Check for voltag virtual type */ + if (CHET_VT == cmd.cm_fromtype) { + find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit); + } else { + /* */ + cmd.cm_fromunit = parse_element_unit(*argv); + } ++argv; --argc; /* */ cmd.cm_totype = parse_element_type(*argv); ++argv; --argc; + /* Check for voltag virtual type, and report error */ + if (CHET_VT == cmd.cm_totype) + errx(1,"%s: voltag only makes sense as an element source", + cname); + /* */ cmd.cm_tounit = parse_element_unit(*argv); ++argv; --argc; @@ -266,16 +287,26 @@ do_exchange(cname, argc, argv) cmd.ce_srctype = parse_element_type(*argv); ++argv; --argc; - /* */ - cmd.ce_srcunit = parse_element_unit(*argv); + /* Check for voltag virtual type */ + if (CHET_VT == cmd.ce_srctype) { + find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit); + } else { + /* */ + cmd.ce_srcunit = parse_element_unit(*argv); + } ++argv; --argc; /* */ cmd.ce_fdsttype = parse_element_type(*argv); ++argv; --argc; - /* */ - cmd.ce_fdstunit = parse_element_unit(*argv); + /* Check for voltag virtual type */ + if (CHET_VT == cmd.ce_fdsttype) { + find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit); + } else { + /* */ + cmd.ce_fdstunit = parse_element_unit(*argv); + } ++argv; --argc; /* @@ -293,6 +324,10 @@ do_exchange(cname, argc, argv) cmd.ce_sdsttype = parse_element_type(*argv); ++argv; --argc; + if (CHET_VT == cmd.ce_sdsttype) + errx(1,"%s %s: voltag only makes sense as an element source", + cname, *argv); + /* */ cmd.ce_sdstunit = parse_element_unit(*argv); ++argv; --argc; @@ -652,9 +687,9 @@ do_status(cname, argc, argv) cesr.cesr_element_base = base; cesr.cesr_element_count = count; /* Allocate storage for the status structures. */ - cesr.cesr_element_status - = (struct changer_element_status *) - malloc(count * sizeof(struct changer_element_status)); + cesr.cesr_element_status = + (struct changer_element_status *) + calloc(count, sizeof(struct changer_element_status)); if (!cesr.cesr_element_status) errx(1, "can't allocate status storage"); @@ -934,6 +969,236 @@ bits_to_string(v, cp) return (buf); } +/* + * do_return() + * + * Given an element reference, ask the changer/picker to move that + * element back to its source slot. + */ +static int +do_return(cname, argc, argv) + char *cname; + int argc; + char **argv; +{ + struct changer_element_status *ces; + struct changer_move cmd; + u_int16_t type, element; + + ++argv; --argc; + + if (argc < 2) { + warnx("%s: too few arguments", cname); + goto usage; + } else if (argc > 3) { + warnx("%s: too many arguments", cname); + goto usage; + } + + type = parse_element_type(*argv); + ++argv; --argc; + + /* Handle voltag virtual Changer Element Type */ + if (CHET_VT == type) { + find_element(*argv, &type, &element); + } else { + element = parse_element_unit(*argv); + } + ++argv; --argc; + + ces = get_element_status(type, element); /* Get the status */ + + if (NULL == ces) + errx(1, "%s: null element status pointer", cname); + + if (!(ces->ces_flags & CES_SOURCE_VALID)) + errx(1, "%s: no source information", cname); + + (void) memset(&cmd, 0, sizeof(cmd)); + + cmd.cm_fromtype = type; + cmd.cm_fromunit = element; + cmd.cm_totype = ces->ces_source_type; + cmd.cm_tounit = ces->ces_source_addr; + + if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1) + err(1, "%s: CHIOMOVE", changer_name); + free(ces); + + return(0); + +usage: + (void) fprintf(stderr, "usage: %s %s " + " \n", __progname, cname); + return(1); +} + +/* + * get_element_status() + * + * return a *cesr for the specified changer element. This + * routing will malloc()/calloc() the memory. The caller + * should free() it when done. + */ +static struct changer_element_status * +get_element_status(type, element) + u_int16_t type; + u_int16_t element; +{ + struct changer_element_status_request cesr; + struct changer_element_status *ces; + + ces = (struct changer_element_status *) + calloc(1, sizeof(struct changer_element_status)); + + if (NULL == ces) + errx(1, "can't allocate status storage"); + + (void)memset(&cesr, 0, sizeof(cesr)); + + cesr.cesr_element_type = type; + cesr.cesr_element_base = element; + cesr.cesr_element_count = 1; /* Only this one element */ + cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */ + cesr.cesr_element_status = ces; + + if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { + free(ces); + err(1, "%s: CHIOGSTATUS", changer_name); + /* NOTREACHED */ + } + + return ces; +} + + +/* + * find_element() + * + * Given a find the chager element and unit, or exit + * with an error if it isn't found. We grab the changer status + * and iterate until we find a match, or crap out. + */ +static void +find_element(voltag, et, eu) + char *voltag; + u_int16_t *et; + u_int16_t *eu; +{ + struct changer_params cp; + struct changer_element_status_request cesr; + struct changer_element_status *ch_ces, *ces; + int elem, total_elem, found = 0; + + /* + * Get the changer parameters, we're interested in the counts + * for all types of elements to perform our search. + */ + if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) + err(1, "%s: CHIOGPARAMS", changer_name); + + /* Allocate some memory for the results */ + total_elem = (cp.cp_nslots + cp.cp_ndrives + + cp.cp_npickers + cp.cp_nportals); + + ch_ces = (struct changer_element_status *) + calloc(total_elem, sizeof(struct changer_element_status)); + + if (NULL == ch_ces) + errx(1, "can't allocate status storage"); + + ces = ch_ces; + + /* Read in the changer slots */ + if (cp.cp_nslots > 0) { + cesr.cesr_element_type = CHET_ST; + cesr.cesr_element_base = 0; + cesr.cesr_element_count = cp.cp_nslots; + cesr.cesr_flags |= CESR_VOLTAGS; + cesr.cesr_element_status = ces; + + if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { + free(ch_ces); + err(1, "%s: CHIOGSTATUS", changer_name); + } + ces += cp.cp_nslots; + } + + /* Read in the drive information */ + if (cp.cp_ndrives > 0 ) { + + (void) memset(&cesr, 0, sizeof(cesr)); + cesr.cesr_element_type = CHET_DT; + cesr.cesr_element_base = 0; + cesr.cesr_element_count = cp.cp_ndrives; + cesr.cesr_flags |= CESR_VOLTAGS; + cesr.cesr_element_status = ces; + + if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { + free(ch_ces); + err(1, "%s: CHIOGSTATUS", changer_name); + } + ces += cp.cp_ndrives; + } + + /* Read in the portal information */ + if (cp.cp_nportals > 0 ) { + (void) memset(&cesr, 0, sizeof(cesr)); + cesr.cesr_element_type = CHET_IE; + cesr.cesr_element_base = 0; + cesr.cesr_element_count = cp.cp_nportals; + cesr.cesr_flags |= CESR_VOLTAGS; + cesr.cesr_element_status = ces; + + if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { + free(ch_ces); + err(1, "%s: CHIOGSTATUS", changer_name); + } + ces += cp.cp_nportals; + } + + /* Read in the picker information */ + if (cp.cp_npickers > 0) { + (void) memset(&cesr, 0, sizeof(cesr)); + cesr.cesr_element_type = CHET_MT; + cesr.cesr_element_base = 0; + cesr.cesr_element_count = cp.cp_npickers; + cesr.cesr_flags |= CESR_VOLTAGS; + cesr.cesr_element_status = ces; + + if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { + free(ch_ces); + err(1, "%s: CHIOGSTATUS", changer_name); + } + } + + /* + * Now search the list the specified + */ + for (elem = 0; elem <= total_elem; ++elem) { + + ces = &ch_ces[elem]; + + /* Make sure we have a tape in this element */ + if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL)) + != (CES_STATUS_ACCESS|CES_STATUS_FULL)) + continue; + + /* Check to see if it is our target */ + if (strcasecmp(voltag, ces->ces_pvoltag.cv_volid) == 0) { + *et = ces->ces_type; + *eu = ces->ces_addr; + ++found; + break; + } + } + if (!found) { + errx(1, "%s: unable to locate voltag: %s", changer_name, + voltag); + } + free(ch_ces); + return; +} static void cleanup() -- cgit v1.1