+/*
+ * Copyright (c) 1998,1999,2000
+ * Traakan, Inc., Los Altos, CA
+ * 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 unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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.
+ */
+
+/*
+ * Project: NDMJOB
+ * Ident: $Id: $
+ *
+ * Description:
+ *
+ *****************************************************************
+ *
+ * NDMP Elements of a test-tape session
+ *
+ * +-----+ ###########
+ * | Job |----># CONTROL #
+ * +-----+ # Agent #
+ * # #
+ * ###########
+ * | |
+ * | +---------------------+
+ * control | connections |
+ * V V
+ * ############ +-------+ #########
+ * # TAPE # | | # ROBOT #
+ * # Agent # | ROBOT |<-># Agent #
+ * # # |+-----+| # #
+ * # ======|DRIVE|| # #
+ * # # |+-----+| # #
+ * ############ +-------+ #########
+ *
+ ****************************************************************
+ */
+
+
+#include "ndmagents.h"
+
+
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+
+
+extern int ndmca_tt_wrapper (struct ndm_session *sess,
+ int (*func)(struct ndm_session *sess));
+
+
+extern int ndmca_op_test_tape (struct ndm_session *sess);
+extern int ndmca_tt_openclose (struct ndm_session *sess);
+extern int ndmca_tt_basic_getstate (struct ndm_session *sess);
+extern int ndmca_tt_basic_write (struct ndm_session *sess);
+extern int ndmca_tt_basic_read (struct ndm_session *sess);
+extern int ndmca_tt_basic_write_and_read (struct ndm_session *sess);
+extern int ndmca_tt_write (struct ndm_session *sess);
+extern int ndmca_tt_read (struct ndm_session *sess);
+extern int ndmca_tt_mtio (struct ndm_session *sess);
+
+extern int ndmca_tt_check_fileno_recno (struct ndm_session *sess,
+ char *what, u_long file_num, u_long blockno,
+ char *note);
+
+extern int ndmca_test_tape_open (struct ndm_session *sess,
+ ndmp9_error expect_err,
+ char *device, int mode);
+extern int ndmca_test_tape_close (struct ndm_session *sess,
+ ndmp9_error expect_err);
+extern int ndmca_test_tape_get_state (struct ndm_session *sess,
+ ndmp9_error expect_err);
+extern int ndmca_test_tape_mtio (struct ndm_session *sess,
+ ndmp9_error expect_err,
+ ndmp9_tape_mtio_op op, u_long count, u_long *resid);
+extern int ndmca_check_tape_mtio (struct ndm_session *sess,
+ ndmp9_error expect_err,
+ ndmp9_tape_mtio_op op, u_long count, u_long resid);
+extern int ndmca_test_tape_write (struct ndm_session *sess,
+ ndmp9_error expect_err,
+ char *buf, unsigned count);
+extern int ndmca_test_tape_read (struct ndm_session *sess,
+ ndmp9_error expect_err,
+ char *buf, unsigned count);
+extern int ndmca_test_tape_read_2cnt (struct ndm_session *sess,
+ ndmp9_error expect_err,
+ char *buf, unsigned count, unsigned true_count);
+
+
+struct series {
+ unsigned n_rec;
+ unsigned recsize;
+};
+
+struct series tt_series[] = {
+ { 1, 512 },
+ { 100, 1024 },
+ { 1, 512 },
+ { 100, 139 },
+ { 1, 512 },
+ { 99, 10240 },
+ { 1, 512 },
+ { 3, 32768 },
+ { 1, 512 },
+ { 0 }
+};
+
+
+
+int
+ndmca_op_test_tape (struct ndm_session *sess)
+{
+ struct ndmconn * conn;
+ int (*save_call) (struct ndmconn *conn,
+ struct ndmp_xa_buf *xa);
+ int rc;
+
+ rc = ndmca_test_load_tape (sess);
+ if (rc) return rc;
+
+ conn = sess->plumb.tape;
+ save_call = conn->call;
+ conn->call = ndma_call_no_tattle;
+
+ if (rc == 0)
+ rc = ndmca_tt_wrapper (sess, ndmca_tt_openclose);
+ if (rc == 0)
+ rc = ndmca_tt_wrapper (sess, ndmca_tt_basic_getstate);
+ if (rc == 0)
+ rc = ndmca_tt_wrapper (sess, ndmca_tt_basic_write);
+ if (rc == 0)
+ rc = ndmca_tt_wrapper (sess, ndmca_tt_basic_read);
+ if (rc == 0)
+ rc = ndmca_tt_wrapper (sess, ndmca_tt_basic_write_and_read);
+ if (rc == 0)
+ rc = ndmca_tt_wrapper (sess, ndmca_tt_write);
+ if (rc == 0)
+ rc = ndmca_tt_wrapper (sess, ndmca_tt_read);
+ if (rc == 0)
+ rc = ndmca_tt_wrapper (sess, ndmca_tt_mtio);
+
+ ndmca_test_unload_tape (sess);
+
+ ndmca_test_done_series (sess, "test-tape");
+
+ conn->call = save_call;
+
+ return 0;
+}
+
+int
+ndmca_tt_wrapper (struct ndm_session *sess,
+ int (*func)(struct ndm_session *sess))
+{
+ int rc;
+
+ rc = (*func)(sess);
+
+ if (rc != 0) {
+ ndmalogf (sess, "Test", 1, "Failure");
+ }
+
+ ndmca_test_done_phase (sess);
+
+ /* clean up mess */
+ ndmca_test_log_note (sess, 2, "Cleaning up...");
+
+ ndmca_tape_open (sess); /* Open the tape, OK if already opened */
+ ndmca_tape_mtio (sess, NDMP9_MTIO_REW, 1, 0);
+ rc = ndmca_tape_close (sess); /* close, collective error */
+ if (rc != 0) {
+ ndmca_test_log_note (sess, 0, "Cleaning up failed, quiting");
+ } else {
+ ndmca_test_log_note (sess, 2, "Cleaning up done");
+ }
+
+ return rc;
+}
+
+
+int
+ndmca_tt_openclose (struct ndm_session *sess)
+{
+ int rc;
+
+ ndmca_test_phase (sess, "T-OC", "Tape Open/Close");
+
+ rc = ndmca_test_tape_close (sess, NDMP9_DEV_NOT_OPEN_ERR);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_open (sess, NDMP9_NO_DEVICE_ERR,
+ "bogus", NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_open (sess, NDMP9_ILLEGAL_ARGS_ERR, 0, 123);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_open (sess,NDMP9_NO_ERR,0,NDMP9_TAPE_RDWR_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_open (sess, NDMP9_DEVICE_OPENED_ERR,
+ 0, NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ return 0; /* pass */
+}
+
+int
+ndmca_tt_basic_getstate (struct ndm_session *sess)
+{
+ int rc;
+
+ ndmca_test_phase (sess, "T-BGS", "Tape Get State Basics");
+
+ rc = ndmca_test_tape_get_state (sess, NDMP9_DEV_NOT_OPEN_ERR);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_get_state (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ return 0; /* pass */
+}
+
+/*
+ * Precedes tt_basic_read() so that we can make a "known" tape.
+ */
+int
+ndmca_tt_basic_write (struct ndm_session *sess)
+{
+ int rc, ix;
+ char buf[1024];
+ ndmp9_error expect_errs[5];
+
+ ndmca_test_phase (sess, "T-BW", "Tape Write Basics");
+
+ rc = ndmca_test_tape_write (sess, NDMP9_DEV_NOT_OPEN_ERR, buf, 1024);
+ if (rc) return rc;
+
+ /*
+ * Write w/ read-only open mode
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_write (sess, NDMP9_PERMISSION_ERR, buf, 1024);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ /*
+ * Write w/ bogus lengths
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_RDWR_MODE);
+ if (rc) return rc;
+
+ /* OPEN Question: what does len==0 mean? */
+ /* write/len=0 MUST be NDMP[234]_NO_ERR or NDMP[234]_ILLEGAL_ARGS */
+ /* write/len=0 MUST be NDMP4_NO_ERR */
+ ix = 0;
+ if (sess->plumb.tape->protocol_version < 5) {
+ expect_errs[ix++] = NDMP9_ILLEGAL_ARGS_ERR;
+ }
+ expect_errs[ix++] = NDMP9_NO_ERR;
+ expect_errs[ix++] = -1;
+
+ rc = ndmca_tape_write (sess, buf, 0);
+
+ rc = ndmca_test_check_expect_errs (sess->plumb.tape, rc, expect_errs);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ /*
+ * TODO: bogus length
+ */
+
+ /*
+ * Write works
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_RDWR_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_write (sess, NDMP9_NO_ERR, buf, 1024);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_EOF, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ return 0; /* pass */
+}
+
+
+/*
+ * Assumes tt_basic_write() passed. Uses resulting tape.
+ */
+
+int
+ndmca_tt_basic_read (struct ndm_session *sess)
+{
+ int rc, ix;
+ char buf[2048];
+ ndmp9_error expect_errs[5];
+
+ ndmca_test_phase (sess, "T-BR", "Tape Read Basics");
+
+ rc = ndmca_test_tape_read (sess, NDMP9_DEV_NOT_OPEN_ERR, buf, 1024);
+ if (rc) return rc;
+
+
+ /*
+ * Read w/ bogus lengths -- mode=READ_MODE
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ /* read/len=0 MUST be NDMP[23]_NO_ERR or NDMP[23]_ILLEGAL_ARGS */
+ /* read/len=0 MUST be NDMP4_NO_ERR */
+ ix = 0;
+ if (sess->plumb.tape->protocol_version < 4) {
+ expect_errs[ix++] = NDMP9_ILLEGAL_ARGS_ERR;
+ }
+ expect_errs[ix++] = NDMP9_NO_ERR;
+ expect_errs[ix++] = -1;
+
+ rc = ndmca_tape_read (sess, buf, 0);
+
+ rc = ndmca_test_check_expect_errs (sess->plumb.tape, rc, expect_errs);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_read(sess,NDMP9_ILLEGAL_ARGS_ERR,buf,0x80000000);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ /*
+ * Read works -- mode=WRITE_MODE (just to mix it up)
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_RDWR_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_read (sess, NDMP9_NO_ERR, buf, 1024);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_read (sess, NDMP9_EOF_ERR, buf, 1024);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+
+ /*
+ * Read works w/ oversize -- mode=READ_MODE (just to mix it up)
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_read_2cnt (sess, NDMP9_NO_ERR, buf, 2048, 1024);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_read_2cnt (sess, NDMP9_EOF_ERR, buf, 2048, 1024);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+
+ /*
+ * Read works w/ undersize -- mode=READ_MODE (just to mix it up)
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_read_2cnt (sess, NDMP9_NO_ERR, buf, 512, 512);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_read_2cnt (sess, NDMP9_EOF_ERR, buf, 512, 512);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ return 0; /* pass */
+}
+
+#define CHECK_FILENO_RECNO(WHAT,FILENO,RECNO) { \
+ what = WHAT; \
+ rc = ndmca_tt_check_fileno_recno (sess, \
+ WHAT, FILENO, RECNO, note); \
+ if (rc) return -1; \
+ }
+
+/*
+ * Assumes tt_basic_read() and tt_basic_write() have been done verifying
+ * READ and WRITE operations work...
+ */
+int
+ndmca_tt_basic_write_and_read (struct ndm_session *sess)
+{
+ int rc, i, f, pass;
+ char buf[64*1024];
+ char *p;
+
+ ndmca_test_phase (sess, "T-BWR", "Tape Write and Read Basics");
+
+ /*
+ * check EOF and EOM by rewinding and putting on 1 EOF mark
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_RDWR_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_check_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_BSR, 100, 100);
+ if (rc) return rc;
+
+ rc = ndmca_check_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_BSF, 100, 100);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_EOF, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_check_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_BSF, 100, 99);
+ if (rc) return rc;
+
+ rc = ndmca_check_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_FSF, 100, 99);
+ if (rc) return rc;
+
+ /* we are at EOM */
+ if (sess->plumb.tape->protocol_version < 4) {
+ rc = ndmca_test_tape_read (sess, NDMP9_EOF_ERR, buf, sizeof(buf));
+ if (rc) return rc;
+
+ /* check it again */
+ rc = ndmca_test_tape_read (sess, NDMP9_EOF_ERR, buf, 1024);
+ if (rc) return rc;
+
+ } else {
+ rc = ndmca_test_tape_read (sess, NDMP9_EOM_ERR, buf, sizeof(buf));
+ if (rc) return rc;
+
+ /* check it again */
+ rc = ndmca_test_tape_read (sess, NDMP9_EOM_ERR, buf, 1024);
+ if (rc) return rc;
+ }
+
+ /* rewind and place 1 record in tape -- no EOF marker by seeking */
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_write (sess, NDMP9_NO_ERR, buf, 512);
+ if (rc) return rc;
+
+ rc = ndmca_check_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_BSR, 100, 99);
+ if (rc) return rc;
+
+ rc = ndmca_check_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_FSR, 100, 99);
+ if (rc) return rc;
+
+ rc = ndmca_check_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_FSR, 100, 100);
+ if (rc) return rc;
+
+ rc = ndmca_check_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_FSF, 100, 100);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ /*
+ * perform tape label type processing with positioning ops
+ */
+ for(pass = 0; pass < 2; pass++) {
+ /*
+ * open the tape and write 1 record and close it
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_RDWR_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ for(p = buf, i = 0; i < 1024; i++, p++)
+ *p = ((i - 4) & 0xff);
+
+ rc = ndmca_test_tape_write (sess, NDMP9_NO_ERR, buf, 1024);
+ if (rc) return rc;
+
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_EOF, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ /*
+ * open the tape and read it
+ */
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_RDWR_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ if (pass == 1)
+ rc = ndmca_test_tape_read_2cnt (sess, NDMP9_NO_ERR, buf, sizeof(buf), 1024);
+ else
+ rc = ndmca_test_tape_read (sess, NDMP9_NO_ERR, buf, 1024);
+ if (rc) return rc;
+
+ for(p = buf, f = i = 0;
+ f < 64 && i < 1024;
+ i++, p++)
+ if (*p != ((i - 4) & 0xff)) {
+ char tmp[80];
+ sprintf (tmp,
+ "%d: 0x%x => 0x%x",
+ i, ((i - 4) & 0xff), *p);
+ ndmalogf (sess, "DATA", 6, tmp);
+ f++;
+ }
+ if (f > 0) {
+ ndmca_test_fail (sess, "Failed compare");
+ return -1;
+ }
+
+ rc = ndmca_test_tape_read (sess, NDMP9_EOF_ERR, buf, 1024);
+ if (rc) return rc;
+
+ /* check EOM */
+ if (sess->plumb.tape->protocol_version < 4) {
+ rc = ndmca_test_tape_read (sess, NDMP9_EOF_ERR, buf, 1024);
+ if (rc) return rc;
+ } else {
+ /* skip over filemark */
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_FSF, 1, 0);
+ /* read EOM */
+ rc = ndmca_test_tape_read (sess, NDMP9_EOM_ERR, buf, 1024);
+ if (rc) return rc;
+ }
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+ }
+
+ return 0; /* pass */
+}
+
+/*
+ * Precedes tt_read() so that we can make a "known" tape.
+ */
+int
+ndmca_tt_write (struct ndm_session *sess)
+{
+ int rc;
+ unsigned n_rec;
+ unsigned recsize;
+ unsigned fileno, recno;
+ char * what;
+ char note[128];
+ char buf[64*1024];
+
+ ndmca_test_phase (sess, "T-WRITE", "Tape Write Series");
+
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_RDWR_MODE);
+ if (rc) return rc;
+
+ for (fileno = 0; tt_series[fileno].n_rec > 0; fileno++) {
+ n_rec = tt_series[fileno].n_rec;
+ recsize = tt_series[fileno].recsize;
+
+ sprintf (note, "Write tape file %d", fileno+1);
+ ndmca_test_open (sess, note, 0);
+
+ sprintf (note, "file #%d, %d records, %d bytes/rec",
+ fileno+1, n_rec, recsize);
+ ndmca_test_log_note (sess, 2, note);
+
+ for (recno = 0; recno < n_rec; recno++) {
+ ndmca_test_fill_data (buf, recsize, recno, fileno);
+
+ what = "write";
+ rc = ndmca_tape_write (sess, buf, recsize);
+ if (rc) goto fail;
+
+ CHECK_FILENO_RECNO ("write", fileno, recno+1);
+ }
+
+ what = "write filemark";
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_EOF, 1, 0);
+ if (rc) goto fail;
+
+ CHECK_FILENO_RECNO ("wfm", fileno+1, 0);
+
+ /* no test calls so the file operation is the test */
+ sprintf (buf, "Passed tape write %s", note);
+ ndmca_test_log_step (sess, 2, buf);
+ }
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ return 0;
+
+ fail:
+ sprintf (buf, "Failed %s recno=%d; %s", what, recno, note);
+ ndmca_test_fail (sess, buf);
+ return -1;
+}
+
+
+
+
+/*
+ * Assumes tt_write() passed
+ */
+int
+ndmca_tt_read (struct ndm_session *sess)
+{
+ int rc;
+ unsigned n_rec;
+ unsigned recsize;
+ unsigned fileno, recno;
+ char * what;
+ char note[128];
+ char pbuf[64*1024];
+ char buf[64*1024];
+
+ ndmca_test_phase (sess, "T-READ", "Tape Read Series");
+
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ for (fileno = 0; tt_series[fileno].n_rec > 0; fileno++) {
+ n_rec = tt_series[fileno].n_rec;
+ recsize = tt_series[fileno].recsize;
+
+ sprintf (note, "Read tape file %d", fileno+1);
+ ndmca_test_open (sess, note, 0);
+
+ sprintf (note, "file #%d, %d records, %d bytes/rec",
+ fileno+1, n_rec, recsize);
+ ndmca_test_log_note (sess, 2, note);
+
+ for (recno = 0; recno < n_rec; recno++) {
+ ndmca_test_fill_data (pbuf, recsize, recno, fileno);
+
+ what = "read";
+ rc = ndmca_tape_read (sess, buf, recsize);
+ if (rc) goto fail;
+
+ CHECK_FILENO_RECNO ("read", fileno, recno+1);
+
+ what = "compare";
+#if 0
+ if (bcmp (buf, pbuf, recsize) != 0)
+ goto fail;
+#else
+ if (bcmp (buf, pbuf, recsize) != 0) {
+ unsigned char *expect_p = (unsigned char *)pbuf;
+ unsigned char *got_p = (unsigned char *)buf;
+ unsigned int i, f;
+ for(f = i = 0;
+ f < 64 && i < recsize;
+ i++, expect_p++, got_p++) {
+ if (*expect_p != *got_p) {
+ char tmp[80];
+ sprintf (tmp,
+ "%d: 0x%x => 0x%x",
+ i, *expect_p, *got_p);
+ ndmalogf (sess, "DATA", 6, tmp);
+ f++;
+ }
+ }
+ goto fail;
+ }
+#endif
+ }
+
+ what = "eof read";
+ rc = ndmca_test_tape_read (sess, NDMP9_EOF_ERR, buf, recsize);
+ if (rc) goto fail;
+
+ if (sess->plumb.tape->protocol_version > 3) {
+ CHECK_FILENO_RECNO ("eof", fileno, -1);
+
+ what = "skip filemark";
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_FSF, 1, 0);
+ if (rc) goto fail;
+
+ CHECK_FILENO_RECNO ("skip", fileno+1, 0);
+ } else {
+ CHECK_FILENO_RECNO ("eof", fileno+1, 0);
+ }
+
+ sprintf (buf, "Passed tape read %s", note);
+ ndmca_test_log_step (sess, 2, buf);
+ }
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ return 0;
+
+ fail:
+ sprintf (buf, "Failed %s recno=%d; %s", what, recno, note);
+ ndmca_test_fail (sess, buf);
+ return -1;
+}
+
+
+/*
+ * Assumes tt_write() passed
+ */
+int
+ndmca_tt_mtio (struct ndm_session *sess)
+{
+ int rc;
+ unsigned n_rec;
+ unsigned recsize;
+ unsigned fileno, recno;
+ u_long count, resid;
+ char * what;
+ char note[128];
+ char pbuf[64*1024];
+ char buf[64*1024];
+
+ ndmca_test_phase (sess, "T-MTIO", "Tape MTIO");
+
+ rc = ndmca_test_tape_open(sess,NDMP9_NO_ERR,0,NDMP9_TAPE_READ_MODE);
+ if (rc) return rc;
+
+ rc = ndmca_test_tape_mtio (sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
+ if (rc) return rc;
+
+ for (fileno = 0; tt_series[fileno].n_rec > 0; fileno++) {
+ n_rec = tt_series[fileno].n_rec;
+ recsize = tt_series[fileno].recsize;
+
+ sprintf (note, "Seek around tape file %d", fileno+1);
+ ndmca_test_open (sess, note, 0);
+
+ sprintf (note, "file #%d, %d records, %d bytes/rec",
+ fileno+1, n_rec, recsize);
+ ndmca_test_log_note (sess, 2, note);
+
+ what = "rew";
+ count = 1;
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_REW, count, &resid);
+ if (rc) goto fail;
+
+ what = "rew resid";
+ if (resid != 0)
+ goto fail;
+
+ CHECK_FILENO_RECNO ("rew", 0, 0);
+
+
+ what = "fsf(n)";
+ count = fileno;
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_FSF, count, &resid);
+ if (rc) goto fail;
+
+ what = "fsf(n) resid";
+ if (resid != 0)
+ goto fail;
+
+ CHECK_FILENO_RECNO ("fsf", fileno, 0);
+
+
+ what = "fsr(1m)";
+ count = 1000000;
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_FSR, count, &resid);
+ if (rc) goto fail;
+
+ what = "fsr(1m) resid";
+ if (n_rec + resid != count)
+ goto fail;
+
+ if (sess->plumb.tape->protocol_version < 4) {
+ CHECK_FILENO_RECNO ("fsr(1m)", fileno + 1, 0);
+
+ what = "bsf 1 after fsr(1m)";
+ count = 1;
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_BSF, count, 0);
+ if (rc) goto fail;
+
+ CHECK_FILENO_RECNO (what, fileno, -1);
+
+ recno = n_rec;
+ } else {
+ /* EOT side of EOF marker */
+ recno = n_rec;
+ CHECK_FILENO_RECNO ("fsr(1m)", fileno, recno);
+ }
+
+ what = "bsr(1m)";
+ count = 1000000;
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_BSR, count, &resid);
+ if (rc) goto fail;
+
+ what = "bsr(1m) resid";
+ if (n_rec + resid != count)
+ goto fail;
+
+ if ((fileno > 0) && (sess->plumb.tape->protocol_version < 4)) {
+ /* at BOT side of EOF marker (not BOT) */
+ CHECK_FILENO_RECNO ("bsr(1m)", fileno - 1, -1);
+
+ what = "fsf 1 after bsr(1m)";
+ count = 1;
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_FSF, count, 0);
+ if (rc) goto fail;
+ }
+
+ recno = 0;
+ CHECK_FILENO_RECNO ("bsr(1m)", fileno, recno);
+
+ what = "fsr(0)";
+ count = 0;
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_FSR, count, &resid);
+ if (rc) goto fail;
+
+ what = "fsr(0) resid";
+ if (resid != 0)
+ goto fail;
+
+ recno = 0;
+ CHECK_FILENO_RECNO ("fsr(0)", fileno, recno);
+
+
+ what = "fsr(x)";
+ count = n_rec / 2;
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_FSR, count, &resid);
+ if (rc) goto fail;
+
+ what = "fsr(x) resid";
+ if (resid != 0)
+ goto fail;
+
+ recno = n_rec / 2;
+ CHECK_FILENO_RECNO ("fsr(x)", fileno, recno);
+
+ what = "fsr(x) read";
+ rc = ndmca_tape_read (sess, buf, recsize);
+ if (rc) goto fail;
+
+ what = "fsr(x) compare";
+ ndmca_test_fill_data (pbuf, recsize, recno, fileno);
+ if (bcmp (buf, pbuf, recsize) != 0)
+ goto fail;
+
+ recno++; /* caused by tape_read */
+
+ if (recno > 1) {
+ what = "bsr(2)";
+ count = 2;
+ rc = ndmca_tape_mtio (sess, NDMP9_MTIO_BSR,
+ count, &resid);
+ if (rc) goto fail;
+
+ what = "bsr(2) resid";
+ if (resid != 0)
+ goto fail;
+
+ recno -= count;
+ CHECK_FILENO_RECNO ("bsr(2)", fileno, recno);
+
+ what = "bsr(2) read";
+ rc = ndmca_tape_read (sess, buf, recsize);
+ if (rc) goto fail;
+
+ what = "bsr(2) compare";
+ ndmca_test_fill_data (pbuf, recsize, recno, fileno);
+ if (bcmp (buf, pbuf, recsize) != 0)
+ goto fail;
+ }
+
+ sprintf (buf, "Passed %s", note);
+ ndmca_test_log_step (sess, 2, buf);
+ }
+
+ rc = ndmca_test_tape_close (sess, NDMP9_NO_ERR);
+ if (rc) return rc;
+
+ return 0;
+
+ fail:
+ sprintf (buf, "Failed %s: %s", what, note);
+ ndmca_test_fail (sess, buf);
+ return -1;
+}
+
+
+
+/*
+ * Check the tape_state accurately reflects position
+ */
+
+int
+ndmca_tt_check_fileno_recno (struct ndm_session *sess,
+ char *what, u_long file_num, u_long blockno, char *note)
+{
+ struct ndm_control_agent *ca = &sess->control_acb;
+ struct ndmp9_tape_get_state_reply *ts = 0;
+ char buf[100];
+ int rc;
+ char * oper;
+
+ oper ="get_state";
+ rc = ndmca_tape_get_state (sess);
+ if (rc) goto fail;
+
+ ts = &ca->tape_state;
+
+ oper = "check file_num";
+ if (ts->file_num.value != file_num)
+ goto fail;
+
+ oper = "check blockno";
+ if ((ts->blockno.value != blockno) && (ts->blockno.value != NDMP9_INVALID_U_LONG))
+ goto fail;
+
+ return 0;
+
+ fail:
+ sprintf (buf, "Failed %s while testing %s", oper, what);
+ ndmca_test_log_note (sess, 1, buf);
+ if (ts) {
+ sprintf (buf, " expect file_num=%ld got file_num=%ld",
+ (long)file_num, (long)ts->file_num.value);
+ ndmca_test_log_note (sess, 1, buf);
+
+ sprintf (buf, " expect blockno=%ld got blockno=%ld",
+ (long)blockno, (long)ts->blockno.value);
+ ndmca_test_log_note (sess, 1, buf);
+ }
+
+ sprintf (buf, " note: %s", note);
+ ndmca_test_fail (sess, buf);
+ return -1;
+}
+
+
+
+
+#define NDMTEST_CALL(CONN) ndmca_test_call(CONN, xa, expect_err);
+
+
+int
+ndmca_test_tape_open (struct ndm_session *sess, ndmp9_error expect_err,
+ char *device, int mode)
+{
+ struct ndmconn * conn = sess->plumb.tape;
+ struct ndm_control_agent *ca = &sess->control_acb;
+ int rc;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ switch (conn->protocol_version) {
+ default: return -1234;
+
+#ifndef NDMOS_OPTION_NO_NDMP2
+ case NDMP2VER:
+ NDMC_WITH (ndmp2_tape_open, NDMP2VER)
+ if (device)
+ request->device.name = device;
+ else
+ request->device.name = ca->job.tape_device;
+ if (mode != -1)
+ request->mode = mode;
+ else
+ request->mode = ca->tape_mode;
+ rc = NDMTEST_CALL(conn);
+ NDMC_ENDWITH
+ break;
+#endif /* !NDMOS_OPTION_NO_NDMP2 */
+#ifndef NDMOS_OPTION_NO_NDMP3
+ case NDMP3VER:
+ NDMC_WITH (ndmp3_tape_open, NDMP3VER)
+ if (device)
+ request->device = device;
+ else
+ request->device = ca->job.tape_device;
+ if (mode != -1)
+ request->mode = mode;
+ else
+ request->mode = ca->tape_mode;
+ rc = NDMTEST_CALL(conn);
+ NDMC_ENDWITH
+ break;
+#endif /* !NDMOS_OPTION_NO_NDMP3 */
+#ifndef NDMOS_OPTION_NO_NDMP4
+ case NDMP4VER:
+ NDMC_WITH (ndmp4_tape_open, NDMP4VER)
+ if (device)
+ request->device = device;
+ else
+ request->device = ca->job.tape_device;
+ if (mode != -1)
+ request->mode = mode;
+ else
+ request->mode = ca->tape_mode;
+ rc = NDMTEST_CALL(conn);
+ NDMC_ENDWITH
+ break;
+#endif /* !NDMOS_OPTION_NO_NDMP4 */
+ }
+
+ return rc;
+}
+
+int
+ndmca_test_tape_close (struct ndm_session *sess, ndmp9_error expect_err)
+{
+ struct ndmconn * conn = sess->plumb.tape;
+ int rc;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ rc = ndmca_tape_close (sess);
+
+ rc = ndmca_test_check_expect (conn, rc, expect_err);
+
+ return rc;
+}
+
+int
+ndmca_test_tape_get_state (struct ndm_session *sess, ndmp9_error expect_err)
+{
+ struct ndmconn * conn = sess->plumb.tape;
+ int rc;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ rc = ndmca_tape_get_state (sess);
+
+ rc = ndmca_test_check_expect (conn, rc, expect_err);
+
+ return rc;
+}
+
+int
+ndmca_test_tape_mtio (struct ndm_session *sess, ndmp9_error expect_err,
+ ndmp9_tape_mtio_op op, u_long count, u_long *resid)
+{
+ struct ndmconn * conn = sess->plumb.tape;
+ int rc;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ rc = ndmca_tape_mtio (sess, op, count, resid);
+
+ rc = ndmca_test_check_expect (conn, rc, expect_err);
+
+ return rc;
+}
+
+int
+ndmca_check_tape_mtio (struct ndm_session *sess, ndmp9_error expect_err,
+ ndmp9_tape_mtio_op op, u_long count, u_long resid)
+{
+ struct ndmconn * conn = sess->plumb.tape;
+ u_long got_resid;
+ int rc;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ got_resid = ~resid;
+
+ rc = ndmca_tape_mtio (sess, op, count, &got_resid);
+
+ rc = ndmca_test_check_expect (conn, rc, expect_err);
+ if (rc) return rc;
+
+ if (resid != got_resid) {
+ char tmp[128];
+ sprintf (tmp,
+ "Residual incorrect, got %lu expected %lu",
+ got_resid,
+ resid);
+ ndmca_test_fail (sess, tmp);
+ return -1;
+ }
+
+ return rc;
+}
+
+
+int
+ndmca_test_tape_write (struct ndm_session *sess, ndmp9_error expect_err,
+ char *buf, unsigned count)
+{
+ struct ndmconn * conn = sess->plumb.tape;
+ int rc;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ rc = ndmca_tape_write (sess, buf, count);
+
+ rc = ndmca_test_check_expect (conn, rc, expect_err);
+
+ return rc;
+}
+
+int
+ndmca_test_tape_read (struct ndm_session *sess, ndmp9_error expect_err,
+ char *buf, unsigned count)
+{
+ struct ndmconn * conn = sess->plumb.tape;
+ int rc;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ rc = ndmca_tape_read (sess, buf, count);
+
+ rc = ndmca_test_check_expect (conn, rc, expect_err);
+
+ return rc;
+}
+
+int
+ndmca_test_tape_read_2cnt (struct ndm_session *sess, ndmp9_error expect_err,
+ char *buf, unsigned count, unsigned true_count)
+{
+ struct ndmconn * conn = sess->plumb.tape;
+ int rc;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ switch (conn->protocol_version) {
+ default: return -1234;
+
+#ifndef NDMOS_OPTION_NO_NDMP2
+ case NDMP2VER:
+ NDMC_WITH(ndmp2_tape_read, NDMP2VER)
+ request->count = count;
+ rc = NDMTEST_CALL(conn);
+ if (rc == 0 && expect_err == NDMP9_NO_ERR) {
+ if (reply->data_in.data_in_len == true_count) {
+ bcopy (reply->data_in.data_in_val,
+ buf, true_count);
+ } else {
+ rc = -1;
+ }
+ }
+ NDMC_FREE_REPLY();
+ NDMC_ENDWITH
+ break;
+#endif /* !NDMOS_OPTION_NO_NDMP2 */
+#ifndef NDMOS_OPTION_NO_NDMP3
+ case NDMP3VER:
+ NDMC_WITH(ndmp3_tape_read, NDMP3VER)
+ request->count = count;
+ rc = NDMTEST_CALL(conn);
+ if (rc == 0 && expect_err == NDMP9_NO_ERR) {
+ if (reply->data_in.data_in_len == true_count) {
+ bcopy (reply->data_in.data_in_val,
+ buf, true_count);
+ } else {
+ rc = -1;
+ }
+ }
+ NDMC_FREE_REPLY();
+ NDMC_ENDWITH
+ break;
+#endif /* !NDMOS_OPTION_NO_NDMP3 */
+#ifndef NDMOS_OPTION_NO_NDMP4
+ case NDMP4VER:
+ NDMC_WITH(ndmp4_tape_read, NDMP4VER)
+ request->count = count;
+ rc = NDMTEST_CALL(conn);
+ if (rc == 0 && expect_err == NDMP9_NO_ERR) {
+ if (reply->data_in.data_in_len == true_count) {
+ bcopy (reply->data_in.data_in_val,
+ buf, true_count);
+ } else {
+ rc = -1;
+ }
+ }
+ NDMC_FREE_REPLY();
+ NDMC_ENDWITH
+ break;
+#endif /* !NDMOS_OPTION_NO_NDMP4 */
+ }
+
+ return rc;
+}
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */