1 /*
2  * Copyright (c) 1998,1999,2000
3  *      Traakan, Inc., Los Altos, CA
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *
35  *****************************************************************
36  *
37  * NDMP Elements of a test-tape session
38  *
39  *                   +-----+     ###########
40  *                   | Job |----># CONTROL #
41  *                   +-----+     #  Agent  #
42  *                               #         #
43  *                               ###########
44  *                                    |  |
45  *                                    |  +---------------------+
46  *                            control | connections            |
47  *                                    V                        V
48  *                               ############  +-------+   #########
49  *                               #  TAPE    #  |       |   # ROBOT #
50  *                               #  Agent   #  | ROBOT |<-># Agent #
51  *                               #          #  |+-----+|   #       #
52  *                               #        ======|DRIVE||   #       #
53  *                               #          #  |+-----+|   #       #
54  *                               ############  +-------+   #########
55  *
56  ****************************************************************
57  */
58 
59 
60 #include "ndmagents.h"
61 
62 
63 #if !defined(NDMOS_OPTION_NO_CONTROL_AGENT) && \
64     !defined(NDMOS_OPTION_NO_TEST_AGENTS)
65 
66 
67 extern int ndmca_tt_wrapper(struct ndm_session* sess,
68                             int (*func)(struct ndm_session* sess));
69 
70 
71 extern int ndmca_op_test_tape(struct ndm_session* sess);
72 extern int ndmca_tt_openclose(struct ndm_session* sess);
73 extern int ndmca_tt_basic_getstate(struct ndm_session* sess);
74 extern int ndmca_tt_basic_write(struct ndm_session* sess);
75 extern int ndmca_tt_basic_read(struct ndm_session* sess);
76 extern int ndmca_tt_basic_write_and_read(struct ndm_session* sess);
77 extern int ndmca_tt_write(struct ndm_session* sess);
78 extern int ndmca_tt_read(struct ndm_session* sess);
79 extern int ndmca_tt_mtio(struct ndm_session* sess);
80 
81 extern int ndmca_tt_check_fileno_recno(struct ndm_session* sess,
82                                        char* what,
83                                        uint32_t file_num,
84                                        uint32_t blockno,
85                                        char* note);
86 
87 extern int ndmca_test_tape_open(struct ndm_session* sess,
88                                 ndmp9_error expect_err,
89                                 char* device,
90                                 int mode);
91 extern int ndmca_test_tape_close(struct ndm_session* sess,
92                                  ndmp9_error expect_err);
93 extern int ndmca_test_tape_get_state(struct ndm_session* sess,
94                                      ndmp9_error expect_err);
95 extern int ndmca_test_tape_mtio(struct ndm_session* sess,
96                                 ndmp9_error expect_err,
97                                 ndmp9_tape_mtio_op op,
98                                 uint32_t count,
99                                 uint32_t* resid);
100 extern int ndmca_check_tape_mtio(struct ndm_session* sess,
101                                  ndmp9_error expect_err,
102                                  ndmp9_tape_mtio_op op,
103                                  uint32_t count,
104                                  uint32_t resid);
105 extern int ndmca_test_tape_write(struct ndm_session* sess,
106                                  ndmp9_error expect_err,
107                                  char* buf,
108                                  unsigned count);
109 extern int ndmca_test_tape_read(struct ndm_session* sess,
110                                 ndmp9_error expect_err,
111                                 char* buf,
112                                 unsigned count);
113 extern int ndmca_test_tape_read_2cnt(struct ndm_session* sess,
114                                      ndmp9_error expect_err,
115                                      char* buf,
116                                      unsigned count,
117                                      unsigned true_count);
118 
119 
120 struct series {
121   unsigned n_rec;
122   unsigned recsize;
123 };
124 
125 struct series tt_series[] = {{1, 512}, {100, 1024}, {1, 512}, {100, 139},
126                              {1, 512}, {99, 10240}, {1, 512}, {3, 32768},
127                              {1, 512}, {0}};
128 
129 
ndmca_op_test_tape(struct ndm_session * sess)130 int ndmca_op_test_tape(struct ndm_session* sess)
131 {
132   struct ndmconn* conn;
133   int (*save_call)(struct ndmconn * conn, struct ndmp_xa_buf * xa);
134   int rc;
135 
136   rc = ndmca_test_load_tape(sess);
137   if (rc) return rc;
138 
139   conn = sess->plumb.tape;
140   save_call = conn->call;
141   conn->call = ndma_call_no_tattle;
142 
143   if (rc == 0) rc = ndmca_tt_wrapper(sess, ndmca_tt_openclose);
144   if (rc == 0) rc = ndmca_tt_wrapper(sess, ndmca_tt_basic_getstate);
145   if (rc == 0) rc = ndmca_tt_wrapper(sess, ndmca_tt_basic_write);
146   if (rc == 0) rc = ndmca_tt_wrapper(sess, ndmca_tt_basic_read);
147   if (rc == 0) rc = ndmca_tt_wrapper(sess, ndmca_tt_basic_write_and_read);
148   if (rc == 0) rc = ndmca_tt_wrapper(sess, ndmca_tt_write);
149   if (rc == 0) rc = ndmca_tt_wrapper(sess, ndmca_tt_read);
150   if (rc == 0) rc = ndmca_tt_wrapper(sess, ndmca_tt_mtio);
151 
152   ndmca_test_unload_tape(sess);
153 
154   ndmca_test_done_series(sess, "test-tape");
155 
156   conn->call = save_call;
157 
158   return 0;
159 }
160 
ndmca_tt_wrapper(struct ndm_session * sess,int (* func)(struct ndm_session * sess))161 int ndmca_tt_wrapper(struct ndm_session* sess,
162                      int (*func)(struct ndm_session* sess))
163 {
164   int rc;
165 
166   rc = (*func)(sess);
167 
168   if (rc != 0) { ndmalogf(sess, "Test", 1, "Failure"); }
169 
170   ndmca_test_done_phase(sess);
171 
172   /* clean up mess */
173   ndmca_test_log_note(sess, 2, "Cleaning up...");
174 
175   ndmca_tape_open(sess); /* Open the tape, OK if already opened */
176   ndmca_tape_mtio(sess, NDMP9_MTIO_REW, 1, 0);
177   rc = ndmca_tape_close(sess); /* close, collective error */
178   if (rc != 0) {
179     ndmca_test_log_note(sess, 0, "Cleaning up failed, quiting");
180   } else {
181     ndmca_test_log_note(sess, 2, "Cleaning up done");
182   }
183 
184   return rc;
185 }
186 
187 
ndmca_tt_openclose(struct ndm_session * sess)188 int ndmca_tt_openclose(struct ndm_session* sess)
189 {
190   int rc;
191 
192   ndmca_test_phase(sess, "T-OC", "Tape Open/Close");
193 
194   rc = ndmca_test_tape_close(sess, NDMP9_DEV_NOT_OPEN_ERR);
195   if (rc) return rc;
196 
197   rc = ndmca_test_tape_open(sess, NDMP9_NO_DEVICE_ERR, "bogus",
198                             NDMP9_TAPE_READ_MODE);
199   if (rc) return rc;
200 
201   rc = ndmca_test_tape_open(sess, NDMP9_ILLEGAL_ARGS_ERR, 0, 123);
202   if (rc) return rc;
203 
204   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_READ_MODE);
205   if (rc) return rc;
206 
207   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
208   if (rc) return rc;
209 
210   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_RDWR_MODE);
211   if (rc) return rc;
212 
213   rc = ndmca_test_tape_open(sess, NDMP9_DEVICE_OPENED_ERR, 0,
214                             NDMP9_TAPE_READ_MODE);
215   if (rc) return rc;
216 
217   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
218   if (rc) return rc;
219 
220   return 0; /* pass */
221 }
222 
ndmca_tt_basic_getstate(struct ndm_session * sess)223 int ndmca_tt_basic_getstate(struct ndm_session* sess)
224 {
225   int rc;
226 
227   ndmca_test_phase(sess, "T-BGS", "Tape Get State Basics");
228 
229   rc = ndmca_test_tape_get_state(sess, NDMP9_DEV_NOT_OPEN_ERR);
230   if (rc) return rc;
231 
232   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_READ_MODE);
233   if (rc) return rc;
234 
235   rc = ndmca_test_tape_get_state(sess, NDMP9_NO_ERR);
236   if (rc) return rc;
237 
238   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
239   if (rc) return rc;
240 
241   return 0; /* pass */
242 }
243 
244 /*
245  * Precedes tt_basic_read() so that we can make a "known" tape.
246  */
ndmca_tt_basic_write(struct ndm_session * sess)247 int ndmca_tt_basic_write(struct ndm_session* sess)
248 {
249   int rc, ix;
250   char buf[1024];
251   ndmp9_error expect_errs[5];
252 
253   ndmca_test_phase(sess, "T-BW", "Tape Write Basics");
254 
255   rc = ndmca_test_tape_write(sess, NDMP9_DEV_NOT_OPEN_ERR, buf, 1024);
256   if (rc) return rc;
257 
258   /*
259    * Write w/ read-only open mode
260    */
261   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_READ_MODE);
262   if (rc) return rc;
263 
264   rc = ndmca_test_tape_write(sess, NDMP9_PERMISSION_ERR, buf, 1024);
265   if (rc) return rc;
266 
267   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
268   if (rc) return rc;
269 
270   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
271   if (rc) return rc;
272 
273   /*
274    * Write w/ bogus lengths
275    */
276   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_RDWR_MODE);
277   if (rc) return rc;
278 
279   /* OPEN Question: what does len==0 mean? */
280   /* write/len=0 MUST be NDMP[234]_NO_ERR or NDMP[234]_ILLEGAL_ARGS */
281   /* write/len=0 MUST be NDMP4_NO_ERR */
282   ix = 0;
283   if (sess->plumb.tape->protocol_version < 5) {
284     expect_errs[ix++] = NDMP9_ILLEGAL_ARGS_ERR;
285   }
286   expect_errs[ix++] = NDMP9_NO_ERR;
287   expect_errs[ix++] = -1;
288 
289   rc = ndmca_tape_write(sess, buf, 0);
290 
291   rc = ndmca_test_check_expect_errs(sess->plumb.tape, rc, expect_errs);
292   if (rc) return rc;
293 
294   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
295   if (rc) return rc;
296 
297   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
298   if (rc) return rc;
299 
300   /*
301    * TODO: bogus length
302    */
303 
304   /*
305    * Write works
306    */
307   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_RDWR_MODE);
308   if (rc) return rc;
309 
310   rc = ndmca_test_tape_write(sess, NDMP9_NO_ERR, buf, 1024);
311   if (rc) return rc;
312 
313   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_EOF, 1, 0);
314   if (rc) return rc;
315 
316   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
317   if (rc) return rc;
318 
319   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
320   if (rc) return rc;
321 
322   return 0; /* pass */
323 }
324 
325 
326 /*
327  * Assumes tt_basic_write() passed. Uses resulting tape.
328  */
329 
ndmca_tt_basic_read(struct ndm_session * sess)330 int ndmca_tt_basic_read(struct ndm_session* sess)
331 {
332   int rc, ix;
333   char buf[2048];
334   ndmp9_error expect_errs[5];
335 
336   ndmca_test_phase(sess, "T-BR", "Tape Read Basics");
337 
338   rc = ndmca_test_tape_read(sess, NDMP9_DEV_NOT_OPEN_ERR, buf, 1024);
339   if (rc) return rc;
340 
341 
342   /*
343    * Read w/ bogus lengths -- mode=READ_MODE
344    */
345   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_READ_MODE);
346   if (rc) return rc;
347 
348   /* read/len=0 MUST be NDMP[23]_NO_ERR or NDMP[23]_ILLEGAL_ARGS */
349   /* read/len=0 MUST be NDMP4_NO_ERR */
350   ix = 0;
351   if (sess->plumb.tape->protocol_version < 4) {
352     expect_errs[ix++] = NDMP9_ILLEGAL_ARGS_ERR;
353   }
354   expect_errs[ix++] = NDMP9_NO_ERR;
355   expect_errs[ix++] = -1;
356 
357   rc = ndmca_tape_read(sess, buf, 0);
358 
359   rc = ndmca_test_check_expect_errs(sess->plumb.tape, rc, expect_errs);
360   if (rc) return rc;
361 
362   rc = ndmca_test_tape_read(sess, NDMP9_ILLEGAL_ARGS_ERR, buf, 0x80000000);
363   if (rc) return rc;
364 
365   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
366   if (rc) return rc;
367 
368   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
369   if (rc) return rc;
370 
371   /*
372    * Read works -- mode=WRITE_MODE (just to mix it up)
373    */
374   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_RDWR_MODE);
375   if (rc) return rc;
376 
377   rc = ndmca_test_tape_read(sess, NDMP9_NO_ERR, buf, 1024);
378   if (rc) return rc;
379 
380   rc = ndmca_test_tape_read(sess, NDMP9_EOF_ERR, buf, 1024);
381   if (rc) return rc;
382 
383   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
384   if (rc) return rc;
385 
386   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
387   if (rc) return rc;
388 
389 
390   /*
391    * Read works w/ oversize -- mode=READ_MODE (just to mix it up)
392    */
393   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_READ_MODE);
394   if (rc) return rc;
395 
396   rc = ndmca_test_tape_read_2cnt(sess, NDMP9_NO_ERR, buf, 2048, 1024);
397   if (rc) return rc;
398 
399   rc = ndmca_test_tape_read_2cnt(sess, NDMP9_EOF_ERR, buf, 2048, 1024);
400   if (rc) return rc;
401 
402   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
403   if (rc) return rc;
404 
405   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
406   if (rc) return rc;
407 
408 
409   /*
410    * Read works w/ undersize -- mode=READ_MODE (just to mix it up)
411    */
412   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_READ_MODE);
413   if (rc) return rc;
414 
415   rc = ndmca_test_tape_read_2cnt(sess, NDMP9_NO_ERR, buf, 512, 512);
416   if (rc) return rc;
417 
418   rc = ndmca_test_tape_read_2cnt(sess, NDMP9_EOF_ERR, buf, 512, 512);
419   if (rc) return rc;
420 
421   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
422   if (rc) return rc;
423 
424   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
425   if (rc) return rc;
426 
427   return 0; /* pass */
428 }
429 
430 #define CHECK_FILENO_RECNO(WHAT, FILENO, RECNO)                        \
431   {                                                                    \
432     what = WHAT;                                                       \
433     rc = ndmca_tt_check_fileno_recno(sess, WHAT, FILENO, RECNO, note); \
434     if (rc) return -1;                                                 \
435   }
436 
437 /*
438  * Assumes tt_basic_read() and tt_basic_write() have been done verifying
439  * READ and WRITE operations work...
440  */
ndmca_tt_basic_write_and_read(struct ndm_session * sess)441 int ndmca_tt_basic_write_and_read(struct ndm_session* sess)
442 {
443   int rc, i, f, pass;
444   char buf[64 * 1024];
445   char* p;
446 
447   ndmca_test_phase(sess, "T-BWR", "Tape Write and Read Basics");
448 
449   /*
450    * check EOF and EOM by rewinding and putting on 1 EOF mark
451    */
452   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_RDWR_MODE);
453   if (rc) return rc;
454 
455   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
456   if (rc) return rc;
457 
458   rc = ndmca_check_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_BSR, 100, 100);
459   if (rc) return rc;
460 
461   rc = ndmca_check_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_BSF, 100, 100);
462   if (rc) return rc;
463 
464   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_EOF, 1, 0);
465   if (rc) return rc;
466 
467   rc = ndmca_check_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_BSF, 100, 99);
468   if (rc) return rc;
469 
470   rc = ndmca_check_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_FSF, 100, 99);
471   if (rc) return rc;
472 
473   /* we are at EOM */
474   if (sess->plumb.tape->protocol_version < 4) {
475     rc = ndmca_test_tape_read(sess, NDMP9_EOF_ERR, buf, sizeof(buf));
476     if (rc) return rc;
477 
478     /* check it again */
479     rc = ndmca_test_tape_read(sess, NDMP9_EOF_ERR, buf, 1024);
480     if (rc) return rc;
481 
482   } else {
483     rc = ndmca_test_tape_read(sess, NDMP9_EOM_ERR, buf, sizeof(buf));
484     if (rc) return rc;
485 
486     /* check it again */
487     rc = ndmca_test_tape_read(sess, NDMP9_EOM_ERR, buf, 1024);
488     if (rc) return rc;
489   }
490 
491   /* rewind and place 1 record in tape -- no EOF marker by seeking */
492 
493   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
494   if (rc) return rc;
495 
496   rc = ndmca_test_tape_write(sess, NDMP9_NO_ERR, buf, 512);
497   if (rc) return rc;
498 
499   rc = ndmca_check_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_BSR, 100, 99);
500   if (rc) return rc;
501 
502   rc = ndmca_check_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_FSR, 100, 99);
503   if (rc) return rc;
504 
505   rc = ndmca_check_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_FSR, 100, 100);
506   if (rc) return rc;
507 
508   rc = ndmca_check_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_FSF, 100, 100);
509   if (rc) return rc;
510 
511   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
512   if (rc) return rc;
513 
514   /*
515    * perform tape label type processing with positioning ops
516    */
517   for (pass = 0; pass < 2; pass++) {
518     /*
519      * open the tape and write 1 record and close it
520      */
521     rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_RDWR_MODE);
522     if (rc) return rc;
523 
524     rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
525     if (rc) return rc;
526 
527     for (p = buf, i = 0; i < 1024; i++, p++) *p = ((i - 4) & 0xff);
528 
529     rc = ndmca_test_tape_write(sess, NDMP9_NO_ERR, buf, 1024);
530     if (rc) return rc;
531 
532     rc = ndmca_tape_mtio(sess, NDMP9_MTIO_EOF, 1, 0);
533     if (rc) return rc;
534 
535     rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
536     if (rc) return rc;
537 
538     /*
539      * open the tape and read it
540      */
541     rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_RDWR_MODE);
542     if (rc) return rc;
543 
544     rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
545     if (rc) return rc;
546 
547     if (pass == 1)
548       rc =
549           ndmca_test_tape_read_2cnt(sess, NDMP9_NO_ERR, buf, sizeof(buf), 1024);
550     else
551       rc = ndmca_test_tape_read(sess, NDMP9_NO_ERR, buf, 1024);
552     if (rc) return rc;
553 
554     for (p = buf, f = i = 0; f < 64 && i < 1024; i++, p++)
555       if (*p != ((i - 4) & 0xff)) {
556         char tmp[80];
557         snprintf(tmp, sizeof(tmp), "%d: 0x%x => 0x%x", i, ((i - 4) & 0xff), *p);
558         ndmalogf(sess, "DATA", 6, tmp);
559         f++;
560       }
561     if (f > 0) {
562       ndmca_test_fail(sess, "Failed compare");
563       return -1;
564     }
565 
566     rc = ndmca_test_tape_read(sess, NDMP9_EOF_ERR, buf, 1024);
567     if (rc) return rc;
568 
569     /* check EOM */
570     if (sess->plumb.tape->protocol_version < 4) {
571       rc = ndmca_test_tape_read(sess, NDMP9_EOF_ERR, buf, 1024);
572       if (rc) return rc;
573     } else {
574       /* skip over filemark */
575       rc = ndmca_tape_mtio(sess, NDMP9_MTIO_FSF, 1, 0);
576       /* read EOM */
577       rc = ndmca_test_tape_read(sess, NDMP9_EOM_ERR, buf, 1024);
578       if (rc) return rc;
579     }
580 
581     rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
582     if (rc) return rc;
583   }
584 
585   return 0; /* pass */
586 }
587 
588 /*
589  * Precedes tt_read() so that we can make a "known" tape.
590  */
ndmca_tt_write(struct ndm_session * sess)591 int ndmca_tt_write(struct ndm_session* sess)
592 {
593   int rc;
594   unsigned n_rec;
595   unsigned recsize;
596   unsigned fileno, recno;
597   char* what;
598   char note[128];
599   char buf[64 * 1024];
600 
601   ndmca_test_phase(sess, "T-WRITE", "Tape Write Series");
602 
603   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_RDWR_MODE);
604   if (rc) return rc;
605 
606   for (fileno = 0; tt_series[fileno].n_rec > 0; fileno++) {
607     n_rec = tt_series[fileno].n_rec;
608     recsize = tt_series[fileno].recsize;
609 
610     snprintf(note, sizeof(note), "Write tape file %d", fileno + 1);
611     ndmca_test_open(sess, note, 0);
612 
613     snprintf(note, sizeof(note), "file #%d, %d records, %d bytes/rec",
614              fileno + 1, n_rec, recsize);
615     ndmca_test_log_note(sess, 2, note);
616 
617     for (recno = 0; recno < n_rec; recno++) {
618       ndmca_test_fill_data(buf, recsize, recno, fileno);
619 
620       what = "write";
621       rc = ndmca_tape_write(sess, buf, recsize);
622       if (rc) goto fail;
623 
624       CHECK_FILENO_RECNO("write", fileno, recno + 1);
625     }
626 
627     what = "write filemark";
628     rc = ndmca_tape_mtio(sess, NDMP9_MTIO_EOF, 1, 0);
629     if (rc) goto fail;
630 
631     CHECK_FILENO_RECNO("wfm", fileno + 1, 0);
632 
633     /* no test calls so the file operation is the test */
634     snprintf(buf, sizeof(buf), "Passed tape write %s", note);
635     ndmca_test_log_step(sess, 2, buf);
636   }
637 
638   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
639   if (rc) return rc;
640 
641   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
642   if (rc) return rc;
643 
644   return 0;
645 
646 fail:
647   snprintf(buf, sizeof(buf), "Failed %s recno=%d; %s", what, recno, note);
648   ndmca_test_fail(sess, buf);
649   return -1;
650 }
651 
652 
653 /*
654  * Assumes tt_write() passed
655  */
ndmca_tt_read(struct ndm_session * sess)656 int ndmca_tt_read(struct ndm_session* sess)
657 {
658   int rc;
659   unsigned n_rec;
660   unsigned recsize;
661   unsigned fileno, recno;
662   char* what;
663   char note[128];
664   char pbuf[64 * 1024];
665   char buf[64 * 1024];
666 
667   ndmca_test_phase(sess, "T-READ", "Tape Read Series");
668 
669   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_READ_MODE);
670   if (rc) return rc;
671 
672   for (fileno = 0; tt_series[fileno].n_rec > 0; fileno++) {
673     n_rec = tt_series[fileno].n_rec;
674     recsize = tt_series[fileno].recsize;
675 
676     snprintf(note, sizeof(note), "Read tape file %d", fileno + 1);
677     ndmca_test_open(sess, note, 0);
678 
679     snprintf(note, sizeof(note), "file #%d, %d records, %d bytes/rec",
680              fileno + 1, n_rec, recsize);
681     ndmca_test_log_note(sess, 2, note);
682 
683     for (recno = 0; recno < n_rec; recno++) {
684       ndmca_test_fill_data(pbuf, recsize, recno, fileno);
685 
686       what = "read";
687       rc = ndmca_tape_read(sess, buf, recsize);
688       if (rc) goto fail;
689 
690       CHECK_FILENO_RECNO("read", fileno, recno + 1);
691 
692       what = "compare";
693       if (bcmp(buf, pbuf, recsize) != 0) {
694         unsigned char* expect_p = (unsigned char*)pbuf;
695         unsigned char* got_p = (unsigned char*)buf;
696         unsigned int i, f;
697         for (f = i = 0; f < 64 && i < recsize; i++, expect_p++, got_p++) {
698           if (*expect_p != *got_p) {
699             char tmp[80];
700             snprintf(tmp, sizeof(tmp), "%d: 0x%x => 0x%x", i, *expect_p,
701                      *got_p);
702             ndmalogf(sess, "DATA", 6, tmp);
703             f++;
704           }
705         }
706         goto fail;
707       }
708     }
709 
710     what = "eof read";
711     rc = ndmca_test_tape_read(sess, NDMP9_EOF_ERR, buf, recsize);
712     if (rc) goto fail;
713 
714     if (sess->plumb.tape->protocol_version > 3) {
715       CHECK_FILENO_RECNO("eof", fileno, -1);
716 
717       what = "skip filemark";
718       rc = ndmca_tape_mtio(sess, NDMP9_MTIO_FSF, 1, 0);
719       if (rc) goto fail;
720 
721       CHECK_FILENO_RECNO("skip", fileno + 1, 0);
722     } else {
723       CHECK_FILENO_RECNO("eof", fileno + 1, 0);
724     }
725 
726     snprintf(buf, sizeof(buf), "Passed tape read %s", note);
727     ndmca_test_log_step(sess, 2, buf);
728   }
729 
730   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
731   if (rc) return rc;
732 
733   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
734   if (rc) return rc;
735 
736   return 0;
737 
738 fail:
739   snprintf(buf, sizeof(buf), "Failed %s recno=%d; %s", what, recno, note);
740   ndmca_test_fail(sess, buf);
741   return -1;
742 }
743 
744 
745 /*
746  * Assumes tt_write() passed
747  */
ndmca_tt_mtio(struct ndm_session * sess)748 int ndmca_tt_mtio(struct ndm_session* sess)
749 {
750   int rc;
751   unsigned n_rec;
752   unsigned recsize;
753   unsigned fileno, recno;
754   uint32_t count, resid;
755   char* what;
756   char note[128];
757   char pbuf[64 * 1024];
758   char buf[64 * 1024];
759 
760   ndmca_test_phase(sess, "T-MTIO", "Tape MTIO");
761 
762   rc = ndmca_test_tape_open(sess, NDMP9_NO_ERR, 0, NDMP9_TAPE_READ_MODE);
763   if (rc) return rc;
764 
765   rc = ndmca_test_tape_mtio(sess, NDMP9_NO_ERR, NDMP9_MTIO_REW, 1, 0);
766   if (rc) return rc;
767 
768   for (fileno = 0; tt_series[fileno].n_rec > 0; fileno++) {
769     n_rec = tt_series[fileno].n_rec;
770     recsize = tt_series[fileno].recsize;
771 
772     snprintf(note, sizeof(note), "Seek around tape file %d", fileno + 1);
773     ndmca_test_open(sess, note, 0);
774 
775     snprintf(note, sizeof(note), "file #%d, %d records, %d bytes/rec",
776              fileno + 1, n_rec, recsize);
777     ndmca_test_log_note(sess, 2, note);
778 
779     what = "rew";
780     count = 1;
781     rc = ndmca_tape_mtio(sess, NDMP9_MTIO_REW, count, &resid);
782     if (rc) goto fail;
783 
784     what = "rew resid";
785     if (resid != 0) goto fail;
786 
787     CHECK_FILENO_RECNO("rew", 0, 0);
788 
789 
790     what = "fsf(n)";
791     count = fileno;
792     rc = ndmca_tape_mtio(sess, NDMP9_MTIO_FSF, count, &resid);
793     if (rc) goto fail;
794 
795     what = "fsf(n) resid";
796     if (resid != 0) goto fail;
797 
798     CHECK_FILENO_RECNO("fsf", fileno, 0);
799 
800 
801     what = "fsr(1m)";
802     count = 1000000;
803     rc = ndmca_tape_mtio(sess, NDMP9_MTIO_FSR, count, &resid);
804     if (rc) goto fail;
805 
806     what = "fsr(1m) resid";
807     if (n_rec + resid != count) goto fail;
808 
809     if (sess->plumb.tape->protocol_version < 4) {
810       CHECK_FILENO_RECNO("fsr(1m)", fileno + 1, 0);
811 
812       what = "bsf 1 after fsr(1m)";
813       count = 1;
814       rc = ndmca_tape_mtio(sess, NDMP9_MTIO_BSF, count, 0);
815       if (rc) goto fail;
816 
817       CHECK_FILENO_RECNO(what, fileno, -1);
818 
819       recno = n_rec;
820     } else {
821       /* EOT side of EOF marker */
822       recno = n_rec;
823       CHECK_FILENO_RECNO("fsr(1m)", fileno, recno);
824     }
825 
826     what = "bsr(1m)";
827     count = 1000000;
828     rc = ndmca_tape_mtio(sess, NDMP9_MTIO_BSR, count, &resid);
829     if (rc) goto fail;
830 
831     what = "bsr(1m) resid";
832     if (n_rec + resid != count) goto fail;
833 
834     if ((fileno > 0) && (sess->plumb.tape->protocol_version < 4)) {
835       /* at BOT side of EOF marker (not BOT) */
836       CHECK_FILENO_RECNO("bsr(1m)", fileno - 1, -1);
837 
838       what = "fsf 1 after bsr(1m)";
839       count = 1;
840       rc = ndmca_tape_mtio(sess, NDMP9_MTIO_FSF, count, 0);
841       if (rc) goto fail;
842     }
843 
844     recno = 0;
845     CHECK_FILENO_RECNO("bsr(1m)", fileno, recno);
846 
847     what = "fsr(0)";
848     count = 0;
849     rc = ndmca_tape_mtio(sess, NDMP9_MTIO_FSR, count, &resid);
850     if (rc) goto fail;
851 
852     what = "fsr(0) resid";
853     if (resid != 0) goto fail;
854 
855     recno = 0;
856     CHECK_FILENO_RECNO("fsr(0)", fileno, recno);
857 
858 
859     what = "fsr(x)";
860     count = n_rec / 2;
861     rc = ndmca_tape_mtio(sess, NDMP9_MTIO_FSR, count, &resid);
862     if (rc) goto fail;
863 
864     what = "fsr(x) resid";
865     if (resid != 0) goto fail;
866 
867     recno = n_rec / 2;
868     CHECK_FILENO_RECNO("fsr(x)", fileno, recno);
869 
870     what = "fsr(x) read";
871     rc = ndmca_tape_read(sess, buf, recsize);
872     if (rc) goto fail;
873 
874     what = "fsr(x) compare";
875     ndmca_test_fill_data(pbuf, recsize, recno, fileno);
876     if (bcmp(buf, pbuf, recsize) != 0) goto fail;
877 
878     recno++; /* caused by tape_read */
879 
880     if (recno > 1) {
881       what = "bsr(2)";
882       count = 2;
883       rc = ndmca_tape_mtio(sess, NDMP9_MTIO_BSR, count, &resid);
884       if (rc) goto fail;
885 
886       what = "bsr(2) resid";
887       if (resid != 0) goto fail;
888 
889       recno -= count;
890       CHECK_FILENO_RECNO("bsr(2)", fileno, recno);
891 
892       what = "bsr(2) read";
893       rc = ndmca_tape_read(sess, buf, recsize);
894       if (rc) goto fail;
895 
896       what = "bsr(2) compare";
897       ndmca_test_fill_data(pbuf, recsize, recno, fileno);
898       if (bcmp(buf, pbuf, recsize) != 0) goto fail;
899     }
900 
901     snprintf(buf, sizeof(buf), "Passed %s", note);
902     ndmca_test_log_step(sess, 2, buf);
903   }
904 
905   rc = ndmca_test_tape_close(sess, NDMP9_NO_ERR);
906   if (rc) return rc;
907 
908   return 0;
909 
910 fail:
911   snprintf(buf, sizeof(buf), "Failed %s: %s", what, note);
912   ndmca_test_fail(sess, buf);
913   return -1;
914 }
915 
916 
917 /*
918  * Check the tape_state accurately reflects position
919  */
920 
ndmca_tt_check_fileno_recno(struct ndm_session * sess,char * what,uint32_t file_num,uint32_t blockno,char * note)921 int ndmca_tt_check_fileno_recno(struct ndm_session* sess,
922                                 char* what,
923                                 uint32_t file_num,
924                                 uint32_t blockno,
925                                 char* note)
926 {
927   struct ndm_control_agent* ca = sess->control_acb;
928   struct ndmp9_tape_get_state_reply* ts = 0;
929   char buf[100];
930   int rc;
931   char* oper;
932 
933   oper = "get_state";
934   rc = ndmca_tape_get_state(sess);
935   if (rc) goto fail;
936 
937   ts = &ca->tape_state;
938 
939   oper = "check file_num";
940   if (ts->file_num.value != file_num) goto fail;
941 
942   oper = "check blockno";
943   if ((ts->blockno.value != blockno) &&
944       (ts->blockno.value != NDMP9_INVALID_U_LONG))
945     goto fail;
946 
947   return 0;
948 
949 fail:
950   snprintf(buf, sizeof(buf), "Failed %s while testing %s", oper, what);
951   ndmca_test_log_note(sess, 1, buf);
952   if (ts) {
953     snprintf(buf, sizeof(buf), "    expect file_num=%ld got file_num=%ld",
954              (long)file_num, (long)ts->file_num.value);
955     ndmca_test_log_note(sess, 1, buf);
956 
957     snprintf(buf, sizeof(buf), "    expect blockno=%ld got blockno=%ld",
958              (long)blockno, (long)ts->blockno.value);
959     ndmca_test_log_note(sess, 1, buf);
960   }
961 
962   snprintf(buf, sizeof(buf), "    note: %s", note);
963   ndmca_test_fail(sess, buf);
964   return -1;
965 }
966 
967 
968 #define NDMTEST_CALL(CONN) ndmca_test_call(CONN, xa, expect_err);
969 
970 
ndmca_test_tape_open(struct ndm_session * sess,ndmp9_error expect_err,char * device,int mode)971 int ndmca_test_tape_open(struct ndm_session* sess,
972                          ndmp9_error expect_err,
973                          char* device,
974                          int mode)
975 {
976   struct ndmconn* conn = sess->plumb.tape;
977   struct ndm_control_agent* ca = sess->control_acb;
978   int rc;
979 
980   /* close previous test if there is one */
981   ndmca_test_close(sess);
982 
983   switch (conn->protocol_version) {
984     default:
985       return -1234;
986 
987 #ifndef NDMOS_OPTION_NO_NDMP2
988     case NDMP2VER:
989       NDMC_WITH(ndmp2_tape_open, NDMP2VER)
990       if (device)
991         request->device.name = device;
992       else
993         request->device.name = ca->job.tape_device;
994       if (mode != -1)
995         request->mode = mode;
996       else
997         request->mode = ca->tape_mode;
998       rc = NDMTEST_CALL(conn);
999       NDMC_ENDWITH
1000       break;
1001 #endif /* !NDMOS_OPTION_NO_NDMP2 */
1002 #ifndef NDMOS_OPTION_NO_NDMP3
1003     case NDMP3VER:
1004       NDMC_WITH(ndmp3_tape_open, NDMP3VER)
1005       if (device)
1006         request->device = device;
1007       else
1008         request->device = ca->job.tape_device;
1009       if (mode != -1)
1010         request->mode = mode;
1011       else
1012         request->mode = ca->tape_mode;
1013       rc = NDMTEST_CALL(conn);
1014       NDMC_ENDWITH
1015       break;
1016 #endif /* !NDMOS_OPTION_NO_NDMP3 */
1017 #ifndef NDMOS_OPTION_NO_NDMP4
1018     case NDMP4VER:
1019       NDMC_WITH(ndmp4_tape_open, NDMP4VER)
1020       if (device)
1021         request->device = device;
1022       else
1023         request->device = ca->job.tape_device;
1024       if (mode != -1)
1025         request->mode = mode;
1026       else
1027         request->mode = ca->tape_mode;
1028       rc = NDMTEST_CALL(conn);
1029       NDMC_ENDWITH
1030       break;
1031 #endif /* !NDMOS_OPTION_NO_NDMP4 */
1032   }
1033 
1034   return rc;
1035 }
1036 
ndmca_test_tape_close(struct ndm_session * sess,ndmp9_error expect_err)1037 int ndmca_test_tape_close(struct ndm_session* sess, ndmp9_error expect_err)
1038 {
1039   struct ndmconn* conn = sess->plumb.tape;
1040   int rc;
1041 
1042   /* close previous test if there is one */
1043   ndmca_test_close(sess);
1044 
1045   rc = ndmca_tape_close(sess);
1046 
1047   rc = ndmca_test_check_expect(conn, rc, expect_err);
1048 
1049   return rc;
1050 }
1051 
ndmca_test_tape_get_state(struct ndm_session * sess,ndmp9_error expect_err)1052 int ndmca_test_tape_get_state(struct ndm_session* sess, ndmp9_error expect_err)
1053 {
1054   struct ndmconn* conn = sess->plumb.tape;
1055   int rc;
1056 
1057   /* close previous test if there is one */
1058   ndmca_test_close(sess);
1059 
1060   rc = ndmca_tape_get_state(sess);
1061 
1062   rc = ndmca_test_check_expect(conn, rc, expect_err);
1063 
1064   return rc;
1065 }
1066 
ndmca_test_tape_mtio(struct ndm_session * sess,ndmp9_error expect_err,ndmp9_tape_mtio_op op,uint32_t count,uint32_t * resid)1067 int ndmca_test_tape_mtio(struct ndm_session* sess,
1068                          ndmp9_error expect_err,
1069                          ndmp9_tape_mtio_op op,
1070                          uint32_t count,
1071                          uint32_t* resid)
1072 {
1073   struct ndmconn* conn = sess->plumb.tape;
1074   int rc;
1075 
1076   /* close previous test if there is one */
1077   ndmca_test_close(sess);
1078 
1079   rc = ndmca_tape_mtio(sess, op, count, resid);
1080 
1081   rc = ndmca_test_check_expect(conn, rc, expect_err);
1082 
1083   return rc;
1084 }
1085 
ndmca_check_tape_mtio(struct ndm_session * sess,ndmp9_error expect_err,ndmp9_tape_mtio_op op,uint32_t count,uint32_t resid)1086 int ndmca_check_tape_mtio(struct ndm_session* sess,
1087                           ndmp9_error expect_err,
1088                           ndmp9_tape_mtio_op op,
1089                           uint32_t count,
1090                           uint32_t resid)
1091 {
1092   struct ndmconn* conn = sess->plumb.tape;
1093   uint32_t got_resid;
1094   int rc;
1095 
1096   /* close previous test if there is one */
1097   ndmca_test_close(sess);
1098 
1099   got_resid = ~resid;
1100 
1101   rc = ndmca_tape_mtio(sess, op, count, &got_resid);
1102 
1103   rc = ndmca_test_check_expect(conn, rc, expect_err);
1104   if (rc) return rc;
1105 
1106   if (resid != got_resid) {
1107     char tmp[128];
1108     snprintf(tmp, sizeof(tmp), "Residual incorrect, got %lu expected %lu",
1109              got_resid, resid);
1110     ndmca_test_fail(sess, tmp);
1111     return -1;
1112   }
1113 
1114   return rc;
1115 }
1116 
1117 
ndmca_test_tape_write(struct ndm_session * sess,ndmp9_error expect_err,char * buf,unsigned count)1118 int ndmca_test_tape_write(struct ndm_session* sess,
1119                           ndmp9_error expect_err,
1120                           char* buf,
1121                           unsigned count)
1122 {
1123   struct ndmconn* conn = sess->plumb.tape;
1124   int rc;
1125 
1126   /* close previous test if there is one */
1127   ndmca_test_close(sess);
1128 
1129   rc = ndmca_tape_write(sess, buf, count);
1130 
1131   rc = ndmca_test_check_expect(conn, rc, expect_err);
1132 
1133   return rc;
1134 }
1135 
ndmca_test_tape_read(struct ndm_session * sess,ndmp9_error expect_err,char * buf,unsigned count)1136 int ndmca_test_tape_read(struct ndm_session* sess,
1137                          ndmp9_error expect_err,
1138                          char* buf,
1139                          unsigned count)
1140 {
1141   struct ndmconn* conn = sess->plumb.tape;
1142   int rc;
1143 
1144   /* close previous test if there is one */
1145   ndmca_test_close(sess);
1146 
1147   rc = ndmca_tape_read(sess, buf, count);
1148 
1149   rc = ndmca_test_check_expect(conn, rc, expect_err);
1150 
1151   return rc;
1152 }
1153 
ndmca_test_tape_read_2cnt(struct ndm_session * sess,ndmp9_error expect_err,char * buf,unsigned count,unsigned true_count)1154 int ndmca_test_tape_read_2cnt(struct ndm_session* sess,
1155                               ndmp9_error expect_err,
1156                               char* buf,
1157                               unsigned count,
1158                               unsigned true_count)
1159 {
1160   struct ndmconn* conn = sess->plumb.tape;
1161   int rc;
1162 
1163   /* close previous test if there is one */
1164   ndmca_test_close(sess);
1165 
1166   switch (conn->protocol_version) {
1167     default:
1168       return -1234;
1169 
1170 #ifndef NDMOS_OPTION_NO_NDMP2
1171     case NDMP2VER:
1172       NDMC_WITH(ndmp2_tape_read, NDMP2VER)
1173       request->count = count;
1174       rc = NDMTEST_CALL(conn);
1175       if (rc == 0 && expect_err == NDMP9_NO_ERR) {
1176         if (reply->data_in.data_in_len == true_count) {
1177           bcopy(reply->data_in.data_in_val, buf, true_count);
1178         } else {
1179           rc = -1;
1180         }
1181       }
1182       NDMC_FREE_REPLY();
1183       NDMC_ENDWITH
1184       break;
1185 #endif /* !NDMOS_OPTION_NO_NDMP2 */
1186 #ifndef NDMOS_OPTION_NO_NDMP3
1187     case NDMP3VER:
1188       NDMC_WITH(ndmp3_tape_read, NDMP3VER)
1189       request->count = count;
1190       rc = NDMTEST_CALL(conn);
1191       if (rc == 0 && expect_err == NDMP9_NO_ERR) {
1192         if (reply->data_in.data_in_len == true_count) {
1193           bcopy(reply->data_in.data_in_val, buf, true_count);
1194         } else {
1195           rc = -1;
1196         }
1197       }
1198       NDMC_FREE_REPLY();
1199       NDMC_ENDWITH
1200       break;
1201 #endif /* !NDMOS_OPTION_NO_NDMP3 */
1202 #ifndef NDMOS_OPTION_NO_NDMP4
1203     case NDMP4VER:
1204       NDMC_WITH(ndmp4_tape_read, NDMP4VER)
1205       request->count = count;
1206       rc = NDMTEST_CALL(conn);
1207       if (rc == 0 && expect_err == NDMP9_NO_ERR) {
1208         if (reply->data_in.data_in_len == true_count) {
1209           bcopy(reply->data_in.data_in_val, buf, true_count);
1210         } else {
1211           rc = -1;
1212         }
1213       }
1214       NDMC_FREE_REPLY();
1215       NDMC_ENDWITH
1216       break;
1217 #endif /* !NDMOS_OPTION_NO_NDMP4 */
1218   }
1219 
1220   return rc;
1221 }
1222 #endif /* !defined(NDMOS_OPTION_NO_CONTROL_AGENT) && \
1223           !defined(NDMOS_OPTION_NO_TEST_AGENTS) */
1224