diff --git a/Makefile b/Makefile index e540e8d..0156f8a 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,11 @@ CFLAGS= -Wall -O2 SBINDIR= /sbin BINDIR= /bin +USRBINDIR= /usr/bin MANDIR= /usr/share/man +MTDIR=$(BINDIR) + all: mt stinit mt: mt.c @@ -12,7 +15,7 @@ stinit: stinit.c $(CC) $(CFLAGS) -o stinit stinit.c install: mt stinit - install -s mt $(BINDIR) + install -s mt $(MTDIR) install -c -m 444 mt.1 $(MANDIR)/man1 (if [ -f $(MANDIR)/man1/mt.1.gz ] ; then \ rm -f $(MANDIR)/man1/mt.1.gz; gzip $(MANDIR)/man1/mt.1; fi) diff --git a/README b/README index df768f2..03edc25 100644 --- a/README +++ b/README @@ -29,6 +29,12 @@ Installation: - make - make install +Changes in version 1.1: +- unused defines removed from mtio.h (compiles also with distributions no + having linux/qic117.h) +- add support for MT_ST_SILI to mt and stinit +- add command showoptions for kernels >= 2.6.26 + Changes in version 0.9b: - only stinit changed @@ -93,4 +99,4 @@ Changes in version 0.3: by the command compression using a new ioctl) - bus fixes -May 29, 2005 Kai Makisara (email Kai.Makisara@kolumbus.fi) +April 27, 2008 Kai Makisara (email Kai.Makisara@kolumbus.fi) diff --git a/README.stinit b/README.stinit index 2db7fc5..25b682a 100644 --- a/README.stinit +++ b/README.stinit @@ -34,6 +34,10 @@ stinit.def.examples - a file containing example definitions for Makefile - a sample makefile for the program README.stinit - this file +Changes in version 1.1: +- fix mode number printing in verbose mode (from Martin Jacobs) +- add support for the sili option + Changes in version 0.9b: - fix back out to SCSI_IOCTL_SEND_COMMAND for 2.4 kernels (2.4 uses errno EINVAL for unsupported ioctls) @@ -64,5 +68,5 @@ Changes in version 0.6: Initial version 0.5. -May 29, 2005 Kai Mäkisara +April 27, 2008 Kai Mäkisara diff --git a/mt-st-0.9b.lsm b/mt-st-1.1.lsm similarity index 74% rename from mt-st-0.9b.lsm rename to mt-st-1.1.lsm index 5b16601..61dbf4b 100644 --- a/mt-st-0.9b.lsm +++ b/mt-st-1.1.lsm @@ -1,16 +1,16 @@ Begin4 Title: mt-st -Version: 0.9b -Entered-date: 2005-08-21 +Version: 1.1 +Entered-date: 2008-04-27 Description: Magnetic tape control tools for Linux SCSI tapes. Includes a mt-like program supporting additional commands using ioctls -specific to the Linux SCSI tape driver (up to kernel 2.6.12), and the program +specific to the Linux SCSI tape driver (up to kernel 2.6.26), and the program stinit to define the SCSI tape devices in system startup scripts. Keywords: tape SCSI Author: Kai.Makisara@kolumbus.fi (Kai Makisara) Maintained-by: Kai.Makisara@kolumbus.fi (Kai Makisara) Primary-site: ftp://ftp.ibiblio.org/pub/linux/system/backup - 37 kB mt-st-0.9b.tar.gz - 0.7 kB mt-st-0.9b.lsm + 36 kB mt-st-1.1.tar.gz + 0.7 kB mt-st-1.1.lsm Copying-policy: GPL End diff --git a/mt.1 b/mt.1 index 72630e1..b1e4941 100644 --- a/mt.1 +++ b/mt.1 @@ -1,4 +1,4 @@ -.TH MT 1 "August 2005" \" -*- nroff -*- +.TH MT 1 "April 2008" \" -*- nroff -*- .SH NAME mt \- control magnetic tape drive operation .SH SYNOPSIS @@ -207,6 +207,11 @@ drive can handle partitioned tapes .IP scsi2logical seek and tell use SCSI-2 logical block addresses instead of device dependent addresses +.IP sili +Set the SILI bit is when reading in variable block mode. This may speed up +reading blocks shorter than the read byte count. Set this option only if +you know that the drive supports SILI and the HBA reliably returns transfer +residual byte counts. Requires kernel version >= 2.6.26. .IP sysv enable the System V semantics .RE @@ -221,6 +226,9 @@ Allowed only for the superuser. The methods to specify the bits to clear are given above in description of .BR stoptions. Allowed only for the superuser. +.IP stshowoptions +(SCSI tapes) Print the currently enabled options for the device. Requires +kernel version >= 2.6.26 and sysfs must be mounted at /sys. .IP stwrthreshold (SCSI tapes) The write threshold for the tape device is set to .I count @@ -268,7 +276,7 @@ failed. .SH AUTHOR The program is written by Kai Makisara . .SH COPYRIGHT -The program and the manual page are copyrighted by Kai Makisara, 1998-2005. +The program and the manual page are copyrighted by Kai Makisara, 1998-2008. They can be distributed according to the GNU Copyleft. .SH SEE ALSO st(4) diff --git a/mt.c b/mt.c index 53cfc31..d4058c0 100644 --- a/mt.c +++ b/mt.c @@ -5,10 +5,10 @@ tape drive. Maintained by Kai Mäkisara (email Kai.Makisara@kolumbus.fi) - Copyright by Kai Mäkisara, 1998 - 2005. The program may be distributed + Copyright by Kai Mäkisara, 1998 - 2008. The program may be distributed according to the GNU Public License - Last Modified: Sun Aug 21 21:48:06 2005 by kai.makisara + Last Modified: Sun Apr 27 19:49:00 2008 by kai.makisara */ #include @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "mtio.h" @@ -27,7 +29,7 @@ #define DEFTAPE "/dev/tape" /* default tape device */ #endif /* DEFTAPE */ -#define VERSION "0.9b" +#define VERSION "1.1" typedef int (* cmdfunc)(/* int, struct cmdef_tr *, int, char ** */); @@ -66,6 +68,7 @@ static int do_partseek(int, cmdef_tr *, int, char **); static int do_status(int, cmdef_tr *, int, char **); static int print_densities(int, cmdef_tr *, int, char **); static int do_asf(int, cmdef_tr *, int, char **); +static int do_show_options(int, cmdef_tr *, int, char **); static void test_error(int, cmdef_tr *); static cmdef_tr cmds[] = { @@ -159,6 +162,8 @@ static cmdef_tr cmds[] = { ET_ONLINE }, { "asf", 0, do_asf, MTREW, FD_RDONLY, ONE_ARG, ET_ONLINE }, + { "stshowopt", 0, do_show_options, 0, FD_RDONLY, ONE_ARG, + 0 }, { NULL, 0, 0, 0 } }; @@ -210,14 +215,18 @@ static struct densities { {0x29, "QIC-3080MC"}, {0x30, "AIT-1 or MLR3"}, {0x31, "AIT-2"}, - {0x32, "AIT-3"}, + {0x32, "AIT-3 or SLR7"}, {0x33, "SLR6"}, {0x34, "SLR100"}, {0x40, "DLT1 40 GB, or Ultrium"}, {0x41, "DLT 40GB, or Ultrium2"}, {0x42, "LTO-2"}, + {0x44, "LTO-3"}, {0x45, "QIC-3095-MC (TR-4)"}, - {0x47, "TR-5"}, + {0x46, "LTO-4"}, + {0x47, "DDS-5 or TR-5"}, + {0x51, "IBM 3592 J1A"}, + {0x52, "IBM 3592 E05"}, {0x80, "DLT 15GB uncomp. or Ecrix"}, {0x81, "DLT 15GB compressed"}, {0x82, "DLT 20GB uncompressed"}, @@ -258,6 +267,7 @@ static struct booleans { #ifdef MT_ST_SYSV {"sysv", MT_ST_SYSV, "enable the SystemV semantics"}, #endif + {"sili", MT_ST_SILI, "enable SILI for variable block mode"}, {"cleaning", MT_ST_SET_CLN, "set the cleaning bit location and mask"}, {NULL, 0}}; @@ -673,6 +683,72 @@ do_status(int mtfd, cmdef_tr *cmd, int argc, char **argv) } +/* From linux/drivers/scsi/st.[ch] */ +#define ST_NBR_MODE_BITS 2 +#define ST_NBR_MODES (1 << ST_NBR_MODE_BITS) +#define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS) +#define ST_MODE_MASK ((ST_NBR_MODES - 1) << ST_MODE_SHIFT) +#define TAPE_NR(minor) ( (((minor) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \ + ((minor) & ~(-1 << ST_MODE_SHIFT)) ) +#define TAPE_MODE(minor) (((minor) & ST_MODE_MASK) >> ST_MODE_SHIFT) +static const char *st_formats[] = { + "", "r", "k", "s", "l", "t", "o", "u", + "m", "v", "p", "x", "a", "y", "q", "z"}; + +/* Show the options if visible in sysfs */ +static int do_show_options(int mtfd, cmdef_tr *cmd, int argc, char **argv) +{ + int i, fd, options, tapeminor, tapeno, tapemode; + struct stat stat; + struct utsname uts; + char fname[100], buf[20]; + + if (uname(&uts) < 0) { + perror(tape_name); + return 2; + } + sscanf(uts.release, "%d.%d.%d", &i, &tapeno, &tapemode); + if (i < 2 || tapeno < 6 || tapemode < 26) + printf("Your kernel (%d.%d.%d) may be too old for this command.\n", + i, tapeno, tapemode); + + if (fstat(mtfd, &stat) < 0) { + perror(tape_name); + return 1; + } + + if (!(stat.st_mode & S_IFCHR)) { + fprintf(stderr, "mt: not a character device.\n"); + return 1; + } + + tapeminor = minor(stat.st_rdev); + tapeno = TAPE_NR(tapeminor); + tapemode = TAPE_MODE(tapeminor); + tapemode <<= 4 - ST_NBR_MODE_BITS; /* from st.c */ + sprintf(fname, "/sys/class/scsi_tape/st%d%s/options", tapeno, + st_formats[tapemode]); + /* printf("Trying file '%s' (st_rdev 0x%lx).\n", fname, stat.st_rdev); */ + + if ((fd = open(fname, O_RDONLY)) < 0 || + read(fd, buf, 20) < 0) { + fprintf(stderr, "Can't read the sysfs file '%s'.\n", fname); + return 2; + } + close(fd); + + options = strtol(buf, NULL, 0); + + printf("The options set:"); + for (i=0; boolean_tbl[i].name != NULL; i++) + if (options & boolean_tbl[i].bitmask) + printf(" %s", boolean_tbl[i].name); + printf("\n"); + + return 0; +} + + /* Print a list of possible density codes */ static int print_densities(int fd, cmdef_tr *cmd, int argc, char **argv) diff --git a/mtio.h b/mtio.h index 692088c..3bbfc56 100644 --- a/mtio.h +++ b/mtio.h @@ -1,8 +1,9 @@ /* * linux/mtio.h header file for Linux. Written by H. Bergman * - * Modified for special ioctls provided by zftape in September 1997 - * by C.-J. Heine. + * Sanitized version for mt/stinit (definitions not used by these + * programs have been removed) 7 Oct 2007/Kai Mäkisara + * */ #ifndef _LINUX_MTIO_H @@ -10,7 +11,6 @@ #include #include -#include /* * Structures and definitions for mag tape io control commands @@ -110,38 +110,6 @@ struct mtget { #define MT_ISSCSI1 0x71 /* Generic ANSI SCSI-1 tape unit */ #define MT_ISSCSI2 0x72 /* Generic ANSI SCSI-2 tape unit */ -/* QIC-40/80/3010/3020 ftape supported drives. - * 20bit vendor ID + 0x800000 (see ftape-vendors.h) - */ -#define MT_ISFTAPE_UNKNOWN 0x800000 /* obsolete */ -#define MT_ISFTAPE_FLAG 0x800000 - -struct mt_tape_info { - long t_type; /* device type id (mt_type) */ - char *t_name; /* descriptive name */ -}; - -#define MT_TAPE_INFO { \ - {MT_ISUNKNOWN, "Unknown type of tape device"}, \ - {MT_ISQIC02, "Generic QIC-02 tape streamer"}, \ - {MT_ISWT5150, "Wangtek 5150, QIC-150"}, \ - {MT_ISARCHIVE_5945L2, "Archive 5945L-2"}, \ - {MT_ISCMSJ500, "CMS Jumbo 500"}, \ - {MT_ISTDC3610, "Tandberg TDC 3610, QIC-24"}, \ - {MT_ISARCHIVE_VP60I, "Archive VP60i, QIC-02"}, \ - {MT_ISARCHIVE_2150L, "Archive Viper 2150L"}, \ - {MT_ISARCHIVE_2060L, "Archive Viper 2060L"}, \ - {MT_ISARCHIVESC499, "Archive SC-499 QIC-36 controller"}, \ - {MT_ISQIC02_ALL_FEATURES, "Generic QIC-02 tape, all features"}, \ - {MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \ - {MT_ISTEAC_MT2ST, "Teac MT-2ST 155mb data cassette drive"}, \ - {MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \ - {MT_ISONSTREAM_SC, "OnStream SC-, DI-, DP-, or USB tape drive"}, \ - {MT_ISSCSI1, "Generic SCSI-1 tape"}, \ - {MT_ISSCSI2, "Generic SCSI-2 tape"}, \ - {0, NULL} \ -} - /* structure for MTIOCPOS - mag tape get position command */ @@ -149,139 +117,6 @@ struct mtpos { long mt_blkno; /* current block number */ }; - -/* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended - * as an interim solution for QIC-02 until DDI is fully implemented. - */ -struct mtconfiginfo { - long mt_type; /* drive type */ - long ifc_type; /* interface card type */ - unsigned short irqnr; /* IRQ number to use */ - unsigned short dmanr; /* DMA channel to use */ - unsigned short port; /* IO port base address */ - - unsigned long debug; /* debugging flags */ - - unsigned have_dens:1; - unsigned have_bsf:1; - unsigned have_fsr:1; - unsigned have_bsr:1; - unsigned have_eod:1; - unsigned have_seek:1; - unsigned have_tell:1; - unsigned have_ras1:1; - unsigned have_ras2:1; - unsigned have_ras3:1; - unsigned have_qfa:1; - - unsigned pad1:5; - char reserved[10]; -}; - -/* structure for MTIOCVOLINFO, query information about the volume - * currently positioned at (zftape) - */ -struct mtvolinfo { - unsigned int mt_volno; /* vol-number */ - unsigned int mt_blksz; /* blocksize used when recording */ - unsigned int mt_rawsize; /* raw tape space consumed, in kb */ - unsigned int mt_size; /* volume size after decompression, in kb */ - unsigned int mt_cmpr:1; /* this volume has been compressed */ -}; - -/* raw access to a floppy drive, read and write an arbitrary segment. - * For ftape/zftape to support formatting etc. - */ -#define MT_FT_RD_SINGLE 0 -#define MT_FT_RD_AHEAD 1 -#define MT_FT_WR_ASYNC 0 /* start tape only when all buffers are full */ -#define MT_FT_WR_MULTI 1 /* start tape, continue until buffers are empty */ -#define MT_FT_WR_SINGLE 2 /* write a single segment and stop afterwards */ -#define MT_FT_WR_DELETE 3 /* write deleted data marks, one segment at time */ - -struct mtftseg -{ - unsigned mt_segno; /* the segment to read or write */ - unsigned mt_mode; /* modes for read/write (sync/async etc.) */ - int mt_result; /* result of r/w request, not of the ioctl */ - void *mt_data; /* User space buffer: must be 29kb */ -}; - -/* get tape capacity (ftape/zftape) - */ -struct mttapesize { - unsigned long mt_capacity; /* entire, uncompressed capacity - * of a cartridge - */ - unsigned long mt_used; /* what has been used so far, raw - * uncompressed amount - */ -}; - -/* possible values of the ftfmt_op field - */ -#define FTFMT_SET_PARMS 1 /* set software parms */ -#define FTFMT_GET_PARMS 2 /* get software parms */ -#define FTFMT_FORMAT_TRACK 3 /* start formatting a tape track */ -#define FTFMT_STATUS 4 /* monitor formatting a tape track */ -#define FTFMT_VERIFY 5 /* verify the given segment */ - -struct ftfmtparms { - unsigned char ft_qicstd; /* QIC-40/QIC-80/QIC-3010/QIC-3020 */ - unsigned char ft_fmtcode; /* Refer to the QIC specs */ - unsigned char ft_fhm; /* floppy head max */ - unsigned char ft_ftm; /* floppy track max */ - unsigned short ft_spt; /* segments per track */ - unsigned short ft_tpc; /* tracks per cartridge */ -}; - -struct ftfmttrack { - unsigned int ft_track; /* track to format */ - unsigned char ft_gap3; /* size of gap3, for FORMAT_TRK */ -}; - -struct ftfmtstatus { - unsigned int ft_segment; /* segment currently being formatted */ -}; - -struct ftfmtverify { - unsigned int ft_segment; /* segment to verify */ - unsigned long ft_bsm; /* bsm as result of VERIFY cmd */ -}; - -struct mtftformat { - unsigned int fmt_op; /* operation to perform */ - union fmt_arg { - struct ftfmtparms fmt_parms; /* format parameters */ - struct ftfmttrack fmt_track; /* ctrl while formatting */ - struct ftfmtstatus fmt_status; - struct ftfmtverify fmt_verify; /* for verifying */ - } fmt_arg; -}; - -struct mtftcmd { - unsigned int ft_wait_before; /* timeout to wait for drive to get ready - * before command is sent. Milliseconds - */ - qic117_cmd_t ft_cmd; /* command to send */ - unsigned char ft_parm_cnt; /* zero: no parm is sent. */ - unsigned char ft_parms[3]; /* parameter(s) to send to - * the drive. The parms are nibbles - * driver sends cmd + 2 step pulses */ - unsigned int ft_result_bits; /* if non zero, number of bits - * returned by the tape drive - */ - unsigned int ft_result; /* the result returned by the tape drive*/ - unsigned int ft_wait_after; /* timeout to wait for drive to get ready - * after command is sent. 0: don't wait */ - int ft_status; /* status returned by ready wait - * undefined if timeout was 0. - */ - int ft_error; /* error code if error status was set by - * command - */ -}; - /* mag tape io control commands */ #define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */ #define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */ @@ -366,6 +201,7 @@ struct mtftcmd { #define MT_ST_SCSI2LOGICAL 0x800 #define MT_ST_SYSV 0x1000 #define MT_ST_NOWAIT 0x2000 +#define MT_ST_SILI 0x4000 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */ #define MT_ST_CLEAR_DEFAULT 0xfffff diff --git a/stinit.8 b/stinit.8 index 341c185..3e3da4b 100644 --- a/stinit.8 +++ b/stinit.8 @@ -1,4 +1,4 @@ -.TH STINIT 8 "August 2005" \" -*- nroff -*- +.TH STINIT 8 "April 2008" \" -*- nroff -*- .SH NAME stinit \- initialize SCSI magnetic tape drives .SH SYNOPSIS @@ -234,6 +234,13 @@ Logical block addresses are used in the MTSEEK and MTIOCPOS commands if .I value is non-zero. The default is to use the device-specific addresses. +.IP sili=value +If +.I value +is non-zero, the SILI bit is set when reading in variable block mode. This +may speed up reading blocks shorter than the read byte count. Set this only if +you know that the drive supports SILI and the HBA reliably returns transfer +residual byte counts. Requires kernel version >= 2.6.26. .IP defs-for-w[rites]=value The parameters defining the tape format (density, block size, etc.) are forced when writing starts at the beginning of a tape if @@ -266,7 +273,7 @@ for the superuser. .SH AUTHOR The program is written by Kai Makisara . .SH COPYRIGHT -The program and the manual page are copyrighted by Kai Makisara, 1998-2005. +The program and the manual page are copyrighted by Kai Makisara, 1998-2008. They can be distributed according to the GNU Copyleft. .SH SEE ALSO st(4) mt(1) diff --git a/stinit.c b/stinit.c index fa18860..5a50341 100644 --- a/stinit.c +++ b/stinit.c @@ -1,11 +1,11 @@ /* This program initializes Linux SCSI tape drives using the inquiry data from the devices and a text database. - Copyright 1996-2005 by Kai Mäkisara (email Kai.Makisara@kolumbus.fi) + Copyright 1996-2008 by Kai Mäkisara (email Kai.Makisara@kolumbus.fi) Distribution of this program is allowed according to the GNU Public Licence. - Last modified: Sun Aug 21 21:47:51 2005 by kai.makisara + Last modified: Sun Apr 27 14:24:16 2008 by kai.makisara */ #include @@ -30,7 +30,7 @@ #endif #define SKIP_WHITE(p) for ( ; *p == ' ' || *p == '\t'; p++) -#define VERSION "0.9b" +#define VERSION "1.1" typedef struct _modepar_tr { int defined; @@ -58,6 +58,7 @@ typedef struct _devdef_tr { int long_timeout; int cleaning; int nowait; + int sili; modepar_tr modedefs[4]; } devdef_tr; @@ -265,6 +266,7 @@ find_pars(FILE *dbf, char *company, char *product, char *rev, devdef_tr *defs, defs->long_timeout = (-1); defs->cleaning = (-1); defs->nowait = (-1); + defs->sili = (-1); for (i=0; i < NBR_MODES; i++) { defs->modedefs[i].defined = FALSE; defs->modedefs[i].blocksize = (-1); @@ -370,6 +372,8 @@ find_pars(FILE *dbf, char *company, char *product, char *rev, devdef_tr *defs, defs->cleaning = num_arg(t); if ((t = find_string(defstr, "no-w", line, LINEMAX)) != NULL) defs->nowait = num_arg(t); + if ((t = find_string(defstr, "sili", line, LINEMAX)) != NULL) + defs->sili = num_arg(t); defs->modedefs[mode].defined = TRUE; if ((t = find_string(defstr, "block", line, LINEMAX)) != NULL) @@ -521,10 +525,10 @@ do_inquiry(char *tname, char *company, char *product, char *rev, int print_non_f } if (result) { close(fn); - sprintf(buffer, + sprintf((char *)buffer, "The SCSI INQUIRY for device '%s' failed (power off?)", tname); - perror(buffer); + perror((char *)buffer); return FALSE; } } @@ -570,7 +574,7 @@ tapenum(char *name) return dev; } else { /* Search from the device directories */ - for (dvd=devdirs; dvd->dir != NULL; dvd++) { + for (dvd=devdirs; dvd->dir[0] != 0; dvd++) { dn = dvd->dir; if ((dirp = opendir(dn)) == NULL) continue; @@ -758,6 +762,8 @@ set_defs(devdef_tr *defs, char **fnames) clear_set[0] = clear_set[1] = 0; if (defs->nowait >= 0) clear_set[defs->nowait != 0] |= MT_ST_NOWAIT; + if (defs->sili >= 0) + clear_set[defs->sili != 0] |= MT_ST_SILI; if (defs->modedefs[i].buffer_writes >= 0) clear_set[defs->modedefs[i].buffer_writes != 0] |= MT_ST_BUFFER_WRITES; if (defs->modedefs[i].async_writes >= 0) @@ -852,7 +858,7 @@ define_tape(int tapeno, FILE *dbf, devdef_tr *defptr, int print_non_found) } if (verbose > 1) for (i=0; i < NBR_MODES; i++) - printf("Mode %d, name '%s'\n", i, fnames[i]); + printf("Mode %d, name '%s'\n", i + 1, fnames[i]); tname = fnames[0]; if (!do_inquiry(tname, company, product, rev, print_non_found)) {