Ultrix-3.1/src/cmd/olx/mtx2.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
static char Sccsid[] = "@(#)mtx2.c 3.0 4/22/86";
/*
* ULTRIX-11 mag tape disk exerciser program (mtx).
*
* PART 2 - (mtx2.c)
*
* Part 2 is called from part 1 (mtx) with arguments in the
* file `mtx_??.arg' (?? = ts, tm, ht, tk). This is the actual
* magtape exerciser. The mtx program is split into two sections
* to optimize memory usage.
*
* Fred Canter 10/15/82
* Bill Burns 4/82
* added event flag usage
* Chung-Wu Lee 2/22/85
* added TMSCP
* George Mathew 7/2/85
* changes for 1K file system
*
* 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 mtx_??.arg efpis efids
* ^ ^
* | event flag bit position and id
* argument passing file name; ht, mt, or ts
*
*/
#include <sys/param.h> /* Don't matter which one ! */
#include <sys/devmaj.h>
#include <sys/tk_info.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <signal.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 for 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];
char *afp; /* Argument file pointer */
char eplmsg[] "\n\n[error printout limit exceeded]";
char noeof[] "\n\n[missing EOF or extra record(s) at end of file]";
/*
* 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];
/*
* Tape write, read, hard error counts.
*/
long rdcnt[64];
long wrtcnt[64];
long hecnt[64];
/*
* The following three lines of code
* are the interface to the system call
* error return messages.
*/
int errno;
int sys_nerr;
char *sys_errlist[];
time_t stbuf; /* I/O statistics time */
time_t btbuf; /* Exerciser run beginning time */
time_t etbuf; /* Exerciser run ending time */
time_t timbuf;
struct tm *tl; /* structure for localtime */
char btime[13]; /* ascii beg time yymmddhhmmss */
char etime[13]; /* ascii end time yymmddhhmmss */
char *tapen; /* name of tape controller */
int wrterr;
int werec;
int rderr;
long randx;
int nfeet[MAXTK];
int pat[] =
{
0000000, /* lo & hi byte all 0's */
0177777, /* lo & hi byte all 1's */
0000377, /* lo byte all 1's, hi byte all 0's */
0177400, /* lo byte all 0's, hi byte all 1's */
0052525, /* lo & hi byte alt 1's & 0's */
0125252, /* lo & hi byte alt 0's & 1's */
0125125, /* lo byte alt 1's & 0's, hi byte comp. */
0052652, /* lo byte alt 0's & 1's, hi byte comp. */
0177001, /* lo byte walking 1, hi byte walking 0 */
0176402, /* " */
0175404, /* " */
0173410, /* " */
0167420, /* " */
0157440, /* " */
0137500, /* " */
0077600, /* " */
0125220, /* address pattern, in case of */
0052521, /* write buffer overrun */
0166422,
0177423,
};
/*
* Write and read buffer address offsets.
*/
int w_off, r_off;
int testno;
/*
* Write/Read buffer,
* large enough for 20 512-byte records.
*/
#ifdef UCB_NKB
char buf[20*1024];
#else
char buf[20*512];
#endif
int sflag, tmflag, htflag, tsflag, tkflag;
#ifdef EFLG
#include <sys/eflg.h>
char *efpis;
char *efids;
int efbit;
int efid;
long evntflg();
int zflag;
#else
char *killfn;
#endif
int stopsig;
int ndrop, ndep;
int rbc; /* byte count returned from read/write calls */
main(argc, argv)
char *argv[];
int argc;
{
int stop(), intr();
register *wp, *rp;
register int k;
FILE *argf;
int *wba, *rba;
int *wbp, *rbp;
int i, j;
int dn, fd, md, maxdrvs;
int nrec, nbytes;
int cnt, iomode, density;
int fsterr, neb;
int dpat;
char *p;
char c;
#ifdef UCB_NKB
int maxrec, recsize;
#endif
/*
* Read needed data from the `mtx_??.arg' file,
* and start the exerciser.
*/
signal(SIGINT, SIG_IGN);
signal(SIGTERM, intr);
signal(SIGQUIT, stop);
close(stdin);
if((argc < 2) || (argc > 4))
exit(1);
afp = argv[1];
if((fd = open(afp, RD)) < 0) {
fprintf(stderr, "\nmtx: Can't open %s\n", afp);
exit(1);
}
if((rbc = read(fd, (char *)&buf, 512)) != 512) {
fprintf(stderr, "\nmtx: %s read error\n", afp);
exit(1);
}
p = &buf;
for(i=0; i<64; i++)
mt_dt[i] = *p++;
rbp = p;
sflag = *rbp++;
tsflag = *rbp++;
tmflag = *rbp++;
htflag = *rbp++;
tkflag = *rbp++;
for(i=0; i<MAXTK; i++)
nfeet[i] = *rbp++;
ndep = *rbp++;
ndrop = *rbp++;
maxdrvs = *rbp++;
#ifdef EFLG
zflag = *rbp++;
#endif
close(fd);
unlink(afp);
#ifdef EFLG
if(zflag) {
efpis = argv[2];
efids = argv[3];
}
#else
killfn = argv[2]; /* run/stop control file name */
#endif
/*
* Print the mtx started message.
*/
time(&btbuf);
randx = btbuf & 0777;
if(tmflag)
tapen = "TM11";
if(tsflag)
tapen = "TS11/TSV05/TSU05/TU80/TK25";
if(htflag)
tapen = "TM02/3";
if(tkflag)
tapen = "TK50/TU81";
printf("\n\n%s magtape exerciser started - %s\n", tapen, ctime(&btbuf));
fflush(stdout);
#ifdef EFLG
if(zflag) {
efbit = atoi(efpis);
efid = atoi(efids);
evntflg(EFCLR, efid, (long)efbit);
}
#else
unlink(killfn);
#endif
/*
* TEST 1 - SHORT FILE TEST
*
* The following test is done on each of the selected tape
* units that is available.
* The test is done in block and raw I/O modes for 800, 1600
* 6250 BPI density or just tk50
* The test consists of writing a number of 512 byte records
* to tape from the write buffer.
* Reading the same number of records into the read buffer
* and comparing the data in the write and read buffers.
* A pass is 32 of the above write/read/compare tests.
* The number of records starts at one and increases to 16,
* and then decreases from 16 back down to one.
* The test insures that the correct number of tape records
* were written by attempting to read one extra record
* and checking for an end of file error.
* The write address is rotated from the end of the
* write buffer towards the beginning write buffer.
* The read address is rotated, within a very narrow range
* ( 32 words), from the start towards the end of
* the read buffer.
* The word before the start of the read data in the read
* buffer and the word after the read data are tested
* to insure that the data was transferred only to the
* correct addresses in the read buffer.
* The data patterns in pat[0] thru pat[19] are loaded
* into the write buffer at the start of the test and
* are constant throughout the test 1.
*/
loop:
wba = &buf;
rba = wba + (18*256);
wp = wba;
*wp++ = pat[0]; /* load first word of write buffer */
for(j=0; j<17; j++) /* fill write buffer with data patterns */
for(k=0; k<256; k++)
*wp++ = pat[j];
testno = 1;
for(cnt=0; cnt<256; cnt++)
{ /* BIG loop, tests all units in all modes */
dn = cnt & 077; /* unit # to be tested */
iomode = cnt & 0100; /* block or raw I/O mode */
/*
* density 0 - 800 BPI (tm11, tm02/3), 1600 BPI (tu81) or tk50
* 1 - 1600 BPI (ts11, tm02/3), 6250 BPI (tu81) but no tk50
*/
density = cnt & 0200; /* 800 ro 1600 BPI density */
if(!mt_dt[dn])
continue; /* unit not selected */
if(!density && ((mt_dt[dn] & 07) == 3))
continue; /* no 800 BPI on ts11 */
if(density && ((mt_dt[dn] & 07) == 1 || (mt_dt[dn] & 07) == 5))
continue; /* no 1600 BPI if unit is tm11 */
mtname(dn, density, iomode); /* generate magtape filename */
#ifndef UCB_NKB
for(i=0; i<32; i++) { /* one test pass */
fd = mtopen(WRT);
if(i < 16) /* set up record count & write offset */
nrec = i + 1;
else
nrec = 32 - i;
w_off = (16 - nrec)*256+1;
wbp = wba + w_off;
for(j=0; j<nrec; j++) {
wrterr = 0;
wrtcnt[dn]++;
wp = wbp + (j*256);
/* intr(); OLD: poll for stop */
if((rbc = write(fd, (char *)wp, 512)) != 512) {
trwse(WRT,dn,density,iomode,512,nrec,j+1);
/*
* WRITE errors are fatal, the "tuready"
* function waits a minimum of 15 minutes
* for the tape unit to be made ready.
*/
fd = tuready(fd);
break;
}
}
close(fd);
if(wrterr) { /* write error, so read must be adjusted */
printf("\n\n******\n");
if(werec == 0) {
printf("READ ABORTED - no records written");
printf("\n******\n");
continue;
} else {
nrec = werec;
printf("READ SHORTENED - %d records will be read",nrec);
}
printf("\n******\n");
}
fd = mtopen(RD);
for(j=0; j<nrec; j++) {
/*
* The read buffer offset is random
* and in the range of 1 - 4096.
*/
rderr = 0;
r_off = i + j;
rbp = rba + r_off;
for(k= -1; k<257; k++)
*(rbp + k) = ~*(wbp + (j*256) + k);
rdcnt[dn]++;
/* intr(); */
if((rbc = read(fd, (char *)rbp, 512)) != 512)
trwse(RD,dn,density,iomode,512,nrec,j+1);
fsterr = 1;
neb = 0;
/*
* Buffer over/under flow test.
* Check the words before and after the buffer
* to insure that data was read into the
* assigned buffer area and no where else.
*/
if((*(rbp - 1) != ~*(wbp + (j*256) - 1)) ||
(*(rbp + 256) != ~*(wbp + (j*256) + 256))) {
if(!rderr)
trwse(DMM,dn,density,iomode,512,nrec,j+1);
rderr++;
printf("\n\nREAD BUFFER OVERRUN ERROR");
printf("\n\nWord before read buffer");
pgb(-1, *(wbp + (j*256) - 1), *(rbp - 1));
printf("\n\nWord after read buffer");
pgb(-1, *(wbp + (j*256) + 256), *(rbp + 256));
}
for(k=0; k<256; k++) {
if(*(rbp + k) != *(wbp + (j*256) + k)) {
if(fsterr && !rderr)
trwse(DMM,dn,density,iomode,512,nrec,j+1);
if(fsterr)
printf("\n\nDATA COMPARE ERROR - RECORD %u",j+1);
fsterr = 0;
if(++neb > ndep) {
printf("%s",&eplmsg);
break;
}
pgb(k, *(wbp + (j*256) + k), *(rbp + k));
}
}
if(!fsterr)
printf("\n******\n");
if(rderr && (errno == ETPL)) {
printf("\n\n[READ ABORTED - ");
printf("fatal read error]\n******\n");
fd = tuready(fd); /* wait for tape ready */
goto fte1;
}
if(rderr && fsterr)
printf("\n******\n");
}
#else UCB_NKB
if (iomode) {
maxrec = 16;
recsize = 512;
} else {
maxrec = 8;
recsize = 1024;
}
for(i=0; i<(maxrec*2); i++) { /* one test pass */
fd = mtopen(WRT);
if(i < maxrec) /* set up record count & write offset */
nrec = i + 1;
else
nrec = maxrec*2 - i;
w_off = (maxrec - nrec)*(recsize/2)+1;
wbp = wba + w_off;
for(j=0; j<nrec; j++) {
wrterr = 0;
wrtcnt[dn]++;
wp = wbp + (j*(recsize/2));
/* intr(); OLD: poll for stop */
/*printf("before write: stopsig= %d\n",stopsig); */
if((rbc = write(fd, (char *)wp, recsize)) != recsize) {
trwse(WRT,dn,density,iomode,recsize,nrec,j+1);
/*
* WRITE errors are fatal, the "tuready"
* function waits a minimum of 15 minutes
* for the tape unit to be made ready.
*/
fd = tuready(fd);
break;
} /* else */
/*printf("\n*** write successful, record no=%d, nrec=%d\n",j+1,nrec); */
}
close(fd);
if(wrterr) { /* write error, so read must be adjusted */
printf("\n\n******\n");
if(werec == 0) {
printf("READ ABORTED - no records written");
printf("\n******\n");
continue;
} else {
nrec = werec;
printf("READ SHORTENED - %d records will be read",nrec);
}
printf("\n******\n");
}
fd = mtopen(RD);
for(j=0; j<nrec; j++) {
/*
* The read buffer offset is random
* and in the range of 1 - 4096.
*/
rderr = 0;
r_off = i + j;
/* printf("r_off=%d\t",r_off); */
rbp = rba + r_off;
/* printf("read buffer ptr: %d\n",rbp);*/
/* printf("before loop: stopsig= %d\t",stopsig); */
for(k= -1; k<(recsize/2 +1) ; k++)
*(rbp + k) = ~*(wbp + (j*(recsize/2)) + k);
/* printf("after loop: stopsig= %d\n",stopsig); */
rdcnt[dn]++;
/* intr(); */
if((rbc = read(fd, (char *)rbp, recsize)) != recsize) {
trwse(RD,dn,density,iomode,recsize,nrec,j+1);
/* printf("\n** no. of chars read=%d\n",rbc); */
} else {
/* printf("\n** read successful, record no=%d, nrec=%d",j+1,nrec); */
}
/* printf("after read: stopsig= %d\n", stopsig); */
fsterr = 1;
neb = 0;
/*
* Buffer over/under flow test.
* Check the words before and after the buffer
* to insure that data was read into the
* assigned buffer area and no where else.
*/
if((*(rbp - 1) != ~*(wbp + (j*(recsize/2)) - 1)) ||
(*(rbp + (recsize/2)) != ~*(wbp + (j*(recsize/2)) + (recsize/2)))) {
if(!rderr)
/* printf("\ncalling trwse after read, stopsig=%d\n",stopsig); */
trwse(DMM,dn,density,iomode,recsize,nrec,j+1);
rderr++;
printf("\n\nREAD BUFFER OVERRUN ERROR");
printf("\n\nWord before read buffer");
pgb(-1, *(wbp + (j*(recsize/2)) - 1), *(rbp - 1));
printf("\n\nWord after read buffer");
pgb(-1, *(wbp + (j*(recsize/2)) + (recsize/2)), *(rbp + (recsize/2)));
}
for(k=0; k<(recsize/2); k++) {
if(*(rbp + k) != *(wbp + (j*(recsize/2)) + k)) {
if(fsterr && !rderr)
trwse(DMM,dn,density,iomode,recsize,nrec,j+1);
if(fsterr)
printf("\n\nDATA COMPARE ERROR - RECORD %u",j+1);
fsterr = 0;
if(++neb > ndep) {
printf("%s",&eplmsg);
break;
}
pgb(k, *(wbp + (j*(recsize/2)) + k), *(rbp + k));
}
}
if(!fsterr)
printf("\n******\n");
if(rderr && (errno == ETPL)) {
printf("\n\n[READ ABORTED - ");
printf("fatal read error]\n******\n");
fd = tuready(fd); /* wait for tape ready */
goto fte1;
}
if(rderr && fsterr)
printf("\n******\n");
}
#endif
/*
* Check for end of file (EOF).
* Attempt to read one more record, if an error is
* returned then EOF is present. If read is successful
* then the EOF is missing or an extra record was written.
*/
if(iomode) /* only RAW mode for now */
{
/* intr(); */
if((rbc = read(fd, (char *)rba, 512)) != 0) {
trwse(MEOF,dn,density,iomode,512,nrec,(nrec+1));
printf("%s", &noeof);
if(wrterr) {
printf("\n[Most likely due to previous");
printf(" fatal write error]\n******\n");
}
}
}
fte1:
fflush(stdout);
close(fd);
}
/*
* The following is necessary because the tm03 tape controller
* will not allow the density to be changed unless the
* tape is at load point.
* This causes the first write after a density change to fail.
* To avoid this problem, the tape is opened at the previous
* density, the first record is read, the tape is closed, and
* then the process sleeps for 2 seconds ( or so ) while the
* tape drive is rewound to load point.
*/
if(htflag && ((!density && iomode) || (density && iomode))) {
fd = mtopen(RD);
read(fd, (char *)rba, 512);
close(fd);
sleep(1);
sleep(1);
}
}
/*
* TEST 2 - VARIABLE LENGTH RECORD TEST
*
* This test writes one record with a length that varies
* from 512 bytes to 10240 bytes in 512 byte increments.
* The record is read and the data comapared with
* the test pattern written.
* The write/read address is the start of the buffer.
* The data patterns are the complement of those
* in test 1, pat[0] thru pat[19].
* The test is done for all selected and available drives,
* in raw I/O mode, at 800 BPI and 1600 BPI
* (if rm02/3) densities.
*/
wba = &buf;
rba = &buf;
w_off = 0;
r_off = 0;
iomode = 1; /* RAW I/O mode only ! */
testno = 2;
for(cnt=0; cnt<128; cnt++)
{ /* BIG loop, tests all units */
dn = cnt & 077; /* unit # to be tested */
/*
* density 0 - 800 BPI (tm11, tm02/3), 1600 BPI (tu81) or tk50
* 1 - 1600 BPI (ts11, tm02/3), 6250 BPI (tu81) but no tk50
*/
density = cnt & 0100; /* 800 ro 1600 BPI density */
if(!mt_dt[dn])
continue; /* unit not selected */
if(!density && ((mt_dt[dn] & 07) == 3))
continue; /* no 800 BPI on ts11 */
if(density && ((mt_dt[dn] & 07) == 1 || (mt_dt[dn] & 07) == 5))
continue; /* no 1600 BPI if unit is tm11 */
mtname(dn, density, iomode); /* generate magtape filename */
for(i=0; i<20; i++) { /* one test pass */
fd = mtopen(WRT);
nbytes = 512 + (i*512);
wp = wba; /* load write buffer with pattern */
for(j=0; j<(i+1); j++)
for(k=0; k<256; k++)
*wp++ = ~pat[j];
nrec = 1;
wrterr = 0;
wrtcnt[dn]++;
/* intr(); */
if((rbc = write(fd, (char *)wba, nbytes)) != nbytes) {
trwse(WRT,dn,density,iomode,nbytes,nrec,1);
fd = tuready(fd); /* wait for tape unit ready */
}
close(fd);
if(wrterr) { /* fatal write error, no read */
printf("\n\n******\nREAD ABORTED - no records");
printf(" written\n******\n");
continue;
}
fd = mtopen(RD);
rderr = 0;
rp = rba; /* load read buffer with complement pattern */
for(j=0; j<(i+1); j++)
for(k=0; k<256; k++)
*rp++ = pat[j];
rdcnt[dn]++;
/* intr(); */
if((rbc = read(fd, (char *)rba, nbytes)) != nbytes)
trwse(RD,dn,density,iomode,nbytes,nrec,1);
fsterr = 1;
neb = 0;
rp = rba;
for(k=0; k<(nbytes/2); k++) {
if(*rp++ != ~pat[k/256]) {
if(fsterr && !rderr)
trwse(DMM,dn,density,iomode,nbytes,nrec,1);
if(fsterr)
printf("\n\nDATA COMPARE ERROR - RECORD %u",1);
fsterr = 0;
if(++neb > ndep) {
printf("%s",&eplmsg);
break;
}
pgb(k, ~pat[k/256], *(rba + k));
}
}
if(!fsterr)
printf("\n******\n");
if(rderr && (errno == ETPL)) {
printf("\n\n[READ ABORTED - ");
printf("fatal read error]\n******\n");
fd = tuready(fd);
goto fte2;
}
if(rderr && fsterr)
printf("\n******\n");
/*
* Check for end of file (EOF).
* Attempt to read one more record, if an error is
* returned then EOF is present. If read is successful
* then the EOF is missing or an extra record was written.
*/
/* intr(); */
if((rbc = read(fd, (char *)rba, 512)) != 0) {
trwse(MEOF,dn,density,iomode,512,nrec,(nrec+1));
printf("%s", &noeof);
}
fte2:
fflush(stdout);
close(fd);
}
/*
* The following is necessary because the tm03 tape controller
* will not allow the density to be changed unless the
* tape is at load point.
* This causes the first write after a density change to fail.
* To avoid this problem, the tape is opened at the previous
* density, the first record is read, the tape is closed, and
* then the process sleeps for 2 seconds ( or so ) while the
* tape drive is rewound to load point.
*/
if(htflag) {
fd = mtopen(RD);
read(fd, (char *)rba, 10240);
close(fd);
sleep(1);
sleep(1);
}
}
/*
* TEST 3 - LARGE FILE TEST
*
* This test simulates very large files, such as dump/restore
* tapes. It writes enough records to fill the
* number of feet of tape specified by "nfeet".
* The value of "nfeet" can be specifed by the [-f#] option,
* the default value is 500 feet. The minimum value is 10 feet and
* the maximum is 2400 feet.
* The test insures that the correct number of tape records
* were written by attempting to read an extra record
* and checking for an end of file error.
* The test is done in block and raw I/O modes at 800
* and 1600 BPI density.
* The record size is 1024 bytes for block mode and
* 10240 bytes for raw mode.
* For the 1024 bytes records the write/read addresses are
* rotated thru the buffer on block boundries.
* For the 10240 byte records the write/read address
* is the start of the buffer.
* Test data patterns (pat[0] -> pat[19]) are used
* for this test.
*/
testno = 3;
wba = &buf;
rba = &buf;
for(cnt=0; cnt<256; cnt++)
{ /* BIG loop, tests all units in all modes */
dn = cnt & 077; /* unit # to be tested */
iomode = cnt & 0100; /* block or raw I/O mode */
/*
* density 0 - 800 BPI (tm11, tm02/3), 1600 BPI (tu81) or tk50
* 1 - 1600 BPI (ts11, tm02/3), 6250 BPI (tu81) but no tk50
*/
density = cnt & 0200; /* 800 ro 1600 BPI density */
if(!mt_dt[dn])
continue; /* unit not selected */
if(!density && ((mt_dt[dn] & 07) == 3))
continue; /* no 800 BPI on ts11 */
if(density && ((mt_dt[dn] & 07) == 1 || (mt_dt[dn] & 07) == 5))
continue; /* no 1600 BPI if unit is tm11 */
/*
* Use the density and iomode to construct the name of the
* mag tape special file to be opened, the number of records
* to write , and the record size as follows:
*
* density mode size # rec's per 10 feet
* 800 block 512 55
* 800 raw 10240 8
* 1600 block 512 70
* 1600 raw 10240 15
* 1600 block 1024 70 - tu81
* 1600 raw 10240 15 - tu81
* 6250 block 1024 160
* 6250 raw 10240 35
* tk50 block 512 95
* tk50 raw 10240 15
*/
if(!density && !iomode) { /* low density & block mode */
if (mt_dt[dn] == 5) { /* tk50 */
nbytes = 1024;
nrec = nfeet[dn];
}
else if (mt_dt[dn] == 4) { /* 1600 BPI for tu81 */
nbytes = 1024;
nrec = (nfeet[dn]/10)*70;
}
else { /* 800 BPI for the rest */
#ifdef UCB_NKB
nbytes = 1024;
nrec = (nfeet[0]/10)*55;
#else
nbytes = 512;
nrec = (nfeet[0]/10)*76;
#endif
}
}
if(!density && iomode) { /* low density & raw mode */
if (mt_dt[dn] == 5) { /* tk50 */
nbytes = 10240;
nrec = nfeet[dn];
}
else if (mt_dt[dn] == 4) { /* 1600 BPI for tu81 */
nbytes = 10240;
nrec = (nfeet[dn]/10)*15;
}
else { /* 800 BPI for the rest */
nbytes = 10240;
nrec = (nfeet[0]/10)*8;
}
}
if(density && !iomode) { /* high density & block mode */
if (mt_dt[dn] == 4) { /* 6250 BPI for tu81 */
nbytes = 1024;
nrec = (nfeet[dn]/10)*160;
}
else { /* 1600 BPI for the resr */
#ifdef UCB_NKB
nbytes = 1024;
nrec = (nfeet[0]/10)*70;
#else
nbytes = 512;
nrec = (nfeet[0]/10)*95;
#endif
}
}
if(density && iomode) { /* high density & raw mode */
if (mt_dt[dn] == 4) { /* 6250 BPI for tu81 */
nbytes = 10240;
nrec = (nfeet[dn]/10)*35;
}
else { /* 1600 BPI for the rest */
nbytes = 10240;
nrec = (nfeet[0]/10)*15;
}
}
mtname(dn, density, iomode); /* generate magtape filename */
fd = mtopen(WRT);
wp = wba; /* load write buffer with test pattern */
for(j=0; j<5120; j++)
*wp++ = pat[j/256];
for(j=0; j<nrec; j++) {
#ifdef UCB_NKB
if((nbytes == 512) || (nbytes == 1024))
#else
if(nbytes == 512)
#endif
w_off = (j&017)*256;
else
w_off = 0;
wrterr = 0;
wrtcnt[dn]++;
wbp = wba + w_off;
/* intr(); */
if((rbc = write(fd, (char *)wbp, nbytes)) != nbytes) {
trwse(WRT,dn,density,iomode,nbytes,nrec,j+1);
fd = tuready(fd); /* wait for tape unit ready */
break;
}
}
close(fd);
if(wrterr) { /* write error, so read must be adjusted */
printf("\n\n******\n");
if(werec == 0) {
printf("READ ABORTED - no records written");
printf("\n******\n");
continue;
} else {
nrec = werec;
printf("READ SHORTENED - ");
printf("%d records will be read",nrec);
}
printf("\n******\n");
}
fd = mtopen(RD);
for(j=0; j<nrec; j++) {
#ifdef UCB_NKB
if((nbytes == 512) || (nbytes == 1024))
#else
if(nbytes == 512)
#endif
r_off = (j&017)*256;
else
r_off = 0;
w_off = r_off;
rderr = 0;
rp = rba + r_off;
for(k=0; k<(nbytes/2); k++)
*rp++ = 0;
rdcnt[dn]++;
rbp = rba + r_off;
/* intr(); */
if((rbc = read(fd, (char *)rbp, nbytes)) != nbytes)
trwse(RD,dn,density,iomode,nbytes,nrec,j+1);
fsterr = 1;
neb = 0;
rp = rba + r_off;
for(k=0; k<(nbytes/2); k++) {
dpat = (r_off/256) + (k/256);
if(*rp++ != pat[dpat]) {
if(fsterr && !rderr)
trwse(DMM,dn,density,iomode,nbytes,nrec,j+1);
if(fsterr)
printf("\n\nDATA COMPARE ERROR - RECORD %u",j+1);
fsterr = 0;
if(++neb > ndep) {
printf("%s",&eplmsg);
break;
}
pgb(k, pat[dpat], *(rbp + k));
}
}
if(!fsterr)
printf("\n******\n");
if(rderr && (errno == ETPL)) {
printf("\n[READ ABORTED - ");
printf("fatal read error]\n******\n");
fd = tuready(fd);
goto fte3;
}
if(rderr && fsterr)
printf("\n******\n");
}
/*
* Check for end of file (EOF).
* Attempt to read one more record, if an error is
* returned the EOF is present. If read is successful
* then EOF is missing or an extra record was written.
*/
if(iomode) /* only in RAW mode for now ! */
{
/* intr(); */
if((rbc = read(fd, (char *)rba, nbytes)) != 0) {
trwse(MEOF,dn,density,iomode,nbytes,nrec,(nrec+1));
printf("%s", &noeof);
if(wrterr) {
printf("\n[Most likely due to previous");
printf(" fatal write error]\n******\n");
}
}
}
fte3:
fflush(stdout);
close(fd);
/*
* The following is necessary because the tm03 tape controller
* will not allow the density to be changed unless the
* tape is at load point.
* This causes the first write after a density change to fail.
* To avoid this problem, the tape is opened at the previous
* density, the first record is read, the tape is closed, and
* then the process sleeps for 2 seconds ( or so ) while the
* tape drive is rewound to load point.
*/
if(htflag && ((!density && iomode) || (density && iomode))) {
fd = mtopen(RD);
read(fd, (char *)rba, 10240);
close(fd);
sleep(1);
sleep(1);
}
}
time(&timbuf);
printf("\n%s exerciser end of pass - %s", tapen, ctime(&timbuf));
if(!sflag)
pios(); /* print I/O stats */
fflush(stdout);
if((i = fork()) == 0)
goto loop;
if(i == -1) {
fprintf(stderr, "\nmtx: Can't fork new copy of mtx !\n");
goto loop;
}
exit(0);
}
/*
* This function is called when a exerciser run is
* terminated via the delete key. This is done by
* catching the interrupt signal.
* The final I/O statistics are printed and the
* the error log printout program is called via execl.
* `elp' will print only the errors for the selected
* tape controller which occurred durring the exerciser run.
*/
intr()
{
signal(SIGTERM, intr);
#ifdef EFLG
if(zflag) {
if(!checkflg())
return;
} else
return;
#else
if(access(killfn, 0) != 0)
return;
#endif
stop();
}
stop()
{
register char *tn;
stopsig++;
signal(SIGTERM, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
time(&etbuf); /* ending time */
printf("\n\n%s magtape exerciser stopped - %s\n", tapen, ctime(&etbuf));
pios(); /* print I/O stats */
tconv(&btbuf, &btime); /* convert beg time to ascii */
tconv(&etbuf, &etime); /* convert end time to ascii */
fflush(stdout);
if(tsflag)
tn = "-ts";
else if(tmflag)
tn = "-tm";
else if(htflag)
tn = "-ht";
else
tn = "-tk";
if(fork() == 0)
execl("/bin/elp","elp","-s",tn,"-d",&btime,&etime,(char *)0);
else
while(wait() != -1) ;
#ifdef EFLG
if(zflag)
evntflg(EFCLR, efid, (long)efbit);
#else
unlink(killfn);
#endif
exit(0);
}
/*
* Tape read/write status error printout function.
* rw = type of function being performed.
* 0 = read, 1 = write, 2 = data mismatch, 3 = missing EOF
* un = tape unit number
* den = 0 for 800 BPI, den = !0 for 1600 BPI
* iom = 0 for block I/O mode , iom = !0 for raw I/O mode
* rl = record length in bytes
* nr = number of records
* rn = record number
*/
trwse(rw, un, den, iom, rl, nr, rn)
{
char tp;
register int i, j;
if(stopsig)
stop(); /* in case of signal durring system call */
tp = mt_dt[un];
hecnt[un]++;
time(&timbuf);
printf("\n\n******\n");
if(rw == DMM)
printf("TEST %d - DATA MISMATCH WITHOUT READ", testno);
else {
printf("TEST %d - HARD TAPE ", testno);
if(rw == WRT)
printf("WRITE");
else
printf("READ");
}
printf(" ERROR - %s",ctime(&timbuf));
if(rw < DMM) {
printf("Returned byte = %d (-1 = error)", rbc);
printf("\nError type: ");
if(errno < sys_nerr)
printf("%s\n", sys_errlist[errno]);
else
printf("Unknown error\n");
}
printf("\nunit\tdensity\tI/O\trecord\t# of\trecord");
printf("\nnumber\tBPI\tmode\tnumber\trecords\tlength\n");
printf("\n%d\t",un);
if(den) {
if (tp == 2 || tp == 3)
printf("1600\t");
else
printf("6250\t");
}
else {
if (tp == 1 || tp == 2)
printf("800\t");
else if (tp == 4)
printf("1600\t");
else
printf("tk50\t");
}
if(iom)
printf("raw\t");
else
printf("block\t");
printf("%d\t%d\t%d bytes",rn,nr,rl);
if(rw != MEOF)
printf("\n\nWrite buffer address = %o", w_off);
if(rw == RD || rw == DMM)
printf("\nRead buffer address = %o", r_off);
if(rw == WRT) {
printf("\n\n[FATAL ERROR - write termintated");
printf(" at record %d of %d]", rn, nr);
wrterr++;
werec = rn - 1;
printf("\n******\n");
}
if(rw == RD)
rderr++;
if(hecnt[un] >= ndrop) {
printf("\n\nTotal error limit exceeded, unit %d dropped !\n", un);
mt_dt[un] = 0;
}
fflush(stdout);
for(i=0, j=0; i<64; i++)
j += mt_dt[i];
if(j == 0) {
for( ;; )
sleep(3600);
}
}
/*
* Print the tape read/write/hard error
* statistics.
*/
pios()
{
register j;
time(&stbuf);
randx = stbuf & 0777;
printf("\n\nI/O statistics - %s", ctime(&stbuf));
printf("\ndrive write read hard");
printf("\nnumber operations operations errors\n");
for(j=0; j<64; j++)
if(mt_dt[j]) {
printf("\n%6.d %10.D", j, wrtcnt[j]);
printf(" %10.D %6.D", rdcnt[j], hecnt[j]);
}
printf("\n");
fflush(stdout);
}
/*
* Wait for tape unit ready.
* The tape is closed, then approximately
* once per second an atttempt is made to
* open the tape again. If after 15 minutes
* the tape can't be opened, a fatal error
* message is printed and the tape exerciser
* exits. If the tape can be opened then
* the file descriptor is returned.
*
* The 15 minute wait is necessary to allow
* for manual intervention to make the tape
* unit ready after such things as opening the
* door on a TS11 or taking the drive off-line.
*/
tuready(fd)
{
register int i;
close(fd);
for(i=0; i<900; i++) {
if((fd = open(&devn, RD)) >= 0)
return(fd);
sleep(1);
}
fprintf(stderr,"\n\nmtx: FATAL TAPE ERROR - can't open %s", &devn);
printf(" after 15 minutes\n\n");
exit(1);
}
/*
* The "mtopen" function opens the magtape for
* actual read/write operations.
* If the open fails, mtopen prints the reason
* for the failure and the calls "tuready"
* which retries the open once per second for 15
* minutes, and prints a fatal error message if
* the open can't be completed by that time.
*/
mtopen(rw)
{
int fd;
while((fd = open(&devn, rw)) < 0) {
fprintf(stderr,"\n\nmtx: can't open %s ", &devn);
if(errno == ETOL)
fprintf(stderr,"[off-line]");
else if(errno == ETWL)
fprintf(stderr,"[write locked]");
else if(errno == ETO)
fprintf(stderr,"[already open]");
else
fprintf(stderr,"[unknown error]");
fprintf(stderr,"\n\nmtx: [will retry for at least 15 minutes, then quit !]");
fd = tuready(fd);
close(fd);
}
return(fd);
}
/*
* This function converts the time from a time_t
* ,as returned by time(), to ascii in the form of
* yymmddhhmmss.
*/
tconv(tim, timbuf)
time_t *tim;
char *timbuf;
{
register int i;
register char *p;
int tb[6];
tl = localtime(tim);
tb[0] = tl->tm_year;
tb[1] = tl->tm_mon + 1;
tb[2] = tl->tm_mday;
tb[3] = tl->tm_hour;
tb[4] = tl->tm_min;
tb[5] = tl->tm_sec;
p = timbuf;
for(i=0; i<6; i++) {
*p++ = (tb[i]/10) + '0';
*p++ = (tb[i]%10) + '0';
}
*p++ = 0;
}
/*
* Generate the special filename for the
* selected magtape unit, depending upon
* the density and iomode arguments.
*/
mtname(dn, den, mode)
{
char tp;
tp = mt_dt[dn];
if(!den && !mode) {
if (tp == 1 || tp == 2)
sprintf(&devn, "%s%d", mtn, dn);
else if (tp == 4)
sprintf(&devn, "%s%d", htn, dn);
else
sprintf(&devn, "%s%d", tkn, dn);
}
if(!den && mode) {
if (tp == 1 || tp == 2)
sprintf(&devn, "%s%d", rmtn, dn);
else if (tp == 4)
sprintf(&devn, "%s%d", rhtn, dn);
else
sprintf(&devn, "%s%d", rtkn, dn);
}
if(den && !mode) {
if (tp == 2 || tp == 3)
sprintf(&devn, "%s%d", htn, dn);
else
sprintf(&devn, "%s%d", gtn, dn);
}
if(den && mode) {
if (tp == 2 || tp == 3)
sprintf(&devn, "%s%d", rhtn, dn);
else
sprintf(&devn, "%s%d", rgtn, dn);
}
}
/*
* Print the address of the word in error
* ( if word not equal to -1)
* followed by the GOOD/BAD data.
*/
pgb(word, good, bad)
{
if(word != -1)
printf("\n\nWORD = %6.d", word);
printf("\nGOOD = %06.o", good);
printf("\nBAD = %06.o", bad);
}
/*
* Check eventflags to stop
* return 0 for continuation
* return 1 to stop
*/
extern int errno;
checkflg()
{
union efrt {
long efret;
struct {
int a;
int b;
} retval
} ef;
errno = 0;
ef.efret = evntflg(EFRD, efid, (long)0);
if(errno && ef.retval.a == -1) {
zflag = 0;
return(0);
}
if(ef.efret & (1L << efbit))
return(1);
return(0);
}