mt.c revision 279261
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 29279219Sken/*- 30279219Sken * Copyright (c) 2013, 2014, 2015 Spectra Logic Corporation 31279219Sken * All rights reserved. 32279219Sken * 33279219Sken * Redistribution and use in source and binary forms, with or without 34279219Sken * modification, are permitted provided that the following conditions 35279219Sken * are met: 36279219Sken * 1. Redistributions of source code must retain the above copyright 37279219Sken * notice, this list of conditions, and the following disclaimer, 38279219Sken * without modification. 39279219Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 40279219Sken * substantially similar to the "NO WARRANTY" disclaimer below 41279219Sken * ("Disclaimer") and any redistribution must be conditioned upon 42279219Sken * including a substantially similar Disclaimer requirement for further 43279219Sken * binary redistribution. 44279219Sken * 45279219Sken * NO WARRANTY 46279219Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 47279219Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 48279219Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 49279219Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 50279219Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51279219Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52279219Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53279219Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 54279219Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 55279219Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 56279219Sken * POSSIBILITY OF SUCH DAMAGES. 57279219Sken * 58279219Sken * Authors: Ken Merry (Spectra Logic Corporation) 59279219Sken */ 601590Srgrimes 611590Srgrimes#ifndef lint 6227752Scharnierstatic const char copyright[] = 631590Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 641590Srgrimes The Regents of the University of California. All rights reserved.\n"; 651590Srgrimes#endif /* not lint */ 661590Srgrimes 671590Srgrimes#ifndef lint 6827752Scharnier#if 0 6923693Speterstatic char sccsid[] = "@(#)mt.c 8.2 (Berkeley) 5/4/95"; 7027752Scharnier#endif 711590Srgrimes#endif /* not lint */ 721590Srgrimes 7394505Scharnier#include <sys/cdefs.h> 7494505Scharnier__FBSDID("$FreeBSD: head/usr.bin/mt/mt.c 279261 2015-02-25 04:30:23Z ken $"); 7594505Scharnier 761590Srgrimes/* 771590Srgrimes * mt -- 781590Srgrimes * magnetic tape manipulation program 791590Srgrimes */ 801590Srgrimes#include <sys/types.h> 811590Srgrimes#include <sys/ioctl.h> 821590Srgrimes#include <sys/mtio.h> 83279219Sken#include <sys/queue.h> 84279219Sken#include <sys/sbuf.h> 8523693Speter 8623693Speter#include <ctype.h> 8727752Scharnier#include <err.h> 881590Srgrimes#include <fcntl.h> 8923693Speter#include <stdio.h> 901590Srgrimes#include <stdlib.h> 911590Srgrimes#include <string.h> 9223693Speter#include <unistd.h> 93279219Sken#include <stdint.h> 94279219Sken#include <errno.h> 95279219Sken#include <bsdxml.h> 96279219Sken#include <mtlib.h> 971590Srgrimes 98279219Sken#include <cam/cam.h> 99279219Sken#include <cam/cam_ccb.h> 100279219Sken#include <cam/cam_periph.h> 101279219Sken#include <cam/scsi/scsi_all.h> 102279219Sken#include <cam/scsi/scsi_sa.h> 103279219Sken 1047913Sjoerg/* the appropriate sections of <sys/mtio.h> are also #ifdef'd for FreeBSD */ 1057913Sjoerg/* c_flags */ 1067913Sjoerg#define NEED_2ARGS 0x01 1077929Sjoerg#define ZERO_ALLOWED 0x02 1087929Sjoerg#define IS_DENSITY 0x04 1099541Sjoerg#define DISABLE_THIS 0x08 11039260Sgibbs#define IS_COMP 0x10 111279219Sken#define USE_GETOPT 0x20 1127913Sjoerg 11339260Sgibbs#ifndef TRUE 11439260Sgibbs#define TRUE 1 11539260Sgibbs#endif 11639260Sgibbs#ifndef FALSE 11739260Sgibbs#define FALSE 0 11839260Sgibbs#endif 119279219Sken#ifndef MAX 120279219Sken#define MAX(a, b) (a > b) ? a : b 121279219Sken#endif 12239260Sgibbs 123279219Skentypedef enum { 124279219Sken MT_CMD_NONE = MTLOAD + 1, 125279219Sken MT_CMD_PROTECT, 126279219Sken MT_CMD_GETDENSITY 127279219Sken} mt_commands; 128279219Sken 129227174Sedstatic const struct commands { 130152396Sdwmalone const char *c_name; 131228619Sdim unsigned long c_code; 1321590Srgrimes int c_ronly; 1337913Sjoerg int c_flags; 1341590Srgrimes} com[] = { 13594505Scharnier { "bsf", MTBSF, 1, 0 }, 13694505Scharnier { "bsr", MTBSR, 1, 0 }, 1379541Sjoerg /* XXX FreeBSD considered "eof" dangerous, since it's being 1389541Sjoerg confused with "eom" (and is an alias for "weof" anyway) */ 1399541Sjoerg { "eof", MTWEOF, 0, DISABLE_THIS }, 14094505Scharnier { "fsf", MTFSF, 1, 0 }, 14194505Scharnier { "fsr", MTFSR, 1, 0 }, 14294505Scharnier { "offline", MTOFFL, 1, 0 }, 143279219Sken { "load", MTLOAD, 1, 0 }, 14494505Scharnier { "rewind", MTREW, 1, 0 }, 14594505Scharnier { "rewoffl", MTOFFL, 1, 0 }, 146279219Sken { "ostatus", MTNOP, 1, 0 }, 14741913Smjacob { "weof", MTWEOF, 0, ZERO_ALLOWED }, 148279219Sken { "weofi", MTWEOFI, 0, ZERO_ALLOWED }, 14939260Sgibbs { "erase", MTERASE, 0, ZERO_ALLOWED}, 1507913Sjoerg { "blocksize", MTSETBSIZ, 0, NEED_2ARGS|ZERO_ALLOWED }, 1517929Sjoerg { "density", MTSETDNSTY, 0, NEED_2ARGS|ZERO_ALLOWED|IS_DENSITY }, 15294505Scharnier { "eom", MTEOD, 1, 0 }, 15394505Scharnier { "eod", MTEOD, 1, 0 }, 15494505Scharnier { "smk", MTWSS, 0, 0 }, 15594505Scharnier { "wss", MTWSS, 0, 0 }, 15694505Scharnier { "fss", MTFSS, 1, 0 }, 15794505Scharnier { "bss", MTBSS, 1, 0 }, 15839260Sgibbs { "comp", MTCOMP, 0, NEED_2ARGS|ZERO_ALLOWED|IS_COMP }, 15994505Scharnier { "retension", MTRETENS, 1, 0 }, 16094505Scharnier { "rdhpos", MTIOCRDHPOS, 0, 0 }, 16194505Scharnier { "rdspos", MTIOCRDSPOS, 0, 0 }, 16241913Smjacob { "sethpos", MTIOCHLOCATE, 0, NEED_2ARGS|ZERO_ALLOWED }, 16341913Smjacob { "setspos", MTIOCSLOCATE, 0, NEED_2ARGS|ZERO_ALLOWED }, 16494505Scharnier { "errstat", MTIOCERRSTAT, 0, 0 }, 16546928Smjacob { "setmodel", MTIOCSETEOTMODEL, 0, NEED_2ARGS|ZERO_ALLOWED }, 16646928Smjacob { "seteotmodel", MTIOCSETEOTMODEL, 0, NEED_2ARGS|ZERO_ALLOWED }, 16794505Scharnier { "getmodel", MTIOCGETEOTMODEL, 0, 0 }, 16894505Scharnier { "geteotmodel", MTIOCGETEOTMODEL, 0, 0 }, 169279219Sken { "rblim", MTIOCRBLIM, 0, 0}, 170279219Sken { "getdensity", MT_CMD_GETDENSITY, 0, USE_GETOPT}, 171279219Sken { "status", MTIOCEXTGET, 0, USE_GETOPT }, 172279219Sken { "locate", MTIOCEXTLOCATE, 0, USE_GETOPT }, 173279219Sken { "param", MTIOCPARAMGET, 0, USE_GETOPT }, 174279219Sken { "protect", MT_CMD_PROTECT, 0, USE_GETOPT }, 17594505Scharnier { NULL, 0, 0, 0 } 1761590Srgrimes}; 1771590Srgrimes 178279219Sken 179227174Sedstatic const char *getblksiz(int); 180227174Sedstatic void printreg(const char *, u_int, const char *); 181227174Sedstatic void status(struct mtget *); 182227174Sedstatic void usage(void); 183279219Skenconst char *get_driver_state_str(int dsreg); 184279219Skenstatic void st_status (struct mtget *); 185279219Skenstatic int mt_locate(int argc, char **argv, int mtfd, const char *tape); 186279219Skenstatic int nstatus_print(int argc, char **argv, char *xml_str, 187279219Sken struct mt_status_data *status_data); 188279219Skenstatic int mt_xml_cmd(unsigned long cmd, int argc, char **argv, int mtfd, 189279219Sken const char *tape); 190279219Skenstatic int mt_print_density_entry(struct mt_status_entry *density_root, int indent); 191279219Skenstatic int mt_print_density_report(struct mt_status_entry *report_root, int indent); 192279219Skenstatic int mt_print_density(struct mt_status_entry *density_root, int indent); 193279219Skenstatic int mt_getdensity(int argc, char **argv, char *xml_str, 194279219Sken struct mt_status_data *status_data); 195279219Skenstatic int mt_set_param(int mtfd, struct mt_status_data *status_data, 196279219Sken char *param_name, char *param_value); 197279219Skenstatic int mt_protect(int argc, char **argv, int mtfd, 198279219Sken struct mt_status_data *status_data); 199279219Skenstatic int mt_param(int argc, char **argv, int mtfd, char *xml_str, 200279219Sken struct mt_status_data *status_data); 201279219Skenstatic const char *denstostring (int d); 202227174Sedstatic u_int32_t stringtocomp(const char *s); 203227174Sedstatic const char *comptostring(u_int32_t comp); 204227174Sedstatic void warn_eof(void); 2051590Srgrimes 2061590Srgrimesint 207152396Sdwmalonemain(int argc, char *argv[]) 2081590Srgrimes{ 209227174Sed const struct commands *comp; 2101590Srgrimes struct mtget mt_status; 2111590Srgrimes struct mtop mt_com; 2121590Srgrimes int ch, len, mtfd; 213152396Sdwmalone const char *p, *tape; 2141590Srgrimes 215279261Sken bzero(&mt_com, sizeof(mt_com)); 216279261Sken 2171590Srgrimes if ((tape = getenv("TAPE")) == NULL) 2181590Srgrimes tape = DEFTAPE; 2191590Srgrimes 22024360Simp while ((ch = getopt(argc, argv, "f:t:")) != -1) 2211590Srgrimes switch(ch) { 2221590Srgrimes case 'f': 2231590Srgrimes case 't': 2241590Srgrimes tape = optarg; 2251590Srgrimes break; 2261590Srgrimes case '?': 227279219Sken usage(); 228279219Sken break; 2291590Srgrimes default: 230279219Sken break; 2311590Srgrimes } 2321590Srgrimes argc -= optind; 2331590Srgrimes argv += optind; 2341590Srgrimes 235279219Sken if (argc < 1) 2361590Srgrimes usage(); 2371590Srgrimes 2381590Srgrimes len = strlen(p = *argv++); 2391590Srgrimes for (comp = com;; comp++) { 2401590Srgrimes if (comp->c_name == NULL) 24127752Scharnier errx(1, "%s: unknown command", p); 2421590Srgrimes if (strncmp(p, comp->c_name, len) == 0) 2431590Srgrimes break; 2441590Srgrimes } 2457913Sjoerg if((comp->c_flags & NEED_2ARGS) && argc != 2) 2467913Sjoerg usage(); 2479541Sjoerg if(comp->c_flags & DISABLE_THIS) { 2489541Sjoerg warn_eof(); 2499541Sjoerg } 250279219Sken if (comp->c_flags & USE_GETOPT) { 251279219Sken argc--; 252279219Sken optind = 0; 253279219Sken } 254279219Sken 2551590Srgrimes if ((mtfd = open(tape, comp->c_ronly ? O_RDONLY : O_RDWR)) < 0) 25627752Scharnier err(1, "%s", tape); 2571590Srgrimes if (comp->c_code != MTNOP) { 2581590Srgrimes mt_com.mt_op = comp->c_code; 2591590Srgrimes if (*argv) { 2607929Sjoerg if (!isdigit(**argv) && 26141925Smjacob (comp->c_flags & IS_DENSITY)) { 2627929Sjoerg const char *dcanon; 263279219Sken mt_com.mt_count = mt_density_num(*argv); 2647929Sjoerg if (mt_com.mt_count == 0) 26527752Scharnier errx(1, "%s: unknown density", *argv); 2667929Sjoerg dcanon = denstostring(mt_com.mt_count); 2677929Sjoerg if (strcmp(dcanon, *argv) != 0) 2687929Sjoerg printf( 2697929Sjoerg "Using \"%s\" as an alias for %s\n", 2707929Sjoerg *argv, dcanon); 2717929Sjoerg p = ""; 27239260Sgibbs } else if (!isdigit(**argv) && 27341925Smjacob (comp->c_flags & IS_COMP)) { 27439260Sgibbs 27539260Sgibbs mt_com.mt_count = stringtocomp(*argv); 27639260Sgibbs if ((u_int32_t)mt_com.mt_count == 0xf0f0f0f0) 27739260Sgibbs errx(1, "%s: unknown compression", 27839260Sgibbs *argv); 27939260Sgibbs p = ""; 280279219Sken } else if ((comp->c_flags & USE_GETOPT) == 0) { 281152396Sdwmalone char *q; 2827929Sjoerg /* allow for hex numbers; useful for density */ 283152396Sdwmalone mt_com.mt_count = strtol(*argv, &q, 0); 284152396Sdwmalone p = q; 285152396Sdwmalone } 286279219Sken if (((comp->c_flags & USE_GETOPT) == 0) 287279219Sken && (((mt_com.mt_count <= 288279219Sken ((comp->c_flags & ZERO_ALLOWED)? -1: 0)) 289279219Sken && ((comp->c_flags & IS_COMP) == 0)) 290279219Sken || *p)) 29127752Scharnier errx(1, "%s: illegal count", *argv); 2921590Srgrimes } 2931590Srgrimes else 2941590Srgrimes mt_com.mt_count = 1; 29541913Smjacob switch (comp->c_code) { 29641945Smjacob case MTIOCERRSTAT: 29741945Smjacob { 29894505Scharnier unsigned int i; 29941945Smjacob union mterrstat umn; 30041945Smjacob struct scsi_tape_errors *s = &umn.scsi_errstat; 30141945Smjacob 30241945Smjacob if (ioctl(mtfd, comp->c_code, (caddr_t)&umn) < 0) 30341945Smjacob err(2, "%s", tape); 30441945Smjacob (void)printf("Last I/O Residual: %u\n", s->io_resid); 30542010Smjacob (void)printf(" Last I/O Command:"); 30642010Smjacob for (i = 0; i < sizeof (s->io_cdb); i++) 30742010Smjacob (void)printf(" %02X", s->io_cdb[i]); 30842010Smjacob (void)printf("\n"); 30941945Smjacob (void)printf(" Last I/O Sense:\n\n\t"); 31041945Smjacob for (i = 0; i < sizeof (s->io_sense); i++) { 31141945Smjacob (void)printf(" %02X", s->io_sense[i]); 31241945Smjacob if (((i + 1) & 0xf) == 0) { 31341945Smjacob (void)printf("\n\t"); 31441945Smjacob } 31541945Smjacob } 31641945Smjacob (void)printf("\n"); 31741945Smjacob (void)printf("Last Control Residual: %u\n", 31841945Smjacob s->ctl_resid); 31942010Smjacob (void)printf(" Last Control Command:"); 32042010Smjacob for (i = 0; i < sizeof (s->ctl_cdb); i++) 32142010Smjacob (void)printf(" %02X", s->ctl_cdb[i]); 32242010Smjacob (void)printf("\n"); 32341945Smjacob (void)printf(" Last Control Sense:\n\n\t"); 32441945Smjacob for (i = 0; i < sizeof (s->ctl_sense); i++) { 32541945Smjacob (void)printf(" %02X", s->ctl_sense[i]); 32641945Smjacob if (((i + 1) & 0xf) == 0) { 32741945Smjacob (void)printf("\n\t"); 32841945Smjacob } 32941945Smjacob } 33041945Smjacob (void)printf("\n\n"); 33141945Smjacob exit(0); 33241945Smjacob /* NOTREACHED */ 33341945Smjacob } 33441913Smjacob case MTIOCRDHPOS: 33541913Smjacob case MTIOCRDSPOS: 33641925Smjacob { 33741925Smjacob u_int32_t block; 33841925Smjacob if (ioctl(mtfd, comp->c_code, (caddr_t)&block) < 0) 33941913Smjacob err(2, "%s", tape); 34041945Smjacob (void)printf("%s: %s block location %u\n", tape, 34141913Smjacob (comp->c_code == MTIOCRDHPOS)? "hardware" : 34241925Smjacob "logical", block); 34341925Smjacob exit(0); 34441913Smjacob /* NOTREACHED */ 34541925Smjacob } 34641913Smjacob case MTIOCSLOCATE: 34741913Smjacob case MTIOCHLOCATE: 34841925Smjacob { 34941925Smjacob u_int32_t block = (u_int32_t)mt_com.mt_count; 35041925Smjacob if (ioctl(mtfd, comp->c_code, (caddr_t)&block) < 0) 35141913Smjacob err(2, "%s", tape); 35241925Smjacob exit(0); 35341913Smjacob /* NOTREACHED */ 35441925Smjacob } 35546928Smjacob case MTIOCGETEOTMODEL: 35646928Smjacob { 35746928Smjacob u_int32_t om; 35846928Smjacob if (ioctl(mtfd, MTIOCGETEOTMODEL, (caddr_t)&om) < 0) 35946928Smjacob err(2, "%s", tape); 36046928Smjacob (void)printf("%s: the model is %u filemar%s at EOT\n", 36146928Smjacob tape, om, (om > 1)? "ks" : "k"); 36246928Smjacob exit(0); 36346928Smjacob /* NOTREACHED */ 36446928Smjacob } 36546928Smjacob case MTIOCSETEOTMODEL: 36646928Smjacob { 36746928Smjacob u_int32_t om, nm = (u_int32_t)mt_com.mt_count; 36846928Smjacob if (ioctl(mtfd, MTIOCGETEOTMODEL, (caddr_t)&om) < 0) 36946928Smjacob err(2, "%s", tape); 37046928Smjacob if (ioctl(mtfd, comp->c_code, (caddr_t)&nm) < 0) 37146928Smjacob err(2, "%s", tape); 37246928Smjacob (void)printf("%s: old model was %u filemar%s at EOT\n", 37346928Smjacob tape, om, (om > 1)? "ks" : "k"); 37446928Smjacob (void)printf("%s: new model is %u filemar%s at EOT\n", 37546928Smjacob tape, nm, (nm > 1)? "ks" : "k"); 37646928Smjacob exit(0); 37746928Smjacob /* NOTREACHED */ 37846928Smjacob } 379279219Sken case MTIOCRBLIM: 380279219Sken { 381279219Sken struct mtrblim rblim; 382279219Sken 383279219Sken bzero(&rblim, sizeof(rblim)); 384279219Sken 385279219Sken if (ioctl(mtfd, MTIOCRBLIM, (caddr_t)&rblim) < 0) 386279219Sken err(2, "%s", tape); 387279219Sken (void)printf("%s: min blocksize %u bytes, " 388279219Sken "max blocksize %u bytes, granularity %u bytes\n", 389279219Sken tape, rblim.min_block_length, 390279219Sken rblim.max_block_length, rblim.granularity); 391279219Sken exit(0); 392279219Sken /* NOTREACHED */ 393279219Sken } 394279219Sken case MTIOCPARAMGET: 395279219Sken case MTIOCEXTGET: 396279219Sken case MT_CMD_PROTECT: 397279219Sken case MT_CMD_GETDENSITY: 398279219Sken { 399279219Sken int retval = 0; 400279219Sken 401279219Sken retval = mt_xml_cmd(comp->c_code, argc, argv, mtfd, 402279219Sken tape); 403279219Sken 404279219Sken exit(retval); 405279219Sken } 406279219Sken case MTIOCEXTLOCATE: 407279219Sken { 408279219Sken int retval = 0; 409279219Sken 410279219Sken retval = mt_locate(argc, argv, mtfd, tape); 411279219Sken 412279219Sken exit(retval); 413279219Sken } 41441913Smjacob default: 41541913Smjacob break; 41641913Smjacob } 4171590Srgrimes if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0) 41827752Scharnier err(1, "%s: %s", tape, comp->c_name); 4191590Srgrimes } else { 4201590Srgrimes if (ioctl(mtfd, MTIOCGET, &mt_status) < 0) 42127752Scharnier err(1, NULL); 4221590Srgrimes status(&mt_status); 4231590Srgrimes } 42441925Smjacob exit(0); 4251590Srgrimes /* NOTREACHED */ 4261590Srgrimes} 4271590Srgrimes 428227174Sedstatic const struct tape_desc { 4291590Srgrimes short t_type; /* type of magtape device */ 430152396Sdwmalone const char *t_name; /* printing name */ 431152396Sdwmalone const char *t_dsbits; /* "drive status" register */ 432152396Sdwmalone const char *t_erbits; /* "error" register */ 4331590Srgrimes} tapes[] = { 4347913Sjoerg { MT_ISAR, "SCSI tape drive", 0, 0 }, 43594505Scharnier { 0, NULL, 0, 0 } 4361590Srgrimes}; 4371590Srgrimes 4381590Srgrimes/* 4391590Srgrimes * Interpret the status buffer returned 4401590Srgrimes */ 441227174Sedstatic void 442152396Sdwmalonestatus(struct mtget *bp) 4431590Srgrimes{ 444227174Sed const struct tape_desc *mt; 4451590Srgrimes 4461590Srgrimes for (mt = tapes;; mt++) { 4471590Srgrimes if (mt->t_type == 0) { 4481590Srgrimes (void)printf("%d: unknown tape drive type\n", 4491590Srgrimes bp->mt_type); 4501590Srgrimes return; 4511590Srgrimes } 4521590Srgrimes if (mt->t_type == bp->mt_type) 4531590Srgrimes break; 4541590Srgrimes } 4557913Sjoerg if(mt->t_type == MT_ISAR) 4567913Sjoerg st_status(bp); 4577913Sjoerg else { 45892764Sphk (void)printf("%s tape drive, residual=%d\n", 45992764Sphk mt->t_name, bp->mt_resid); 46092764Sphk printreg("ds", (unsigned short)bp->mt_dsreg, mt->t_dsbits); 46192764Sphk printreg("\ner", (unsigned short)bp->mt_erreg, mt->t_erbits); 46292764Sphk (void)putchar('\n'); 4637913Sjoerg } 4641590Srgrimes} 4651590Srgrimes 4661590Srgrimes/* 4671590Srgrimes * Print a register a la the %b format of the kernel's printf. 4681590Srgrimes */ 469227174Sedstatic void 470152396Sdwmaloneprintreg(const char *s, u_int v, const char *bits) 4711590Srgrimes{ 472152396Sdwmalone int i, any = 0; 473152396Sdwmalone char c; 4741590Srgrimes 4751590Srgrimes if (bits && *bits == 8) 4761590Srgrimes printf("%s=%o", s, v); 4771590Srgrimes else 4781590Srgrimes printf("%s=%x", s, v); 47911608Sbde if (!bits) 48011608Sbde return; 4811590Srgrimes bits++; 4821590Srgrimes if (v && bits) { 4831590Srgrimes putchar('<'); 48427752Scharnier while ((i = *bits++)) { 4851590Srgrimes if (v & (1 << (i-1))) { 4861590Srgrimes if (any) 4871590Srgrimes putchar(','); 4881590Srgrimes any = 1; 4891590Srgrimes for (; (c = *bits) > 32; bits++) 4901590Srgrimes putchar(c); 4911590Srgrimes } else 4921590Srgrimes for (; *bits > 32; bits++) 4931590Srgrimes ; 4941590Srgrimes } 4951590Srgrimes putchar('>'); 4961590Srgrimes } 4971590Srgrimes} 4981590Srgrimes 499227174Sedstatic void 500152396Sdwmaloneusage(void) 5011590Srgrimes{ 50294505Scharnier (void)fprintf(stderr, "usage: mt [-f device] command [count]\n"); 5031590Srgrimes exit(1); 5041590Srgrimes} 5051590Srgrimes 506227174Sedstatic const struct compression_types { 50739260Sgibbs u_int32_t comp_number; 50839260Sgibbs const char *name; 50939260Sgibbs} comp_types[] = { 51039260Sgibbs { 0x00, "none" }, 51139260Sgibbs { 0x00, "off" }, 51239260Sgibbs { 0x10, "IDRC" }, 51339260Sgibbs { 0x20, "DCLZ" }, 51439260Sgibbs { 0xffffffff, "enable" }, 51539260Sgibbs { 0xffffffff, "on" }, 51639260Sgibbs { 0xf0f0f0f0, NULL} 51739260Sgibbs}; 51839260Sgibbs 519227174Sedstatic const char * 5207929Sjoergdenstostring(int d) 5217913Sjoerg{ 5227913Sjoerg static char buf[20]; 523279219Sken const char *name = mt_density_name(d); 5247913Sjoerg 525279219Sken if (name == NULL) 5267929Sjoerg sprintf(buf, "0x%02x", d); 52744397Smjacob else 528279219Sken sprintf(buf, "0x%02x:%s", d, name); 52944397Smjacob return buf; 5307913Sjoerg} 5317913Sjoerg 532227174Sedstatic const char * 5337913Sjoerggetblksiz(int bs) 5347913Sjoerg{ 5357913Sjoerg static char buf[25]; 5367913Sjoerg if (bs == 0) 5377913Sjoerg return "variable"; 5387913Sjoerg else { 53939260Sgibbs sprintf(buf, "%d bytes", bs); 5407913Sjoerg return buf; 5417913Sjoerg } 5427913Sjoerg} 5437913Sjoerg 544227174Sedstatic const char * 54539260Sgibbscomptostring(u_int32_t comp) 54639260Sgibbs{ 54739260Sgibbs static char buf[20]; 548227174Sed const struct compression_types *ct; 5497913Sjoerg 55039260Sgibbs if (comp == MT_COMP_DISABLED) 55139260Sgibbs return "disabled"; 55239260Sgibbs else if (comp == MT_COMP_UNSUPP) 55339260Sgibbs return "unsupported"; 55439260Sgibbs 55539260Sgibbs for (ct = comp_types; ct->name; ct++) 55639260Sgibbs if (ct->comp_number == comp) 55739260Sgibbs break; 55839260Sgibbs 55939260Sgibbs if (ct->comp_number == 0xf0f0f0f0) { 56044618Smjacob sprintf(buf, "0x%x", comp); 56139260Sgibbs return(buf); 56239260Sgibbs } else 56339260Sgibbs return(ct->name); 56439260Sgibbs} 56539260Sgibbs 566227174Sedstatic u_int32_t 56739260Sgibbsstringtocomp(const char *s) 56839260Sgibbs{ 569227174Sed const struct compression_types *ct; 57039260Sgibbs size_t l = strlen(s); 57139260Sgibbs 57239260Sgibbs for (ct = comp_types; ct->name; ct++) 57339260Sgibbs if (strncasecmp(ct->name, s, l) == 0) 57439260Sgibbs break; 57539260Sgibbs 57639260Sgibbs return(ct->comp_number); 57739260Sgibbs} 57839260Sgibbs 579279219Skenstatic struct driver_state { 580279219Sken int dsreg; 581279219Sken const char *desc; 582279219Sken} driver_states[] = { 583279219Sken { MTIO_DSREG_REST, "at rest" }, 584279219Sken { MTIO_DSREG_RBSY, "Communicating with drive" }, 585279219Sken { MTIO_DSREG_WR, "Writing" }, 586279219Sken { MTIO_DSREG_FMK, "Writing Filemarks" }, 587279219Sken { MTIO_DSREG_ZER, "Erasing" }, 588279219Sken { MTIO_DSREG_RD, "Reading" }, 589279219Sken { MTIO_DSREG_FWD, "Spacing Forward" }, 590279219Sken { MTIO_DSREG_REV, "Spacing Reverse" }, 591279219Sken { MTIO_DSREG_POS, "Hardware Positioning (direction unknown)" }, 592279219Sken { MTIO_DSREG_REW, "Rewinding" }, 593279219Sken { MTIO_DSREG_TEN, "Retensioning" }, 594279219Sken { MTIO_DSREG_UNL, "Unloading" }, 595279219Sken { MTIO_DSREG_LD, "Loading" }, 596279219Sken}; 597279219Sken 598279219Skenconst char * 599279219Skenget_driver_state_str(int dsreg) 600279219Sken{ 601279219Sken unsigned int i; 602279219Sken 603279219Sken for (i = 0; i < (sizeof(driver_states)/sizeof(driver_states[0])); i++) { 604279219Sken if (driver_states[i].dsreg == dsreg) 605279219Sken return (driver_states[i].desc); 606279219Sken } 607279219Sken 608279219Sken return (NULL); 609279219Sken} 610279219Sken 611227174Sedstatic void 6127913Sjoergst_status(struct mtget *bp) 6137913Sjoerg{ 61444644Smjacob printf("Mode Density Blocksize bpi " 61539260Sgibbs "Compression\n" 61644644Smjacob "Current: %-17s %-12s %-7d %s\n" 61739260Sgibbs "---------available modes---------\n" 61844644Smjacob "0: %-17s %-12s %-7d %s\n" 61944644Smjacob "1: %-17s %-12s %-7d %s\n" 62044644Smjacob "2: %-17s %-12s %-7d %s\n" 62144644Smjacob "3: %-17s %-12s %-7d %s\n", 62239260Sgibbs denstostring(bp->mt_density), getblksiz(bp->mt_blksiz), 623279219Sken mt_density_bp(bp->mt_density, TRUE), comptostring(bp->mt_comp), 62439260Sgibbs denstostring(bp->mt_density0), getblksiz(bp->mt_blksiz0), 625279219Sken mt_density_bp(bp->mt_density0, TRUE), comptostring(bp->mt_comp0), 62639260Sgibbs denstostring(bp->mt_density1), getblksiz(bp->mt_blksiz1), 627279219Sken mt_density_bp(bp->mt_density1, TRUE), comptostring(bp->mt_comp1), 62839260Sgibbs denstostring(bp->mt_density2), getblksiz(bp->mt_blksiz2), 629279219Sken mt_density_bp(bp->mt_density2, TRUE), comptostring(bp->mt_comp2), 63039260Sgibbs denstostring(bp->mt_density3), getblksiz(bp->mt_blksiz3), 631279219Sken mt_density_bp(bp->mt_density3, TRUE), comptostring(bp->mt_comp3)); 63243629Smjacob 63343629Smjacob if (bp->mt_dsreg != MTIO_DSREG_NIL) { 63469248Skris const char sfmt[] = "Current Driver State: %s.\n"; 63543629Smjacob printf("---------------------------------\n"); 636279219Sken const char *state_str; 637279219Sken 638279219Sken state_str = get_driver_state_str(bp->mt_dsreg); 639279219Sken if (state_str == NULL) { 640279219Sken char foo[32]; 641279219Sken (void) sprintf(foo, "Unknown state 0x%x", bp->mt_dsreg); 642279219Sken printf(sfmt, foo); 643279219Sken } else { 644279219Sken printf(sfmt, state_str); 645279219Sken } 646279219Sken } 647279219Sken if (bp->mt_resid == 0 && bp->mt_fileno == (daddr_t) -1 && 648279219Sken bp->mt_blkno == (daddr_t) -1) 649279219Sken return; 650279219Sken printf("---------------------------------\n"); 651279219Sken printf("File Number: %d\tRecord Number: %d\tResidual Count %d\n", 652279219Sken bp->mt_fileno, bp->mt_blkno, bp->mt_resid); 653279219Sken} 654279219Sken 655279219Skenstatic int 656279219Skenmt_locate(int argc, char **argv, int mtfd, const char *tape) 657279219Sken{ 658279219Sken struct mtlocate mtl; 659279219Sken uint64_t logical_id = 0; 660279219Sken mt_locate_dest_type dest_type = MT_LOCATE_DEST_FILE; 661279219Sken int eod = 0, explicit = 0, immediate = 0; 662279219Sken int64_t partition = 0; 663279219Sken int block_addr_set = 0, partition_set = 0, file_set = 0, set_set = 0; 664279219Sken int c, retval; 665279219Sken 666279219Sken retval = 0; 667279219Sken bzero(&mtl, sizeof(mtl)); 668279219Sken 669279219Sken while ((c = getopt(argc, argv, "b:eEf:ip:s:")) != -1) { 670279219Sken switch (c) { 671279219Sken case 'b': 672279219Sken /* Block address */ 673279219Sken logical_id = strtoull(optarg, NULL, 0); 674279219Sken dest_type = MT_LOCATE_DEST_OBJECT; 675279219Sken block_addr_set = 1; 67643629Smjacob break; 677279219Sken case 'e': 678279219Sken /* end of data */ 679279219Sken eod = 1; 680279219Sken dest_type = MT_LOCATE_DEST_EOD; 68143629Smjacob break; 682279219Sken case 'E': 683279219Sken /* 684279219Sken * XXX KDM explicit address mode. Should we even 685279219Sken * allow this, since the driver doesn't operate in 686279219Sken * explicit address mode? 687279219Sken */ 688279219Sken explicit = 1; 68943629Smjacob break; 690279219Sken case 'f': 691279219Sken /* file number */ 692279219Sken logical_id = strtoull(optarg, NULL, 0); 693279219Sken dest_type = MT_LOCATE_DEST_FILE; 694279219Sken file_set = 1; 69543629Smjacob break; 696279219Sken case 'i': 697279219Sken /* 698279219Sken * Immediate address mode. XXX KDM do we want to 699279219Sken * implement this? The other commands in the 700279219Sken * tape driver will need to be able to handle this. 701279219Sken */ 702279219Sken immediate = 1; 70343629Smjacob break; 704279219Sken case 'p': 705279219Sken /* 706279219Sken * Change partition to the given partition. 707279219Sken */ 708279219Sken partition = strtol(optarg, NULL, 0); 709279219Sken partition_set = 1; 71043629Smjacob break; 711279219Sken case 's': 712279219Sken /* Go to the given set mark */ 713279219Sken logical_id = strtoull(optarg, NULL, 0); 714279219Sken dest_type = MT_LOCATE_DEST_SET; 715279219Sken set_set = 1; 71643629Smjacob break; 717279219Sken default: 71843629Smjacob break; 719279219Sken } 720279219Sken } 721279219Sken 722279219Sken /* 723279219Sken * These options are mutually exclusive. The user may only specify 724279219Sken * one. 725279219Sken */ 726279219Sken if ((block_addr_set + file_set + eod + set_set) != 1) 727279219Sken errx(1, "You must specify only one of -b, -f, -e, or -s"); 728279219Sken 729279219Sken mtl.dest_type = dest_type; 730279219Sken switch (dest_type) { 731279219Sken case MT_LOCATE_DEST_OBJECT: 732279219Sken case MT_LOCATE_DEST_FILE: 733279219Sken case MT_LOCATE_DEST_SET: 734279219Sken mtl.logical_id = logical_id; 735279219Sken break; 736279219Sken case MT_LOCATE_DEST_EOD: 737279219Sken break; 738279219Sken } 739279219Sken 740279219Sken if (immediate != 0) 741279219Sken mtl.flags |= MT_LOCATE_FLAG_IMMED; 742279219Sken 743279219Sken if (partition_set != 0) { 744279219Sken mtl.flags |= MT_LOCATE_FLAG_CHANGE_PART; 745279219Sken mtl.partition = partition; 746279219Sken } 747279219Sken 748279219Sken if (explicit != 0) 749279219Sken mtl.block_address_mode = MT_LOCATE_BAM_EXPLICIT; 750279219Sken else 751279219Sken mtl.block_address_mode = MT_LOCATE_BAM_IMPLICIT; 752279219Sken 753279219Sken if (ioctl(mtfd, MTIOCEXTLOCATE, &mtl) == -1) 754279219Sken err(1, "MTIOCEXTLOCATE ioctl failed on %s", tape); 755279219Sken 756279219Sken return (retval); 757279219Sken} 758279219Sken 759279219Skentypedef enum { 760279219Sken MT_PERIPH_NAME = 0, 761279219Sken MT_UNIT_NUMBER = 1, 762279219Sken MT_VENDOR = 2, 763279219Sken MT_PRODUCT = 3, 764279219Sken MT_REVISION = 4, 765279219Sken MT_COMPRESSION_SUPPORTED = 5, 766279219Sken MT_COMPRESSION_ENABLED = 6, 767279219Sken MT_COMPRESSION_ALGORITHM = 7, 768279219Sken MT_MEDIA_DENSITY = 8, 769279219Sken MT_MEDIA_BLOCKSIZE = 9, 770279219Sken MT_CALCULATED_FILENO = 10, 771279219Sken MT_CALCULATED_REL_BLKNO = 11, 772279219Sken MT_REPORTED_FILENO = 12, 773279219Sken MT_REPORTED_BLKNO = 13, 774279219Sken MT_PARTITION = 14, 775279219Sken MT_BOP = 15, 776279219Sken MT_EOP = 16, 777279219Sken MT_BPEW = 17, 778279219Sken MT_DSREG = 18, 779279219Sken MT_RESID = 19, 780279219Sken MT_FIXED_MODE = 20, 781279219Sken MT_SERIAL_NUM = 21, 782279219Sken MT_MAXIO = 22, 783279219Sken MT_CPI_MAXIO = 23, 784279219Sken MT_MAX_BLK = 24, 785279219Sken MT_MIN_BLK = 25, 786279219Sken MT_BLK_GRAN = 26, 787279219Sken MT_MAX_EFF_IOSIZE = 27 788279219Sken} status_item_index; 789279219Sken 790279219Skenstatic struct mt_status_items { 791279219Sken const char *name; 792279219Sken struct mt_status_entry *entry; 793279219Sken} req_status_items[] = { 794279219Sken { "periph_name", NULL }, 795279219Sken { "unit_number", NULL }, 796279219Sken { "vendor", NULL }, 797279219Sken { "product", NULL }, 798279219Sken { "revision", NULL }, 799279219Sken { "compression_supported", NULL }, 800279219Sken { "compression_enabled", NULL }, 801279219Sken { "compression_algorithm", NULL }, 802279219Sken { "media_density", NULL }, 803279219Sken { "media_blocksize", NULL }, 804279219Sken { "calculated_fileno", NULL }, 805279219Sken { "calculated_rel_blkno", NULL }, 806279219Sken { "reported_fileno", NULL }, 807279219Sken { "reported_blkno", NULL }, 808279219Sken { "partition", NULL }, 809279219Sken { "bop", NULL }, 810279219Sken { "eop", NULL }, 811279219Sken { "bpew", NULL }, 812279219Sken { "dsreg", NULL }, 813279219Sken { "residual", NULL }, 814279219Sken { "fixed_mode", NULL }, 815279219Sken { "serial_num", NULL }, 816279219Sken { "maxio", NULL }, 817279219Sken { "cpi_maxio", NULL }, 818279219Sken { "max_blk", NULL }, 819279219Sken { "min_blk", NULL }, 820279219Sken { "blk_gran", NULL }, 821279219Sken { "max_effective_iosize", NULL } 822279219Sken}; 823279219Sken 824279219Skenint 825279219Skennstatus_print(int argc, char **argv, char *xml_str, 826279219Sken struct mt_status_data *status_data) 827279219Sken{ 828279219Sken unsigned int i; 829279219Sken int64_t calculated_fileno, calculated_rel_blkno; 830279219Sken int64_t rep_fileno, rep_blkno, partition, resid; 831279219Sken char block_str[32]; 832279219Sken const char *dens_str; 833279219Sken int dsreg, bop, eop, bpew; 834279219Sken int xml_dump = 0; 835279219Sken size_t dens_len; 836279219Sken unsigned int field_width; 837279219Sken int verbose = 0; 838279219Sken int c; 839279219Sken 840279219Sken while ((c = getopt(argc, argv, "xv")) != -1) { 841279219Sken switch (c) { 842279219Sken case 'x': 843279219Sken xml_dump = 1; 84443629Smjacob break; 845279219Sken case 'v': 846279219Sken verbose = 1; 84743629Smjacob break; 848279219Sken default: 84943629Smjacob break; 850279219Sken } 851279219Sken } 852279219Sken 853279219Sken if (xml_dump != 0) { 854279219Sken printf("%s", xml_str); 855279219Sken return (0); 856279219Sken } 857279219Sken 858279219Sken for (i = 0; i < (sizeof(req_status_items)/sizeof(req_status_items[0])); 859279219Sken i++) { 860279219Sken char *name; 861279219Sken 862279219Sken name = __DECONST(char *, req_status_items[i].name); 863279219Sken req_status_items[i].entry = mt_status_entry_find(status_data, 864279219Sken name); 865279219Sken if (req_status_items[i].entry == NULL) { 866279219Sken errx(1, "Cannot find status entry %s", 867279219Sken req_status_items[i].name); 868279219Sken } 869279219Sken } 870279219Sken 871279219Sken printf("Drive: %s%ju: <%s %s %s> Serial Number: %s\n", 872279219Sken req_status_items[MT_PERIPH_NAME].entry->value, 873279219Sken (uintmax_t)req_status_items[MT_UNIT_NUMBER].entry->value_unsigned, 874279219Sken req_status_items[MT_VENDOR].entry->value, 875279219Sken req_status_items[MT_PRODUCT].entry->value, 876279219Sken req_status_items[MT_REVISION].entry->value, 877279219Sken (req_status_items[MT_SERIAL_NUM].entry->value) ? 878279219Sken req_status_items[MT_SERIAL_NUM].entry->value : "none"); 879279219Sken printf("---------------------------------\n"); 880279219Sken 881279219Sken /* 882279219Sken * We check to see whether we're in fixed mode or not, and don't 883279219Sken * just believe the blocksize. If the SILI bit is turned on, the 884279219Sken * blocksize will be set to 4, even though we're doing variable 885279219Sken * length (well, multiples of 4) blocks. 886279219Sken */ 887279219Sken if (req_status_items[MT_FIXED_MODE].entry->value_signed == 0) 888279219Sken snprintf(block_str, sizeof(block_str), "variable"); 889279219Sken else 890279219Sken snprintf(block_str, sizeof(block_str), "%s", 891279219Sken getblksiz(req_status_items[ 892279219Sken MT_MEDIA_BLOCKSIZE].entry->value_unsigned)); 893279219Sken 894279219Sken dens_str = denstostring(req_status_items[ 895279219Sken MT_MEDIA_DENSITY].entry->value_unsigned); 896279219Sken if (dens_str == NULL) 897279219Sken dens_len = 0; 898279219Sken else 899279219Sken dens_len = strlen(dens_str); 900279219Sken field_width = MAX(dens_len, 17); 901279219Sken printf("Mode %-*s Blocksize bpi Compression\n" 902279219Sken "Current: %-*s %-12s %-7d ", 903279219Sken field_width, "Density", field_width, dens_str, block_str, 904279219Sken mt_density_bp(req_status_items[ 905279219Sken MT_MEDIA_DENSITY].entry->value_unsigned, TRUE)); 906279219Sken 907279219Sken if (req_status_items[MT_COMPRESSION_SUPPORTED].entry->value_signed == 0) 908279219Sken printf("unsupported\n"); 909279219Sken else if (req_status_items[ 910279219Sken MT_COMPRESSION_ENABLED].entry->value_signed == 0) 911279219Sken printf("disabled\n"); 912279219Sken else { 913279219Sken printf("enabled (%s)\n", 914279219Sken comptostring(req_status_items[ 915279219Sken MT_COMPRESSION_ALGORITHM].entry->value_unsigned)); 916279219Sken } 917279219Sken 918279219Sken dsreg = req_status_items[MT_DSREG].entry->value_signed; 919279219Sken if (dsreg != MTIO_DSREG_NIL) { 920279219Sken const char sfmt[] = "Current Driver State: %s.\n"; 921279219Sken printf("---------------------------------\n"); 922279219Sken const char *state_str; 923279219Sken 924279219Sken state_str = get_driver_state_str(dsreg); 925279219Sken if (state_str == NULL) { 926279219Sken char foo[32]; 927279219Sken (void) sprintf(foo, "Unknown state 0x%x", dsreg); 928279219Sken printf(sfmt, foo); 929279219Sken } else { 930279219Sken printf(sfmt, state_str); 931279219Sken } 932279219Sken } 933279219Sken resid = req_status_items[MT_RESID].entry->value_signed; 934279219Sken calculated_fileno = req_status_items[ 935279219Sken MT_CALCULATED_FILENO].entry->value_signed; 936279219Sken calculated_rel_blkno = req_status_items[ 937279219Sken MT_CALCULATED_REL_BLKNO].entry->value_signed; 938279219Sken rep_fileno = req_status_items[ 939279219Sken MT_REPORTED_FILENO].entry->value_signed; 940279219Sken rep_blkno = req_status_items[ 941279219Sken MT_REPORTED_BLKNO].entry->value_signed; 942279219Sken bop = req_status_items[MT_BOP].entry->value_signed; 943279219Sken eop = req_status_items[MT_EOP].entry->value_signed; 944279219Sken bpew = req_status_items[MT_BPEW].entry->value_signed; 945279219Sken partition = req_status_items[MT_PARTITION].entry->value_signed; 946279219Sken 947279219Sken printf("---------------------------------\n"); 948279219Sken printf("Partition: %3jd Calc File Number: %3jd " 949279219Sken " Calc Record Number: %jd\n" 950279219Sken "Residual: %3jd Reported File Number: %3jd " 951279219Sken "Reported Record Number: %jd\n", partition, calculated_fileno, 952279219Sken calculated_rel_blkno, resid, rep_fileno, rep_blkno); 953279219Sken 954279219Sken printf("Flags: "); 955279219Sken if (bop > 0 || eop > 0 || bpew > 0) { 956279219Sken int need_comma = 0; 957279219Sken 958279219Sken if (bop > 0) { 959279219Sken printf("BOP"); 960279219Sken need_comma = 1; 961279219Sken } 962279219Sken if (eop > 0) { 963279219Sken if (need_comma != 0) 964279219Sken printf(","); 965279219Sken printf("EOP"); 966279219Sken need_comma = 1; 967279219Sken } 968279219Sken if (bpew > 0) { 969279219Sken if (need_comma != 0) 970279219Sken printf(","); 971279219Sken printf("BPEW"); 972279219Sken need_comma = 1; 973279219Sken } 974279219Sken } else { 975279219Sken printf("None"); 976279219Sken } 977279219Sken printf("\n"); 978279219Sken if (verbose != 0) { 979279219Sken printf("---------------------------------\n"); 980279219Sken printf("Tape I/O parameters:\n"); 981279219Sken for (i = MT_MAXIO; i <= MT_MAX_EFF_IOSIZE; i++) { 982279219Sken printf(" %s (%s): %ju bytes\n", 983279219Sken req_status_items[i].entry->desc, 984279219Sken req_status_items[i].name, 985279219Sken req_status_items[i].entry->value_unsigned); 986279219Sken } 987279219Sken } 988279219Sken 989279219Sken return (0); 990279219Sken} 991279219Sken 992279219Skenint 993279219Skenmt_xml_cmd(unsigned long cmd, int argc, char **argv, int mtfd, const char *tape) 994279219Sken{ 995279219Sken struct mt_status_data status_data; 996279219Sken#if 0 997279219Sken struct mt_status_entry *entry; 998279219Sken#endif 999279219Sken char *xml_str; 1000279219Sken int retval; 1001279219Sken unsigned long ioctl_cmd; 1002279219Sken 1003279219Sken switch (cmd) { 1004279219Sken case MT_CMD_PROTECT: 1005279219Sken case MTIOCPARAMGET: 1006279219Sken ioctl_cmd = MTIOCPARAMGET; 1007279219Sken break; 1008279219Sken default: 1009279219Sken ioctl_cmd = MTIOCEXTGET; 1010279219Sken break; 1011279219Sken } 1012279219Sken 1013279219Sken retval = mt_get_xml_str(mtfd, ioctl_cmd, &xml_str); 1014279219Sken if (retval != 0) 1015279219Sken err(1, "Couldn't get mt XML string"); 1016279219Sken 1017279219Sken retval = mt_get_status(xml_str, &status_data); 1018279219Sken if (retval != XML_STATUS_OK) { 1019279219Sken warn("Couldn't get mt status for %s", tape); 1020279219Sken goto bailout; 1021279219Sken } 1022279219Sken 1023279219Sken /* 1024279219Sken * This gets set if there are memory allocation or other errors in 1025279219Sken * our parsing of the XML. 1026279219Sken */ 1027279219Sken if (status_data.error != 0) { 1028279219Sken warnx("%s", status_data.error_str); 1029279219Sken retval = 1; 1030279219Sken goto bailout; 1031279219Sken } 1032279219Sken#if 0 1033279219Sken STAILQ_FOREACH(entry, &status_data.entries, links) 1034279219Sken mt_status_tree_print(entry, 0, NULL); 1035279219Sken#endif 1036279219Sken 1037279219Sken switch (cmd) { 1038279219Sken case MTIOCEXTGET: 1039279219Sken retval = nstatus_print(argc, argv, xml_str, &status_data); 1040279219Sken break; 1041279219Sken case MTIOCPARAMGET: 1042279219Sken retval = mt_param(argc, argv, mtfd, xml_str, &status_data); 1043279219Sken break; 1044279219Sken case MT_CMD_PROTECT: 1045279219Sken retval = mt_protect(argc, argv, mtfd, &status_data); 1046279219Sken break; 1047279219Sken case MT_CMD_GETDENSITY: 1048279219Sken retval = mt_getdensity(argc, argv, xml_str, &status_data); 1049279219Sken break; 1050279219Sken } 1051279219Sken 1052279219Skenbailout: 1053279219Sken if (xml_str != NULL) 1054279219Sken free(xml_str); 1055279219Sken 1056279219Sken mt_status_free(&status_data); 1057279219Sken 1058279219Sken return (retval); 1059279219Sken} 1060279219Sken 1061279219Skenstatic int 1062279219Skenmt_set_param(int mtfd, struct mt_status_data *status_data, char *param_name, 1063279219Sken char *param_value) 1064279219Sken{ 1065279219Sken struct mt_status_entry *entry; 1066279219Sken struct mtparamset param_set; 1067279219Sken 1068279219Sken entry = mt_status_entry_find(status_data, 1069279219Sken __DECONST(char *, "mtparamget")); 1070279219Sken if (entry == NULL) 1071279219Sken errx(1, "Cannot find parameter root node"); 1072279219Sken 1073279219Sken bzero(¶m_set, sizeof(param_set)); 1074279219Sken entry = mt_entry_find(entry, param_name); 1075279219Sken if (entry == NULL) 1076279219Sken errx(1, "Unknown parameter name \"%s\"", param_name); 1077279219Sken 1078279219Sken strlcpy(param_set.value_name, param_name, sizeof(param_set.value_name)); 1079279219Sken 1080279219Sken switch (entry->var_type) { 1081279219Sken case MT_TYPE_INT: 1082279219Sken param_set.value.value_signed = strtoll(param_value, NULL, 0); 1083279219Sken param_set.value_type = MT_PARAM_SET_SIGNED; 1084279219Sken param_set.value_len = entry->size; 1085279219Sken break; 1086279219Sken case MT_TYPE_UINT: 1087279219Sken param_set.value.value_unsigned = strtoull(param_value, NULL, 0); 1088279219Sken param_set.value_type = MT_PARAM_SET_UNSIGNED; 1089279219Sken param_set.value_len = entry->size; 1090279219Sken break; 1091279219Sken case MT_TYPE_STRING: { 1092279219Sken size_t param_len; 1093279219Sken 1094279219Sken param_len = strlen(param_value) + 1; 1095279219Sken if (param_len > sizeof(param_set.value.value_fixed_str)) { 1096279219Sken param_set.value_type = MT_PARAM_SET_VAR_STR; 1097279219Sken param_set.value.value_var_str = param_value; 1098279219Sken } else { 1099279219Sken param_set.value_type = MT_PARAM_SET_FIXED_STR; 1100279219Sken strlcpy(param_set.value.value_fixed_str, param_value, 1101279219Sken sizeof(param_set.value.value_fixed_str)); 1102279219Sken } 1103279219Sken param_set.value_len = param_len; 1104279219Sken break; 1105279219Sken } 1106279219Sken default: 1107279219Sken errx(1, "Unknown parameter type %d for %s", entry->var_type, 1108279219Sken param_name); 1109279219Sken break; 1110279219Sken } 1111279219Sken 1112279219Sken if (ioctl(mtfd, MTIOCPARAMSET, ¶m_set) == -1) 1113279219Sken err(1, "MTIOCPARAMSET"); 1114279219Sken 1115279219Sken if (param_set.status != MT_PARAM_STATUS_OK) 1116279219Sken errx(1, "Failed to set %s: %s", param_name, 1117279219Sken param_set.error_str); 1118279219Sken 1119279219Sken return (0); 1120279219Sken} 1121279219Sken 1122279219Sken 1123279219Skentypedef enum { 1124279219Sken MT_PP_LBP_R, 1125279219Sken MT_PP_LBP_W, 1126279219Sken MT_PP_RBDP, 1127279219Sken MT_PP_PI_LENGTH, 1128279219Sken MT_PP_PROT_METHOD 1129279219Sken} mt_protect_param; 1130279219Sken 1131279219Skenstatic struct mt_protect_info { 1132279219Sken const char *name; 1133279219Sken struct mt_status_entry *entry; 1134279219Sken uint32_t value; 1135279219Sken} mt_protect_list[] = { 1136279219Sken { "lbp_r", NULL, 0 }, 1137279219Sken { "lbp_w", NULL, 0 }, 1138279219Sken { "rbdp", NULL, 0 }, 1139279219Sken { "pi_length", NULL, 0 }, 1140279219Sken { "prot_method", NULL, 0 } 1141279219Sken}; 1142279219Sken 1143279219Sken#define MT_NUM_PROTECT_PARAMS (sizeof(mt_protect_list)/sizeof(mt_protect_list[0])) 1144279219Sken 1145279219Sken#define MT_PROT_NAME "protection" 1146279219Sken 1147279219Skenstatic int 1148279219Skenmt_protect(int argc, char **argv, int mtfd, struct mt_status_data *status_data) 1149279219Sken{ 1150279219Sken int retval = 0; 1151279219Sken int do_enable = 0, do_disable = 0, do_list = 0; 1152279219Sken int rbdp_set = 0, lbp_w_set = 0, lbp_r_set = 0; 1153279219Sken int prot_method_set = 0, pi_length_set = 0; 1154279219Sken int verbose = 0; 1155279219Sken uint32_t rbdp = 0, lbp_w = 0, lbp_r = 0; 1156279219Sken uint32_t prot_method = 0, pi_length = 0; 1157279219Sken struct mt_status_entry *prot_entry, *supported_entry; 1158279219Sken struct mt_status_entry *entry; 1159279219Sken struct mtparamset params[MT_NUM_PROTECT_PARAMS]; 1160279219Sken struct mtsetlist param_list; 1161279219Sken unsigned int i; 1162279219Sken int c; 1163279219Sken 1164279219Sken while ((c = getopt(argc, argv, "b:delL:m:r:vw:")) != -1) { 1165279219Sken switch (c) { 1166279219Sken case 'b': 1167279219Sken rbdp_set = 1; 1168279219Sken rbdp = strtoul(optarg, NULL, 0); 1169279219Sken if ((rbdp != 0) && (rbdp != 1)) 1170279219Sken errx(1, "valid values for -b are 0 and 1"); 117143629Smjacob break; 1172279219Sken case 'd': 1173279219Sken do_disable = 1; 117443629Smjacob break; 1175279219Sken case 'e': 1176279219Sken do_enable = 1; 1177279219Sken break; 1178279219Sken case 'l': 1179279219Sken do_list = 1; 1180279219Sken break; 1181279219Sken case 'L': 1182279219Sken pi_length_set = 1; 1183279219Sken pi_length = strtoul(optarg, NULL, 0); 1184279219Sken if (pi_length > SA_CTRL_DP_PI_LENGTH_MASK) 1185279219Sken errx(1, "PI length %u > maximum %u", 1186279219Sken pi_length, SA_CTRL_DP_PI_LENGTH_MASK); 1187279219Sken break; 1188279219Sken case 'm': 1189279219Sken prot_method_set = 1; 1190279219Sken prot_method = strtoul(optarg, NULL, 0); 1191279219Sken if (prot_method > SA_CTRL_DP_METHOD_MAX) 1192279219Sken errx(1, "Method %u > maximum %u", 1193279219Sken prot_method, SA_CTRL_DP_METHOD_MAX); 1194279219Sken break; 1195279219Sken case 'r': 1196279219Sken lbp_r_set = 1; 1197279219Sken lbp_r = strtoul(optarg, NULL, 0); 1198279219Sken if ((lbp_r != 0) && (lbp_r != 1)) 1199279219Sken errx(1, "valid values for -r are 0 and 1"); 1200279219Sken break; 1201279219Sken case 'v': 1202279219Sken verbose = 1; 1203279219Sken break; 1204279219Sken case 'w': 1205279219Sken lbp_w_set = 1; 1206279219Sken lbp_w = strtoul(optarg, NULL, 0); 1207279219Sken if ((lbp_w != 0) && (lbp_r != 1)) 1208279219Sken errx(1, "valid values for -r are 0 and 1"); 1209279219Sken break; 121043629Smjacob default: 121143629Smjacob break; 121243629Smjacob } 121343629Smjacob } 1214279219Sken 1215279219Sken if ((rbdp_set + do_disable + do_enable + do_list + pi_length_set + 1216279219Sken prot_method_set + lbp_r_set + lbp_w_set) == 0) 1217279219Sken errx(1, "Need an argument for protect"); 1218279219Sken 1219279219Sken if ((do_disable + do_enable + do_list) != 1) 1220279219Sken errx(1, "You must specify only one of -e, -d or -l"); 1221279219Sken 1222279219Sken if (do_list != 0) { 1223279219Sken retval = mt_protect_print(status_data, verbose); 1224279219Sken goto bailout; 1225279219Sken } 1226279219Sken if (do_enable != 0) { 1227279219Sken /* 1228279219Sken * Enable protection, but allow the user to override 1229279219Sken * settings if he doesn't want everything turned on. 1230279219Sken */ 1231279219Sken if (rbdp_set == 0) 1232279219Sken rbdp = 1; 1233279219Sken if (lbp_w_set == 0) 1234279219Sken lbp_w = 1; 1235279219Sken if (lbp_r_set == 0) 1236279219Sken lbp_r = 1; 1237279219Sken /* 1238279219Sken * If the user doesn't override it, we default to enabling 1239279219Sken * Reed-Solomon checkums. 1240279219Sken */ 1241279219Sken if (prot_method_set == 0) 1242279219Sken prot_method = SA_CTRL_DP_REED_SOLOMON; 1243279219Sken if (pi_length_set == 0) 1244279219Sken pi_length = SA_CTRL_DP_RS_LENGTH; 1245279219Sken } else if (do_disable != 0) { 1246279219Sken /* 1247279219Sken * If the user wants to disable protection, we ignore any 1248279219Sken * other parameters he has set. Everything gets set to 0. 1249279219Sken */ 1250279219Sken rbdp = lbp_w = lbp_r = 0; 1251279219Sken prot_method = pi_length = 0; 1252279219Sken } 1253279219Sken 1254279219Sken prot_entry = mt_status_entry_find(status_data, 1255279219Sken __DECONST(char *, MT_PROT_NAME)); 1256279219Sken if (prot_entry == NULL) 1257279219Sken errx(1, "Unable to find protection information status"); 1258279219Sken 1259279219Sken supported_entry = mt_entry_find(prot_entry, 1260279219Sken __DECONST(char *, "protection_supported")); 1261279219Sken if (supported_entry == NULL) 1262279219Sken errx(1, "Unable to find protection support information"); 1263279219Sken 1264279219Sken if (((supported_entry->var_type == MT_TYPE_INT) 1265279219Sken && (supported_entry->value_signed == 0)) 1266279219Sken || ((supported_entry->var_type == MT_TYPE_UINT) 1267279219Sken && (supported_entry->value_unsigned == 0))) 1268279219Sken errx(1, "This device does not support protection information"); 1269279219Sken 1270279219Sken mt_protect_list[MT_PP_LBP_R].value = lbp_r; 1271279219Sken mt_protect_list[MT_PP_LBP_W].value = lbp_w; 1272279219Sken mt_protect_list[MT_PP_RBDP].value = rbdp; 1273279219Sken mt_protect_list[MT_PP_PI_LENGTH].value = pi_length; 1274279219Sken mt_protect_list[MT_PP_PROT_METHOD].value = prot_method; 1275279219Sken 1276279219Sken bzero(¶ms, sizeof(params)); 1277279219Sken bzero(¶m_list, sizeof(param_list)); 1278279219Sken 1279279219Sken /* 1280279219Sken * Go through the list and make sure that we have this parameter, 1281279219Sken * and that it is still an unsigned integer. If not, we've got a 1282279219Sken * problem. 1283279219Sken */ 1284279219Sken for (i = 0; i < MT_NUM_PROTECT_PARAMS; i++) { 1285279219Sken entry = mt_entry_find(prot_entry, 1286279219Sken __DECONST(char *, mt_protect_list[i].name)); 1287279219Sken if (entry == NULL) { 1288279219Sken errx(1, "Unable to find parameter %s", 1289279219Sken mt_protect_list[i].name); 1290279219Sken } 1291279219Sken mt_protect_list[i].entry = entry; 1292279219Sken 1293279219Sken if (entry->var_type != MT_TYPE_UINT) 1294279219Sken errx(1, "Parameter %s is type %d, not unsigned, " 1295279219Sken "cannot proceed", mt_protect_list[i].name, 1296279219Sken entry->var_type); 1297279219Sken snprintf(params[i].value_name, sizeof(params[i].value_name), 1298279219Sken "%s.%s", MT_PROT_NAME, mt_protect_list[i].name); 1299279219Sken /* XXX KDM unify types here */ 1300279219Sken params[i].value_type = MT_PARAM_SET_UNSIGNED; 1301279219Sken params[i].value_len = sizeof(mt_protect_list[i].value); 1302279219Sken params[i].value.value_unsigned = mt_protect_list[i].value; 1303279219Sken 1304279219Sken } 1305279219Sken param_list.num_params = MT_NUM_PROTECT_PARAMS; 1306279219Sken param_list.param_len = sizeof(params); 1307279219Sken param_list.params = params; 1308279219Sken 1309279219Sken if (ioctl(mtfd, MTIOCSETLIST, ¶m_list) == -1) 1310279219Sken err(1, "error issuing MTIOCSETLIST ioctl"); 1311279219Sken 1312279219Sken for (i = 0; i < MT_NUM_PROTECT_PARAMS; i++) { 1313279219Sken if (params[i].status != MT_PARAM_STATUS_OK) { 1314279219Sken warnx("%s", params[i].error_str); 1315279219Sken retval = 1; 1316279219Sken } 1317279219Sken } 1318279219Skenbailout: 1319279219Sken 1320279219Sken return (retval); 13217913Sjoerg} 13227913Sjoerg 1323279219Skenstatic int 1324279219Skenmt_param(int argc, char **argv, int mtfd, char *xml_str, 1325279219Sken struct mt_status_data *status_data) 1326279219Sken{ 1327279219Sken int list = 0, do_set = 0, xml_dump = 0; 1328279219Sken char *param_name = NULL, *param_value = NULL; 1329279219Sken int retval = 0, quiet = 0; 1330279219Sken int c; 1331279219Sken 1332279219Sken while ((c = getopt(argc, argv, "lp:qs:x")) != -1) { 1333279219Sken switch (c) { 1334279219Sken case 'l': 1335279219Sken list = 1; 1336279219Sken break; 1337279219Sken case 'p': 1338279261Sken if (param_name != NULL) { 1339279261Sken warnx("Only one paramter name may be " 1340279261Sken "specified"); 1341279261Sken retval = 1; 1342279261Sken goto bailout; 1343279261Sken } 1344279219Sken param_name = strdup(optarg); 1345279219Sken break; 1346279219Sken case 'q': 1347279219Sken quiet = 1; 1348279219Sken break; 1349279219Sken case 's': 1350279261Sken if (param_value != NULL) { 1351279261Sken warnx("Only one paramter value may be " 1352279261Sken "specified"); 1353279261Sken retval = 1; 1354279261Sken goto bailout; 1355279261Sken } 1356279219Sken param_value = strdup(optarg); 1357279219Sken do_set = 1; 1358279219Sken break; 1359279219Sken case 'x': 1360279219Sken xml_dump = 1; 1361279219Sken break; 1362279219Sken default: 1363279219Sken break; 1364279219Sken } 1365279219Sken } 1366279219Sken 1367279261Sken if ((list + do_set + xml_dump) != 1) { 1368279261Sken warnx("You must specify only one of -s, -l or -x"); 1369279261Sken retval = 1; 1370279261Sken goto bailout; 1371279261Sken } 1372279219Sken 1373279219Sken if (xml_dump != 0) { 1374279219Sken printf("%s", xml_str); 1375279261Sken retval = 0; 1376279261Sken goto bailout; 1377279219Sken } 1378279219Sken 1379279219Sken if (do_set != 0) { 1380279219Sken if (param_name == NULL) 1381279219Sken errx(1, "You must specify -p with -s"); 1382279219Sken 1383279219Sken retval = mt_set_param(mtfd, status_data, param_name, 1384279219Sken param_value); 1385279219Sken } else if (list != 0) 1386279219Sken retval = mt_param_list(status_data, param_name, quiet); 1387279219Sken 1388279261Skenbailout: 1389279261Sken free(param_name); 1390279261Sken free(param_value); 1391279219Sken return (retval); 1392279219Sken} 1393279219Sken 1394279219Skenint 1395279219Skenmt_print_density_entry(struct mt_status_entry *density_root, int indent) 1396279219Sken{ 1397279219Sken struct mt_status_entry *entry; 1398279219Sken int retval = 0; 1399279219Sken 1400279219Sken STAILQ_FOREACH(entry, &density_root->child_entries, links) { 1401279219Sken if (entry->var_type == MT_TYPE_NODE) { 1402279219Sken retval = mt_print_density_entry(entry, indent + 2); 1403279219Sken if (retval != 0) 1404279219Sken break; 1405279219Sken else 1406279219Sken continue; 1407279219Sken } 1408279219Sken if ((strcmp(entry->entry_name, "primary_density_code") == 0) 1409279219Sken || (strcmp(entry->entry_name, "secondary_density_code") == 0)){ 1410279219Sken 1411279219Sken /* XXX KDM this should really be unsigned */ 1412279219Sken printf("%*s%s (%s): %s\n", indent, "", entry->desc ? 1413279219Sken entry->desc : "", entry->entry_name, 1414279219Sken denstostring(entry->value_unsigned)); 1415279219Sken } else if (strcmp(entry->entry_name, "density_flags") == 0) { 1416279219Sken printf("%*sMedium Access: ", indent, ""); 1417279219Sken if (entry->value_unsigned & MT_DENS_WRITE_OK) { 1418279219Sken printf("Read and Write\n"); 1419279219Sken } else { 1420279219Sken printf("Read Only\n"); 1421279219Sken } 1422279219Sken printf("%*sDefault Density: %s\n", indent, "", 1423279219Sken (entry->value_unsigned & MT_DENS_DEFLT) ? "Yes" : 1424279219Sken "No"); 1425279219Sken printf("%*sDuplicate Density: %s\n", indent, "", 1426279219Sken (entry->value_unsigned & MT_DENS_DUP) ? "Yes" : 1427279219Sken "No"); 1428279219Sken } else if (strcmp(entry->entry_name, "media_width") == 0) { 1429279219Sken printf("%*s%s (%s): %.1f mm\n", indent, "", 1430279219Sken entry->desc ? entry->desc : "", entry->entry_name, 1431279219Sken (double)((double)entry->value_unsigned / 10)); 1432279219Sken } else if (strcmp(entry->entry_name, "medium_length") == 0) { 1433279219Sken printf("%*s%s (%s): %ju m\n", indent, "", 1434279219Sken entry->desc ? entry->desc : "", entry->entry_name, 1435279219Sken (uintmax_t)entry->value_unsigned); 1436279219Sken } else if (strcmp(entry->entry_name, "capacity") == 0) { 1437279219Sken printf("%*s%s (%s): %ju MB\n", indent, "", entry->desc ? 1438279219Sken entry->desc : "", entry->entry_name, 1439279219Sken (uintmax_t)entry->value_unsigned); 1440279219Sken } else { 1441279219Sken printf("%*s%s (%s): %s\n", indent, "", entry->desc ? 1442279219Sken entry->desc : "", entry->entry_name, entry->value); 1443279219Sken } 1444279219Sken } 1445279219Sken 1446279219Sken return (retval); 1447279219Sken} 1448279219Sken 1449279219Skenint 1450279219Skenmt_print_density_report(struct mt_status_entry *report_root, int indent) 1451279219Sken{ 1452279219Sken struct mt_status_entry *mt_report, *media_report; 1453279219Sken struct mt_status_entry *entry; 1454279219Sken int retval = 0; 1455279219Sken 1456279219Sken mt_report = mt_entry_find(report_root, 1457279219Sken __DECONST(char *, MT_MEDIUM_TYPE_REPORT_NAME)); 1458279219Sken if (mt_report == NULL) 1459279219Sken return (1); 1460279219Sken 1461279219Sken media_report = mt_entry_find(report_root, 1462279219Sken __DECONST(char *, MT_MEDIA_REPORT_NAME)); 1463279219Sken if (media_report == NULL) 1464279219Sken return (1); 1465279219Sken 1466279219Sken if ((mt_report->value_signed == 0) 1467279219Sken && (media_report->value_signed == 0)) { 1468279219Sken printf("%*sThis tape drive supports the following " 1469279219Sken "media densities:\n", indent, ""); 1470279219Sken } else if ((mt_report->value_signed == 0) 1471279219Sken && (media_report->value_signed != 0)) { 1472279219Sken printf("%*sThe tape currently in this drive supports " 1473279219Sken "the following media densities:\n", indent, ""); 1474279219Sken } else if ((mt_report->value_signed != 0) 1475279219Sken && (media_report->value_signed == 0)) { 1476279219Sken printf("%*sThis tape drive supports the following " 1477279219Sken "media types:\n", indent, ""); 1478279219Sken } else { 1479279219Sken printf("%*sThis tape currently in this drive supports " 1480279219Sken "the following media types:\n", indent, ""); 1481279219Sken } 1482279219Sken 1483279219Sken STAILQ_FOREACH(entry, &report_root->child_entries, links) { 1484279219Sken struct mt_status_nv *nv; 1485279219Sken 1486279219Sken if (strcmp(entry->entry_name, MT_DENSITY_ENTRY_NAME) != 0) 1487279219Sken continue; 1488279219Sken 1489279219Sken STAILQ_FOREACH(nv, &entry->nv_list, links) { 1490279219Sken if (strcmp(nv->name, "num") != 0) 1491279219Sken continue; 1492279219Sken 1493279219Sken break; 1494279219Sken } 1495279219Sken 1496279219Sken indent += 2; 1497279219Sken 1498279219Sken printf("%*sDensity Entry", indent, ""); 1499279219Sken if (nv != NULL) 1500279219Sken printf(" %s", nv->value); 1501279219Sken printf(":\n"); 1502279219Sken 1503279219Sken retval = mt_print_density_entry(entry, indent + 2); 1504279219Sken 1505279219Sken indent -= 2; 1506279219Sken } 1507279219Sken 1508279219Sken return (retval); 1509279219Sken} 1510279219Sken 1511279219Skenint 1512279219Skenmt_print_density(struct mt_status_entry *density_root, int indent) 1513279219Sken{ 1514279219Sken struct mt_status_entry *entry; 1515279219Sken int retval = 0; 1516279219Sken 1517279219Sken /* 1518279219Sken * We should have this entry for every tape drive. This particular 1519279219Sken * value is reported via the mode page block header, not the 1520279219Sken * SCSI REPORT DENSITY SUPPORT command. 1521279219Sken */ 1522279219Sken entry = mt_entry_find(density_root, 1523279219Sken __DECONST(char *, MT_MEDIA_DENSITY_NAME)); 1524279219Sken if (entry == NULL) 1525279219Sken errx(1, "Unable to find node %s", MT_MEDIA_DENSITY_NAME); 1526279219Sken 1527279219Sken printf("%*sCurrent density: %s\n", indent, "", 1528279219Sken denstostring(entry->value_unsigned)); 1529279219Sken 1530279219Sken /* 1531279219Sken * It isn't an error if we don't have any density reports. Tape 1532279219Sken * drives that don't support the REPORT DENSITY SUPPORT command 1533279219Sken * won't have any; they will only have the current density entry 1534279219Sken * above. 1535279219Sken */ 1536279219Sken STAILQ_FOREACH(entry, &density_root->child_entries, links) { 1537279219Sken if (strcmp(entry->entry_name, MT_DENSITY_REPORT_NAME) != 0) 1538279219Sken continue; 1539279219Sken 1540279219Sken retval = mt_print_density_report(entry, indent); 1541279219Sken } 1542279219Sken 1543279219Sken return (retval); 1544279219Sken} 1545279219Sken 1546279219Skenint 1547279219Skenmt_getdensity(int argc, char **argv, char *xml_str, 1548279219Sken struct mt_status_data *status_data) 1549279219Sken{ 1550279219Sken int retval = 0; 1551279219Sken int verbose = 0, xml_dump = 0; 1552279219Sken struct mt_status_entry *density_root = NULL; 1553279219Sken int c; 1554279219Sken 1555279219Sken while ((c = getopt(argc, argv, "vx")) != -1) { 1556279219Sken switch (c) { 1557279219Sken case 'v': 1558279219Sken verbose = 1; 1559279219Sken break; 1560279219Sken case 'x': 1561279219Sken xml_dump = 1; 1562279219Sken break; 1563279219Sken } 1564279219Sken } 1565279219Sken 1566279219Sken if (xml_dump != 0) { 1567279219Sken printf("%s", xml_str); 1568279219Sken return (0); 1569279219Sken } 1570279219Sken 1571279219Sken density_root = mt_status_entry_find(status_data, 1572279219Sken __DECONST(char *, MT_DENSITY_ROOT_NAME)); 1573279219Sken if (density_root == NULL) 1574279219Sken errx(1, "Cannot find density root node %s", 1575279219Sken MT_DENSITY_ROOT_NAME); 1576279219Sken 1577279219Sken retval = mt_print_density(density_root, 0); 1578279219Sken 1579279219Sken return (retval); 1580279219Sken} 1581279219Sken 1582227174Sedstatic void 15839541Sjoergwarn_eof(void) 15849541Sjoerg{ 15859541Sjoerg fprintf(stderr, 15869541Sjoerg "The \"eof\" command has been disabled.\n" 15879541Sjoerg "Use \"weof\" if you really want to write end-of-file marks,\n" 15889541Sjoerg "or \"eom\" if you rather want to skip to the end of " 15899541Sjoerg "recorded medium.\n"); 15909541Sjoerg exit(1); 15919541Sjoerg} 1592