Ultrix-3.1/src/cmd/olx/mtx1.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
static char Sccsid[] = "@(#)mtx1.c 3.0 4/22/86";
/*
* ULTRIX-11 mag tape disk exerciser program (mtx).
*
* PART 1 - (mtx1.c)
*
* Part 1 does the initial setup and argument processing,
* writes the results into a file `mtx_??.arg' (?? = ts, tm, ht),
* and then calls part 2 of mtx, which is the actual exerciser.
* The mtx program is split into two sections to optimize
* memory usage.
*
* Fred Canter 6/23/82
* Bill Burns 4/84
* added event flags
* Chung-Wu Lee 2/22/85
* added TMSCP (TK50/TU81)
*
* This program exercises the tm11 - tu10/ts03, ts11/tsv05/tu80/tk25,
* tm02/3 - tu16/te16/tu77 or tk50 - tk50/tu81 mag tape subsystems,
* using the unix block and raw I/O interfaces at the user level.
* Each of the four types of tape controllers requires
* a dedicated copy of this program to exercise that
* tape controller. There can be a maximum of four
* copies of (mtx) running, the text segment is shared.
* Each copy of (mtx) can exercise all drives that
* are attached to its specified controller.
* (mtx) can only report on errors that are detected at
* the user level, i.e., hard errors.
* Detailed error information must be obtained
* from the error log (elp -ht, elp -tm, elp -ts or elp -tk).
*
* USAGE:
*
* mtx -h Print the help message.
*
* mtx -z # event flag bit position, used to start/stop
* exercisers
*
* mtx -tm Select the TM11 controller for testing.
* mtx -ts Select the TS11 controller for testing.
* mtx -ht Select the TM02/3 controller for testing.
* mtx -tk Select the TMSCP controller for testing.
*
* mtx -d# Select drive (#) for testing.
* Multiple [-d#] may be specified.
* All drives is default.
*
* mtx -n # Print (#) data errors per tape record,
* default # is 5, maximum is 256.
*
* mtx -e # Stop exercising a tape drive after # errors,
* Default # is 100, maximum is 1000.
*
* mtx -i Inhibit the drive status message.
*
* mtx -s Suppress the end of pass tape I/O
* statistics printouts.
*
* mtx -f# Specify (#) feet of tape to be used
* for the large file test.
* 10 feet min, 2400 feet max, & 500 feet default,
* 10 foot minimum increments, rounded down.
* But for TK50, it specify (#) records) of tape to be
* used for the large file test.
* 1 record min, 10000 records max, & 500 records default.
*/
#include <sys/param.h> /* Don't matter which one ! */
#include <sys/devmaj.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <signal.h>
#include <a.out.h>
#include <sys/tk_info.h>
#define RD 0
#define WRT 1
#define DMM 2
#define MEOF 3
#define MT_OFL 0100
#define MT_WL 040
#define MT_OPN 020
/*
* Mag tape block and raw I/O file names.
* mt & rmt are for 800 BPI.
* ht & rht are for 1600 BPI.
* gt & rgt are for 6250 BPI.
* tk & rtk are TK50 only.
*/
char mtn[] "/dev/mt";
char rmtn[] "/dev/rmt";
char htn[] "/dev/ht";
char rhtn[] "/dev/rht";
char gtn[] "/dev/gt";
char rgtn[] "/dev/rgt";
char tkn[] "/dev/tk";
char rtkn[] "/dev/rtk";
char devn[12];
/*
* Argument file name
*/
char afn[] = "mtx_xx.arg";
/*
* Help message.
*/
char *help[]
{
"\n\n(mtx) - ULTRIX-11 mag tape exerciser.",
"\nUsage:\n",
"\tmtx [-h] [-tm -ts -ht -tk] [-d#] [-n #] [-i] [-s] [-f#]",
"\n\t-h\tPrint this help message.",
"\n\t-tm\tSelect TM11 controller for testing.",
"\t-ts\tSelect TS11/TSV05/TU80/TK25 controller for testing.",
"\t-ht\tSelect TM02/3 controller for testing.",
"\t-tk\tSelect TMSCP controller for testing.",
"\t\tMust select one and only one controller.",
"\n\t-d#\tSelect drive (#) for testing.",
"\t\tMultiple drives may be selected.",
"\t\tThe default is all drives selected.",
"\n\t-n #\tPrint a maximum of (#) data compare errors",
"\t\tper tape record. The default is 5 errors printed.",
"\n\t-i\tInhibit the drive status printout.",
"\n\t-s\tSuppress the end of pass tape I/O statistics.",
"\n\t-f#\tSpecify (#) feet of tape to be used",
"\t\tfor the large file test (test 3).",
"\t\t10 feet minimum, 2400 feet maximum, 500 feet is default.",
"\t\t(#) must be specified in 10 foot increments.",
"\t\tBut for TK50, it specify (#) records of tape to be used",
"\t\tfor the large file test (test 3).",
"\t\t1 record min, 10000 records maximum, 500 records is default.",
"\n\n\n\n",
0
};
/*
* Mag tape drive type array.
* 0 = drive is not selected or special file does not exist.
* 1 = drive is on tm11 controller & special file exists.
* 2 = drive is on tm02/3 controller & special file exists.
* 3 = drive is on ts11 controller & special file exists.
* 4 = drive is tu81 and is on TMSCP controller & special file exists.
* 5 = drive is tk50 and is on TMSCP controller & special file exists.
* For each of the mtx processes the drive types will
* all be the same.
*/
char mt_dt[64];
/*
* Buffer for information returned from stat system call.
* Used to find the major device number of the tape, in order
* to know what type of tape controller is on the system.
*/
struct stat statb;
struct nlist nl[] =
{
{ "_ntk" },
{ "_tk_ctid" },
{ "_tk_csr" },
{ "" },
};
char tk_ctid[MAXTK];
int tk_csr[MAXTK];
int ntk;
int mem;
int errno; /* external error number variable */
int nfeet[MAXTK];
char argbuf[512];
int dflag, iflag, fflag, sflag, tmflag, tsflag, htflag, tkflag;
#ifdef EFLG
char *efbit;
char *efids;
int zflag;
#else
char *killfn = "mtx.kill";
#endif
int ndep = 5;
int ndrop = 100;
main(argc, argv)
char *argv[];
int argc;
{
int stop(), intr();
register int *ap;
register char *p;
register int i;
int j, k, fn, gtflag;
int dn, fd, md, maxdrvs;
char *n;
char c;
setpgrp(0, 31111);
signal(SIGTTOU, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGQUIT, stop);
fn = 0;
for(i=1; i < MAXTK; i++)
nfeet[i] = 0;
for(i=1; i < argc; i++) { /* decode arg's */
p = argv[i];
if(*p++ != '-') {
argerr:
fprintf(stderr,"\nmtx: bad arg\n");
exit(1);
}
switch(*p) {
case 'h': /* print the help message */
/* or select controller type */
if(*++p == 't') {
htflag++; /* tm02/3 */
break;
}
for(j=0; help[j]; j++)
printf("\n%s",help[j]);
exit();
#ifdef EFLG
case 'z':
zflag++;
i++;
efbit = argv[i++];
efids = argv[i];
break;
#else
case 'r': /* kill file name */
i++;
killfn = argv[i];
break;
#endif
case 'i': /* inhibit drive status */
iflag++;
break;
case 'n': /* # of errors to print */
i++;
ndep = atoi(argv[i]);
if((ndep <= 0) || (ndep > 256))
ndep = 5;
break;
case 'e': /* drop drive after # errors */
i++;
ndrop = atoi(argv[i]);
if((ndrop <= 0) || (ndrop > 1000))
ndrop = 100;
break;
case 'd': /* drive select */
dflag++;
p++;
dn = atoi(p);
if(dn >= 64)
goto argerr;
mt_dt[dn] = 1;
break;
case 'f': /* # of feet of tape */
fflag++;
p++;
nfeet[fn++] = atoi(p);
break;
case 's': /* suppress I/O stats */
sflag++;
break;
case 't': /* select controller type */
if(*++p == 'm')
tmflag++;
if(*p == 's')
tsflag++;
if(*p == 'k')
tkflag++;
break;
default: /* bad argument */
goto argerr;
}
}
if(!zflag) {
if(isatty(2)) {
fprintf(stderr,"mtx: detaching... type \"sysxstop\" to stop\n");
fflush(stderr);
}
if((i = fork()) == -1) {
printf("mtx: Can't fork new copy !\n");
exit(1);
}
if(i != 0)
exit(0);
}
setpgrp(0, 31111);
/*
* Verify that one and only one type of tape
* controller has been selected for testing.
*/
if((i = tmflag + tsflag + htflag + tkflag) != 1) {
fprintf(stderr,"\nmtx: Controller specification error\n");
exit(1);
}
/*
* In order not to waste time
* opening drives that can't exist,
* the variable "maxdrvs" is set to the maximum
* number of drives that can exist for the type
* of controller to exercised.
* TS = 4, TM = 8, HT = 64, TK = 4
*/
if(tsflag) {
maxdrvs = 4;
afn[4] = 't';
afn[5] = 's';
} else if(tmflag) {
maxdrvs = 8;
afn[4] = 't';
afn[5] = 'm';
} else if(htflag) {
maxdrvs = 64;
afn[4] = 'h';
afn[5] = 't';
} else {
nlist("/unix", nl);
if(nl[0].n_type == 0) {
fprintf(stderr,"\nmtx: kernel not configured for TMSCP magtape\n");
exit(1);
}
if((mem = open("/dev/mem", 0)) < 0) {
fprintf(stderr,"\nmtx: can't open /dev/mem\n");
exit(1);
}
lseek(mem, (long)nl[0].n_value, 0);
read(mem, &ntk, sizeof(ntk));
if(ntk <= 0) {
fprintf(stderr,"\nmtx: kernel not configured for TMSCP magtape\n");
exit(1);
}
lseek(mem, (long)nl[1].n_value, 0);
read(mem, &tk_ctid, sizeof(tk_ctid));
lseek(mem, (long)nl[2].n_value, 0);
read(mem, &tk_csr, sizeof(tk_csr));
maxdrvs = MAXTK;
afn[4] = 't';
afn[5] = 'k';
}
/*
* IF no drives were selected with -d#,
* then select all drives.
*/
if(!dflag) {
for(i=0; i<maxdrvs; i++)
mt_dt[i] = 1;
}
/*
* Set up the number of feet of tape
* to be used for large file test.
*
* for TMSCP, it is number of blocks
* to be used for large file test.
*/
if (!tkflag) {
if(!fflag)
nfeet[0] = 500;
if(nfeet[0] < 10)
nfeet[0] = 10;
if(nfeet[0] > 2400)
nfeet[0] = 2400;
}
else {
for (i=0; i<ntk; i++) {
if (((tk_ctid[i] >> 4)&017) == TK50) {
if(!fflag)
nfeet[i] = 500;
if(nfeet[i] < 1)
nfeet[i] = 1;
if(nfeet[i] > 10000)
nfeet[i] = 10000;
} else if (((tk_ctid[i] >> 4)&017) == TU81) {
if(!fflag)
nfeet[i] = 500;
if(nfeet[i] < 10)
nfeet[i] = 10;
if(nfeet[i] > 2400)
nfeet[i] = 2400;
}
}
}
/*
* Use the stat system call to determine how many of the
* selected drives have special files and what drive type
* they are.
* The special file for the selected unit is checked.
* It must be a block mode special file.
* The major device number of the special file is
* compared with the major device numbers in the
* devmaj.h header file to determine the drive type.
* For the tm11 & ts11 the minor device number of the
* special file must match the unit number.
* For the tm02/3 at 800 BPI the minor device
* number in the special file must match the unit
* number plus 64.
* For the tm02/3 at 1600 BPI it must match the unit number.
*/
for(i=0; i<maxdrvs; i++) {
if(!mt_dt[i])
continue;
if (!tkflag) {
sprintf(&devn, "%s%d", mtn, i);
if(tsflag)
dn = -1;
else
dn = stat(&devn, &statb);
if(dn < 0) {
sprintf(&devn, "%s%d", htn, i);
dn = stat(&devn, &statb);
if(dn < 0) {
mt_dt[i] = 0;
continue;
}
}
if((statb.st_mode & S_IFMT) != S_IFBLK)
goto sferr; /* not block mode special file */
md = (statb.st_rdev >> 8) & 077; /* major device */
dn = statb.st_rdev & 0377; /* minor device */
if(tmflag && md == TM_BMAJ && dn == i)
mt_dt[i] = 1; /* tm11 */
else if(tsflag && md == TS_BMAJ && dn == i)
mt_dt[i] = 3; /* ts11 */
else if(htflag && md == HT_BMAJ && dn == (i + 64)) {
sprintf(&devn, "%s%d", htn, i);
dn = stat(&devn, &statb);
if(dn < 0)
goto sferr;
md = (statb.st_rdev >> 8) & 077;
dn = statb.st_rdev & 0377;
if(md != HT_BMAJ || dn != i)
goto sferr;
mt_dt[i] = 2; /* tm02/3 */
} else {
sferr:
fprintf(stderr,"\nmtx: %s - special file mismatch\n",devn);
exit(1);
}
}
else {
if (tk_csr[i]) {
if (((tk_ctid[i] >> 4)&017) == TK50) {
sprintf(&devn, "%s%d", tkn, i);
dn = stat(&devn, &statb);
if(dn < 0) {
mt_dt[i] = 0;
continue;
}
mt_dt[i] = 5;
}
else if (((tk_ctid[i] >> 4)&017) == TU81) {
gtflag = 0;
sprintf(&devn, "%s%d", htn, i);
dn = stat(&devn, &statb);
if(dn < 0) {
sprintf(&devn, "%s%d", gtn, i);
dn = stat(&devn, &statb);
gtflag = 1;
}
if(dn < 0 && gtflag == 1) {
mt_dt[i] = 0;
continue;
}
else if (dn < 0 || gtflag == 1)
goto sferr;
mt_dt[i] = 4;
}
else
mt_dt[i] = 0;
}
else
mt_dt[i] = 0;
}
/*
* Deselect any drive that has a special file
* but cannot actually be opened, i.e. , is
* nonexistent, off-line, write locked,
* or is already open.
*/
if(mt_dt[i] == 1 || mt_dt[i] == 2) {
sprintf(&devn, "%s%d", mtn, i);
if((fd = open(&devn, WRT)) < 0) {
if(errno == ETOL)
mt_dt[i] |= MT_OFL;
else if(errno == ETWL)
mt_dt[i] |= MT_WL;
else if(errno == ETO)
mt_dt[i] |= MT_OPN;
}
close(fd);
}
if(mt_dt[i] >= 2 && mt_dt[i] <= 4) {
sprintf(&devn, "%s%d", htn, i);
if((fd = open(&devn, WRT)) < 0) {
if(errno == ETOL)
mt_dt[i] |= MT_OFL;
else if(errno == ETWL)
mt_dt[i] |= MT_WL;
else if(errno == ETO)
mt_dt[i] |= MT_OPN;
}
close(fd);
}
if(mt_dt[i] == 4) {
sprintf(&devn, "%s%d", gtn, i);
if((fd = open(&devn, WRT)) < 0) {
if(errno == ETOL)
mt_dt[i] |= MT_OFL;
else if(errno == ETWL)
mt_dt[i] |= MT_WL;
else if(errno == ETO)
mt_dt[i] |= MT_OPN;
}
close(fd);
}
if(mt_dt[i] == 5) {
sprintf(&devn, "%s%d", tkn, i);
if((fd = open(&devn, WRT)) < 0) {
if(errno == ETOL)
mt_dt[i] |= MT_OFL;
else if(errno == ETWL)
mt_dt[i] |= MT_WL;
else if(errno == ETO)
mt_dt[i] |= MT_OPN;
}
close(fd);
}
}
/*
* Print the drive status.
*/
j = 0;
if(!iflag) {
for(i=0; i<maxdrvs; i++) {
if(mt_dt[i] == 0)
continue;
k = mt_dt[i] & 7;
if(mt_dt[i] <= 5)
j++;
printf("\nUnit %d - ",i);
if(k == 1)
printf("tm11 - tu10/ts03");
else if(k == 2)
printf("tm02/3 - tu16/te16");
else if(k == 3)
printf("ts11/tsv05/tsu05/tu80/tk25");
else if(k == 4)
printf("tu81");
else
printf("tk50");
if(mt_dt[i] & MT_OFL) {
printf(" [off-line]");
j++;
}
else if(mt_dt[i] & MT_WL)
printf(" [write locked]");
else if(mt_dt[i] & MT_OPN)
printf(" [already open]");
}
if(j == 0) {
printf("\n\nNo drives available\n");
exit(1);
}
}
/*
* Write data needed by mtx2 into the `argbuf',
* write it out to a file and call mtx2.
*/
p = &argbuf;
for(i=0; i<64; i++)
*p++ = mt_dt[i];
ap = p;
*ap++ = sflag;
*ap++ = tsflag;
*ap++ = tmflag;
*ap++ = htflag;
*ap++ = tkflag;
for(i=0; i<MAXTK; i++)
*ap++ = nfeet[i];
*ap++ = ndep;
*ap++ = ndrop;
*ap++ = maxdrvs;
#ifdef EFLG
*ap++ = zflag;
#endif
if((fd = creat(afn, 0644)) < 0) {
fprintf(stderr, "\nmtx: Can't create %s file\n", afn);
exit(1);
}
if(write(fd, (char *)&argbuf, 512) != 512) {
fprintf(stderr, "\nmtx: %s write error\n", afn);
exit(1);
}
close(fd);
fflush(stdout);
signal(SIGQUIT, SIG_IGN);
#ifdef EFLG
if(zflag)
execl("mtxr", "mtxr", afn, efbit, efids, (char *)0);
else
execl("mtxr", "mtxr", afn, (char *)0);
#else
execl("mtxr", "mtxr", afn, killfn, (char *)0);
#endif
fprintf(stderr, "\nmtx: Can't exec mtxr\n");
exit(1);
}
stop()
{
exit(0);
}