Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Dec 1997 11:30:26 -0800 (PST)
From:      Matt Dillon <dillon@best.net>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/5275: tape changer device volume support added
Message-ID:  <199712111930.LAA07999@flea.best.net>
Resent-Message-ID: <199712111940.LAA08420@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         5275
>Category:       kern
>Synopsis:       Added volume (barcode) support to tape changer device (ch)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Dec 11 11:40:01 PST 1997
>Last-Modified:
>Originator:     Matt Dillon
>Organization:
Best Internet Communications
>Release:        FreeBSD 2.2.5-STABLE i386
>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 <scsi/scsi_all.h>
  #include <scsi/scsi_changer.h>
  #include <scsi/scsiconf.h>
+ #include <stddef.h>
  
  #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 [<element type>]\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;
+     }
+ }
+ 
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199712111930.LAA07999>