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" <csg@waterspout.com> Reviewed by: ken
This commit is contained in:
parent
3dc41a81fd
commit
91f91457a7
@ -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 <from ET> <from EU>
|
||||
.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 <to ET> <to EU>
|
||||
.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
|
||||
|
283
bin/chio/chio.c
283
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;
|
||||
|
||||
/* <from EU> */
|
||||
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 {
|
||||
/* <from EU> */
|
||||
cmd.cm_fromunit = parse_element_unit(*argv);
|
||||
}
|
||||
++argv; --argc;
|
||||
|
||||
/* <to ET> */
|
||||
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);
|
||||
|
||||
/* <to EU> */
|
||||
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;
|
||||
|
||||
/* <src EU> */
|
||||
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 {
|
||||
/* <from EU> */
|
||||
cmd.ce_srcunit = parse_element_unit(*argv);
|
||||
}
|
||||
++argv; --argc;
|
||||
|
||||
/* <dst1 ET> */
|
||||
cmd.ce_fdsttype = parse_element_type(*argv);
|
||||
++argv; --argc;
|
||||
|
||||
/* <dst1 EU> */
|
||||
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 {
|
||||
/* <from EU> */
|
||||
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);
|
||||
|
||||
/* <dst2 EU> */
|
||||
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 "
|
||||
"<from ET> <from EU>\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 <voltag> 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 <voltag>
|
||||
*/
|
||||
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()
|
||||
|
Loading…
Reference in New Issue
Block a user