11590Srgrimes/* 2331722Seadler * 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$"); 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> 8423693Speter 8523693Speter#include <ctype.h> 8627752Scharnier#include <err.h> 871590Srgrimes#include <fcntl.h> 8823693Speter#include <stdio.h> 891590Srgrimes#include <stdlib.h> 901590Srgrimes#include <string.h> 9123693Speter#include <unistd.h> 92279219Sken#include <stdint.h> 93279219Sken#include <errno.h> 94279219Sken#include <bsdxml.h> 95279219Sken#include <mtlib.h> 961590Srgrimes 97279219Sken#include <cam/cam.h> 98279219Sken#include <cam/cam_ccb.h> 99279219Sken#include <cam/cam_periph.h> 100279219Sken#include <cam/scsi/scsi_all.h> 101279219Sken#include <cam/scsi/scsi_sa.h> 102279219Sken 1037913Sjoerg/* the appropriate sections of <sys/mtio.h> are also #ifdef'd for FreeBSD */ 1047913Sjoerg/* c_flags */ 1057913Sjoerg#define NEED_2ARGS 0x01 1067929Sjoerg#define ZERO_ALLOWED 0x02 1077929Sjoerg#define IS_DENSITY 0x04 1089541Sjoerg#define DISABLE_THIS 0x08 10939260Sgibbs#define IS_COMP 0x10 110279219Sken#define USE_GETOPT 0x20 1117913Sjoerg 11239260Sgibbs#ifndef TRUE 11339260Sgibbs#define TRUE 1 11439260Sgibbs#endif 11539260Sgibbs#ifndef FALSE 11639260Sgibbs#define FALSE 0 11739260Sgibbs#endif 118279219Sken#ifndef MAX 119279219Sken#define MAX(a, b) (a > b) ? a : b 120279219Sken#endif 121280231Sken#define MT_PLURAL(a) (a == 1) ? "" : "s" 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); 387280231Sken (void)printf("%s:\n" 388280231Sken " min blocksize %u byte%s\n" 389280231Sken " max blocksize %u byte%s\n" 390280231Sken " granularity %u byte%s\n", 391279219Sken tape, rblim.min_block_length, 392280231Sken MT_PLURAL(rblim.min_block_length), 393280231Sken rblim.max_block_length, 394280231Sken MT_PLURAL(rblim.max_block_length), 395280231Sken (1 << rblim.granularity), 396280231Sken MT_PLURAL((1 << rblim.granularity))); 397279219Sken exit(0); 398279219Sken /* NOTREACHED */ 399279219Sken } 400279219Sken case MTIOCPARAMGET: 401279219Sken case MTIOCEXTGET: 402279219Sken case MT_CMD_PROTECT: 403279219Sken case MT_CMD_GETDENSITY: 404279219Sken { 405279219Sken int retval = 0; 406279219Sken 407279219Sken retval = mt_xml_cmd(comp->c_code, argc, argv, mtfd, 408279219Sken tape); 409279219Sken 410279219Sken exit(retval); 411279219Sken } 412279219Sken case MTIOCEXTLOCATE: 413279219Sken { 414279219Sken int retval = 0; 415279219Sken 416279219Sken retval = mt_locate(argc, argv, mtfd, tape); 417279219Sken 418279219Sken exit(retval); 419279219Sken } 42041913Smjacob default: 42141913Smjacob break; 42241913Smjacob } 4231590Srgrimes if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0) 42427752Scharnier err(1, "%s: %s", tape, comp->c_name); 4251590Srgrimes } else { 4261590Srgrimes if (ioctl(mtfd, MTIOCGET, &mt_status) < 0) 42727752Scharnier err(1, NULL); 4281590Srgrimes status(&mt_status); 4291590Srgrimes } 43041925Smjacob exit(0); 4311590Srgrimes /* NOTREACHED */ 4321590Srgrimes} 4331590Srgrimes 434227174Sedstatic const struct tape_desc { 4351590Srgrimes short t_type; /* type of magtape device */ 436152396Sdwmalone const char *t_name; /* printing name */ 437152396Sdwmalone const char *t_dsbits; /* "drive status" register */ 438152396Sdwmalone const char *t_erbits; /* "error" register */ 4391590Srgrimes} tapes[] = { 4407913Sjoerg { MT_ISAR, "SCSI tape drive", 0, 0 }, 44194505Scharnier { 0, NULL, 0, 0 } 4421590Srgrimes}; 4431590Srgrimes 4441590Srgrimes/* 4451590Srgrimes * Interpret the status buffer returned 4461590Srgrimes */ 447227174Sedstatic void 448152396Sdwmalonestatus(struct mtget *bp) 4491590Srgrimes{ 450227174Sed const struct tape_desc *mt; 4511590Srgrimes 4521590Srgrimes for (mt = tapes;; mt++) { 4531590Srgrimes if (mt->t_type == 0) { 4541590Srgrimes (void)printf("%d: unknown tape drive type\n", 4551590Srgrimes bp->mt_type); 4561590Srgrimes return; 4571590Srgrimes } 4581590Srgrimes if (mt->t_type == bp->mt_type) 4591590Srgrimes break; 4601590Srgrimes } 4617913Sjoerg if(mt->t_type == MT_ISAR) 4627913Sjoerg st_status(bp); 4637913Sjoerg else { 46492764Sphk (void)printf("%s tape drive, residual=%d\n", 46592764Sphk mt->t_name, bp->mt_resid); 46692764Sphk printreg("ds", (unsigned short)bp->mt_dsreg, mt->t_dsbits); 46792764Sphk printreg("\ner", (unsigned short)bp->mt_erreg, mt->t_erbits); 46892764Sphk (void)putchar('\n'); 4697913Sjoerg } 4701590Srgrimes} 4711590Srgrimes 4721590Srgrimes/* 4731590Srgrimes * Print a register a la the %b format of the kernel's printf. 4741590Srgrimes */ 475227174Sedstatic void 476152396Sdwmaloneprintreg(const char *s, u_int v, const char *bits) 4771590Srgrimes{ 478152396Sdwmalone int i, any = 0; 479152396Sdwmalone char c; 4801590Srgrimes 4811590Srgrimes if (bits && *bits == 8) 4821590Srgrimes printf("%s=%o", s, v); 4831590Srgrimes else 4841590Srgrimes printf("%s=%x", s, v); 48511608Sbde if (!bits) 48611608Sbde return; 4871590Srgrimes bits++; 4881590Srgrimes if (v && bits) { 4891590Srgrimes putchar('<'); 49027752Scharnier while ((i = *bits++)) { 4911590Srgrimes if (v & (1 << (i-1))) { 4921590Srgrimes if (any) 4931590Srgrimes putchar(','); 4941590Srgrimes any = 1; 4951590Srgrimes for (; (c = *bits) > 32; bits++) 4961590Srgrimes putchar(c); 4971590Srgrimes } else 4981590Srgrimes for (; *bits > 32; bits++) 4991590Srgrimes ; 5001590Srgrimes } 5011590Srgrimes putchar('>'); 5021590Srgrimes } 5031590Srgrimes} 5041590Srgrimes 505227174Sedstatic void 506152396Sdwmaloneusage(void) 5071590Srgrimes{ 50894505Scharnier (void)fprintf(stderr, "usage: mt [-f device] command [count]\n"); 5091590Srgrimes exit(1); 5101590Srgrimes} 5111590Srgrimes 512227174Sedstatic const struct compression_types { 51339260Sgibbs u_int32_t comp_number; 51439260Sgibbs const char *name; 51539260Sgibbs} comp_types[] = { 51639260Sgibbs { 0x00, "none" }, 51739260Sgibbs { 0x00, "off" }, 51839260Sgibbs { 0x10, "IDRC" }, 51939260Sgibbs { 0x20, "DCLZ" }, 52039260Sgibbs { 0xffffffff, "enable" }, 52139260Sgibbs { 0xffffffff, "on" }, 52239260Sgibbs { 0xf0f0f0f0, NULL} 52339260Sgibbs}; 52439260Sgibbs 525227174Sedstatic const char * 5267929Sjoergdenstostring(int d) 5277913Sjoerg{ 5287913Sjoerg static char buf[20]; 529279219Sken const char *name = mt_density_name(d); 5307913Sjoerg 531279219Sken if (name == NULL) 5327929Sjoerg sprintf(buf, "0x%02x", d); 53344397Smjacob else 534279219Sken sprintf(buf, "0x%02x:%s", d, name); 53544397Smjacob return buf; 5367913Sjoerg} 5377913Sjoerg 538227174Sedstatic const char * 5397913Sjoerggetblksiz(int bs) 5407913Sjoerg{ 5417913Sjoerg static char buf[25]; 5427913Sjoerg if (bs == 0) 5437913Sjoerg return "variable"; 5447913Sjoerg else { 54539260Sgibbs sprintf(buf, "%d bytes", bs); 5467913Sjoerg return buf; 5477913Sjoerg } 5487913Sjoerg} 5497913Sjoerg 550227174Sedstatic const char * 55139260Sgibbscomptostring(u_int32_t comp) 55239260Sgibbs{ 55339260Sgibbs static char buf[20]; 554227174Sed const struct compression_types *ct; 5557913Sjoerg 55639260Sgibbs if (comp == MT_COMP_DISABLED) 55739260Sgibbs return "disabled"; 55839260Sgibbs else if (comp == MT_COMP_UNSUPP) 55939260Sgibbs return "unsupported"; 56039260Sgibbs 56139260Sgibbs for (ct = comp_types; ct->name; ct++) 56239260Sgibbs if (ct->comp_number == comp) 56339260Sgibbs break; 56439260Sgibbs 56539260Sgibbs if (ct->comp_number == 0xf0f0f0f0) { 56644618Smjacob sprintf(buf, "0x%x", comp); 56739260Sgibbs return(buf); 56839260Sgibbs } else 56939260Sgibbs return(ct->name); 57039260Sgibbs} 57139260Sgibbs 572227174Sedstatic u_int32_t 57339260Sgibbsstringtocomp(const char *s) 57439260Sgibbs{ 575227174Sed const struct compression_types *ct; 57639260Sgibbs size_t l = strlen(s); 57739260Sgibbs 57839260Sgibbs for (ct = comp_types; ct->name; ct++) 57939260Sgibbs if (strncasecmp(ct->name, s, l) == 0) 58039260Sgibbs break; 58139260Sgibbs 58239260Sgibbs return(ct->comp_number); 58339260Sgibbs} 58439260Sgibbs 585279219Skenstatic struct driver_state { 586279219Sken int dsreg; 587279219Sken const char *desc; 588279219Sken} driver_states[] = { 589279219Sken { MTIO_DSREG_REST, "at rest" }, 590279219Sken { MTIO_DSREG_RBSY, "Communicating with drive" }, 591279219Sken { MTIO_DSREG_WR, "Writing" }, 592279219Sken { MTIO_DSREG_FMK, "Writing Filemarks" }, 593279219Sken { MTIO_DSREG_ZER, "Erasing" }, 594279219Sken { MTIO_DSREG_RD, "Reading" }, 595279219Sken { MTIO_DSREG_FWD, "Spacing Forward" }, 596279219Sken { MTIO_DSREG_REV, "Spacing Reverse" }, 597279219Sken { MTIO_DSREG_POS, "Hardware Positioning (direction unknown)" }, 598279219Sken { MTIO_DSREG_REW, "Rewinding" }, 599279219Sken { MTIO_DSREG_TEN, "Retensioning" }, 600279219Sken { MTIO_DSREG_UNL, "Unloading" }, 601279219Sken { MTIO_DSREG_LD, "Loading" }, 602279219Sken}; 603279219Sken 604279219Skenconst char * 605279219Skenget_driver_state_str(int dsreg) 606279219Sken{ 607279219Sken unsigned int i; 608279219Sken 609279219Sken for (i = 0; i < (sizeof(driver_states)/sizeof(driver_states[0])); i++) { 610279219Sken if (driver_states[i].dsreg == dsreg) 611279219Sken return (driver_states[i].desc); 612279219Sken } 613279219Sken 614279219Sken return (NULL); 615279219Sken} 616279219Sken 617227174Sedstatic void 6187913Sjoergst_status(struct mtget *bp) 6197913Sjoerg{ 62044644Smjacob printf("Mode Density Blocksize bpi " 62139260Sgibbs "Compression\n" 62244644Smjacob "Current: %-17s %-12s %-7d %s\n" 62339260Sgibbs "---------available modes---------\n" 62444644Smjacob "0: %-17s %-12s %-7d %s\n" 62544644Smjacob "1: %-17s %-12s %-7d %s\n" 62644644Smjacob "2: %-17s %-12s %-7d %s\n" 62744644Smjacob "3: %-17s %-12s %-7d %s\n", 62839260Sgibbs denstostring(bp->mt_density), getblksiz(bp->mt_blksiz), 629279219Sken mt_density_bp(bp->mt_density, TRUE), comptostring(bp->mt_comp), 63039260Sgibbs denstostring(bp->mt_density0), getblksiz(bp->mt_blksiz0), 631279219Sken mt_density_bp(bp->mt_density0, TRUE), comptostring(bp->mt_comp0), 63239260Sgibbs denstostring(bp->mt_density1), getblksiz(bp->mt_blksiz1), 633279219Sken mt_density_bp(bp->mt_density1, TRUE), comptostring(bp->mt_comp1), 63439260Sgibbs denstostring(bp->mt_density2), getblksiz(bp->mt_blksiz2), 635279219Sken mt_density_bp(bp->mt_density2, TRUE), comptostring(bp->mt_comp2), 63639260Sgibbs denstostring(bp->mt_density3), getblksiz(bp->mt_blksiz3), 637279219Sken mt_density_bp(bp->mt_density3, TRUE), comptostring(bp->mt_comp3)); 63843629Smjacob 63943629Smjacob if (bp->mt_dsreg != MTIO_DSREG_NIL) { 64069248Skris const char sfmt[] = "Current Driver State: %s.\n"; 64143629Smjacob printf("---------------------------------\n"); 642279219Sken const char *state_str; 643279219Sken 644279219Sken state_str = get_driver_state_str(bp->mt_dsreg); 645279219Sken if (state_str == NULL) { 646279219Sken char foo[32]; 647279219Sken (void) sprintf(foo, "Unknown state 0x%x", bp->mt_dsreg); 648279219Sken printf(sfmt, foo); 649279219Sken } else { 650279219Sken printf(sfmt, state_str); 651279219Sken } 652279219Sken } 653279219Sken if (bp->mt_resid == 0 && bp->mt_fileno == (daddr_t) -1 && 654279219Sken bp->mt_blkno == (daddr_t) -1) 655279219Sken return; 656279219Sken printf("---------------------------------\n"); 657279219Sken printf("File Number: %d\tRecord Number: %d\tResidual Count %d\n", 658279219Sken bp->mt_fileno, bp->mt_blkno, bp->mt_resid); 659279219Sken} 660279219Sken 661279219Skenstatic int 662279219Skenmt_locate(int argc, char **argv, int mtfd, const char *tape) 663279219Sken{ 664279219Sken struct mtlocate mtl; 665279219Sken uint64_t logical_id = 0; 666279219Sken mt_locate_dest_type dest_type = MT_LOCATE_DEST_FILE; 667279219Sken int eod = 0, explicit = 0, immediate = 0; 668279219Sken int64_t partition = 0; 669279219Sken int block_addr_set = 0, partition_set = 0, file_set = 0, set_set = 0; 670279219Sken int c, retval; 671279219Sken 672279219Sken retval = 0; 673279219Sken bzero(&mtl, sizeof(mtl)); 674279219Sken 675279219Sken while ((c = getopt(argc, argv, "b:eEf:ip:s:")) != -1) { 676279219Sken switch (c) { 677279219Sken case 'b': 678279219Sken /* Block address */ 679279219Sken logical_id = strtoull(optarg, NULL, 0); 680279219Sken dest_type = MT_LOCATE_DEST_OBJECT; 681279219Sken block_addr_set = 1; 68243629Smjacob break; 683279219Sken case 'e': 684279219Sken /* end of data */ 685279219Sken eod = 1; 686279219Sken dest_type = MT_LOCATE_DEST_EOD; 68743629Smjacob break; 688279219Sken case 'E': 689279219Sken /* 690279219Sken * XXX KDM explicit address mode. Should we even 691279219Sken * allow this, since the driver doesn't operate in 692279219Sken * explicit address mode? 693279219Sken */ 694279219Sken explicit = 1; 69543629Smjacob break; 696279219Sken case 'f': 697279219Sken /* file number */ 698279219Sken logical_id = strtoull(optarg, NULL, 0); 699279219Sken dest_type = MT_LOCATE_DEST_FILE; 700279219Sken file_set = 1; 70143629Smjacob break; 702279219Sken case 'i': 703279219Sken /* 704279219Sken * Immediate address mode. XXX KDM do we want to 705279219Sken * implement this? The other commands in the 706279219Sken * tape driver will need to be able to handle this. 707279219Sken */ 708279219Sken immediate = 1; 70943629Smjacob break; 710279219Sken case 'p': 711279219Sken /* 712279219Sken * Change partition to the given partition. 713279219Sken */ 714279219Sken partition = strtol(optarg, NULL, 0); 715279219Sken partition_set = 1; 71643629Smjacob break; 717279219Sken case 's': 718279219Sken /* Go to the given set mark */ 719279219Sken logical_id = strtoull(optarg, NULL, 0); 720279219Sken dest_type = MT_LOCATE_DEST_SET; 721279219Sken set_set = 1; 72243629Smjacob break; 723279219Sken default: 72443629Smjacob break; 725279219Sken } 726279219Sken } 727279219Sken 728279219Sken /* 729279219Sken * These options are mutually exclusive. The user may only specify 730279219Sken * one. 731279219Sken */ 732279219Sken if ((block_addr_set + file_set + eod + set_set) != 1) 733279219Sken errx(1, "You must specify only one of -b, -f, -e, or -s"); 734279219Sken 735279219Sken mtl.dest_type = dest_type; 736279219Sken switch (dest_type) { 737279219Sken case MT_LOCATE_DEST_OBJECT: 738279219Sken case MT_LOCATE_DEST_FILE: 739279219Sken case MT_LOCATE_DEST_SET: 740279219Sken mtl.logical_id = logical_id; 741279219Sken break; 742279219Sken case MT_LOCATE_DEST_EOD: 743279219Sken break; 744279219Sken } 745279219Sken 746279219Sken if (immediate != 0) 747279219Sken mtl.flags |= MT_LOCATE_FLAG_IMMED; 748279219Sken 749279219Sken if (partition_set != 0) { 750279219Sken mtl.flags |= MT_LOCATE_FLAG_CHANGE_PART; 751279219Sken mtl.partition = partition; 752279219Sken } 753279219Sken 754279219Sken if (explicit != 0) 755279219Sken mtl.block_address_mode = MT_LOCATE_BAM_EXPLICIT; 756279219Sken else 757279219Sken mtl.block_address_mode = MT_LOCATE_BAM_IMPLICIT; 758279219Sken 759279219Sken if (ioctl(mtfd, MTIOCEXTLOCATE, &mtl) == -1) 760279219Sken err(1, "MTIOCEXTLOCATE ioctl failed on %s", tape); 761279219Sken 762279219Sken return (retval); 763279219Sken} 764279219Sken 765279219Skentypedef enum { 766279219Sken MT_PERIPH_NAME = 0, 767279219Sken MT_UNIT_NUMBER = 1, 768279219Sken MT_VENDOR = 2, 769279219Sken MT_PRODUCT = 3, 770279219Sken MT_REVISION = 4, 771279219Sken MT_COMPRESSION_SUPPORTED = 5, 772279219Sken MT_COMPRESSION_ENABLED = 6, 773279219Sken MT_COMPRESSION_ALGORITHM = 7, 774279219Sken MT_MEDIA_DENSITY = 8, 775279219Sken MT_MEDIA_BLOCKSIZE = 9, 776279219Sken MT_CALCULATED_FILENO = 10, 777279219Sken MT_CALCULATED_REL_BLKNO = 11, 778279219Sken MT_REPORTED_FILENO = 12, 779279219Sken MT_REPORTED_BLKNO = 13, 780279219Sken MT_PARTITION = 14, 781279219Sken MT_BOP = 15, 782279219Sken MT_EOP = 16, 783279219Sken MT_BPEW = 17, 784279219Sken MT_DSREG = 18, 785279219Sken MT_RESID = 19, 786279219Sken MT_FIXED_MODE = 20, 787279219Sken MT_SERIAL_NUM = 21, 788279219Sken MT_MAXIO = 22, 789279219Sken MT_CPI_MAXIO = 23, 790279219Sken MT_MAX_BLK = 24, 791279219Sken MT_MIN_BLK = 25, 792279219Sken MT_BLK_GRAN = 26, 793279219Sken MT_MAX_EFF_IOSIZE = 27 794279219Sken} status_item_index; 795279219Sken 796279219Skenstatic struct mt_status_items { 797279219Sken const char *name; 798279219Sken struct mt_status_entry *entry; 799279219Sken} req_status_items[] = { 800279219Sken { "periph_name", NULL }, 801279219Sken { "unit_number", NULL }, 802279219Sken { "vendor", NULL }, 803279219Sken { "product", NULL }, 804279219Sken { "revision", NULL }, 805279219Sken { "compression_supported", NULL }, 806279219Sken { "compression_enabled", NULL }, 807279219Sken { "compression_algorithm", NULL }, 808279219Sken { "media_density", NULL }, 809279219Sken { "media_blocksize", NULL }, 810279219Sken { "calculated_fileno", NULL }, 811279219Sken { "calculated_rel_blkno", NULL }, 812279219Sken { "reported_fileno", NULL }, 813279219Sken { "reported_blkno", NULL }, 814279219Sken { "partition", NULL }, 815279219Sken { "bop", NULL }, 816279219Sken { "eop", NULL }, 817279219Sken { "bpew", NULL }, 818279219Sken { "dsreg", NULL }, 819279219Sken { "residual", NULL }, 820279219Sken { "fixed_mode", NULL }, 821279219Sken { "serial_num", NULL }, 822279219Sken { "maxio", NULL }, 823279219Sken { "cpi_maxio", NULL }, 824279219Sken { "max_blk", NULL }, 825279219Sken { "min_blk", NULL }, 826279219Sken { "blk_gran", NULL }, 827279219Sken { "max_effective_iosize", NULL } 828279219Sken}; 829279219Sken 830279219Skenint 831279219Skennstatus_print(int argc, char **argv, char *xml_str, 832279219Sken struct mt_status_data *status_data) 833279219Sken{ 834279219Sken unsigned int i; 835279219Sken int64_t calculated_fileno, calculated_rel_blkno; 836279219Sken int64_t rep_fileno, rep_blkno, partition, resid; 837279219Sken char block_str[32]; 838279219Sken const char *dens_str; 839279219Sken int dsreg, bop, eop, bpew; 840279219Sken int xml_dump = 0; 841279219Sken size_t dens_len; 842279219Sken unsigned int field_width; 843279219Sken int verbose = 0; 844279219Sken int c; 845279219Sken 846279219Sken while ((c = getopt(argc, argv, "xv")) != -1) { 847279219Sken switch (c) { 848279219Sken case 'x': 849279219Sken xml_dump = 1; 85043629Smjacob break; 851279219Sken case 'v': 852279219Sken verbose = 1; 85343629Smjacob break; 854279219Sken default: 85543629Smjacob break; 856279219Sken } 857279219Sken } 858279219Sken 859279219Sken if (xml_dump != 0) { 860279219Sken printf("%s", xml_str); 861279219Sken return (0); 862279219Sken } 863279219Sken 864279219Sken for (i = 0; i < (sizeof(req_status_items)/sizeof(req_status_items[0])); 865279219Sken i++) { 866279219Sken char *name; 867279219Sken 868279219Sken name = __DECONST(char *, req_status_items[i].name); 869279219Sken req_status_items[i].entry = mt_status_entry_find(status_data, 870279219Sken name); 871279219Sken if (req_status_items[i].entry == NULL) { 872279219Sken errx(1, "Cannot find status entry %s", 873279219Sken req_status_items[i].name); 874279219Sken } 875279219Sken } 876279219Sken 877279219Sken printf("Drive: %s%ju: <%s %s %s> Serial Number: %s\n", 878279219Sken req_status_items[MT_PERIPH_NAME].entry->value, 879279219Sken (uintmax_t)req_status_items[MT_UNIT_NUMBER].entry->value_unsigned, 880279219Sken req_status_items[MT_VENDOR].entry->value, 881279219Sken req_status_items[MT_PRODUCT].entry->value, 882279219Sken req_status_items[MT_REVISION].entry->value, 883279219Sken (req_status_items[MT_SERIAL_NUM].entry->value) ? 884279219Sken req_status_items[MT_SERIAL_NUM].entry->value : "none"); 885279219Sken printf("---------------------------------\n"); 886279219Sken 887279219Sken /* 888279219Sken * We check to see whether we're in fixed mode or not, and don't 889279219Sken * just believe the blocksize. If the SILI bit is turned on, the 890279219Sken * blocksize will be set to 4, even though we're doing variable 891279219Sken * length (well, multiples of 4) blocks. 892279219Sken */ 893279219Sken if (req_status_items[MT_FIXED_MODE].entry->value_signed == 0) 894279219Sken snprintf(block_str, sizeof(block_str), "variable"); 895279219Sken else 896279219Sken snprintf(block_str, sizeof(block_str), "%s", 897279219Sken getblksiz(req_status_items[ 898279219Sken MT_MEDIA_BLOCKSIZE].entry->value_unsigned)); 899279219Sken 900279219Sken dens_str = denstostring(req_status_items[ 901279219Sken MT_MEDIA_DENSITY].entry->value_unsigned); 902279219Sken if (dens_str == NULL) 903279219Sken dens_len = 0; 904279219Sken else 905279219Sken dens_len = strlen(dens_str); 906279219Sken field_width = MAX(dens_len, 17); 907279219Sken printf("Mode %-*s Blocksize bpi Compression\n" 908279219Sken "Current: %-*s %-12s %-7d ", 909279219Sken field_width, "Density", field_width, dens_str, block_str, 910279219Sken mt_density_bp(req_status_items[ 911279219Sken MT_MEDIA_DENSITY].entry->value_unsigned, TRUE)); 912279219Sken 913279219Sken if (req_status_items[MT_COMPRESSION_SUPPORTED].entry->value_signed == 0) 914279219Sken printf("unsupported\n"); 915279219Sken else if (req_status_items[ 916279219Sken MT_COMPRESSION_ENABLED].entry->value_signed == 0) 917279219Sken printf("disabled\n"); 918279219Sken else { 919279219Sken printf("enabled (%s)\n", 920279219Sken comptostring(req_status_items[ 921279219Sken MT_COMPRESSION_ALGORITHM].entry->value_unsigned)); 922279219Sken } 923279219Sken 924279219Sken dsreg = req_status_items[MT_DSREG].entry->value_signed; 925279219Sken if (dsreg != MTIO_DSREG_NIL) { 926279219Sken const char sfmt[] = "Current Driver State: %s.\n"; 927279219Sken printf("---------------------------------\n"); 928279219Sken const char *state_str; 929279219Sken 930279219Sken state_str = get_driver_state_str(dsreg); 931279219Sken if (state_str == NULL) { 932279219Sken char foo[32]; 933279219Sken (void) sprintf(foo, "Unknown state 0x%x", dsreg); 934279219Sken printf(sfmt, foo); 935279219Sken } else { 936279219Sken printf(sfmt, state_str); 937279219Sken } 938279219Sken } 939279219Sken resid = req_status_items[MT_RESID].entry->value_signed; 940279219Sken calculated_fileno = req_status_items[ 941279219Sken MT_CALCULATED_FILENO].entry->value_signed; 942279219Sken calculated_rel_blkno = req_status_items[ 943279219Sken MT_CALCULATED_REL_BLKNO].entry->value_signed; 944279219Sken rep_fileno = req_status_items[ 945279219Sken MT_REPORTED_FILENO].entry->value_signed; 946279219Sken rep_blkno = req_status_items[ 947279219Sken MT_REPORTED_BLKNO].entry->value_signed; 948279219Sken bop = req_status_items[MT_BOP].entry->value_signed; 949279219Sken eop = req_status_items[MT_EOP].entry->value_signed; 950279219Sken bpew = req_status_items[MT_BPEW].entry->value_signed; 951279219Sken partition = req_status_items[MT_PARTITION].entry->value_signed; 952279219Sken 953279219Sken printf("---------------------------------\n"); 954279219Sken printf("Partition: %3jd Calc File Number: %3jd " 955279219Sken " Calc Record Number: %jd\n" 956279219Sken "Residual: %3jd Reported File Number: %3jd " 957279219Sken "Reported Record Number: %jd\n", partition, calculated_fileno, 958279219Sken calculated_rel_blkno, resid, rep_fileno, rep_blkno); 959279219Sken 960279219Sken printf("Flags: "); 961279219Sken if (bop > 0 || eop > 0 || bpew > 0) { 962279219Sken int need_comma = 0; 963279219Sken 964279219Sken if (bop > 0) { 965279219Sken printf("BOP"); 966279219Sken need_comma = 1; 967279219Sken } 968279219Sken if (eop > 0) { 969279219Sken if (need_comma != 0) 970279219Sken printf(","); 971279219Sken printf("EOP"); 972279219Sken need_comma = 1; 973279219Sken } 974279219Sken if (bpew > 0) { 975279219Sken if (need_comma != 0) 976279219Sken printf(","); 977279219Sken printf("BPEW"); 978279219Sken need_comma = 1; 979279219Sken } 980279219Sken } else { 981279219Sken printf("None"); 982279219Sken } 983279219Sken printf("\n"); 984279219Sken if (verbose != 0) { 985279219Sken printf("---------------------------------\n"); 986279219Sken printf("Tape I/O parameters:\n"); 987279219Sken for (i = MT_MAXIO; i <= MT_MAX_EFF_IOSIZE; i++) { 988279219Sken printf(" %s (%s): %ju bytes\n", 989279219Sken req_status_items[i].entry->desc, 990279219Sken req_status_items[i].name, 991279219Sken req_status_items[i].entry->value_unsigned); 992279219Sken } 993279219Sken } 994279219Sken 995279219Sken return (0); 996279219Sken} 997279219Sken 998279219Skenint 999279219Skenmt_xml_cmd(unsigned long cmd, int argc, char **argv, int mtfd, const char *tape) 1000279219Sken{ 1001279219Sken struct mt_status_data status_data; 1002279219Sken#if 0 1003279219Sken struct mt_status_entry *entry; 1004279219Sken#endif 1005279219Sken char *xml_str; 1006279219Sken int retval; 1007279219Sken unsigned long ioctl_cmd; 1008279219Sken 1009279219Sken switch (cmd) { 1010279219Sken case MT_CMD_PROTECT: 1011279219Sken case MTIOCPARAMGET: 1012279219Sken ioctl_cmd = MTIOCPARAMGET; 1013279219Sken break; 1014279219Sken default: 1015279219Sken ioctl_cmd = MTIOCEXTGET; 1016279219Sken break; 1017279219Sken } 1018279219Sken 1019279219Sken retval = mt_get_xml_str(mtfd, ioctl_cmd, &xml_str); 1020279219Sken if (retval != 0) 1021279219Sken err(1, "Couldn't get mt XML string"); 1022279219Sken 1023279219Sken retval = mt_get_status(xml_str, &status_data); 1024279219Sken if (retval != XML_STATUS_OK) { 1025279219Sken warn("Couldn't get mt status for %s", tape); 1026279219Sken goto bailout; 1027279219Sken } 1028279219Sken 1029279219Sken /* 1030279219Sken * This gets set if there are memory allocation or other errors in 1031279219Sken * our parsing of the XML. 1032279219Sken */ 1033279219Sken if (status_data.error != 0) { 1034279219Sken warnx("%s", status_data.error_str); 1035279219Sken retval = 1; 1036279219Sken goto bailout; 1037279219Sken } 1038279219Sken#if 0 1039279219Sken STAILQ_FOREACH(entry, &status_data.entries, links) 1040279219Sken mt_status_tree_print(entry, 0, NULL); 1041279219Sken#endif 1042279219Sken 1043279219Sken switch (cmd) { 1044279219Sken case MTIOCEXTGET: 1045279219Sken retval = nstatus_print(argc, argv, xml_str, &status_data); 1046279219Sken break; 1047279219Sken case MTIOCPARAMGET: 1048279219Sken retval = mt_param(argc, argv, mtfd, xml_str, &status_data); 1049279219Sken break; 1050279219Sken case MT_CMD_PROTECT: 1051279219Sken retval = mt_protect(argc, argv, mtfd, &status_data); 1052279219Sken break; 1053279219Sken case MT_CMD_GETDENSITY: 1054279219Sken retval = mt_getdensity(argc, argv, xml_str, &status_data); 1055279219Sken break; 1056279219Sken } 1057279219Sken 1058279219Skenbailout: 1059279219Sken if (xml_str != NULL) 1060279219Sken free(xml_str); 1061279219Sken 1062279219Sken mt_status_free(&status_data); 1063279219Sken 1064279219Sken return (retval); 1065279219Sken} 1066279219Sken 1067279219Skenstatic int 1068279219Skenmt_set_param(int mtfd, struct mt_status_data *status_data, char *param_name, 1069279219Sken char *param_value) 1070279219Sken{ 1071279219Sken struct mt_status_entry *entry; 1072279219Sken struct mtparamset param_set; 1073279219Sken 1074279219Sken entry = mt_status_entry_find(status_data, 1075279219Sken __DECONST(char *, "mtparamget")); 1076279219Sken if (entry == NULL) 1077279219Sken errx(1, "Cannot find parameter root node"); 1078279219Sken 1079279219Sken bzero(¶m_set, sizeof(param_set)); 1080279219Sken entry = mt_entry_find(entry, param_name); 1081279219Sken if (entry == NULL) 1082279219Sken errx(1, "Unknown parameter name \"%s\"", param_name); 1083279219Sken 1084279219Sken strlcpy(param_set.value_name, param_name, sizeof(param_set.value_name)); 1085279219Sken 1086279219Sken switch (entry->var_type) { 1087279219Sken case MT_TYPE_INT: 1088279219Sken param_set.value.value_signed = strtoll(param_value, NULL, 0); 1089279219Sken param_set.value_type = MT_PARAM_SET_SIGNED; 1090279219Sken param_set.value_len = entry->size; 1091279219Sken break; 1092279219Sken case MT_TYPE_UINT: 1093279219Sken param_set.value.value_unsigned = strtoull(param_value, NULL, 0); 1094279219Sken param_set.value_type = MT_PARAM_SET_UNSIGNED; 1095279219Sken param_set.value_len = entry->size; 1096279219Sken break; 1097279219Sken case MT_TYPE_STRING: { 1098279219Sken size_t param_len; 1099279219Sken 1100279219Sken param_len = strlen(param_value) + 1; 1101279219Sken if (param_len > sizeof(param_set.value.value_fixed_str)) { 1102279219Sken param_set.value_type = MT_PARAM_SET_VAR_STR; 1103279219Sken param_set.value.value_var_str = param_value; 1104279219Sken } else { 1105279219Sken param_set.value_type = MT_PARAM_SET_FIXED_STR; 1106279219Sken strlcpy(param_set.value.value_fixed_str, param_value, 1107279219Sken sizeof(param_set.value.value_fixed_str)); 1108279219Sken } 1109279219Sken param_set.value_len = param_len; 1110279219Sken break; 1111279219Sken } 1112279219Sken default: 1113279219Sken errx(1, "Unknown parameter type %d for %s", entry->var_type, 1114279219Sken param_name); 1115279219Sken break; 1116279219Sken } 1117279219Sken 1118279219Sken if (ioctl(mtfd, MTIOCPARAMSET, ¶m_set) == -1) 1119279219Sken err(1, "MTIOCPARAMSET"); 1120279219Sken 1121279219Sken if (param_set.status != MT_PARAM_STATUS_OK) 1122279219Sken errx(1, "Failed to set %s: %s", param_name, 1123279219Sken param_set.error_str); 1124279219Sken 1125279219Sken return (0); 1126279219Sken} 1127279219Sken 1128279219Sken 1129279219Skentypedef enum { 1130279219Sken MT_PP_LBP_R, 1131279219Sken MT_PP_LBP_W, 1132279219Sken MT_PP_RBDP, 1133279219Sken MT_PP_PI_LENGTH, 1134279219Sken MT_PP_PROT_METHOD 1135279219Sken} mt_protect_param; 1136279219Sken 1137279219Skenstatic struct mt_protect_info { 1138279219Sken const char *name; 1139279219Sken struct mt_status_entry *entry; 1140279219Sken uint32_t value; 1141279219Sken} mt_protect_list[] = { 1142279219Sken { "lbp_r", NULL, 0 }, 1143279219Sken { "lbp_w", NULL, 0 }, 1144279219Sken { "rbdp", NULL, 0 }, 1145279219Sken { "pi_length", NULL, 0 }, 1146279219Sken { "prot_method", NULL, 0 } 1147279219Sken}; 1148279219Sken 1149279219Sken#define MT_NUM_PROTECT_PARAMS (sizeof(mt_protect_list)/sizeof(mt_protect_list[0])) 1150279219Sken 1151279219Sken#define MT_PROT_NAME "protection" 1152279219Sken 1153279219Skenstatic int 1154279219Skenmt_protect(int argc, char **argv, int mtfd, struct mt_status_data *status_data) 1155279219Sken{ 1156279219Sken int retval = 0; 1157279219Sken int do_enable = 0, do_disable = 0, do_list = 0; 1158279219Sken int rbdp_set = 0, lbp_w_set = 0, lbp_r_set = 0; 1159279219Sken int prot_method_set = 0, pi_length_set = 0; 1160279219Sken int verbose = 0; 1161279219Sken uint32_t rbdp = 0, lbp_w = 0, lbp_r = 0; 1162279219Sken uint32_t prot_method = 0, pi_length = 0; 1163279219Sken struct mt_status_entry *prot_entry, *supported_entry; 1164279219Sken struct mt_status_entry *entry; 1165279219Sken struct mtparamset params[MT_NUM_PROTECT_PARAMS]; 1166279219Sken struct mtsetlist param_list; 1167279219Sken unsigned int i; 1168279219Sken int c; 1169279219Sken 1170279219Sken while ((c = getopt(argc, argv, "b:delL:m:r:vw:")) != -1) { 1171279219Sken switch (c) { 1172279219Sken case 'b': 1173279219Sken rbdp_set = 1; 1174279219Sken rbdp = strtoul(optarg, NULL, 0); 1175279219Sken if ((rbdp != 0) && (rbdp != 1)) 1176279219Sken errx(1, "valid values for -b are 0 and 1"); 117743629Smjacob break; 1178279219Sken case 'd': 1179279219Sken do_disable = 1; 118043629Smjacob break; 1181279219Sken case 'e': 1182279219Sken do_enable = 1; 1183279219Sken break; 1184279219Sken case 'l': 1185279219Sken do_list = 1; 1186279219Sken break; 1187279219Sken case 'L': 1188279219Sken pi_length_set = 1; 1189279219Sken pi_length = strtoul(optarg, NULL, 0); 1190279219Sken if (pi_length > SA_CTRL_DP_PI_LENGTH_MASK) 1191279219Sken errx(1, "PI length %u > maximum %u", 1192279219Sken pi_length, SA_CTRL_DP_PI_LENGTH_MASK); 1193279219Sken break; 1194279219Sken case 'm': 1195279219Sken prot_method_set = 1; 1196279219Sken prot_method = strtoul(optarg, NULL, 0); 1197279219Sken if (prot_method > SA_CTRL_DP_METHOD_MAX) 1198279219Sken errx(1, "Method %u > maximum %u", 1199279219Sken prot_method, SA_CTRL_DP_METHOD_MAX); 1200279219Sken break; 1201279219Sken case 'r': 1202279219Sken lbp_r_set = 1; 1203279219Sken lbp_r = strtoul(optarg, NULL, 0); 1204279219Sken if ((lbp_r != 0) && (lbp_r != 1)) 1205279219Sken errx(1, "valid values for -r are 0 and 1"); 1206279219Sken break; 1207279219Sken case 'v': 1208279219Sken verbose = 1; 1209279219Sken break; 1210279219Sken case 'w': 1211279219Sken lbp_w_set = 1; 1212279219Sken lbp_w = strtoul(optarg, NULL, 0); 1213279219Sken if ((lbp_w != 0) && (lbp_r != 1)) 1214279219Sken errx(1, "valid values for -r are 0 and 1"); 1215279219Sken break; 121643629Smjacob default: 121743629Smjacob break; 121843629Smjacob } 121943629Smjacob } 1220279219Sken 1221279219Sken if ((rbdp_set + do_disable + do_enable + do_list + pi_length_set + 1222279219Sken prot_method_set + lbp_r_set + lbp_w_set) == 0) 1223279219Sken errx(1, "Need an argument for protect"); 1224279219Sken 1225279219Sken if ((do_disable + do_enable + do_list) != 1) 1226279219Sken errx(1, "You must specify only one of -e, -d or -l"); 1227279219Sken 1228279219Sken if (do_list != 0) { 1229279219Sken retval = mt_protect_print(status_data, verbose); 1230279219Sken goto bailout; 1231279219Sken } 1232279219Sken if (do_enable != 0) { 1233279219Sken /* 1234279219Sken * Enable protection, but allow the user to override 1235279219Sken * settings if he doesn't want everything turned on. 1236279219Sken */ 1237279219Sken if (rbdp_set == 0) 1238279219Sken rbdp = 1; 1239279219Sken if (lbp_w_set == 0) 1240279219Sken lbp_w = 1; 1241279219Sken if (lbp_r_set == 0) 1242279219Sken lbp_r = 1; 1243279219Sken /* 1244279219Sken * If the user doesn't override it, we default to enabling 1245279219Sken * Reed-Solomon checkums. 1246279219Sken */ 1247279219Sken if (prot_method_set == 0) 1248279219Sken prot_method = SA_CTRL_DP_REED_SOLOMON; 1249279219Sken if (pi_length_set == 0) 1250279219Sken pi_length = SA_CTRL_DP_RS_LENGTH; 1251279219Sken } else if (do_disable != 0) { 1252279219Sken /* 1253279219Sken * If the user wants to disable protection, we ignore any 1254279219Sken * other parameters he has set. Everything gets set to 0. 1255279219Sken */ 1256279219Sken rbdp = lbp_w = lbp_r = 0; 1257279219Sken prot_method = pi_length = 0; 1258279219Sken } 1259279219Sken 1260279219Sken prot_entry = mt_status_entry_find(status_data, 1261279219Sken __DECONST(char *, MT_PROT_NAME)); 1262279219Sken if (prot_entry == NULL) 1263279219Sken errx(1, "Unable to find protection information status"); 1264279219Sken 1265279219Sken supported_entry = mt_entry_find(prot_entry, 1266279219Sken __DECONST(char *, "protection_supported")); 1267279219Sken if (supported_entry == NULL) 1268279219Sken errx(1, "Unable to find protection support information"); 1269279219Sken 1270279219Sken if (((supported_entry->var_type == MT_TYPE_INT) 1271279219Sken && (supported_entry->value_signed == 0)) 1272279219Sken || ((supported_entry->var_type == MT_TYPE_UINT) 1273279219Sken && (supported_entry->value_unsigned == 0))) 1274279219Sken errx(1, "This device does not support protection information"); 1275279219Sken 1276279219Sken mt_protect_list[MT_PP_LBP_R].value = lbp_r; 1277279219Sken mt_protect_list[MT_PP_LBP_W].value = lbp_w; 1278279219Sken mt_protect_list[MT_PP_RBDP].value = rbdp; 1279279219Sken mt_protect_list[MT_PP_PI_LENGTH].value = pi_length; 1280279219Sken mt_protect_list[MT_PP_PROT_METHOD].value = prot_method; 1281279219Sken 1282279219Sken bzero(¶ms, sizeof(params)); 1283279219Sken bzero(¶m_list, sizeof(param_list)); 1284279219Sken 1285279219Sken /* 1286279219Sken * Go through the list and make sure that we have this parameter, 1287279219Sken * and that it is still an unsigned integer. If not, we've got a 1288279219Sken * problem. 1289279219Sken */ 1290279219Sken for (i = 0; i < MT_NUM_PROTECT_PARAMS; i++) { 1291279219Sken entry = mt_entry_find(prot_entry, 1292279219Sken __DECONST(char *, mt_protect_list[i].name)); 1293279219Sken if (entry == NULL) { 1294279219Sken errx(1, "Unable to find parameter %s", 1295279219Sken mt_protect_list[i].name); 1296279219Sken } 1297279219Sken mt_protect_list[i].entry = entry; 1298279219Sken 1299279219Sken if (entry->var_type != MT_TYPE_UINT) 1300279219Sken errx(1, "Parameter %s is type %d, not unsigned, " 1301279219Sken "cannot proceed", mt_protect_list[i].name, 1302279219Sken entry->var_type); 1303279219Sken snprintf(params[i].value_name, sizeof(params[i].value_name), 1304279219Sken "%s.%s", MT_PROT_NAME, mt_protect_list[i].name); 1305279219Sken /* XXX KDM unify types here */ 1306279219Sken params[i].value_type = MT_PARAM_SET_UNSIGNED; 1307279219Sken params[i].value_len = sizeof(mt_protect_list[i].value); 1308279219Sken params[i].value.value_unsigned = mt_protect_list[i].value; 1309279219Sken 1310279219Sken } 1311279219Sken param_list.num_params = MT_NUM_PROTECT_PARAMS; 1312279219Sken param_list.param_len = sizeof(params); 1313279219Sken param_list.params = params; 1314279219Sken 1315279219Sken if (ioctl(mtfd, MTIOCSETLIST, ¶m_list) == -1) 1316279219Sken err(1, "error issuing MTIOCSETLIST ioctl"); 1317279219Sken 1318279219Sken for (i = 0; i < MT_NUM_PROTECT_PARAMS; i++) { 1319279219Sken if (params[i].status != MT_PARAM_STATUS_OK) { 1320279219Sken warnx("%s", params[i].error_str); 1321279219Sken retval = 1; 1322279219Sken } 1323279219Sken } 1324279219Skenbailout: 1325279219Sken 1326279219Sken return (retval); 13277913Sjoerg} 13287913Sjoerg 1329279219Skenstatic int 1330279219Skenmt_param(int argc, char **argv, int mtfd, char *xml_str, 1331279219Sken struct mt_status_data *status_data) 1332279219Sken{ 1333279219Sken int list = 0, do_set = 0, xml_dump = 0; 1334279219Sken char *param_name = NULL, *param_value = NULL; 1335279219Sken int retval = 0, quiet = 0; 1336279219Sken int c; 1337279219Sken 1338279219Sken while ((c = getopt(argc, argv, "lp:qs:x")) != -1) { 1339279219Sken switch (c) { 1340279219Sken case 'l': 1341279219Sken list = 1; 1342279219Sken break; 1343279219Sken case 'p': 1344279261Sken if (param_name != NULL) { 1345289677Seadler warnx("Only one parameter name may be " 1346279261Sken "specified"); 1347279261Sken retval = 1; 1348279261Sken goto bailout; 1349279261Sken } 1350279219Sken param_name = strdup(optarg); 1351279219Sken break; 1352279219Sken case 'q': 1353279219Sken quiet = 1; 1354279219Sken break; 1355279219Sken case 's': 1356279261Sken if (param_value != NULL) { 1357289677Seadler warnx("Only one parameter value may be " 1358279261Sken "specified"); 1359279261Sken retval = 1; 1360279261Sken goto bailout; 1361279261Sken } 1362279219Sken param_value = strdup(optarg); 1363279219Sken do_set = 1; 1364279219Sken break; 1365279219Sken case 'x': 1366279219Sken xml_dump = 1; 1367279219Sken break; 1368279219Sken default: 1369279219Sken break; 1370279219Sken } 1371279219Sken } 1372279219Sken 1373279261Sken if ((list + do_set + xml_dump) != 1) { 1374279261Sken warnx("You must specify only one of -s, -l or -x"); 1375279261Sken retval = 1; 1376279261Sken goto bailout; 1377279261Sken } 1378279219Sken 1379279219Sken if (xml_dump != 0) { 1380279219Sken printf("%s", xml_str); 1381279261Sken retval = 0; 1382279261Sken goto bailout; 1383279219Sken } 1384279219Sken 1385279219Sken if (do_set != 0) { 1386279219Sken if (param_name == NULL) 1387279219Sken errx(1, "You must specify -p with -s"); 1388279219Sken 1389279219Sken retval = mt_set_param(mtfd, status_data, param_name, 1390279219Sken param_value); 1391279219Sken } else if (list != 0) 1392279219Sken retval = mt_param_list(status_data, param_name, quiet); 1393279219Sken 1394279261Skenbailout: 1395279261Sken free(param_name); 1396279261Sken free(param_value); 1397279219Sken return (retval); 1398279219Sken} 1399279219Sken 1400279219Skenint 1401279219Skenmt_print_density_entry(struct mt_status_entry *density_root, int indent) 1402279219Sken{ 1403279219Sken struct mt_status_entry *entry; 1404279219Sken int retval = 0; 1405279219Sken 1406279219Sken STAILQ_FOREACH(entry, &density_root->child_entries, links) { 1407279219Sken if (entry->var_type == MT_TYPE_NODE) { 1408279219Sken retval = mt_print_density_entry(entry, indent + 2); 1409279219Sken if (retval != 0) 1410279219Sken break; 1411279219Sken else 1412279219Sken continue; 1413279219Sken } 1414279219Sken if ((strcmp(entry->entry_name, "primary_density_code") == 0) 1415280230Sken || (strcmp(entry->entry_name, "secondary_density_code") == 0) 1416280230Sken || (strcmp(entry->entry_name, "density_code") == 0)) { 1417279219Sken 1418279219Sken printf("%*s%s (%s): %s\n", indent, "", entry->desc ? 1419279219Sken entry->desc : "", entry->entry_name, 1420279219Sken denstostring(entry->value_unsigned)); 1421279219Sken } else if (strcmp(entry->entry_name, "density_flags") == 0) { 1422279219Sken printf("%*sMedium Access: ", indent, ""); 1423279219Sken if (entry->value_unsigned & MT_DENS_WRITE_OK) { 1424279219Sken printf("Read and Write\n"); 1425279219Sken } else { 1426279219Sken printf("Read Only\n"); 1427279219Sken } 1428279219Sken printf("%*sDefault Density: %s\n", indent, "", 1429279219Sken (entry->value_unsigned & MT_DENS_DEFLT) ? "Yes" : 1430279219Sken "No"); 1431279219Sken printf("%*sDuplicate Density: %s\n", indent, "", 1432279219Sken (entry->value_unsigned & MT_DENS_DUP) ? "Yes" : 1433279219Sken "No"); 1434279219Sken } else if (strcmp(entry->entry_name, "media_width") == 0) { 1435279219Sken printf("%*s%s (%s): %.1f mm\n", indent, "", 1436279219Sken entry->desc ? entry->desc : "", entry->entry_name, 1437279219Sken (double)((double)entry->value_unsigned / 10)); 1438279219Sken } else if (strcmp(entry->entry_name, "medium_length") == 0) { 1439279219Sken printf("%*s%s (%s): %ju m\n", indent, "", 1440279219Sken entry->desc ? entry->desc : "", entry->entry_name, 1441279219Sken (uintmax_t)entry->value_unsigned); 1442279219Sken } else if (strcmp(entry->entry_name, "capacity") == 0) { 1443279219Sken printf("%*s%s (%s): %ju MB\n", indent, "", entry->desc ? 1444279219Sken entry->desc : "", entry->entry_name, 1445279219Sken (uintmax_t)entry->value_unsigned); 1446279219Sken } else { 1447279219Sken printf("%*s%s (%s): %s\n", indent, "", entry->desc ? 1448279219Sken entry->desc : "", entry->entry_name, entry->value); 1449279219Sken } 1450279219Sken } 1451279219Sken 1452279219Sken return (retval); 1453279219Sken} 1454279219Sken 1455279219Skenint 1456279219Skenmt_print_density_report(struct mt_status_entry *report_root, int indent) 1457279219Sken{ 1458279219Sken struct mt_status_entry *mt_report, *media_report; 1459279219Sken struct mt_status_entry *entry; 1460279219Sken int retval = 0; 1461279219Sken 1462279219Sken mt_report = mt_entry_find(report_root, 1463279219Sken __DECONST(char *, MT_MEDIUM_TYPE_REPORT_NAME)); 1464279219Sken if (mt_report == NULL) 1465279219Sken return (1); 1466279219Sken 1467279219Sken media_report = mt_entry_find(report_root, 1468279219Sken __DECONST(char *, MT_MEDIA_REPORT_NAME)); 1469279219Sken if (media_report == NULL) 1470279219Sken return (1); 1471279219Sken 1472279219Sken if ((mt_report->value_signed == 0) 1473279219Sken && (media_report->value_signed == 0)) { 1474279219Sken printf("%*sThis tape drive supports the following " 1475279219Sken "media densities:\n", indent, ""); 1476279219Sken } else if ((mt_report->value_signed == 0) 1477279219Sken && (media_report->value_signed != 0)) { 1478279219Sken printf("%*sThe tape currently in this drive supports " 1479279219Sken "the following media densities:\n", indent, ""); 1480279219Sken } else if ((mt_report->value_signed != 0) 1481279219Sken && (media_report->value_signed == 0)) { 1482279219Sken printf("%*sThis tape drive supports the following " 1483279219Sken "media types:\n", indent, ""); 1484279219Sken } else { 1485279219Sken printf("%*sThis tape currently in this drive supports " 1486279219Sken "the following media types:\n", indent, ""); 1487279219Sken } 1488279219Sken 1489279219Sken STAILQ_FOREACH(entry, &report_root->child_entries, links) { 1490279219Sken struct mt_status_nv *nv; 1491279219Sken 1492279219Sken if (strcmp(entry->entry_name, MT_DENSITY_ENTRY_NAME) != 0) 1493279219Sken continue; 1494279219Sken 1495279219Sken STAILQ_FOREACH(nv, &entry->nv_list, links) { 1496279219Sken if (strcmp(nv->name, "num") != 0) 1497279219Sken continue; 1498279219Sken 1499279219Sken break; 1500279219Sken } 1501279219Sken 1502279219Sken indent += 2; 1503279219Sken 1504279219Sken printf("%*sDensity Entry", indent, ""); 1505279219Sken if (nv != NULL) 1506279219Sken printf(" %s", nv->value); 1507279219Sken printf(":\n"); 1508279219Sken 1509279219Sken retval = mt_print_density_entry(entry, indent + 2); 1510279219Sken 1511279219Sken indent -= 2; 1512279219Sken } 1513279219Sken 1514279219Sken return (retval); 1515279219Sken} 1516279219Sken 1517279219Skenint 1518279219Skenmt_print_density(struct mt_status_entry *density_root, int indent) 1519279219Sken{ 1520279219Sken struct mt_status_entry *entry; 1521279219Sken int retval = 0; 1522279219Sken 1523279219Sken /* 1524279219Sken * We should have this entry for every tape drive. This particular 1525279219Sken * value is reported via the mode page block header, not the 1526279219Sken * SCSI REPORT DENSITY SUPPORT command. 1527279219Sken */ 1528279219Sken entry = mt_entry_find(density_root, 1529279219Sken __DECONST(char *, MT_MEDIA_DENSITY_NAME)); 1530279219Sken if (entry == NULL) 1531279219Sken errx(1, "Unable to find node %s", MT_MEDIA_DENSITY_NAME); 1532279219Sken 1533279219Sken printf("%*sCurrent density: %s\n", indent, "", 1534279219Sken denstostring(entry->value_unsigned)); 1535279219Sken 1536279219Sken /* 1537279219Sken * It isn't an error if we don't have any density reports. Tape 1538279219Sken * drives that don't support the REPORT DENSITY SUPPORT command 1539279219Sken * won't have any; they will only have the current density entry 1540279219Sken * above. 1541279219Sken */ 1542279219Sken STAILQ_FOREACH(entry, &density_root->child_entries, links) { 1543279219Sken if (strcmp(entry->entry_name, MT_DENSITY_REPORT_NAME) != 0) 1544279219Sken continue; 1545279219Sken 1546279219Sken retval = mt_print_density_report(entry, indent); 1547279219Sken } 1548279219Sken 1549279219Sken return (retval); 1550279219Sken} 1551279219Sken 1552279219Skenint 1553279219Skenmt_getdensity(int argc, char **argv, char *xml_str, 1554279219Sken struct mt_status_data *status_data) 1555279219Sken{ 1556279219Sken int retval = 0; 1557279219Sken int verbose = 0, xml_dump = 0; 1558279219Sken struct mt_status_entry *density_root = NULL; 1559279219Sken int c; 1560279219Sken 1561279219Sken while ((c = getopt(argc, argv, "vx")) != -1) { 1562279219Sken switch (c) { 1563279219Sken case 'v': 1564279219Sken verbose = 1; 1565279219Sken break; 1566279219Sken case 'x': 1567279219Sken xml_dump = 1; 1568279219Sken break; 1569279219Sken } 1570279219Sken } 1571279219Sken 1572279219Sken if (xml_dump != 0) { 1573279219Sken printf("%s", xml_str); 1574279219Sken return (0); 1575279219Sken } 1576279219Sken 1577279219Sken density_root = mt_status_entry_find(status_data, 1578279219Sken __DECONST(char *, MT_DENSITY_ROOT_NAME)); 1579279219Sken if (density_root == NULL) 1580279219Sken errx(1, "Cannot find density root node %s", 1581279219Sken MT_DENSITY_ROOT_NAME); 1582279219Sken 1583279219Sken retval = mt_print_density(density_root, 0); 1584279219Sken 1585279219Sken return (retval); 1586279219Sken} 1587279219Sken 1588227174Sedstatic void 15899541Sjoergwarn_eof(void) 15909541Sjoerg{ 15919541Sjoerg fprintf(stderr, 15929541Sjoerg "The \"eof\" command has been disabled.\n" 15939541Sjoerg "Use \"weof\" if you really want to write end-of-file marks,\n" 15949541Sjoerg "or \"eom\" if you rather want to skip to the end of " 15959541Sjoerg "recorded medium.\n"); 15969541Sjoerg exit(1); 15979541Sjoerg} 1598