Date: Wed, 15 Nov 2000 17:15:20 -0800 (PST) From: Matthew Jacob <mjacob@feral.com> To: "Jacques A. Vidrine" <n@nectar.com> Cc: freebsd-scsi@FreeBSD.ORG Subject: Re: [ TAPE TIMEOUT] Re: afio & SCB 0xc - timed out while idle Message-ID: <Pine.BSF.4.21.0011151659250.96707-100000@beppo.feral.com> In-Reply-To: <20001115183155.A11050@hamlet.nectar.com>
next in thread | previous in thread | raw e-mail | index | archive | help
Hmm. Save me some time/grief and check whether your tape drive is happy under
freebsd. Take the program below, compile it, put a scratch tape in the drive,
execute 'mt -f /dev/nrsa0 status' (and send us the output) and then execute:
pat_test v -b 64k -r 1000 -n 10 -f /dev/nrsa0
and send the output.
/*
* Copyright (c) 2000 by Matthew Jacob.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
*
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/mtio.h>
#ifndef roundup
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */
#endif
static int szarg(char *);
static __inline void filbuf(void *, int, int, int);
static __inline int chkbuf(void *, int, int, int);
static int rewind_tape(char *);
static int
szarg(char *n)
{
register int mult = 1;
register char *q = n;
while (*q != (char) 0)
q++;
--q;
if (*q == 'k' || *q == 'K') {
mult = 1024;
*q = 0;
} else if (*q == 'm' || *q == 'M') {
mult = 1024 * 1024;
*q = 0;
}
return (atoi(n) * mult);
}
static __inline void
filbuf(void *buffer, int fileno, int recno, int blksiz)
{
int i;
u_int64_t *lb = buffer;
u_int64_t tseed = ((u_int64_t)fileno << 40) | ((u_int64_t)recno << 24);
for (i = 0; i < (blksiz / (sizeof (u_int64_t))); i++) {
lb[i] = tseed | i;
}
}
static __inline int
chkbuf(void *buffer, int fileno, int recno, int blksiz)
{
register int i;
u_int64_t *lb = buffer;
u_int64_t tseed = ((u_int64_t)fileno << 40) | ((u_int64_t)recno << 24);
for (i = 0; i < (blksiz / (sizeof (u_int64_t))); i++) {
if (lb[i] != (tseed | i)) {
fprintf(stdout,
"compare error at file %d, record %d, offset %d\n",
fileno, recno, i * sizeof (u_int64_t));
fprintf(stdout, "Should be 0x%llx, got 0x%llx\n",
tseed | i, lb[i]);
return (i+1);
}
}
return (0);
}
static int
rewind_tape(char *file)
{
struct mtop mtop;
int fd = open(file, O_RDONLY);
if (fd < 0) {
perror(file);
return (-1);
}
mtop.mt_op = MTREW;
mtop.mt_count = 1;
if (ioctl(fd, MTIOCTOP, &mtop) < 0) {
perror("MTREW");
return (-1);
}
if (close(fd) < 0) {
perror("close");
return (-1);
}
return (0);
}
int
main(int argc, char **argv)
{
const char *usage = "[ -v ] [ -b blksize ] [ -r blocks per file ] "
"[ -n number-of-files ] -f no-rewinding-tape-drive";
time_t stime, etime;
int blksize, recperfile, nfiles;
char *file, *bp;
u_int64_t nw, nr;
int fd, c, wrecno, wfileno, rrecno, rfileno, verbose, last_recno;
int w, r, lastw, lastr, nzr;
nw = nr = 0;
lastw = lastr = 0;
w = wrecno = rrecno = last_recno = 0;
nfiles = -1;
recperfile = 1000;
blksize = 32 << 10;
file = NULL;
verbose = 0;
while ((c = getopt(argc, argv, "b:r:n:f:v")) != -1) {
switch (c) {
case 'b':
blksize = szarg(optarg);
break;
case 'r':
recperfile = atoi(optarg);
break;
case 'n':
nfiles = atoi(optarg);
break;
case 'f':
file = optarg;
break;
case 'v':
verbose++;
break;
default:
fprintf(stderr, "%s: %s\n", argv[0], usage);
exit(1);
}
}
setbuf(stdout, NULL);
/*
* Make sure tape can be opened (and rewound)
*/
if (file == NULL) {
fprintf(stderr, "%s: %s\n", argv[0], usage);
exit(1);
}
if (verbose)
fprintf(stdout, ".......Rewind Tape\n");
if (rewind_tape(file) < 0) {
exit(1);
}
/*
* Allocate Buffer
*/
blksize &= ~(sizeof (u_int64_t) - 1);
bp = calloc(blksize / sizeof (u_int64_t), sizeof (u_int64_t));
if (bp == NULL) {
perror("calloc");
exit(1);
}
/*
* Do write pass.
*/
if (verbose)
fprintf(stdout, "........Write Pass\n");
time(&stime);
wfileno = 0;
for (;;) {
fd = open(file, O_RDWR);
if (fd < 0) {
perror(file);
w = 0;
break;
}
for (wrecno = 0; wrecno < recperfile; wrecno++) {
filbuf(bp, wfileno, wrecno, blksize);
if ((w = write(fd, bp, blksize)) > 0) {
nw += w;
lastw = w;
}
if (verbose > 2) {
fprintf(stdout,
"Wrote File %d Record %d w=%d\n", wfileno,
wrecno, w);
}
if (w != blksize) {
break;
}
}
if ((verbose && ((wfileno+1) & 0xf) == 0) || verbose > 1) {
fprintf(stdout,
"End of File %d (%lld total bytes written)\n",
wfileno, nw);
}
if (w != blksize) {
(void) close(fd);
break;
}
if (close(fd) < 0) {
perror("close");
w = 0;
break;
}
if (nfiles > 0 && wfileno == nfiles-1) {
break;
}
wfileno++;
}
time(&etime);
if (w < 0) {
perror("write");
w = 0;
}
fprintf(stdout,
"EOT at File %d Record %d Offset %d (%lld total bytes written)\n",
wfileno, wrecno, w, nw);
etime -= stime;
fprintf(stdout, "Elapsed Seconds: %ld; Data Rate: %gMB/s\n",
(long) etime, ((double) (nw >> 20)) / ((double) etime));
/*
* Rewind tape.
*/
if (verbose)
fprintf(stdout, ".......Rewind Tape\n");
if (rewind_tape(file) < 0) {
exit(1);
}
/*
* Do read pass
*/
if (verbose)
fprintf(stdout, ".........Read Pass\n");
time(&stime);
for (nzr = 0, rfileno = 0;; rfileno++) {
fd = open(file, O_RDONLY);
if (fd < 0) {
perror(file);
r = 0;
break;
}
for (rrecno = 0;; rrecno++) {
if ((r = read(fd, bp, blksize)) > 0) {
last_recno = rrecno;
nzr = 0;
nr += r;
lastr = r;
if (chkbuf(bp, rfileno, rrecno, r)) {
exit(1);
}
}
if (verbose > 2) {
fprintf(stdout,
"Read File %d Record %d w=%d\n", rfileno,
rrecno, r);
}
if (r != blksize) {
break;
}
if (rrecno > recperfile) {
fprintf(stdout, "read more records per file "
"(%d) than written (%d)\n", rrecno,
recperfile);
exit(1);
}
}
if ((verbose && ((rfileno+1) & 0xf) == 0) || verbose > 1) {
fprintf(stdout,
"End of File %d (%lld total bytes read)\n",
rfileno, nr);
}
/*
* We can't break out of this loop on just plain
* zero length reads- because those signal an
* EOF condition- not EOT. We have to wait until
* we get an error or two zero length reads in a row
*/
if (r == 0) {
if (nzr++) {
(void) close(fd);
break;
} else {
rrecno = last_recno;
}
} else if (r < 0) {
if (rrecno == 0)
rrecno = last_recno;
(void) close(fd);
break;
}
if (close(fd) < 0) {
perror("close");
r = 0;
break;
}
}
time(&etime);
if (r < 0) {
perror("read");
r = 0;
}
fprintf(stdout,
"EOT at File %d Record %d Offset %d (%lld total bytes read)\n",
rfileno, rrecno, r, nr);
etime -= stime;
fprintf(stdout, "Elapsed Seconds: %ld: Data Rate: %gMB/s\n",
(long) etime, ((double) (nr >> 2) / ((double) etime)));
return (0);
}
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-scsi" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0011151659250.96707-100000>
