chio.c revision 184484
148983Skris/*	$NetBSD: chio.c,v 1.6 1998/01/04 23:53:58 thorpej Exp $ */
2139969Simp/*-
323449Sjoerg * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com>
423449Sjoerg * All rights reserved.
523449Sjoerg *
623449Sjoerg * Redistribution and use in source and binary forms, with or without
723449Sjoerg * modification, are permitted provided that the following conditions
823449Sjoerg * are met:
923449Sjoerg * 1. Redistributions of source code must retain the above copyright
1023449Sjoerg *    notice, this list of conditions and the following disclaimer.
1123449Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1223449Sjoerg *    notice, this list of conditions and the following disclaimer in the
1323449Sjoerg *    documentation and/or other materials provided with the distribution.
1423449Sjoerg * 3. All advertising materials mentioning features or use of this software
1523449Sjoerg *    must display the following acknowledgements:
1623449Sjoerg *	This product includes software developed by Jason R. Thorpe
1723449Sjoerg *	for And Communications, http://www.and.com/
1823449Sjoerg * 4. The name of the author may not be used to endorse or promote products
1923449Sjoerg *    derived from this software without specific prior written permission.
2023449Sjoerg *
2123449Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2223449Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2323449Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2423449Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2523449Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2623449Sjoerg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2723449Sjoerg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2823449Sjoerg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2923449Sjoerg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3023449Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3123449Sjoerg * SUCH DAMAGE.
3223449Sjoerg */
3339227Sgibbs/*
3439227Sgibbs * Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr.
3566019Sken * Addidional Copyright (c) 2000, by C. Stephen Gunn, Waterspout Communications
3639227Sgibbs */
3723449Sjoerg
38114433Sobrien#if 0
3935773Scharnier#ifndef lint
4048073Skrisstatic const char copyright[] =
4148073Skris	"@(#) Copyright (c) 1996 Jason R. Thorpe.  All rights reserved.";
4248073Skris#endif /* not lint */
43114433Sobrien#endif
4435773Scharnier
4593101Smarkm#include <sys/cdefs.h>
4693101Smarkm__FBSDID("$FreeBSD: head/bin/chio/chio.c 184484 2008-10-30 19:51:02Z joerg $");
4793101Smarkm
4836001Scharnier#include <sys/param.h>
4923449Sjoerg#include <sys/chio.h>
5023449Sjoerg#include <err.h>
5123449Sjoerg#include <fcntl.h>
5223449Sjoerg#include <stdio.h>
5391665Simp#include <stdint.h>
5423449Sjoerg#include <stdlib.h>
5523449Sjoerg#include <string.h>
5623449Sjoerg#include <unistd.h>
5723449Sjoerg
5823449Sjoerg#include "defs.h"
5923449Sjoerg#include "pathnames.h"
6023449Sjoerg
6190107Simpstatic	void usage(void);
6290107Simpstatic	void cleanup(void);
6391086Smarkmstatic	u_int16_t parse_element_type(char *);
6491086Smarkmstatic	u_int16_t parse_element_unit(char *);
6590107Simpstatic	const char * element_type_name(int et);
6690107Simpstatic	int parse_special(char *);
6790107Simpstatic	int is_special(char *);
6890107Simpstatic	const char *bits_to_string(ces_status_flags, const char *);
6923449Sjoerg
7091665Simpstatic	void find_element(char *, uint16_t *, uint16_t *);
7179253Smikehstatic	struct changer_element_status *get_element_status
72184484Sjoerg	   (unsigned int, unsigned int, int);
7366019Sken
7490107Simpstatic	int do_move(const char *, int, char **);
7590107Simpstatic	int do_exchange(const char *, int, char **);
7690107Simpstatic	int do_position(const char *, int, char **);
7790107Simpstatic	int do_params(const char *, int, char **);
7890107Simpstatic	int do_getpicker(const char *, int, char **);
7990107Simpstatic	int do_setpicker(const char *, int, char **);
8090107Simpstatic	int do_status(const char *, int, char **);
8190107Simpstatic	int do_ielem(const char *, int, char **);
8290107Simpstatic	int do_return(const char *, int, char **);
8390107Simpstatic	int do_voltag(const char *, int, char **);
8439227Sgibbs
8566019Sken#ifndef CHET_VT
8666019Sken#define	CHET_VT		10			/* Completely Arbitrary */
8766019Sken#endif
8866019Sken
8923449Sjoerg/* Valid changer element types. */
9023449Sjoergconst struct element_type elements[] = {
9147816Skris	{ "drive",		CHET_DT },
9223449Sjoerg	{ "picker",		CHET_MT },
9347816Skris	{ "portal",		CHET_IE },
9423449Sjoerg	{ "slot",		CHET_ST },
9566019Sken	{ "voltag",		CHET_VT },	/* Select tapes by barcode */
9623449Sjoerg	{ NULL,			0 },
9723449Sjoerg};
9823449Sjoerg
9923449Sjoerg/* Valid commands. */
10023449Sjoergconst struct changer_command commands[] = {
10147816Skris	{ "exchange",		do_exchange },
10247816Skris	{ "getpicker",		do_getpicker },
10347816Skris	{ "ielem", 		do_ielem },
10423449Sjoerg	{ "move",		do_move },
10547816Skris	{ "params",		do_params },
10623449Sjoerg	{ "position",		do_position },
10723449Sjoerg	{ "setpicker",		do_setpicker },
10823449Sjoerg	{ "status",		do_status },
10966019Sken	{ "return",		do_return },
11039227Sgibbs	{ "voltag",		do_voltag },
11123449Sjoerg	{ NULL,			0 },
11223449Sjoerg};
11323449Sjoerg
11423449Sjoerg/* Valid special words. */
11523449Sjoergconst struct special_word specials[] = {
11623449Sjoerg	{ "inv",		SW_INVERT },
11723449Sjoerg	{ "inv1",		SW_INVERT1 },
11823449Sjoerg	{ "inv2",		SW_INVERT2 },
11923449Sjoerg	{ NULL,			0 },
12023449Sjoerg};
12123449Sjoerg
12223449Sjoergstatic	int changer_fd;
12348073Skrisstatic	const char *changer_name;
12423449Sjoerg
12523449Sjoergint
12690107Simpmain(int argc, char **argv)
12723449Sjoerg{
12823449Sjoerg	int ch, i;
12923449Sjoerg
13023449Sjoerg	while ((ch = getopt(argc, argv, "f:")) != -1) {
13123449Sjoerg		switch (ch) {
13223449Sjoerg		case 'f':
13323449Sjoerg			changer_name = optarg;
13423449Sjoerg			break;
13523449Sjoerg
13623449Sjoerg		default:
13723449Sjoerg			usage();
13823449Sjoerg		}
13923449Sjoerg	}
14023449Sjoerg	argc -= optind;
14123449Sjoerg	argv += optind;
14223449Sjoerg
14323449Sjoerg	if (argc == 0)
14423449Sjoerg		usage();
14523449Sjoerg
14623449Sjoerg	/* Get the default changer if not already specified. */
14723449Sjoerg	if (changer_name == NULL)
14823449Sjoerg		if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL)
14923449Sjoerg			changer_name = _PATH_CH;
15023449Sjoerg
15123449Sjoerg	/* Open the changer device. */
15223449Sjoerg	if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1)
15323449Sjoerg		err(1, "%s: open", changer_name);
15423449Sjoerg
15523449Sjoerg	/* Register cleanup function. */
15623449Sjoerg	if (atexit(cleanup))
15723449Sjoerg		err(1, "can't register cleanup function");
15823449Sjoerg
15923449Sjoerg	/* Find the specified command. */
16023449Sjoerg	for (i = 0; commands[i].cc_name != NULL; ++i)
16123449Sjoerg		if (strcmp(*argv, commands[i].cc_name) == 0)
16223449Sjoerg			break;
16347816Skris	if (commands[i].cc_name == NULL) {
16447816Skris		/* look for abbreviation */
16547816Skris		for (i = 0; commands[i].cc_name != NULL; ++i)
16647816Skris			if (strncmp(*argv, commands[i].cc_name,
16747816Skris			    strlen(*argv)) == 0)
16847816Skris				break;
16948073Skris	}
17047816Skris
17123449Sjoerg	if (commands[i].cc_name == NULL)
17223449Sjoerg		errx(1, "unknown command: %s", *argv);
17323449Sjoerg
17448073Skris	exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv));
17539227Sgibbs	/* NOTREACHED */
17623449Sjoerg}
17723449Sjoerg
17823449Sjoergstatic int
17990107Simpdo_move(const char *cname, int argc, char **argv)
18023449Sjoerg{
18123449Sjoerg	struct changer_move cmd;
18223449Sjoerg	int val;
18323449Sjoerg
18423449Sjoerg	/*
18523449Sjoerg	 * On a move command, we expect the following:
18623449Sjoerg	 *
18723449Sjoerg	 * <from ET> <from EU> <to ET> <to EU> [inv]
18823449Sjoerg	 *
18923449Sjoerg	 * where ET == element type and EU == element unit.
19023449Sjoerg	 */
19139227Sgibbs
19239227Sgibbs	++argv; --argc;
19339227Sgibbs
19423449Sjoerg	if (argc < 4) {
19523449Sjoerg		warnx("%s: too few arguments", cname);
19623449Sjoerg		goto usage;
19723449Sjoerg	} else if (argc > 5) {
19823449Sjoerg		warnx("%s: too many arguments", cname);
19923449Sjoerg		goto usage;
20023449Sjoerg	}
20139227Sgibbs	(void) memset(&cmd, 0, sizeof(cmd));
20223449Sjoerg
20323449Sjoerg	/* <from ET>  */
20423449Sjoerg	cmd.cm_fromtype = parse_element_type(*argv);
20523449Sjoerg	++argv; --argc;
20623449Sjoerg
20766019Sken	/* Check for voltag virtual type */
20866019Sken	if (CHET_VT == cmd.cm_fromtype) {
20966019Sken		find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit);
21066019Sken	} else {
21166019Sken		/* <from EU> */
21266019Sken		cmd.cm_fromunit = parse_element_unit(*argv);
21366019Sken	}
21423449Sjoerg	++argv; --argc;
21523449Sjoerg
21623449Sjoerg	/* <to ET> */
21723449Sjoerg	cmd.cm_totype = parse_element_type(*argv);
21823449Sjoerg	++argv; --argc;
21923449Sjoerg
22066019Sken	/* Check for voltag virtual type, and report error */
22166019Sken	if (CHET_VT == cmd.cm_totype)
22266019Sken		errx(1,"%s: voltag only makes sense as an element source",
22366019Sken		     cname);
22466019Sken
22523449Sjoerg	/* <to EU> */
22623449Sjoerg	cmd.cm_tounit = parse_element_unit(*argv);
22723449Sjoerg	++argv; --argc;
22823449Sjoerg
22923449Sjoerg	/* Deal with optional command modifier. */
23023449Sjoerg	if (argc) {
23123449Sjoerg		val = parse_special(*argv);
23223449Sjoerg		switch (val) {
23323449Sjoerg		case SW_INVERT:
23423449Sjoerg			cmd.cm_flags |= CM_INVERT;
23523449Sjoerg			break;
23623449Sjoerg
23723449Sjoerg		default:
23823449Sjoerg			errx(1, "%s: inappropriate modifier `%s'",
23923449Sjoerg			    cname, *argv);
24023449Sjoerg			/* NOTREACHED */
24123449Sjoerg		}
24223449Sjoerg	}
24323449Sjoerg
24423449Sjoerg	/* Send command to changer. */
24539227Sgibbs	if (ioctl(changer_fd, CHIOMOVE, &cmd))
24623449Sjoerg		err(1, "%s: CHIOMOVE", changer_name);
24723449Sjoerg
24823449Sjoerg	return (0);
24923449Sjoerg
25023449Sjoerg usage:
25139227Sgibbs	(void) fprintf(stderr, "usage: %s %s "
25293101Smarkm	    "<from ET> <from EU> <to ET> <to EU> [inv]\n", getprogname(), cname);
25323449Sjoerg	return (1);
25423449Sjoerg}
25523449Sjoerg
25623449Sjoergstatic int
25790107Simpdo_exchange(const char *cname, int argc, char **argv)
25823449Sjoerg{
25923449Sjoerg	struct changer_exchange cmd;
26023449Sjoerg	int val;
26123449Sjoerg
26223449Sjoerg	/*
26323449Sjoerg	 * On an exchange command, we expect the following:
26423449Sjoerg	 *
26523449Sjoerg  * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2]
26623449Sjoerg	 *
26723449Sjoerg	 * where ET == element type and EU == element unit.
26823449Sjoerg	 */
26939227Sgibbs
27039227Sgibbs	++argv; --argc;
27139227Sgibbs
27223449Sjoerg	if (argc < 4) {
27323449Sjoerg		warnx("%s: too few arguments", cname);
27423449Sjoerg		goto usage;
27523449Sjoerg	} else if (argc > 8) {
27623449Sjoerg		warnx("%s: too many arguments", cname);
27723449Sjoerg		goto usage;
27823449Sjoerg	}
27939227Sgibbs	(void) memset(&cmd, 0, sizeof(cmd));
28023449Sjoerg
28123449Sjoerg	/* <src ET>  */
28223449Sjoerg	cmd.ce_srctype = parse_element_type(*argv);
28323449Sjoerg	++argv; --argc;
28423449Sjoerg
28566019Sken	/* Check for voltag virtual type */
28666019Sken	if (CHET_VT == cmd.ce_srctype) {
28766019Sken		find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit);
28866019Sken	} else {
28966019Sken		/* <from EU> */
29066019Sken		cmd.ce_srcunit = parse_element_unit(*argv);
29166019Sken	}
29223449Sjoerg	++argv; --argc;
29323449Sjoerg
29423449Sjoerg	/* <dst1 ET> */
29523449Sjoerg	cmd.ce_fdsttype = parse_element_type(*argv);
29623449Sjoerg	++argv; --argc;
29723449Sjoerg
29866019Sken	/* Check for voltag virtual type */
29966019Sken	if (CHET_VT == cmd.ce_fdsttype) {
30066019Sken		find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit);
30166019Sken	} else {
30266019Sken		/* <from EU> */
30366019Sken		cmd.ce_fdstunit = parse_element_unit(*argv);
30466019Sken	}
30523449Sjoerg	++argv; --argc;
30623449Sjoerg
30723449Sjoerg	/*
30823449Sjoerg	 * If the next token is a special word or there are no more
30923449Sjoerg	 * arguments, then this is a case of simple exchange.
31023449Sjoerg	 * dst2 == src.
31123449Sjoerg	 */
31223449Sjoerg	if ((argc == 0) || is_special(*argv)) {
31323449Sjoerg		cmd.ce_sdsttype = cmd.ce_srctype;
31423449Sjoerg		cmd.ce_sdstunit = cmd.ce_srcunit;
31523449Sjoerg		goto do_special;
31623449Sjoerg	}
31723449Sjoerg
31823449Sjoerg	/* <dst2 ET> */
31923449Sjoerg	cmd.ce_sdsttype = parse_element_type(*argv);
32023449Sjoerg	++argv; --argc;
32123449Sjoerg
32266019Sken	if (CHET_VT == cmd.ce_sdsttype)
32366019Sken		errx(1,"%s %s: voltag only makes sense as an element source",
32466019Sken		     cname, *argv);
32566019Sken
32623449Sjoerg	/* <dst2 EU> */
32723449Sjoerg	cmd.ce_sdstunit = parse_element_unit(*argv);
32823449Sjoerg	++argv; --argc;
32923449Sjoerg
33023449Sjoerg do_special:
33123449Sjoerg	/* Deal with optional command modifiers. */
33223449Sjoerg	while (argc) {
33323449Sjoerg		val = parse_special(*argv);
33423449Sjoerg		++argv; --argc;
33523449Sjoerg		switch (val) {
33623449Sjoerg		case SW_INVERT1:
33723449Sjoerg			cmd.ce_flags |= CE_INVERT1;
33823449Sjoerg			break;
33923449Sjoerg
34023449Sjoerg		case SW_INVERT2:
34123449Sjoerg			cmd.ce_flags |= CE_INVERT2;
34223449Sjoerg			break;
34323449Sjoerg
34423449Sjoerg		default:
34523449Sjoerg			errx(1, "%s: inappropriate modifier `%s'",
34623449Sjoerg			    cname, *argv);
34723449Sjoerg			/* NOTREACHED */
34823449Sjoerg		}
34923449Sjoerg	}
35023449Sjoerg
35123449Sjoerg	/* Send command to changer. */
35239227Sgibbs	if (ioctl(changer_fd, CHIOEXCHANGE, &cmd))
35323449Sjoerg		err(1, "%s: CHIOEXCHANGE", changer_name);
35423449Sjoerg
35523449Sjoerg	return (0);
35623449Sjoerg
35723449Sjoerg usage:
35839227Sgibbs	(void) fprintf(stderr,
35939227Sgibbs	    "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n"
36039227Sgibbs	    "       [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n",
36193101Smarkm	    getprogname(), cname);
36223449Sjoerg	return (1);
36323449Sjoerg}
36423449Sjoerg
36523449Sjoergstatic int
36690107Simpdo_position(const char *cname, int argc, char **argv)
36723449Sjoerg{
36823449Sjoerg	struct changer_position cmd;
36923449Sjoerg	int val;
37023449Sjoerg
37123449Sjoerg	/*
37223449Sjoerg	 * On a position command, we expect the following:
37323449Sjoerg	 *
37423449Sjoerg	 * <to ET> <to EU> [inv]
37523449Sjoerg	 *
37623449Sjoerg	 * where ET == element type and EU == element unit.
37723449Sjoerg	 */
37839227Sgibbs
37939227Sgibbs	++argv; --argc;
38039227Sgibbs
38123449Sjoerg	if (argc < 2) {
38223449Sjoerg		warnx("%s: too few arguments", cname);
38323449Sjoerg		goto usage;
38423449Sjoerg	} else if (argc > 3) {
38523449Sjoerg		warnx("%s: too many arguments", cname);
38623449Sjoerg		goto usage;
38723449Sjoerg	}
38839227Sgibbs	(void) memset(&cmd, 0, sizeof(cmd));
38923449Sjoerg
39023449Sjoerg	/* <to ET>  */
39123449Sjoerg	cmd.cp_type = parse_element_type(*argv);
39223449Sjoerg	++argv; --argc;
39323449Sjoerg
39423449Sjoerg	/* <to EU> */
39523449Sjoerg	cmd.cp_unit = parse_element_unit(*argv);
39623449Sjoerg	++argv; --argc;
39723449Sjoerg
39823449Sjoerg	/* Deal with optional command modifier. */
39923449Sjoerg	if (argc) {
40023449Sjoerg		val = parse_special(*argv);
40123449Sjoerg		switch (val) {
40223449Sjoerg		case SW_INVERT:
40323449Sjoerg			cmd.cp_flags |= CP_INVERT;
40423449Sjoerg			break;
40523449Sjoerg
40623449Sjoerg		default:
40723449Sjoerg			errx(1, "%s: inappropriate modifier `%s'",
40823449Sjoerg			    cname, *argv);
40923449Sjoerg			/* NOTREACHED */
41023449Sjoerg		}
41123449Sjoerg	}
41223449Sjoerg
41323449Sjoerg	/* Send command to changer. */
41439227Sgibbs	if (ioctl(changer_fd, CHIOPOSITION, &cmd))
41523449Sjoerg		err(1, "%s: CHIOPOSITION", changer_name);
41623449Sjoerg
41723449Sjoerg	return (0);
41823449Sjoerg
41923449Sjoerg usage:
42039227Sgibbs	(void) fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n",
42193101Smarkm	    getprogname(), cname);
42223449Sjoerg	return (1);
42323449Sjoerg}
42423449Sjoerg
42539227Sgibbs/* ARGSUSED */
42623449Sjoergstatic int
42790107Simpdo_params(const char *cname, int argc, char **argv)
42823449Sjoerg{
42923449Sjoerg	struct changer_params data;
43039876Sken	int picker;
43123449Sjoerg
43223449Sjoerg	/* No arguments to this command. */
43339227Sgibbs
43439227Sgibbs	++argv; --argc;
43539227Sgibbs
43623449Sjoerg	if (argc) {
43741579Sbde		warnx("%s: no arguments expected", cname);
43823449Sjoerg		goto usage;
43923449Sjoerg	}
44023449Sjoerg
44123449Sjoerg	/* Get params from changer and display them. */
44239227Sgibbs	(void) memset(&data, 0, sizeof(data));
44339227Sgibbs	if (ioctl(changer_fd, CHIOGPARAMS, &data))
44423449Sjoerg		err(1, "%s: CHIOGPARAMS", changer_name);
44523449Sjoerg
44639227Sgibbs	(void) printf("%s: %d slot%s, %d drive%s, %d picker%s",
44723449Sjoerg	    changer_name,
44823449Sjoerg	    data.cp_nslots, (data.cp_nslots > 1) ? "s" : "",
44923449Sjoerg	    data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "",
45023449Sjoerg	    data.cp_npickers, (data.cp_npickers > 1) ? "s" : "");
45123449Sjoerg	if (data.cp_nportals)
45239227Sgibbs		(void) printf(", %d portal%s", data.cp_nportals,
45323449Sjoerg		    (data.cp_nportals > 1) ? "s" : "");
45423449Sjoerg
45539876Sken	/* Get current picker from changer and display it. */
45639876Sken	if (ioctl(changer_fd, CHIOGPICKER, &picker))
45739876Sken		err(1, "%s: CHIOGPICKER", changer_name);
45839876Sken
45939876Sken	(void) printf("\n%s: current picker: %d\n", changer_name, picker);
46039876Sken
46123449Sjoerg	return (0);
46223449Sjoerg
46323449Sjoerg usage:
46493101Smarkm	(void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname);
46523449Sjoerg	return (1);
46623449Sjoerg}
46723449Sjoerg
46839227Sgibbs/* ARGSUSED */
46923449Sjoergstatic int
47090107Simpdo_getpicker(const char *cname, int argc, char **argv)
47123449Sjoerg{
47223449Sjoerg	int picker;
47323449Sjoerg
47423449Sjoerg	/* No arguments to this command. */
47539227Sgibbs
47639227Sgibbs	++argv; --argc;
47739227Sgibbs
47823449Sjoerg	if (argc) {
47923449Sjoerg		warnx("%s: no arguments expected", cname);
48023449Sjoerg		goto usage;
48123449Sjoerg	}
48223449Sjoerg
48323449Sjoerg	/* Get current picker from changer and display it. */
48439227Sgibbs	if (ioctl(changer_fd, CHIOGPICKER, &picker))
48523449Sjoerg		err(1, "%s: CHIOGPICKER", changer_name);
48623449Sjoerg
48739227Sgibbs	(void) printf("%s: current picker: %d\n", changer_name, picker);
48823449Sjoerg
48923449Sjoerg	return (0);
49023449Sjoerg
49123449Sjoerg usage:
49293101Smarkm	(void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname);
49323449Sjoerg	return (1);
49423449Sjoerg}
49523449Sjoerg
49623449Sjoergstatic int
49790107Simpdo_setpicker(const char *cname, int argc, char **argv)
49823449Sjoerg{
49923449Sjoerg	int picker;
50023449Sjoerg
50139227Sgibbs	++argv; --argc;
50239227Sgibbs
50323449Sjoerg	if (argc < 1) {
50423449Sjoerg		warnx("%s: too few arguments", cname);
50523449Sjoerg		goto usage;
50623449Sjoerg	} else if (argc > 1) {
50723449Sjoerg		warnx("%s: too many arguments", cname);
50823449Sjoerg		goto usage;
50923449Sjoerg	}
51023449Sjoerg
51123449Sjoerg	picker = parse_element_unit(*argv);
51223449Sjoerg
51323449Sjoerg	/* Set the changer picker. */
51439227Sgibbs	if (ioctl(changer_fd, CHIOSPICKER, &picker))
51523449Sjoerg		err(1, "%s: CHIOSPICKER", changer_name);
51623449Sjoerg
51723449Sjoerg	return (0);
51823449Sjoerg
51923449Sjoerg usage:
52093101Smarkm	(void) fprintf(stderr, "usage: %s %s <picker>\n", getprogname(), cname);
52123449Sjoerg	return (1);
52223449Sjoerg}
52323449Sjoerg
52423449Sjoergstatic int
52590107Simpdo_status(const char *cname, int argc, char **argv)
52623449Sjoerg{
52739227Sgibbs	struct changer_params cp;
52839227Sgibbs	struct changer_element_status_request cesr;
52991086Smarkm	int i;
53091086Smarkm	u_int16_t base, count, chet, schet, echet;
53179121Smikeh	const char *description;
53239227Sgibbs	int pvoltag = 0;
53339227Sgibbs	int avoltag = 0;
53439227Sgibbs	int sense = 0;
53539227Sgibbs	int scsi = 0;
53639227Sgibbs	int source = 0;
53739227Sgibbs	int intaddr = 0;
53839227Sgibbs	int c;
53923449Sjoerg
54026361Scharnier	count = 0;
54139227Sgibbs	base = 0;
54226361Scharnier	description = NULL;
54326361Scharnier
54439227Sgibbs	optind = optreset = 1;
54547442Simp	while ((c = getopt(argc, argv, "vVsSbaI")) != -1) {
54639227Sgibbs		switch (c) {
54739227Sgibbs		case 'v':
54839227Sgibbs			pvoltag = 1;
54939227Sgibbs			break;
55039227Sgibbs		case 'V':
55139227Sgibbs			avoltag = 1;
55239227Sgibbs			break;
55339227Sgibbs		case 's':
55439227Sgibbs			sense = 1;
55539227Sgibbs			break;
55639227Sgibbs		case 'S':
55739227Sgibbs			source = 1;
55839227Sgibbs			break;
55939227Sgibbs		case 'b':
56039227Sgibbs			scsi = 1;
56139227Sgibbs			break;
56239227Sgibbs		case 'I':
56339227Sgibbs			intaddr = 1;
56439227Sgibbs			break;
56539227Sgibbs		case 'a':
56639227Sgibbs			pvoltag = avoltag = source = sense = scsi = intaddr = 1;
56739227Sgibbs			break;
56839227Sgibbs		default:
56941579Sbde			warnx("%s: bad option", cname);
57039227Sgibbs			goto usage;
57139227Sgibbs		}
57239227Sgibbs	}
57339227Sgibbs
57439227Sgibbs	argc -= optind;
57539227Sgibbs	argv += optind;
57639227Sgibbs
57723449Sjoerg	/*
57823449Sjoerg	 * On a status command, we expect the following:
57923449Sjoerg	 *
58039227Sgibbs	 * [<ET> [<start> [<end>] ] ]
58123449Sjoerg	 *
58239227Sgibbs	 * where ET == element type, start == first element to report,
58339227Sgibbs	 * end == number of elements to report
58423449Sjoerg	 *
58523449Sjoerg	 * If we get no arguments, we get the status of all
58623449Sjoerg	 * known element types.
58723449Sjoerg	 */
58839227Sgibbs	if (argc > 3) {
58923449Sjoerg		warnx("%s: too many arguments", cname);
59023449Sjoerg		goto usage;
59123449Sjoerg	}
59223449Sjoerg
59323449Sjoerg	/*
59423449Sjoerg	 * Get params from changer.  Specifically, we need the element
59523449Sjoerg	 * counts.
59623449Sjoerg	 */
59739227Sgibbs	if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp))
59823449Sjoerg		err(1, "%s: CHIOGPARAMS", changer_name);
59923449Sjoerg
60039227Sgibbs	if (argc > 0)
60139227Sgibbs		schet = echet = parse_element_type(argv[0]);
60223449Sjoerg	else {
60323449Sjoerg		schet = CHET_MT;
60423449Sjoerg		echet = CHET_DT;
60523449Sjoerg	}
60639227Sgibbs	if (argc > 1) {
60791086Smarkm		base = (u_int16_t)atol(argv[1]);
60839227Sgibbs		count = 1;
60939227Sgibbs	}
61039227Sgibbs	if (argc > 2)
61191086Smarkm		count = (u_int16_t)atol(argv[2]) - base + 1;
61223449Sjoerg
61323449Sjoerg	for (chet = schet; chet <= echet; ++chet) {
61423449Sjoerg		switch (chet) {
61523449Sjoerg		case CHET_MT:
61639227Sgibbs			if (count == 0)
61739227Sgibbs				count = cp.cp_npickers;
61839227Sgibbs			else if (count > cp.cp_npickers)
61939227Sgibbs				errx(1, "not that many pickers in device");
62023449Sjoerg			description = "picker";
62123449Sjoerg			break;
62223449Sjoerg
62323449Sjoerg		case CHET_ST:
62439227Sgibbs			if (count == 0)
62539227Sgibbs				count = cp.cp_nslots;
62639227Sgibbs			else if (count > cp.cp_nslots)
62739227Sgibbs				errx(1, "not that many slots in device");
62823449Sjoerg			description = "slot";
62923449Sjoerg			break;
63023449Sjoerg
63123449Sjoerg		case CHET_IE:
63239227Sgibbs			if (count == 0)
63339227Sgibbs				count = cp.cp_nportals;
63439227Sgibbs			else if (count > cp.cp_nportals)
63539227Sgibbs				errx(1, "not that many portals in device");
63623449Sjoerg			description = "portal";
63723449Sjoerg			break;
63823449Sjoerg
63923449Sjoerg		case CHET_DT:
64039227Sgibbs			if (count == 0)
64139227Sgibbs				count = cp.cp_ndrives;
64239227Sgibbs			else if (count > cp.cp_ndrives)
64339227Sgibbs				errx(1, "not that many drives in device");
64423449Sjoerg			description = "drive";
64523449Sjoerg			break;
64639227Sgibbs
64739227Sgibbs 		default:
64839227Sgibbs 			/* To appease gcc -Wuninitialized. */
64939227Sgibbs 			count = 0;
65039227Sgibbs 			description = NULL;
65123449Sjoerg		}
65223449Sjoerg
65323449Sjoerg		if (count == 0) {
65423449Sjoerg			if (argc == 0)
65523449Sjoerg				continue;
65623449Sjoerg			else {
65723449Sjoerg				printf("%s: no %s elements\n",
65823449Sjoerg				    changer_name, description);
65923449Sjoerg				return (0);
66023449Sjoerg			}
66123449Sjoerg		}
66223449Sjoerg
66339227Sgibbs		bzero(&cesr, sizeof(cesr));
66439227Sgibbs		cesr.cesr_element_type = chet;
66539227Sgibbs		cesr.cesr_element_base = base;
66639227Sgibbs		cesr.cesr_element_count = count;
66739227Sgibbs		/* Allocate storage for the status structures. */
66866019Sken		cesr.cesr_element_status =
66966019Sken		  (struct changer_element_status *)
67079253Smikeh		  calloc((size_t)count, sizeof(struct changer_element_status));
67139227Sgibbs
67239227Sgibbs		if (!cesr.cesr_element_status)
67323449Sjoerg			errx(1, "can't allocate status storage");
67423449Sjoerg
67539227Sgibbs		if (avoltag || pvoltag)
67639227Sgibbs			cesr.cesr_flags |= CESR_VOLTAGS;
67723449Sjoerg
67839227Sgibbs		if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) {
67939227Sgibbs			free(cesr.cesr_element_status);
68023449Sjoerg			err(1, "%s: CHIOGSTATUS", changer_name);
68123449Sjoerg		}
68223449Sjoerg
68339227Sgibbs		/* Dump the status for each reported element. */
68423449Sjoerg		for (i = 0; i < count; ++i) {
68539227Sgibbs			struct changer_element_status *ces =
68639227Sgibbs			         &(cesr.cesr_element_status[i]);
68739227Sgibbs			printf("%s %d: %s", description, ces->ces_addr,
68839227Sgibbs			    bits_to_string(ces->ces_flags,
68939227Sgibbs					   CESTATUS_BITS));
69039227Sgibbs			if (sense)
69139227Sgibbs				printf(" sense: <0x%02x/0x%02x>",
69239227Sgibbs				       ces->ces_sensecode,
69339227Sgibbs				       ces->ces_sensequal);
69439227Sgibbs			if (pvoltag)
69539227Sgibbs				printf(" voltag: <%s:%d>",
69639227Sgibbs				       ces->ces_pvoltag.cv_volid,
69739227Sgibbs				       ces->ces_pvoltag.cv_serial);
69839227Sgibbs			if (avoltag)
69939227Sgibbs				printf(" avoltag: <%s:%d>",
70039227Sgibbs				       ces->ces_avoltag.cv_volid,
70139227Sgibbs				       ces->ces_avoltag.cv_serial);
70246073Simp			if (source) {
70339227Sgibbs				if (ces->ces_flags & CES_SOURCE_VALID)
70439227Sgibbs					printf(" source: <%s %d>",
70539227Sgibbs					       element_type_name(
70639227Sgibbs						       ces->ces_source_type),
70739227Sgibbs					       ces->ces_source_addr);
70839227Sgibbs				else
70939227Sgibbs					printf(" source: <>");
71046073Simp			}
71139227Sgibbs			if (intaddr)
71239227Sgibbs				printf(" intaddr: <%d>", ces->ces_int_addr);
71339227Sgibbs			if (scsi) {
71439227Sgibbs				printf(" scsi: <");
71539227Sgibbs				if (ces->ces_flags & CES_SCSIID_VALID)
71639227Sgibbs					printf("%d", ces->ces_scsi_id);
71739227Sgibbs				else
71839227Sgibbs					putchar('?');
71939227Sgibbs				putchar(':');
72039227Sgibbs				if (ces->ces_flags & CES_LUN_VALID)
72139227Sgibbs					printf("%d", ces->ces_scsi_lun);
72239227Sgibbs				else
72339227Sgibbs					putchar('?');
72439227Sgibbs				putchar('>');
72539227Sgibbs			}
72639227Sgibbs			putchar('\n');
72723449Sjoerg		}
72823449Sjoerg
72939227Sgibbs		free(cesr.cesr_element_status);
73039227Sgibbs		count = 0;
73123449Sjoerg	}
73223449Sjoerg
73323449Sjoerg	return (0);
73423449Sjoerg
73523449Sjoerg usage:
73639227Sgibbs	(void) fprintf(stderr, "usage: %s %s [-vVsSbaA] [<element type> [<start-addr> [<end-addr>] ] ]\n",
73793101Smarkm		       getprogname(), cname);
73823449Sjoerg	return (1);
73923449Sjoerg}
74023449Sjoerg
74123449Sjoergstatic int
74290107Simpdo_ielem(const char *cname, int argc, char **argv)
74323449Sjoerg{
74439227Sgibbs	int timeout = 0;
74539227Sgibbs
74639227Sgibbs	if (argc == 2) {
74739227Sgibbs		timeout = atol(argv[1]);
74839227Sgibbs	} else if (argc > 1) {
74939227Sgibbs		warnx("%s: too many arguments", cname);
75039227Sgibbs		goto usage;
75139227Sgibbs	}
75239227Sgibbs
75339227Sgibbs	if (ioctl(changer_fd, CHIOIELEM, &timeout))
75439227Sgibbs		err(1, "%s: CHIOIELEM", changer_name);
75539227Sgibbs
75639227Sgibbs	return (0);
75739227Sgibbs
75839227Sgibbs usage:
75939227Sgibbs	(void) fprintf(stderr, "usage: %s %s [<timeout>]\n",
76093101Smarkm		       getprogname(), cname);
76139227Sgibbs	return (1);
76239227Sgibbs}
76339227Sgibbs
76439227Sgibbsstatic int
76590107Simpdo_voltag(const char *cname, int argc, char **argv)
76639227Sgibbs{
76739227Sgibbs	int force = 0;
76839227Sgibbs	int clear = 0;
76939227Sgibbs	int alternate = 0;
77039227Sgibbs	int c;
77139227Sgibbs	struct changer_set_voltag_request csvr;
77239227Sgibbs
77339227Sgibbs	bzero(&csvr, sizeof(csvr));
77439227Sgibbs
77539227Sgibbs	optind = optreset = 1;
77647442Simp	while ((c = getopt(argc, argv, "fca")) != -1) {
77739227Sgibbs		switch (c) {
77839227Sgibbs		case 'f':
77939227Sgibbs			force = 1;
78039227Sgibbs			break;
78139227Sgibbs		case 'c':
78239227Sgibbs			clear = 1;
78339227Sgibbs			break;
78439227Sgibbs		case 'a':
78539227Sgibbs			alternate = 1;
78639227Sgibbs			break;
78739227Sgibbs		default:
78841579Sbde			warnx("%s: bad option", cname);
78939227Sgibbs			goto usage;
79039227Sgibbs		}
79139227Sgibbs	}
79239227Sgibbs
79339227Sgibbs	argc -= optind;
79439227Sgibbs	argv += optind;
79539227Sgibbs
79639227Sgibbs	if (argc < 2) {
79741579Sbde		warnx("%s: missing element specification", cname);
79839227Sgibbs		goto usage;
79939227Sgibbs	}
80039227Sgibbs
80139227Sgibbs	csvr.csvr_type = parse_element_type(argv[0]);
80291086Smarkm	csvr.csvr_addr = (u_int16_t)atol(argv[1]);
80339227Sgibbs
80439227Sgibbs	if (!clear) {
80539227Sgibbs		if (argc < 3 || argc > 4) {
80641579Sbde			warnx("%s: missing argument", cname);
80739227Sgibbs			goto usage;
80839227Sgibbs		}
80939227Sgibbs
81039227Sgibbs		if (force)
81139227Sgibbs			csvr.csvr_flags = CSVR_MODE_REPLACE;
81239227Sgibbs		else
81339227Sgibbs			csvr.csvr_flags = CSVR_MODE_SET;
81439227Sgibbs
81539227Sgibbs		if (strlen(argv[2]) > sizeof(csvr.csvr_voltag.cv_volid)) {
81641579Sbde			warnx("%s: volume label too long", cname);
81739227Sgibbs			goto usage;
81839227Sgibbs		}
81939227Sgibbs
82079253Smikeh		strlcpy((char *)csvr.csvr_voltag.cv_volid, argv[2],
82139227Sgibbs		       sizeof(csvr.csvr_voltag.cv_volid));
82239227Sgibbs
82339227Sgibbs		if (argc == 4) {
82491086Smarkm			csvr.csvr_voltag.cv_serial = (u_int16_t)atol(argv[3]);
82539227Sgibbs		}
82639227Sgibbs	} else {
82739227Sgibbs		if (argc != 2) {
82841579Sbde			warnx("%s: unexpected argument", cname);
82939227Sgibbs			goto usage;
83039227Sgibbs		}
83139227Sgibbs		csvr.csvr_flags = CSVR_MODE_CLEAR;
83239227Sgibbs	}
83339227Sgibbs
83439227Sgibbs	if (alternate) {
83539227Sgibbs		csvr.csvr_flags |= CSVR_ALTERNATE;
83639227Sgibbs	}
83739227Sgibbs
83839227Sgibbs	if (ioctl(changer_fd, CHIOSETVOLTAG, &csvr))
83939227Sgibbs		err(1, "%s: CHIOSETVOLTAG", changer_name);
84039227Sgibbs
84139227Sgibbs	return 0;
84239227Sgibbs usage:
84339227Sgibbs	(void) fprintf(stderr,
84439227Sgibbs		       "usage: %s %s [-fca] <element> [<voltag> [<vsn>] ]\n",
84593101Smarkm		       getprogname(), cname);
84639227Sgibbs	return 1;
84739227Sgibbs}
84839227Sgibbs
84991086Smarkmstatic u_int16_t
85090107Simpparse_element_type(char *cp)
85139227Sgibbs{
85223449Sjoerg	int i;
85323449Sjoerg
85423449Sjoerg	for (i = 0; elements[i].et_name != NULL; ++i)
85523449Sjoerg		if (strcmp(elements[i].et_name, cp) == 0)
85691086Smarkm			return ((u_int16_t)elements[i].et_type);
85723449Sjoerg
85823449Sjoerg	errx(1, "invalid element type `%s'", cp);
85939227Sgibbs	/* NOTREACHED */
86023449Sjoerg}
86123449Sjoerg
86239227Sgibbsstatic const char *
86390107Simpelement_type_name(int et)
86439227Sgibbs{
86539227Sgibbs	int i;
86639227Sgibbs
86739227Sgibbs	for (i = 0; elements[i].et_name != NULL; i++)
86839227Sgibbs		if (elements[i].et_type == et)
86939227Sgibbs			return elements[i].et_name;
87039227Sgibbs
87139227Sgibbs	return "unknown";
87239227Sgibbs}
87339227Sgibbs
87491086Smarkmstatic u_int16_t
87590107Simpparse_element_unit(char *cp)
87623449Sjoerg{
87723449Sjoerg	int i;
87823449Sjoerg	char *p;
87923449Sjoerg
88023449Sjoerg	i = (int)strtol(cp, &p, 10);
88123449Sjoerg	if ((i < 0) || (*p != '\0'))
88223449Sjoerg		errx(1, "invalid unit number `%s'", cp);
88323449Sjoerg
88491086Smarkm	return ((u_int16_t)i);
88523449Sjoerg}
88623449Sjoerg
88723449Sjoergstatic int
88890107Simpparse_special(char *cp)
88923449Sjoerg{
89023449Sjoerg	int val;
89123449Sjoerg
89223449Sjoerg	val = is_special(cp);
89323449Sjoerg	if (val)
89423449Sjoerg		return (val);
89523449Sjoerg
89623449Sjoerg	errx(1, "invalid modifier `%s'", cp);
89739227Sgibbs	/* NOTREACHED */
89823449Sjoerg}
89923449Sjoerg
90023449Sjoergstatic int
90190107Simpis_special(char *cp)
90223449Sjoerg{
90323449Sjoerg	int i;
90423449Sjoerg
90523449Sjoerg	for (i = 0; specials[i].sw_name != NULL; ++i)
90623449Sjoerg		if (strcmp(specials[i].sw_name, cp) == 0)
90723449Sjoerg			return (specials[i].sw_value);
90823449Sjoerg
90923449Sjoerg	return (0);
91023449Sjoerg}
91123449Sjoerg
91248073Skrisstatic const char *
91390107Simpbits_to_string(ces_status_flags v, const char *cp)
91423449Sjoerg{
91523449Sjoerg	const char *np;
91623449Sjoerg	char f, sep, *bp;
91723449Sjoerg	static char buf[128];
91823449Sjoerg
91923449Sjoerg	bp = buf;
92039227Sgibbs	(void) memset(buf, 0, sizeof(buf));
92123449Sjoerg
92223449Sjoerg	for (sep = '<'; (f = *cp++) != 0; cp = np) {
92323449Sjoerg		for (np = cp; *np >= ' ';)
92423449Sjoerg			np++;
92591086Smarkm		if (((int)v & (1 << (f - 1))) == 0)
92623449Sjoerg			continue;
92791086Smarkm		(void) snprintf(bp, sizeof(buf) - (size_t)(bp - &buf[0]),
92848073Skris			"%c%.*s", sep, (int)(long)(np - cp), cp);
92947816Skris		bp += strlen(bp);
93023449Sjoerg		sep = ',';
93123449Sjoerg	}
93223449Sjoerg	if (sep != '<')
93323449Sjoerg		*bp = '>';
93423449Sjoerg
93523449Sjoerg	return (buf);
93623449Sjoerg}
93766019Sken/*
93866019Sken * do_return()
93966019Sken *
94066019Sken * Given an element reference, ask the changer/picker to move that
94166019Sken * element back to its source slot.
94266019Sken */
94366019Skenstatic int
94490107Simpdo_return(const char *cname, int argc, char **argv)
94566019Sken{
94666019Sken	struct changer_element_status *ces;
94766019Sken	struct changer_move cmd;
94891665Simp	uint16_t	type, element;
94923449Sjoerg
95066019Sken	++argv; --argc;
95166019Sken
95266019Sken	if (argc < 2) {
95366019Sken		warnx("%s: too few arguments", cname);
95466019Sken		goto usage;
95566019Sken	} else if (argc > 3) {
95666019Sken		warnx("%s: too many arguments", cname);
95766019Sken		goto usage;
95866019Sken	}
95966019Sken
96066019Sken	type = parse_element_type(*argv);
96166019Sken	++argv; --argc;
96266019Sken
96366019Sken	/* Handle voltag virtual Changer Element Type */
96466019Sken	if (CHET_VT == type) {
96566019Sken		find_element(*argv, &type, &element);
96666019Sken	} else {
96766019Sken		element = parse_element_unit(*argv);
96866019Sken	}
96966019Sken	++argv; --argc;
97066019Sken
97179253Smikeh	/* Get the status */
972184484Sjoerg	ces = get_element_status((unsigned int)type, (unsigned int)element,
973184484Sjoerg	    CHET_VT == type);
97466019Sken
97566019Sken	if (NULL == ces)
97666019Sken		errx(1, "%s: null element status pointer", cname);
97766019Sken
97866019Sken	if (!(ces->ces_flags & CES_SOURCE_VALID))
97966019Sken		errx(1, "%s: no source information", cname);
98066019Sken
98166019Sken	(void) memset(&cmd, 0, sizeof(cmd));
98266019Sken
98366019Sken	cmd.cm_fromtype = type;
98466019Sken	cmd.cm_fromunit = element;
98566019Sken	cmd.cm_totype = ces->ces_source_type;
98666019Sken	cmd.cm_tounit = ces->ces_source_addr;
98766019Sken
98866019Sken	if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1)
98966019Sken		err(1, "%s: CHIOMOVE", changer_name);
99066019Sken	free(ces);
99166019Sken
99266019Sken	return(0);
99366019Sken
99466019Skenusage:
99566019Sken	(void) fprintf(stderr, "usage: %s %s "
99693101Smarkm	    "<from ET> <from EU>\n", getprogname(), cname);
99766019Sken	return(1);
99866019Sken}
99966019Sken
100066019Sken/*
100166019Sken * get_element_status()
100266019Sken *
100366019Sken * return a *cesr for the specified changer element.  This
100466019Sken * routing will malloc()/calloc() the memory.  The caller
100566019Sken * should free() it when done.
100666019Sken */
100766019Skenstatic struct changer_element_status *
1008184484Sjoergget_element_status(unsigned int type, unsigned int element, int use_voltags)
100966019Sken{
101066019Sken	struct changer_element_status_request cesr;
101166019Sken	struct changer_element_status *ces;
101266019Sken
101366019Sken	ces = (struct changer_element_status *)
101479253Smikeh	    calloc((size_t)1, sizeof(struct changer_element_status));
101566019Sken
101666019Sken	if (NULL == ces)
101766019Sken		errx(1, "can't allocate status storage");
101866019Sken
101966019Sken	(void)memset(&cesr, 0, sizeof(cesr));
102066019Sken
102191665Simp	cesr.cesr_element_type = (uint16_t)type;
102291665Simp	cesr.cesr_element_base = (uint16_t)element;
102366019Sken	cesr.cesr_element_count = 1;		/* Only this one element */
1024184484Sjoerg	if (use_voltags)
1025184484Sjoerg		cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */
102666019Sken	cesr.cesr_element_status = ces;
102766019Sken
102866019Sken	if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
102966019Sken		free(ces);
103066019Sken		err(1, "%s: CHIOGSTATUS", changer_name);
103166019Sken		/* NOTREACHED */
103266019Sken	}
103366019Sken
103466019Sken	return ces;
103566019Sken}
103666019Sken
103766019Sken
103866019Sken/*
103966019Sken * find_element()
104066019Sken *
104166019Sken * Given a <voltag> find the chager element and unit, or exit
104266019Sken * with an error if it isn't found.  We grab the changer status
104366019Sken * and iterate until we find a match, or crap out.
104466019Sken */
104523449Sjoergstatic void
104691665Simpfind_element(char *voltag, uint16_t *et, uint16_t *eu)
104766019Sken{
104866019Sken	struct changer_params cp;
104966019Sken	struct changer_element_status_request cesr;
105066019Sken	struct changer_element_status *ch_ces, *ces;
105179253Smikeh	int found = 0;
105279253Smikeh	size_t elem, total_elem;
105366019Sken
105466019Sken	/*
105566019Sken	 * Get the changer parameters, we're interested in the counts
105666019Sken	 * for all types of elements to perform our search.
105766019Sken	 */
105866019Sken	if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp))
105966019Sken		err(1, "%s: CHIOGPARAMS", changer_name);
106066019Sken
106166019Sken	/* Allocate some memory for the results */
106266019Sken	total_elem = (cp.cp_nslots + cp.cp_ndrives
106366019Sken	    + cp.cp_npickers + cp.cp_nportals);
106466019Sken
106566019Sken	ch_ces = (struct changer_element_status *)
106666019Sken	    calloc(total_elem, sizeof(struct changer_element_status));
106766019Sken
106866019Sken	if (NULL == ch_ces)
106966019Sken		errx(1, "can't allocate status storage");
107066019Sken
107166019Sken	ces = ch_ces;
107266019Sken
107366019Sken	/* Read in the changer slots */
107466019Sken	if (cp.cp_nslots > 0) {
107566019Sken		cesr.cesr_element_type = CHET_ST;
107666019Sken		cesr.cesr_element_base = 0;
107766019Sken		cesr.cesr_element_count = cp.cp_nslots;
107866019Sken		cesr.cesr_flags |= CESR_VOLTAGS;
107966019Sken		cesr.cesr_element_status = ces;
108066019Sken
108166019Sken		if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
108266019Sken			free(ch_ces);
108366019Sken			err(1, "%s: CHIOGSTATUS", changer_name);
108466019Sken		}
108566019Sken		ces += cp.cp_nslots;
108666019Sken	}
108766019Sken
108866019Sken	/* Read in the drive information */
108966019Sken	if (cp.cp_ndrives > 0 ) {
109066019Sken
109166019Sken		(void) memset(&cesr, 0, sizeof(cesr));
109266019Sken		cesr.cesr_element_type = CHET_DT;
109366019Sken		cesr.cesr_element_base = 0;
109466019Sken		cesr.cesr_element_count = cp.cp_ndrives;
109566019Sken		cesr.cesr_flags |= CESR_VOLTAGS;
109666019Sken		cesr.cesr_element_status = ces;
109766019Sken
109866019Sken		if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
109966019Sken			free(ch_ces);
110066019Sken			err(1, "%s: CHIOGSTATUS", changer_name);
110166019Sken		}
110266019Sken		ces += cp.cp_ndrives;
110366019Sken	}
110466019Sken
110566019Sken	/* Read in the portal information */
110666019Sken	if (cp.cp_nportals > 0 ) {
110766019Sken		(void) memset(&cesr, 0, sizeof(cesr));
110866019Sken		cesr.cesr_element_type = CHET_IE;
110966019Sken		cesr.cesr_element_base = 0;
111066019Sken		cesr.cesr_element_count = cp.cp_nportals;
111166019Sken		cesr.cesr_flags |= CESR_VOLTAGS;
111266019Sken		cesr.cesr_element_status = ces;
111366019Sken
111466019Sken		if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
111566019Sken			free(ch_ces);
111666019Sken			err(1, "%s: CHIOGSTATUS", changer_name);
111766019Sken		}
111866019Sken		ces += cp.cp_nportals;
111966019Sken	}
112066019Sken
112166019Sken	/* Read in the picker information */
112266019Sken	if (cp.cp_npickers > 0) {
112366019Sken		(void) memset(&cesr, 0, sizeof(cesr));
112466019Sken		cesr.cesr_element_type = CHET_MT;
112566019Sken		cesr.cesr_element_base = 0;
112666019Sken		cesr.cesr_element_count = cp.cp_npickers;
112766019Sken		cesr.cesr_flags |= CESR_VOLTAGS;
112866019Sken		cesr.cesr_element_status = ces;
112966019Sken
113066019Sken		if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
113166019Sken			free(ch_ces);
113266019Sken			err(1, "%s: CHIOGSTATUS", changer_name);
113366019Sken		}
113466019Sken	}
113566019Sken
113666019Sken	/*
113766019Sken	 * Now search the list the specified <voltag>
113866019Sken	 */
113966019Sken	for (elem = 0; elem <= total_elem; ++elem) {
114066019Sken
114166019Sken		ces = &ch_ces[elem];
114266019Sken
114366019Sken		/* Make sure we have a tape in this element */
114466019Sken		if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL))
114566019Sken		    != (CES_STATUS_ACCESS|CES_STATUS_FULL))
114666019Sken			continue;
114766019Sken
114866019Sken		/* Check to see if it is our target */
114979253Smikeh		if (strcasecmp(voltag,
115079253Smikeh		    (const char *)ces->ces_pvoltag.cv_volid) == 0) {
115166019Sken			*et = ces->ces_type;
115266019Sken			*eu = ces->ces_addr;
115366019Sken			++found;
115466019Sken			break;
115566019Sken		}
115666019Sken	}
115766019Sken	if (!found) {
115866019Sken		errx(1, "%s: unable to locate voltag: %s", changer_name,
115966019Sken		     voltag);
116066019Sken	}
116166019Sken	free(ch_ces);
116266019Sken	return;
116366019Sken}
116466019Sken
116566019Skenstatic void
116690107Simpcleanup(void)
116723449Sjoerg{
116823449Sjoerg	/* Simple enough... */
116923449Sjoerg	(void)close(changer_fd);
117023449Sjoerg}
117123449Sjoerg
117223449Sjoergstatic void
117390107Simpusage(void)
117423449Sjoerg{
117590107Simp	(void)fprintf(stderr, "usage: %s [-f changer] command [-<flags>] "
117693101Smarkm		"arg1 arg2 [arg3 [...]]\n", getprogname());
117723449Sjoerg	exit(1);
117823449Sjoerg}
1179