4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/time_impl.h>
31 #include <stdio_ext.h>
38 #include <sys/resource.h>
44 #include <libdevinfo.h>
46 #include <sys/dditypes.h>
47 #include <sys/sunddi.h>
50 #define BOFI_DEV "/devices/pseudo/bofi@0:bofi,ctl"
52 #define GETSTRUCT(s, num) \
53 ((s *) memalign(sizeof (void*), (num) * sizeof (s)))
55 #define MAXEDEFS (0x64) /* controls max no of concurent edefs */
56 #define DFLTLOGSZ (0x4000) /* default size of an access log */
57 #define DFLT_NONPIO_LOGSZ (0x400) /* default size of a log */
58 #define MAXALRMCALL (0x1000ull) /* alarm does not permit big values */
59 #define MIN_REPORT_TIME (5) /* min time to wait for edef status */
60 #define DISTRIB_CUTOFF (3) /* useful when reducing a log */
61 #define myLLMAX (0x7fffffffffffffffll)
62 #define myULLMAX (0xffffffffffffffffull)
65 * default interval to wait between kicking off workload and injecting fault
67 #define DEFAULT_EDEF_SLEEP 3
69 * when generating dma corruptions, it is best to corrupt each double word
70 * individually for control areas - however for data areas this can be
71 * excessive and would generate so many cases we would never finish the run.
72 * So set a cut-off value where we switch from corrupting each double word
73 * separately to corrupting th elot in one go. 0x100 bytes seems a good value
74 * on the drivers we have seen so far.
76 #define DMA_INDIVIDUAL_CORRUPT_CUTOFF 0x100
78 struct collector_def
{
79 struct bofi_errdef ed
; /* definition of the log criteria */
80 struct bofi_errstate es
; /* the current status of the log */
81 struct acc_log_elem
*lp
; /* array of logged accesses */
85 static uint16_t policy
;
87 #define BYTEPOLICY (0xf)
88 #define MULTIPOLICY (0x10)
89 #define SIZEPOLICY (BYTEPOLICY|MULTIPOLICY)
90 #define UNBIASEDPOLICY 0x20
91 #define UNCOMMONPOLICY 0x40
92 #define COMMONPOLICY 0x80
93 #define MEDIANPOLICY 0x100
94 #define MAXIMALPOLICY 0x200
95 #define OPERATORSPOLICY 0x400
96 #define VALIDPOLICY (0x7ff)
104 static coding_t ptypes
[] = {
105 {"onebyte", 0x1}, {"twobyte", 0x2},
106 {"fourbyte", 0x4}, {"eightbyte", 0x8},
107 {"multibyte", 0x10}, {"unbiased", 0x20}, {"uncommon", 0x40},
108 {"common", 0x80}, {"median", 0x100}, {"maximal", 0x200},
109 {"operators", 0x400}, {0, 0}
111 static coding_t atypes
[] = {
112 {"pio_r", BOFI_PIO_R
}, {"pio_w", BOFI_PIO_W
},
113 {"dma_r", BOFI_DMA_R
}, {"dma_w", BOFI_DMA_W
},
114 {"pio", BOFI_PIO_RW
}, {"dma", BOFI_DMA_RW
},
115 {"log", BOFI_LOG
}, {"intr", BOFI_INTR
},
116 {"PIO_R", BOFI_PIO_R
}, {"PIO_W", BOFI_PIO_W
},
117 {"DMA_R", BOFI_DMA_R
}, {"DMA_W", BOFI_DMA_W
},
118 {"PIO", BOFI_PIO_RW
}, {"DMA", BOFI_DMA_RW
},
119 {"LOG", BOFI_LOG
}, {"INTR", BOFI_INTR
}, {0, 0}
121 static coding_t optypes
[] = {
122 {"EQ", BOFI_EQUAL
}, {"AND", BOFI_AND
}, {"OR", BOFI_OR
},
123 {"XOR", BOFI_XOR
}, {"NO", BOFI_NO_TRANSFER
},
124 {"DELAY", BOFI_DELAY_INTR
}, {"LOSE", BOFI_LOSE_INTR
},
125 {"EXTRA", BOFI_EXTRA_INTR
}, {0, 0}
127 static coding_t doptypes
[] = {
128 {"EQ", BOFI_EQUAL
}, {"AND", BOFI_AND
}, {"OR", BOFI_OR
},
129 {"XOR", BOFI_XOR
}, {0, 0}
131 static coding_t ioptypes
[] = {
132 {"DELAY", BOFI_DELAY_INTR
}, {"LOSE", BOFI_LOSE_INTR
},
133 {"EXTRA", BOFI_EXTRA_INTR
}, {0, 0}
136 static const unsigned long long DFLTLOGTIME
= -1ull; /* log forever */
139 * This global controls the generation of errdefs for PIO_W. The default should
140 * be to only perform an access check errdef but not to corrupt writes - this
141 * may trash non-FT platforms.
143 static uint_t atype_is_default
; /* do not corrupt PIO_W by default */
144 static uint_t lsize_is_default
; /* set when the user has not given a size */
146 static uint64_t random_operand
= 0xdeadbeafdeadbeafull
;
147 #define NPIO_DEFAULTS (3) /* number of default corruption values */
148 static longlong_t pio_default_values
[NPIO_DEFAULTS
] = {
149 0x0ull
, /* corresponds to a line going high/low */
150 0x32f1f03232f1f032ull
, /* the value returned when the fake ta is set */
151 (longlong_t
)(~0) /* corresponds to a line going high/low */
154 static uint_t dbglvl
= 0; /* debug this program */
155 static int alarmed
= 0;
156 static int killed
= 0;
159 * name of a script to call before offlining a driver being tested
161 static char **fixup_script
= 0;
162 static int scriptargs
= 0;
166 static int max_edef_wait
= 0;
167 static int edef_sleep
= 0;
168 static int do_status
= 0; /* report edef status in parsable format */
169 static char *user_comment
= 0;
171 static char *Progname
;
172 static FILE *errfile
;
173 static FILE *outfile
;
176 * The th_define utility provides an interface to the bus_ops fault injection
177 * bofi device driver for defining error injection specifications (referred to
178 * as errdefs). An errdef corresponds to a specification of how to corrupt a
179 * device driver's accesses to its hardware. The command line arguments
180 * determine the precise nature of the fault to be injected. If the supplied
181 * arguments define a consistent errdef, the th_define process will store the
182 * errdef with the bofi driver and suspend itself until the criteria given by
183 * the errdef become satisfied (in practice, this will occur when the access
184 * counts go to zero).
186 * When the resulting errdef is activated using the th_manage(1M) user command
187 * utility, the bofi driver will act upon the errdef by matching the number of
188 * hardware accesses - specified in count, that are of the type specified in
189 * acc_types, made by instance number instance - of the driver whose name is
190 * name, (or by the driver instance specified by * path ) to the register set
191 * (or DMA handle) specified by rnumber, that lie within the range offset to
192 * offset + length from the beginning of the register set or DMA handle. It then
193 * applies operator and operand to the next failcount matching accesses.
195 * If acc_types includes LOG, th_define runs in automatic test script generation
196 * mode, and a set of test scripts (written in the Korn shell) is created and
197 * placed in a sub-directory of the current directory with the name
198 * driver.test.<id>. A separate, executable script is generated for each access
199 * handle that matches the logging criteria. The log of accesses is placed at
200 * the top of each script as a record of the session. If the current directory
201 * is not writable, file output is written to standard output. The base name of
202 * each test file is the driver name, and the extension is a number that
203 * discriminates between different access handles. A control script (with the
204 * same name as the created test directory) is generated that will run all the
205 * test scripts sequentially.
207 * Executing the scripts will install, and then activate, the resulting error
208 * definitions. Error definitions are activated sequentially and the driver
209 * instance under test is taken offline and brought back online before each test
210 * (refer to the -e option for more information). By default, logging will apply
211 * to all PIO accesses, interrupts and DMA accesses to and from areas mapped
212 * for both reading and writing, but it can be constrained by specifying
213 * additional acc_types, rnumber, offset and length. Logging will continue for
214 * count matching accesses, with an optional time limit of collect_time seconds.
216 * Either the -n or -P option must be provided. The other options are optional.
217 * If an option (other than the -a option) is specified multiple times, only
218 * the final value for the option is used. If an option is not specified, its
219 * associated value is set to an appropriate default, which will provide
220 * maximal error coverage as described below.
225 msg(uint_t lvl
, char *msg
, ...)
236 count
= vsnprintf(buf
, BUFSZ
, msg
, args
);
240 if (count
>= sizeof (buf
))
243 (void) fprintf(errfile
, "%s", buf
);
249 kill_sighandler(int sig
)
266 (void) sigfillset(&(sa
.sa_mask
));
268 sa
.sa_handler
= kill_sighandler
;
269 if (sigaction(sig
, &sa
, NULL
) != 0)
270 /* install handler */
271 msg(0, "bad sigaction: %s\n", strerror(errno
));
275 * Compare two driver access handles
278 hdl_cmp(const void *p1
, const void *p2
)
280 struct handle_info
*e1
= (struct handle_info
*)p1
;
281 struct handle_info
*e2
= (struct handle_info
*)p2
;
283 if (e1
->instance
< e2
->instance
)
285 else if (e1
->instance
> e2
->instance
)
287 else if (e1
->access_type
< e2
->access_type
)
289 else if (e1
->access_type
> e2
->access_type
)
291 else if (e1
->rnumber
< e2
->rnumber
)
293 else if (e1
->rnumber
> e2
->rnumber
)
295 else if (e1
->len
< e2
->len
)
297 else if (e1
->len
> e2
->len
)
299 else if (e1
->offset
< e2
->offset
)
301 else if (e1
->offset
> e2
->offset
)
303 else if (e1
->addr_cookie
< e2
->addr_cookie
)
305 else if (e1
->addr_cookie
> e2
->addr_cookie
)
312 * Compare two hardware accesses.
315 elem_cmp(const void *p1
, const void *p2
)
317 struct acc_log_elem
*e1
= (struct acc_log_elem
*)p1
;
318 struct acc_log_elem
*e2
= (struct acc_log_elem
*)p2
;
320 if (e1
->access_type
< e2
->access_type
)
322 else if (e1
->access_type
> e2
->access_type
)
324 else if (e1
->offset
< e2
->offset
)
326 else if (e1
->offset
> e2
->offset
)
328 else if (e1
->size
< e2
->size
)
330 else if (e1
->size
> e2
->size
)
337 * Another way of comparing two hardware accesses.
340 log_cmp(const void *p1
, const void *p2
)
342 struct acc_log_elem
*e1
= (struct acc_log_elem
*)p1
;
343 struct acc_log_elem
*e2
= (struct acc_log_elem
*)p2
;
345 int rval
= elem_cmp(p1
, p2
);
348 if (e1
->repcount
< e2
->repcount
)
350 else if (e1
->repcount
> e2
->repcount
)
359 * And a final way of sorting a log (by access type followed by repcount).
362 log_cmp2(const void *p1
, const void *p2
)
364 struct acc_log_elem
*e1
= (struct acc_log_elem
*)p1
;
365 struct acc_log_elem
*e2
= (struct acc_log_elem
*)p2
;
367 if (e1
->access_type
< e2
->access_type
)
369 else if (e1
->access_type
> e2
->access_type
)
371 else if (e1
->repcount
< e2
->repcount
)
373 else if (e1
->repcount
> e2
->repcount
)
380 dump_log(uint_t lvl
, FILE *fp
, struct acc_log_elem
*items
,
381 size_t nitems
, uint_t logflags
)
385 uint_t offset
, allthesame
= 1;
387 if (logflags
& BOFI_LOG_TIMESTAMP
&&
388 getenv("DUMP_FULL_LOG") != 0)
391 for (i
= 1; i
< nitems
; i
++)
392 if (elem_cmp(items
+i
, items
) != 0)
396 "# Logged Accesses:\n# %-4s\t%-12s\t%-4s\t%-18s"
397 " (%-1s)\t%-10s\n\n", "type",
398 (items
->access_type
& BOFI_DMA_RW
) ?
399 "address" : "offset",
400 "size", "value", "repcnt", "time");
402 for (i
= 0; i
< nitems
; i
++, items
++) {
403 offset
= items
->offset
;
406 "# 0x%-2x\t0x%-10x\t%-4d\t0x%-16llx"
407 " (0x%-1x)\t%-8llu\n",
408 items
->access_type
, offset
, items
->size
,
409 items
->value
, items
->repcount
,
410 (logflags
& BOFI_LOG_TIMESTAMP
) ?
411 items
->access_time
: 0ull);
415 "# Access duplicated %d times\n",
420 msg(lvl
, "# 0x%x 0x%x %d 0x%llx(0x%x) %llu\n",
421 items
->access_type
, offset
, items
->size
,
422 items
->value
, items
->repcount
,
423 (logflags
& BOFI_LOG_TIMESTAMP
) ?
424 items
->access_time
: 0ull);
430 str_to_bm(char *optarg
, coding_t
*c
, uint_t
*bm
)
436 msg(2, "str_to_bm: optarg %s\n", optarg
);
437 if (optarg
!= NULL
&& (str
= strtok(optarg
, s
))) {
438 msg(2, "str_to_bm: str %s\n", str
);
440 for (; c
->str
!= 0; c
++)
441 if (strcmp(str
, c
->str
) == 0) {
443 msg(2, "str_to_bm: %s matches\n",
448 } while ((str
= strtok(NULL
, s
)));
451 msg(2, "str_to_bm: done 0x%x\n", *bm
);
457 * Generic routine for commands that apply to a particular instance of
458 * a driver under test (e.g. activate all errdefs defined on an instance).
461 manage_instance(int fd
, char *namep
, int instance
, int cmd
)
463 struct bofi_errctl errctl
;
465 errctl
.namesize
= strlen(namep
);
466 (void) strncpy(errctl
.name
, namep
, MAXNAMELEN
);
467 errctl
.instance
= instance
;
469 msg(8, "manage_instance: %s %d\n", namep
, instance
);
470 if (ioctl(fd
, cmd
, &errctl
) == -1) {
471 msg(0, "bofi ioctl %d failed: %s\n", cmd
, strerror(errno
));
481 struct bofi_errdef
*edp
,
482 struct acc_log_elem
*item
,
486 int fon
, /* corrupt after this many accesses */
487 size_t fcnt
, /* and then fail it fcnt times */
493 "-n %s -i %d -r %d -l 0x%llx 0x%x -a %s -c %d %d -f %d"
498 edp
->offset
+ item
->offset
, /* offset into the regset */
499 item
->size
, /* corrupt addrs from offset to offset+size */
501 fon
, /* corrupt after this many accesses */
502 fcnt
, /* and then fail it fcnt times */
507 (void) fprintf(fp
, " -w %lu %lu\n", nttime
, interval
);
512 define_op_err(FILE *fp
, int *ecnt
, struct bofi_errdef
*edp
,
513 struct acc_log_elem
*item
, ulong_t nttime
, ulong_t interval
, char *type
,
514 int fon
, size_t fcnt
)
521 uint64_t save_offset
;
523 if (item
->access_type
& BOFI_INTR
)
529 * errdefs for dma accesses are too numerous so assume that dma writes
530 * (DDI_DMA_SYNC_FORDEV) create less exposure to potential errors than
531 * do dma reads (DDI_DMA_SYNC_FORCPU).
533 * also by default do not corrupt PIO_W - it may hang a non-FT platform.
535 if (item
->access_type
!= BOFI_DMA_W
&&
536 ((item
->access_type
& BOFI_PIO_W
) == 0 || !atype_is_default
)) {
538 * user has asked for PIO_W
540 for (; ct
->str
!= 0; ct
++) {
545 operand
= random_operand
; /* a random value */
546 random_operand
= lrand48() | ((uint64_t)
550 operand
= 0xaddedabadb00bull
;
559 case BOFI_DELAY_INTR
: /* delay for 1 msec */
562 case BOFI_LOSE_INTR
: /* op not applicable */
565 case BOFI_EXTRA_INTR
: /* extra intrs */
571 if ((item
->access_type
== BOFI_DMA_W
||
572 item
->access_type
== BOFI_DMA_R
) &&
573 item
->size
> sizeof (uint64_t) && item
->size
<
574 DMA_INDIVIDUAL_CORRUPT_CUTOFF
) {
575 save_size
= item
->size
;
576 save_offset
= item
->offset
;
577 for (k
= (item
->size
+
578 sizeof (uint64_t) - 1) &
579 ~(sizeof (uint64_t) - 1);
580 k
> 0; k
-= sizeof (uint64_t)) {
581 item
->size
= sizeof (uint64_t);
582 (void) define_one_error(fp
, edp
,
583 item
, nttime
, interval
, type
, fon
,
584 fcnt
, edp
->acc_chk
, opname
,
586 item
->offset
+= sizeof (uint64_t);
588 item
->size
= save_size
;
589 item
->offset
= save_offset
;
591 (void) define_one_error(fp
, edp
, item
,
592 nttime
, interval
, type
, fon
, fcnt
,
593 edp
->acc_chk
, opname
, operand
);
596 if (op
== BOFI_EQUAL
) {
598 for (cnt
= 0; cnt
< NPIO_DEFAULTS
;
599 cnt
++, *ecnt
= *ecnt
+ 1) {
600 if ((item
->access_type
== BOFI_DMA_W
||
601 item
->access_type
== BOFI_DMA_R
) &&
602 item
->size
> sizeof (uint64_t) &&
604 DMA_INDIVIDUAL_CORRUPT_CUTOFF
) {
605 save_size
= item
->size
;
606 save_offset
= item
->offset
;
607 for (k
= (item
->size
+
608 sizeof (uint64_t) - 1) &
609 ~(sizeof (uint64_t) - 1);
611 k
-= sizeof (uint64_t)) {
614 (void) define_one_error(
625 item
->size
= save_size
;
626 item
->offset
= save_offset
;
628 (void) define_one_error(fp
,
629 edp
, item
, nttime
, interval
,
631 edp
->acc_chk
, opname
,
632 pio_default_values
[cnt
]);
639 if ((item
->access_type
& BOFI_PIO_W
) && !atype_is_default
) {
641 * user has asked for PIO_W
643 (void) define_one_error(fp
, edp
, item
, nttime
, interval
,
644 type
, fon
, fcnt
, edp
->acc_chk
, "NO", 0);
649 * and finally an access check errdef
651 if (item
->access_type
& BOFI_PIO_RW
)
652 (void) define_one_error(fp
, edp
, item
, nttime
, interval
,
653 type
, fon
, fcnt
, 1, "OR", 0);
655 if (item
->access_type
& BOFI_DMA_RW
)
656 (void) define_one_error(fp
, edp
, item
, nttime
, interval
,
657 type
, fon
, fcnt
, 2, "OR", 0);
662 * Convert a collection of log entries into error definitions.
666 define_nerrs(int fd
, FILE *fp
, int *ecnt
, struct bofi_errdef
*edp
,
667 struct acc_log_elem
*items
,
678 struct acc_log_elem
*item
;
682 int cycleiops
, cycledops
;
684 ulong_t ttime
, nttime
, interval
;
687 operand
= edp
->operand
;
688 msg(3, "define_nerrs: nitems %d (ac %d at 0x%x): (%d %d)"
689 " (op 0x%x 0x%llx)\n\n", nitems
, naccess
, items
->access_type
,
690 minac
, maxac
, op
, operand
);
693 * all items are guaranteed have values in the two element set {0, at}
694 * where at is a valid access type (so find the value of at)
696 for (i
= 0, item
= items
, at
= 0; i
< nitems
; i
++, item
++)
697 if (item
->access_type
!= 0) {
698 at
= item
->access_type
;
705 * find the string form of the access type
707 for (i
= 0, type
= 0; atypes
[i
].str
!= 0; i
++) {
708 if (atypes
[i
].code
== at
) {
709 type
= atypes
[i
].str
;
714 msg(0, "Unknown access type returned from bofi\n\t");
715 dump_log(0, 0, item
, 1, BOFI_LOG_TIMESTAMP
);
716 msg(1, "0x%x 0x%x 0x%x 0x%x\n", BOFI_LOG
, BOFI_INTR
,
717 BOFI_DMA_RW
, BOFI_PIO_RW
);
721 msg(1, "define_n: at = 0x%d (%s)\n", at
, type
== 0 ? "null" : type
);
723 * find the string form of the operator
725 for (i
= 0, opname
= 0; optypes
[i
].str
!= 0; i
++) {
726 if (op
== optypes
[i
].code
) {
727 opname
= optypes
[i
].str
;
733 * if not found or inconsistent default to XOR
736 (op
== BOFI_NO_TRANSFER
&&
737 (at
& (BOFI_DMA_RW
|BOFI_PIO_R
))) ||
738 (op
>= BOFI_DELAY_INTR
&& (at
& BOFI_INTR
) == 0)) {
739 opname
= optypes
[3].str
; /* "XOR" */
741 op
= optypes
[3].code
;
745 * if operator and access type are inconsistent choose a sensible
750 if (op
< BOFI_DELAY_INTR
)
752 else if (op
== BOFI_LOSE_INTR
)
756 if (nitems
== 1 && (at
& BOFI_DMA_RW
))
759 * for each access in the list define one or more error definitions
761 for (i
= 0, item
= items
; i
< nitems
; i
++, item
++) {
765 if (item
->access_type
== 0)
769 * base number of errors to inject on 3% of number of
770 * similar accesses seen during LOG phase
772 acnt
= item
->repcount
/ 10 + 1; /* 10% */
773 fcnt
= (acnt
>= 3) ? acnt
/ 3 : 1; /* 3% */
776 * wait for twice the time it took during LOG phase
778 if ((ttime
= (item
->access_time
* 2)) < MIN_REPORT_TIME
)
779 ttime
= MIN_REPORT_TIME
;
780 else if (max_edef_wait
!= 0 && ttime
> max_edef_wait
)
781 ttime
= max_edef_wait
;
783 * if edef_sleep set (-w) the use that, otherwise use default
785 interval
= edef_sleep
? edef_sleep
: DEFAULT_EDEF_SLEEP
;
788 "define_n: item %d limit %d step %d (intr %d) tt(%lu)\n",
789 i
, item
->repcount
, acnt
, intrs
, ttime
);
791 for (j
= 0, fon
= 1, nttime
= ttime
; j
< item
->repcount
;
793 if (policy
& OPERATORSPOLICY
) {
794 define_op_err(fp
, ecnt
, edp
, item
,
795 nttime
, interval
, type
, fon
, fcnt
);
798 op
= ioptypes
[intrs
].code
;
799 opname
= ioptypes
[intrs
++].str
;
801 case BOFI_DELAY_INTR
:
802 /* delay for 1 sec */
806 /* op not applicable */
809 case BOFI_EXTRA_INTR
:
811 /* generate 2 extra intrs */
816 } else if (cycledops
) {
817 op
= doptypes
[intrs
].code
;
818 opname
= doptypes
[intrs
++].str
;
821 random_operand
= lrand48() |
824 break; /* a random value */
826 operand
= 0xaddedabadb00bull
;
829 operand
= 0xd1ab011c0af1a5c0ull
;
838 (void) define_one_error(fp
, edp
, item
,
839 nttime
, interval
, type
, fon
,
840 fcnt
, edp
->acc_chk
, opname
, operand
);
842 if (op
== BOFI_EQUAL
) {
844 for (cnt
= 0; cnt
< NPIO_DEFAULTS
;
845 cnt
++, *ecnt
= *ecnt
+ 1)
846 (void) define_one_error(fp
,
848 interval
, type
, fon
, fcnt
,
849 edp
->acc_chk
, opname
,
850 pio_default_values
[cnt
]);
855 * all non maximal policies should only generate
856 * a single error definition set per access.
858 if (!(policy
& MAXIMALPOLICY
))
861 nttime
= (logtime
- item
->access_time
) *
862 (j
+ acnt
+ fcnt
- 1) / logsize
;
863 if (nttime
< MIN_REPORT_TIME
)
864 nttime
= MIN_REPORT_TIME
;
865 else if (nttime
> max_edef_wait
)
866 nttime
= max_edef_wait
;
868 msg(11, "define_nerrs: %lu %d %d %d %llu\n", nttime
,
869 max_edef_wait
, fon
, fcnt
, item
->access_time
);
871 if (item
->access_type
!= BOFI_INTR
)
880 reduce_log(uint16_t pol
, struct acc_log
*log
, /* input args */
881 struct acc_log_elem
**llp
, size_t *cntp
) /* output args */
884 struct acc_log_elem
*items
, *item
, *elem
;
885 int cnt
, nitems
, acnt
;
886 int i
, j
, k
, lb
, ub
, mina
, maxa
, cutoff
[2], mean
;
888 if (llp
== 0 || cntp
== 0) /* subroutine interface violated */
892 items
= (void *)log
->logbase
;
893 nitems
= log
->entries
;
895 items
= *llp
; /* outputs double up as inputs */
898 /* has the utc time wrapped over ULMAX - unlikely so fix it at 10 */
899 logtime
= (log
->stop_time
>= log
->start_time
) ?
900 log
->stop_time
- log
->start_time
: 10ul;
902 msg(1, "reduce %d: logtime %lu\n", nitems
, logtime
);
904 * Sort the log by access type - do not remove duplicates yet (but do
905 * remove access that do not match the requested log -> errdef policy
906 * (defined by union pu pol). Set the repcount field of each entry to a
907 * unique value (in the control statement of the for loop) - this
908 * ensures that the qsort (following the for loop) will not remove any
911 for (i
= 0, cnt
= 0, elem
= items
; i
< nitems
;
912 elem
->repcount
= i
, i
++, elem
++) {
914 * If interested in the I/O transfer size and this access
915 * does not match the requested size then ignore the access
917 if ((pol
& SIZEPOLICY
) &&
918 (!(pol
& MULTIPOLICY
) || elem
->repcount
== 1) &&
919 /* req for DMA / ddi_rep */
920 (pol
& elem
->size
) == 0)
921 elem
->access_type
= 0;
922 /* these will end up sorted at the head */
925 elem
->size
*= elem
->repcount
;
926 if (log
->flags
& BOFI_LOG_TIMESTAMP
)
927 /* real access time */
928 elem
->access_time
-= log
->start_time
;
931 elem
->access_time
= logtime
* (i
+ 1) / nitems
;
935 qsort((void *)items
, nitems
, sizeof (*items
), log_cmp
);
937 msg(5, "qsorted log raw (nitems %d cnt %d:\n", nitems
, cnt
);
938 dump_log(14, 0, items
, nitems
, log
->flags
);
940 if (cnt
!= nitems
) { /* some items should be ignored */
941 items
+= (nitems
- cnt
); /* ignore these ones */
942 if ((nitems
= cnt
) == 0) {
946 /* the chosen policy has ignored everything */
951 * Now remove duplicate entries based on access type, address and size.
952 * Reuse the repcount field to store the no. of duplicate accesses.
953 * Store the average access time in the single remaining
954 * representative of the duplicate set.
957 for (i
= 1, cnt
= 1, elem
= items
, elem
->repcount
= 1, item
= elem
+ 1;
958 i
< nitems
; i
++, item
++) {
959 if (elem_cmp(elem
, item
) == 0) {
960 elem
->access_time
+= item
->access_time
;
962 } else { /* not a duplicate */
963 elem
->access_time
= logtime
/ elem
->repcount
;
970 elem
->access_time
= logtime
/ elem
->repcount
;
973 * The log is sorted by access type - now resort to order by frequency
974 * of accesses (ie for a given access type uncommon access will come
978 qsort((void *)items
, cnt
, sizeof (*items
), log_cmp2
);
979 msg(4, "qsorted log2: cnt is %d\n", cnt
);
980 dump_log(4, 0, items
, cnt
, log
->flags
);
982 for (i
= 0; i
< cnt
; i
= j
) {
985 * Pick out the set [i, j) consisting of elements with the same
988 for (j
= i
+ 1, acnt
= items
[i
].repcount
; j
< cnt
&&
989 items
[j
].access_type
== items
[i
].access_type
; j
++)
990 acnt
+= items
[j
].repcount
;
992 if (j
- i
== 1) /* never ignore solo accesses of a given type */
995 * Now determine what constitutes uncommon and common accesses:
997 mina
= items
[i
].repcount
;
998 maxa
= items
[j
-1].repcount
;
999 mean
= acnt
/ (j
- i
); /* mean value */
1001 if (pol
& (UNCOMMONPOLICY
|MEDIANPOLICY
)) {
1002 cutoff
[0] = (mean
- mina
) / DISTRIB_CUTOFF
+ mina
;
1004 for (ub
= i
; ub
< j
; ub
++)
1005 if (items
[ub
].repcount
> cutoff
[0])
1013 if (pol
& (COMMONPOLICY
|MEDIANPOLICY
)) {
1014 cutoff
[1] = maxa
- (maxa
- mean
) / DISTRIB_CUTOFF
;
1015 for (lb
= j
- 1; lb
>= i
; lb
--)
1016 if (items
[lb
].repcount
< cutoff
[1])
1018 if (!(pol
& (UNCOMMONPOLICY
|MEDIANPOLICY
)))
1022 msg(3, "reduce_log: p 0x%x at %d:0x%x %d:0x%x acnt mina maxa"
1024 " mean %d cutoffs(%d %d) bnds(%d, %d)\n",
1025 pol
, i
, items
[i
].access_type
, j
, items
[j
].access_type
,
1026 acnt
, mina
, maxa
, mean
, cutoff
[0], cutoff
[1], lb
, ub
);
1029 if (!(pol
& MEDIANPOLICY
))
1030 /* delete all the mid accesses */
1031 for (k
= ub
; k
<= lb
; k
++)
1032 items
[k
].access_type
= 0;
1034 if (!(pol
& UNCOMMONPOLICY
))
1035 /* delete uncommon accesses */
1036 for (k
= i
; k
< ub
; k
++)
1037 items
[k
].access_type
= 0;
1038 if (!(pol
& COMMONPOLICY
))
1039 /* delete common accesses */
1040 for (k
= lb
+1; k
< j
; k
++)
1041 items
[k
].access_type
= 0;
1044 msg(4, "reduce_log: returning %d items\n", cnt
);
1045 dump_log(5, 0, items
, cnt
, log
->flags
);
1052 log2errdefs(int fd
, struct bofi_errdef
*edp
, struct acc_log
*log
,
1055 struct acc_log_elem
*items
;
1059 char fname
[_POSIX_PATH_MAX
];
1061 time_t utc
= time(NULL
);
1066 struct stat statbuf
;
1068 items
= (void *)log
->logbase
;
1069 nitems
= log
->entries
;
1070 logtime
= (log
->stop_time
>= log
->start_time
) ?
1071 log
->stop_time
- log
->start_time
: 10ul;
1076 /* ensure that generated errdefs complete in bounded time */
1077 if (max_edef_wait
== 0)
1079 logtime
> MIN_REPORT_TIME
? logtime
: MIN_REPORT_TIME
* 2;
1081 msg(4, "log2errdefs(0x%p, 0x%p, %d, 0x%x):\n",
1082 (void *) edp
, (void *) items
, nitems
, policy
);
1084 (void) snprintf(fname
, sizeof (fname
), "%s.%d", (char *)edp
->name
,
1086 if ((fp
= fopen(fname
, "w")) == 0)
1089 (void) fprintf(fp
, "#!/bin/ksh -p\n\n");
1090 (void) fprintf(fp
, "# %-24s%s\n", "Script creation time:", ctime(&utc
));
1091 (void) fprintf(fp
, "# %-24s%llu\n",
1092 "Activation time:", log
->start_time
);
1093 (void) fprintf(fp
, "# %-24s%llu\n",
1094 "Deactivation time:", log
->stop_time
);
1095 (void) fprintf(fp
, "# %-24s%d\n", "Log size:", nitems
);
1096 (void) fprintf(fp
, "# %-24s", "Errdef policy:");
1097 for (i
= 0; ptypes
[i
].str
!= 0; i
++)
1098 if (policy
& ptypes
[i
].code
)
1099 (void) fprintf(fp
, "%s ", ptypes
[i
].str
);
1100 (void) fprintf(fp
, "\n");
1101 (void) fprintf(fp
, "# %-24s%s\n", "Driver:", (char *)edp
->name
);
1102 (void) fprintf(fp
, "# %-24s%d\n", "Instance:", edp
->instance
);
1103 if (edp
->access_type
& BOFI_PIO_RW
) {
1104 (void) fprintf(fp
, "# %-24s%d\n",
1105 "Register set:", edp
->rnumber
);
1106 (void) fprintf(fp
, "# %-24s0x%llx\n", "Offset:", edp
->offset
);
1107 (void) fprintf(fp
, "# %-24s0x%llx\n", "Length:", edp
->len
);
1108 } else if (edp
->access_type
& BOFI_DMA_RW
) {
1109 (void) fprintf(fp
, "# %-24s%d\n", "DMA handle:", edp
->rnumber
);
1110 (void) fprintf(fp
, "# %-24s0x%llx\n", "Offset:", edp
->offset
);
1111 (void) fprintf(fp
, "# %-24s0x%llx\n", "Length:", edp
->len
);
1112 } else if ((edp
->access_type
& BOFI_INTR
) == 0) {
1113 (void) fprintf(fp
, "# %-24s%d\n",
1114 "Unknown Handle Type:", edp
->rnumber
);
1117 (void) fprintf(fp
, "# %-24s0x%x ( ", "Access type:",
1118 (edp
->access_type
& ~BOFI_LOG
));
1119 if (edp
->access_type
& BOFI_PIO_R
)
1120 (void) fprintf(fp
, "%s ", "pio_r");
1121 if (edp
->access_type
& BOFI_PIO_W
)
1122 (void) fprintf(fp
, "%s ", "pio_w");
1123 if (edp
->access_type
& BOFI_DMA_W
)
1124 (void) fprintf(fp
, "%s ", "dma_w");
1125 if (edp
->access_type
& BOFI_DMA_R
)
1126 (void) fprintf(fp
, "%s ", "dma_r");
1127 if (edp
->access_type
& BOFI_INTR
)
1128 (void) fprintf(fp
, "%s ", "intr");
1129 (void) fprintf(fp
, ")\n\n");
1131 (void) fprintf(fp
, "# %-24s%s\n\n",
1132 "Test Comment:", user_comment
);
1134 dump_log(0, fp
, items
, nitems
, log
->flags
);
1137 if ((err
= reduce_log(policy
, log
, &items
, &nitems
)) < 0 ||
1139 msg(4, "log2errdefs: reduce_log err %d nitems %d\n",
1143 (void) fprintf(fp
, "\nerror() { echo \""
1145 " >&2; exit 2; }\n");
1147 "trap ' ' 16\t# ignore - it is trapped by abort monitor_edef\n");
1149 (void) fprintf(fp
, "\nfixup_script()\n{\n");
1150 if (scriptargs
> 0) {
1151 (void) fprintf(fp
, "\tif [[ $1 -eq 1 ]]\n\tthen\n");
1152 (void) fprintf(fp
, "\t\t# Call a user defined workload\n");
1153 (void) fprintf(fp
, "\t\t# while injecting errors\n\t\t");
1154 for (i
= 0; i
< scriptargs
; i
++)
1155 (void) fprintf(fp
, "%s ", fixup_script
[i
]);
1156 (void) fprintf(fp
, "\n\tfi\n");
1157 (void) fprintf(fp
, "\treturn 0\n");
1159 (void) fprintf(fp
, "\tif [[ $1 -eq 0 ]]\n\tthen\n");
1161 "\t\t# terminate any outstanding workload\n");
1162 (void) fprintf(fp
, "\t\tif [ $script_pid -gt 0 ]; then\n");
1163 (void) fprintf(fp
, "\t\t\tkill $script_pid\n");
1164 (void) fprintf(fp
, "\t\t\tscript_pid=0\n");
1165 (void) fprintf(fp
, "\t\tfi\n");
1166 (void) fprintf(fp
, "\tfi\n");
1167 (void) fprintf(fp
, "\treturn -1\n");
1169 (void) fprintf(fp
, "}\n\n");
1170 (void) fprintf(fp
, "devpath=/devices%s\n\n", devpath
);
1171 (void) fprintf(fp
, "#\n");
1172 (void) fprintf(fp
, "# following text extracted from th_script\n");
1173 (void) fprintf(fp
, "#\n");
1174 if (stat("/usr/lib/th_script", &statbuf
) == -1) {
1175 msg(0, "log2errdefs: stat of /usr/lib/th_script failed\n");
1178 fd
= open("/usr/lib/th_script", O_RDONLY
);
1180 msg(0, "log2errdefs: open of /usr/lib/th_script failed\n");
1183 buffer
= malloc(statbuf
.st_size
);
1185 msg(0, "log2errdefs: malloc for /usr/lib/th_script failed\n");
1188 if (read(fd
, buffer
, statbuf
.st_size
) != statbuf
.st_size
) {
1189 msg(0, "log2errdefs: read of /usr/lib/th_script failed\n");
1192 (void) fwrite(buffer
, statbuf
.st_size
, 1, fp
);
1194 (void) fprintf(fp
, "#\n");
1195 (void) fprintf(fp
, "# end of extracted text\n");
1196 (void) fprintf(fp
, "#\n");
1197 (void) fprintf(fp
, "run_subtest %s %d <<ERRDEFS\n",
1198 (char *)edp
->name
, edp
->instance
);
1200 for (i
= 0; i
< nitems
; i
= j
) {
1202 acc_cnt
= items
[i
].repcount
;
1204 j
< nitems
&& items
[j
].access_type
== items
[i
].access_type
;
1206 acc_cnt
+= items
[j
].repcount
;
1207 msg(1, "l2e: nitems %d i %d j %d at 0x%x\n",
1208 nitems
, i
, j
, items
[i
].access_type
);
1209 if (items
[i
].access_type
!= 0)
1210 (void) define_nerrs(fd
, fp
, &ecnt
, edp
, items
+i
, j
-i
,
1211 acc_cnt
, items
[i
].repcount
, items
[j
-1].repcount
,
1212 logtime
, log
->entries
);
1215 (void) fprintf(fp
, "ERRDEFS\n");
1216 (void) fprintf(fp
, "exit 0\n");
1218 if (fp
!= stdout
&& fp
!= stderr
) {
1219 if (fchmod(fileno(fp
), S_IRWXU
|S_IRGRP
|S_IROTH
))
1220 msg(0, "fchmod failed: %s\n", strerror(errno
));
1221 if (fclose(fp
) != 0)
1222 msg(0, "close of %s failed: %s\n", fname
,
1225 msg(10, "log2errdefs: done\n");
1228 #define LLSZMASK (sizeof (longlong_t) -1)
1232 struct bofi_errdef
*errdef
, /* returned access criteria */
1233 struct bofi_errstate
*errstate
,
1234 struct handle_info
*hdl
, /* handle to match against request */
1235 struct bofi_errdef
*edp
) /* requested access criteria */
1238 errdef
->instance
= hdl
->instance
;
1241 if (hdl
->access_type
== 0)
1244 errdef
->access_type
=
1245 errdef
->access_type
& (hdl
->access_type
|BOFI_LOG
);
1247 /* use a big log for PIO and a small one otherwise */
1248 if (lsize_is_default
&&
1249 (errdef
->access_type
& BOFI_PIO_RW
) == 0) {
1250 errdef
->access_count
= DFLT_NONPIO_LOGSZ
;
1251 errdef
->fail_count
= 0;
1253 errdef
->log
.logsize
= errstate
->log
.logsize
=
1254 errdef
->access_count
+ errdef
->fail_count
- 1;
1255 if (errdef
->log
.logsize
== -1U) {
1256 errdef
->log
.logsize
= errstate
->log
.logsize
= 0;
1258 errdef
->log
.logbase
= errstate
->log
.logbase
=
1259 (caddr_t
)GETSTRUCT(struct acc_log_elem
, errdef
->log
.logsize
);
1261 if (errdef
->log
.logbase
== 0)
1264 errdef
->rnumber
= hdl
->rnumber
;
1265 errdef
->offset
= hdl
->offset
;
1266 errdef
->len
= hdl
->len
;
1268 msg(4, "creating errdef: %d %s %d %d 0x%llx 0x%llx 0x%x 0x%x 0x%x"
1269 " 0x%x 0x%x 0x%llx\n",
1270 errdef
->namesize
, (char *)errdef
->name
,
1271 errdef
->instance
, errdef
->rnumber
,
1272 errdef
->offset
, errdef
->len
,
1273 errdef
->access_type
,
1274 errdef
->access_count
, errdef
->fail_count
,
1275 errdef
->acc_chk
, errdef
->optype
, errdef
->operand
);
1276 if (ioctl(fd
, BOFI_ADD_DEF
, errdef
) == -1) {
1277 perror("th_define - adding errdef failed");
1280 errdef
->optype
= edp
->optype
; /* driver clears it if fcnt is zero */
1281 errstate
->errdef_handle
= errdef
->errdef_handle
;
1286 collect_state(int fd
, int cmd
,
1287 struct bofi_errstate
*errstate
,
1288 struct bofi_errdef
*errdef
,
1292 size_t ls
= errstate
->log
.logsize
;
1294 msg(2, "collect_state: pre: edp->access_type 0x%x (logsize %d)\n",
1295 errdef
->access_type
, errdef
->log
.logsize
);
1298 errstate
->log
.logsize
= 0; /* only copy the driver log once */
1300 msg(10, "collecting state (lsize %d) ...\n",
1301 errstate
->log
.logsize
);
1304 if (ioctl(fd
, cmd
, errstate
) == -1 && errno
!= EINTR
) {
1305 perror("th_define (collect) -"
1306 " waiting for error report failed");
1310 (void) fprintf(outfile
, "Logged %d out of %d accesses"
1311 " (%s %d %d 0x%x %d).\n",
1312 errstate
->log
.entries
, ls
,
1313 (char *)errdef
->name
, errdef
->instance
, errdef
->rnumber
,
1314 errdef
->access_type
, errstate
->log
.wrapcnt
);
1316 (void) msg(1, "\t(ac %d fc %d lf 0x%x wc %d).\n",
1317 errstate
->access_count
, errstate
->fail_count
,
1318 errstate
->log
.flags
, errstate
->log
.wrapcnt
);
1321 if ((errstate
->log
.flags
& BOFI_LOG_WRAP
) &&
1322 errstate
->access_count
> 0)
1324 if (errstate
->access_count
<= 1 &&
1325 errstate
->fail_count
== 0 &&
1326 errstate
->acc_chk
== 0) {
1327 msg(3, "collecting state complete entries %d\n",
1328 errstate
->log
.entries
);
1332 msg(5, "still collecting state: %d, %d, %d\n",
1333 errstate
->access_count
, errstate
->fail_count
,
1335 (void) msg(2, "Log: errno %d size %d entries %d "
1336 "(off 0x%llx len 0x%llx) ac %d\n", errno
,
1337 errstate
->log
.logsize
, errstate
->log
.entries
,
1338 errdef
->offset
, errdef
->len
, errstate
->access_count
);
1340 } while (rval
== 0 && errstate
->log
.entries
< ls
);
1342 /* now grab the log itself */
1343 errstate
->log
.logsize
= ls
;
1344 if (errstate
->log
.entries
!= 0) {
1345 if (ioctl(fd
, BOFI_CHK_STATE
, errstate
) == -1) {
1347 "%s: errorwhile retrieving %d log entries: %s\n",
1348 Progname
, errstate
->log
.entries
, strerror(errno
));
1350 msg(2, "collect_state: post: edp->access_type 0x%x"
1351 " (log entries %d %d) (%llu - %llu)\n",
1352 errdef
->access_type
,
1353 errstate
->log
.entries
, errstate
->access_count
,
1354 errstate
->log
.start_time
, errstate
->log
.stop_time
);
1356 log2errdefs(fd
, errdef
, &(errstate
->log
), devpath
);
1362 print_err_reports(FILE *fp
, struct bofi_errstate
*esp
,
1363 char *fname
, char *cmt
, int id
)
1365 if (fname
!= 0 && *fname
!= 0)
1366 (void) fprintf(fp
, "%sErrdef file %s definition %d:",
1369 (void) fprintf(fp
, "%s", cmt
);
1371 if (esp
->access_count
!= 0) {
1372 (void) fprintf(fp
, " (access count %d).\n", esp
->access_count
);
1374 (void) fprintf(fp
, "\n%s\tremaining fail count %d acc_chk %d\n",
1375 cmt
, esp
->fail_count
, esp
->acc_chk
);
1376 (void) fprintf(fp
, "%s\tfail time 0x%llx error reported time"
1377 " 0x%llx errors reported %d\n", cmt
,
1378 esp
->fail_time
, esp
->msg_time
,
1381 (void) fprintf(fp
, "%s\tmessage \"%s\" severity 0x%x\n",
1382 cmt
, esp
->buffer
, (uint_t
)esp
->severity
);
1387 thr_collect(void *arg
, char *devpath
)
1390 struct collector_def
*hi
= (struct collector_def
*)arg
;
1392 msg(4, "thr_collect: collecting %s inst %d rn %d at = 0x%x.\n",
1393 hi
->ed
.name
, hi
->ed
.instance
,
1394 hi
->ed
.rnumber
, hi
->ed
.access_type
);
1396 if ((fd
= open(BOFI_DEV
, O_RDWR
)) == -1) {
1397 if (errno
== EAGAIN
)
1398 msg(0, "Too many instances of bofi currently open\n");
1400 msg(0, "Error while opening bofi driver: %s",
1404 * Activate the logging errdefs - then collect the results.
1406 (void) manage_instance(fd
, hi
->ed
.name
,
1407 hi
->ed
.instance
, BOFI_START
);
1408 collect_state(fd
, BOFI_CHK_STATE_W
, &hi
->es
, &hi
->ed
, devpath
);
1412 * there is no more work to do on this access handle so clean up / exit.
1414 msg(3, "thr_collect: closing and broadcasting.\n");
1419 * Given an access handle known to the bofi driver see if the user has
1420 * specified access criteria that match that handle. Note: this matching
1421 * algorithm should be kept consistent with the drivers alogorithm.
1424 match_hinfo(struct handle_info
*hp
, int instance
, uint_t access_type
,
1425 int rnumber
, offset_t offset
, offset_t len
)
1428 msg(9, "matching (%d %d) 0x%x %d offset (%llx, %llx) len (%llx %llx)\n",
1429 hp
->instance
, instance
, access_type
, rnumber
,
1430 hp
->offset
, offset
, hp
->len
, len
);
1432 if (instance
!= -1 && hp
->instance
!= instance
)
1434 if ((access_type
& BOFI_DMA_RW
) &&
1435 (hp
->access_type
& BOFI_DMA_RW
) &&
1436 (rnumber
== -1 || hp
->rnumber
== rnumber
))
1438 else if ((access_type
& BOFI_INTR
) &&
1439 (hp
->access_type
& BOFI_INTR
))
1441 else if ((access_type
& BOFI_PIO_RW
) &&
1442 (hp
->access_type
& BOFI_PIO_RW
) &&
1443 (rnumber
== -1 || hp
->rnumber
== rnumber
) &&
1444 (len
== 0 || hp
->offset
< offset
+ len
) &&
1445 (hp
->len
== 0 || hp
->offset
+ hp
->len
> offset
))
1452 * Obtain all the handles created by the driver specified by the name parameter
1453 * that match the remaining arguments. The output parameter nhdls indicates how
1454 * many of the structures pointed to by the output parameter hip match the
1457 * It is the responsibility of the caller to free *hip when *nhdls != 0.
1460 get_hinfo(int fd
, char *name
, struct handle_info
**hip
, size_t *nhdls
,
1461 int instance
, int atype
, int rset
, offset_t offset
, offset_t len
,
1464 struct bofi_get_hdl_info hdli
;
1467 command
= BOFI_GET_HANDLE_INFO
;
1468 hdli
.namesize
= strlen(name
);
1469 (void) strncpy(hdli
.name
, name
, MAXNAMELEN
);
1471 * Initially ask for the number of access handles (not the structures)
1472 * in order to allocate memory
1479 * Ask the bofi driver for all handles created by the driver under test.
1481 if (ioctl(fd
, command
, &hdli
) == -1) {
1483 msg(0, "driver failed to return handles: %s\n",
1486 } else if ((*nhdls
= hdli
.count
) == 0) {
1487 msg(1, "get_hinfo: no registered handles\n");
1488 return (0); /* no handles */
1489 } else if ((*hip
= GETSTRUCT(struct handle_info
, *nhdls
)) == 0) {
1492 struct handle_info
*hp
, **chosen
;
1495 /* Ask for *nhdls handles */
1496 hdli
.hdli
= (caddr_t
)*hip
;
1497 if (ioctl(fd
, command
, &hdli
) == -1) {
1500 msg(0, "BOFI_GET_HANDLE_INFO ioctl returned error %d\n",
1506 if (hdli
.count
< *nhdls
)
1507 *nhdls
= hdli
.count
; /* some handles have gone away */
1509 msg(4, "qsorting %d handles\n", *nhdls
);
1511 /* sort them naturally (NB ordering is not mandatory) */
1512 qsort((void *)*hip
, *nhdls
, sizeof (**hip
), hdl_cmp
);
1514 if ((chosen
= malloc(sizeof (hp
) * *nhdls
)) != NULL
) {
1515 struct handle_info
**ip
;
1516 /* the selected handles */
1517 struct handle_info
*prev
= 0;
1520 for (i
= 0, hp
= *hip
, ip
= chosen
; i
< *nhdls
;
1523 * Remark: unbound handles never match
1524 * (access_type == 0)
1526 if (match_hinfo(hp
, instance
, atype
, rset
,
1527 offset
&0x7fffffff, len
&0x7fffffff)) {
1528 msg(3, "match: 0x%x 0x%llx 0x%llx"
1529 " 0x%llx (0x%llx)\n",
1530 hp
->access_type
, hp
->addr_cookie
,
1531 hp
->offset
, hp
->len
,
1532 (hp
->len
& 0x7fffffff));
1534 (prev
->access_type
& BOFI_DMA_RW
) &&
1535 (hp
->access_type
& BOFI_DMA_RW
) &&
1536 hp
->instance
== prev
->instance
&&
1537 hp
->len
== prev
->len
&&
1542 if ((hp
->access_type
& BOFI_DMA_RW
) &&
1543 (atype
& BOFI_DMA_RW
) !=
1549 msg(3, "match_hinfo: match:"
1550 " 0x%llx (%d %d) (%d %d)"
1551 " (0x%x 0x%x) (0x%llx,"
1555 hp
->instance
, prev
->rnumber
,
1558 hp
->access_type
, prev
->len
,
1561 /* it matches so remember it */
1567 if (*nhdls
!= scnt
) {
1569 * Reuse the alloc'ed memory to return
1570 * only those handles the user has asked for.
1571 * But first prune the handles to get rid of
1572 * overlapping ranges (they are ordered by
1573 * offset and length).
1576 for (i
= 0, hp
= *hip
, ip
= chosen
; i
< scnt
;
1579 (void) memcpy(hp
, *ip
,
1585 for (i
= 0, hp
= *hip
; i
< *nhdls
; i
++, hp
++) {
1586 msg(4, "\t%d 0x%x %d 0x%llx 0x%llx 0x%llx\n",
1587 hp
->instance
, hp
->access_type
, hp
->rnumber
,
1588 hp
->len
, hp
->offset
, hp
->addr_cookie
);
1591 if (*nhdls
== 0 && *hip
)
1594 msg(4, "get_info: %s got %d handles\n", name
, *nhdls
);
1601 struct sigaction sa
;
1602 int *ip
, sigs
[] = {SIGINT
, SIGTERM
, 0};
1604 sa
.sa_handler
= kill_sighandler
;
1605 (void) sigemptyset(&sa
.sa_mask
);
1606 for (ip
= sigs
; *ip
; ip
++)
1607 (void) sigaddset(&sa
.sa_mask
, *ip
);
1609 for (ip
= sigs
; *ip
; ip
++)
1610 (void) sigaction(*ip
, &sa
, NULL
);
1618 /* Potentially hungry on resources so up them all to their maximums */
1619 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0)
1620 msg(0, "failed to obtain RLIMIT_NOFILE: %s\n", strerror(errno
));
1622 msg(12, "RLIMIT_NOFILE\t %lu (%lu)\n",
1623 rl
.rlim_cur
, rl
.rlim_max
);
1624 rl
.rlim_cur
= rl
.rlim_max
;
1625 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0)
1626 msg(0, "failed to set RLIMIT_NOFILE: %s\n",
1628 (void) enable_extended_FILE_stdio(-1, -1);
1630 if (getrlimit(RLIMIT_DATA
, &rl
) < 0)
1631 msg(0, "failed to obtain RLIMIT_DATA: %s\n", strerror(errno
));
1633 msg(12, "RLIMIT_DATA\t %lu (%lu)\n", rl
.rlim_cur
, rl
.rlim_max
);
1634 rl
.rlim_cur
= rl
.rlim_max
;
1635 if (setrlimit(RLIMIT_DATA
, &rl
) < 0)
1636 msg(0, "failed to set RLIMIT_DATA: %s\n",
1639 if (getrlimit(RLIMIT_FSIZE
, &rl
) < 0)
1640 msg(0, "failed to obtain RLIMIT_FSIZE: %s\n", strerror(errno
));
1642 msg(12, "RLIMIT_FSIZE\t %lu (%lu)\n", rl
.rlim_cur
, rl
.rlim_max
);
1643 rl
.rlim_cur
= rl
.rlim_max
;
1644 if (setrlimit(RLIMIT_FSIZE
, &rl
) < 0)
1645 msg(0, "failed to set RLIMIT_FSIZE: %s\n",
1651 create_test_file(char *drvname
)
1653 char dirname
[_POSIX_PATH_MAX
];
1654 char testname
[_POSIX_PATH_MAX
];
1656 time_t utc
= time(NULL
);
1658 if (snprintf(dirname
, sizeof (dirname
), "%s.test.%lu",
1659 drvname
, utc
) == -1 ||
1660 snprintf(testname
, sizeof (testname
), "%s.test.%lu",
1661 drvname
, utc
) == -1)
1664 if (mkdir(dirname
, S_IRWXU
|S_IRGRP
|S_IROTH
)) {
1665 msg(0, "Error creating %s: %s\n", dirname
, strerror(errno
));
1668 if (chdir(dirname
)) {
1669 (void) rmdir(dirname
);
1672 if ((fp
= fopen(testname
, "w")) == 0)
1673 return (0); /* leave created directory intact */
1681 char name
[MAXPATHLEN
];
1686 walk_callback(di_node_t node
, void *arg
)
1688 struct walk_arg
*warg
= (struct walk_arg
*)arg
;
1692 driver_name
= di_driver_name(node
);
1693 if (driver_name
!= NULL
) {
1694 if (strcmp(driver_name
, warg
->name
) == NULL
&&
1695 di_instance(node
) == warg
->instance
) {
1696 path
= di_devfs_path(node
);
1700 (void) strncpy(warg
->path
, path
, warg
->pathlen
);
1701 return (DI_WALK_TERMINATE
);
1704 return (DI_WALK_CONTINUE
);
1708 getpath(char *path
, int instance
, char *name
, int pathlen
)
1711 struct walk_arg warg
;
1713 warg
.instance
= instance
;
1714 (void) strncpy(warg
.name
, name
, MAXPATHLEN
);
1716 warg
.pathlen
= pathlen
;
1717 if ((node
= di_init("/", DINFOSUBTREE
)) == DI_NODE_NIL
)
1719 if (di_walk_node(node
, DI_WALK_CLDFIRST
, &warg
, walk_callback
) == -1) {
1723 if (warg
.path
== NULL
) {
1732 * Record logsize h/w accesses of type 'edp->access_type' made by instance
1733 * 'edp->instance' of driver 'edp->name' to the register set (or dma handle)
1734 * 'edp->rnumber' that lie within the range 'edp->offset' to
1735 * 'edp->offset' + 'edp->len'.
1736 * Access criteria may be mixed and matched:
1737 * - access types may be combined (PIO read/write, DMA read write or intrs);
1738 * - if 'edp->instance' is -1 all instances are checked for the criteria;
1739 * - if 'edp->rnumber' is -1 all register sets and dma handles are matched;
1740 * - 'offset' and 'len' indicate that only PIO and DMA accesses within the
1741 * range 'edp->offset' to 'edp->len' will be logged. Putting 'edp->offset'
1742 * to zero and 'edp->len' to -1ull gives maximal coverage.
1744 * 'collecttime' is the number of seconds used to log accesses
1745 * (default is infinity).
1748 test_driver(struct bofi_errdef
*edp
,
1749 unsigned long long collecttime
)
1753 struct collector_def
*cdefs
, *cdp
;
1754 struct handle_info
*hdls
, *hdl
;
1758 unsigned long long timechunk
;
1759 FILE *sfp
; /* generated control test file */
1760 char buf
[MAXPATHLEN
];
1761 char devpath
[MAXPATHLEN
];
1762 char *devpathp
= "NULL";
1766 char *name
= (char *)edp
->name
;
1767 uint_t logsize
= edp
->access_count
+ edp
->fail_count
- 1;
1768 int inst
= edp
->instance
;
1769 uint_t atype
= edp
->access_type
;
1770 int rset
= edp
->rnumber
;
1771 offset_t offset
= edp
->offset
;
1772 offset_t len
= edp
->len
;
1774 msg(4, "test_driver: %s %d inst %d 0x%x rset %d %llx %llx\n",
1775 name
, logsize
, inst
, atype
, rset
, offset
, len
);
1778 if (getpath(devpath
, inst
, name
, MAXPATHLEN
) != -1) {
1784 fd
= open(BOFI_DEV
, O_RDWR
);
1786 perror("get_hdl_info - bad open of bofi driver");
1790 (void) snprintf(buf
, sizeof (buf
),
1791 "th_manage /devices%s offline", devpathp
);
1793 (void) snprintf(buf
, sizeof (buf
),
1794 "th_manage /devices%s online", devpathp
);
1796 (void) snprintf(buf
, sizeof (buf
),
1797 "th_manage /devices%s getstate >/dev/null", devpathp
);
1800 if (get_hinfo(fd
, name
, &hdls
, &cnt
,
1801 inst
, atype
, rset
, offset
, len
, 1) != 0) {
1802 msg(0, "driver_test: bad get_info for %d hdls\n", cnt
);
1804 } else if (logsize
== 0 || collecttime
== 0 || cnt
== 0) {
1806 msg(1, "No matching handles.\n");
1809 if ((cdefs
= GETSTRUCT(struct collector_def
, cnt
)) == 0) {
1810 msg(0, "driver_test: can't get memory for %d cdefs\n", cnt
);
1815 if (scriptargs
> 0) {
1816 (void) snprintf(buf
, sizeof (buf
),
1817 "DRIVER_PATH=/devices%s DRIVER_INSTANCE=%d"
1818 " DRIVER_UNCONFIGURE=0 DRIVER_CONFIGURE=1",
1819 devpathp
, drv_inst
);
1820 for (i
= 0; i
< scriptargs
; i
++) {
1821 (void) strcat(buf
, " ");
1822 (void) strcat(buf
, fixup_script
[i
]);
1824 (void) strcat(buf
, " &");
1826 (void) snprintf(buf
, sizeof (buf
),
1827 "while : ; do th_manage /devices%s online;"
1828 " th_manage /devices%s getstate >/dev/null;"
1829 " th_manage /devices%s offline;done &"
1830 " echo $! >/tmp/bofi.pid",
1831 devpathp
, devpathp
, devpathp
);
1834 (void) snprintf(buf
, sizeof (buf
), "sleep %d",
1835 edef_sleep
? edef_sleep
: DEFAULT_EDEF_SLEEP
);
1839 (void) fprintf(outfile
,
1840 "Logging accesses to instances ");
1841 for (i
= 0, inst
= -1, hdl
= hdls
; i
< cnt
;
1843 if (inst
!= hdl
->instance
) {
1844 inst
= hdl
->instance
;
1845 (void) fprintf(outfile
, "%d ", inst
);
1848 (void) fprintf(outfile
, " (%d logs of size 0x%x).\n\t"
1849 "(Use th_manage ... clear_errdefs to terminate"
1850 " logging)\n", cnt
, logsize
);
1852 sfp
= create_test_file(name
);
1854 * Install a logging errdef for each matching handle,
1855 * and then create a child to collect the log.
1856 * The child is responsible for activating the log.
1858 for (i
= 0, cdp
= cdefs
, hdl
= hdls
, nchildren
= 0;
1859 i
< cnt
; i
++, cdp
++, hdl
++) {
1860 if (add_edef(fd
, &cdp
->ed
, &cdp
->es
, hdl
, edp
) != 0) {
1864 cdp
->lp
= (void *)cdp
->ed
.log
.logbase
;
1865 msg(1, "test_driver: thr_create:"
1866 " lsize 0x%x 0x%x at 0x%x\n",
1867 cdp
->es
.log
.logsize
,
1868 cdp
->ed
.log
.logsize
,
1869 cdp
->ed
.access_type
);
1870 if ((pid
= fork()) == -1) {
1871 msg(0, "fork failed for handle"
1872 " %d: %s\n", i
, strerror(errno
));
1873 cdp
->pid
= 0; /* ignore */
1874 } else if (pid
== 0) {
1875 thr_collect(cdp
, devpathp
);
1883 if (nchildren
!= 0) {
1885 (void) fprintf(sfp
, "#!/bin/ksh -p\n\n");
1887 "\n# Test control script generated using:\n#");
1888 for (i
= 0; i
< pargc
; i
++)
1889 (void) fprintf(sfp
, " %s", pargv
[i
]);
1890 (void) fprintf(sfp
, "\n\n");
1891 (void) fprintf(sfp
, "\nrun_tests()\n{\n");
1892 for (i
= 0, cdp
= cdefs
; i
< cnt
; i
++, cdp
++)
1895 "\tif [ -x ./%s.%d ]\n\tthen\n",
1896 name
, (int)cdp
->pid
);
1898 "\t\techo \"Starting test"
1901 (void) fprintf(sfp
, "\t\t./%s.%d\n",
1902 name
, (int)cdp
->pid
);
1903 (void) fprintf(sfp
, "\t\techo \""
1904 "Test %d (id %d) complete\"\n",
1906 (void) fprintf(sfp
, "\tfi\n");
1908 (void) fprintf(sfp
, "}\n\nrun_tests\n");
1909 if (fchmod(fileno(sfp
), S_IRWXU
|S_IRGRP
|S_IROTH
))
1910 msg(0, "fchmod on control script failed: %s\n",
1912 if (fclose(sfp
) != 0)
1913 msg(0, "Error closing control script: %s\n",
1917 set_handler(SIGALRM
); /* handle it */
1919 * The user may want to terminate logging before the log fills
1920 * so use a timer to signal the logging children to handle this
1923 timechunk
= collecttime
/ MAXALRMCALL
;
1924 collecttime
= collecttime
- timechunk
* MAXALRMCALL
;
1926 msg(2, "logging for (0x%llx 0x%llx)\n", timechunk
, collecttime
);
1928 (void) alarm(collecttime
); /* odd bit of collect time */
1930 /* wait for the log to fill or deadline satisfied */
1932 pid
= wait(&statloc
);
1933 for (i
= 0, nchildren
= 0, cdp
= cdefs
;
1934 i
< cnt
; i
++, cdp
++)
1935 if (cdp
->pid
== pid
)
1937 for (i
= 0, nchildren
= 0, cdp
= cdefs
;
1938 i
< cnt
; i
++, cdp
++)
1946 if (timechunk
-- > 0) {
1948 * prepare for the next timeslice by
1949 * rearming the clock
1951 if (alarm(MAXALRMCALL
) == 0)
1955 * must have been a user abort
1966 (void) fprintf(outfile
, "Logging complete.\n");
1969 if (scriptargs
> 0) {
1970 (void) snprintf(buf
, sizeof (buf
),
1971 "DRIVER_PATH=/devices%s DRIVER_INSTANCE=%d"
1972 " DRIVER_UNCONFIGURE=1 DRIVER_CONFIGURE=0",
1973 devpathp
, drv_inst
);
1974 for (i
= 0; i
< scriptargs
; i
++) {
1975 (void) strcat(buf
, " ");
1976 (void) strcat(buf
, fixup_script
[i
]);
1980 (void) system("kill `cat /tmp/bofi.pid`");
1983 msg(2, "test_driver: terminating\n");
1987 getnameinst(char *orig_path
, int *instance
, char *name
, int namelen
)
1992 if ((node
= di_init(&orig_path
[8], DINFOSUBTREE
|DINFOMINOR
)) ==
1995 if ((binding_name
= di_driver_name(node
)) == NULL
)
1997 *instance
= di_instance(node
);
1998 (void) strncpy(name
, binding_name
, namelen
);
2003 static char syntax
[] =
2004 " [ -n name [ -i instance ] | -P path ]\n"
2005 " [ -a acc_types ] [ -r rnumber ]\n"
2006 " [ -l offset [ length ] ] [ -c count [ failcount ] ]\n"
2007 " [ -o operator [ operand ] ] [ -f acc_chk ]\n"
2008 " [ -w max_wait_period [ report_interval ] ]\n"
2010 " [ -n name [ -i instance ] | -P path ]\n"
2011 " -a LOG [ acc_types ] [ -r rnumber]\n"
2012 " [ -l offset [ length ] ] [ -c count [ failcount ] ]\n"
2013 " [ -s collect_time ] [ -p policy ] [ -x flags ]\n"
2014 " [ -C ] [-e fixup_script ]\n"
2019 main(int argc
, char *argv
[])
2021 extern char *optarg
;
2024 char c
; /* for parsing getopts */
2025 int nopts
= 0; /* for backward compatibility */
2028 /* use a maximal set of defaults for logging or injecting */
2029 struct bofi_errdef errdef
= {
2030 0, /* length of driver name */
2031 {0}, /* driver name */
2032 -1, /* monitor all instances */
2033 -1, /* monitor all register sets and DMA handles */
2034 (offset_t
)0, /* monitor from start of reg. set or DMA hd */
2035 myLLMAX
, /* monitor whole reg set or DMA hdl(no LLMAX) */
2036 0, /* qualify all */
2037 DFLTLOGSZ
, /* default no. of accesses before corrupting */
2038 0u, /* default no. of accesses to corrupt */
2039 0u, /* no check access corruption */
2040 BOFI_NOP
, /* no corruption operator by default */
2041 myULLMAX
, /* default operand */
2042 {0, 0, BOFI_LOG_TIMESTAMP
, /* timestamp by default */
2043 0, 0, 0, 0}, /* no logging by default */
2047 /* specify the default no of seconds for which to monitor */
2048 unsigned long long collecttime
= DFLTLOGTIME
;
2050 char *str
; /* temporary variable */
2051 long tmpl
; /* another one */
2055 char buf
[MAXPATHLEN
];
2057 Progname
= (char *)strrchr(*argv
, '/');
2058 Progname
= (Progname
== NULL
) ? *argv
: Progname
+ 1;
2063 lsize_is_default
= 1;
2067 while ((c
= getopt(argc
, argv
, "a:c:C:dD:e:f:h:i:l:n:o:p:P:r:s:tw:x"))
2072 msg(2, "option a: optarg %s optind %d argc %d\n",
2073 optarg
, optind
, argc
);
2074 if ((err
= str_to_bm(optarg
, atypes
,
2075 &errdef
.access_type
)) == 0)
2076 while (optind
< argc
&& *argv
[optind
] != '-') {
2077 if ((err
= str_to_bm(argv
[optind
++],
2078 atypes
, &errdef
.access_type
)))
2083 lsize_is_default
= 0;
2085 errdef
.access_count
= strtoul(optarg
, &str
, 0);
2088 else if (optind
< argc
&& (argv
[optind
][0] != '-' ||
2089 (strlen(argv
[optind
]) > 1 &&
2090 isdigit(argv
[optind
][1]))))
2092 strtoull(argv
[optind
++], 0, 0);
2095 user_comment
= optarg
;
2096 if (optind
< argc
&& argv
[optind
][0] != '-')
2100 dbglvl
= strtoul(optarg
, &str
, 0);
2105 fixup_script
= &argv
[optind
- 1];
2107 while (optind
< argc
) {
2113 tmpl
= strtol(optarg
, &str
, 0);
2116 errdef
.acc_chk
= tmpl
;
2117 else if (strcmp(optarg
, "PIO") == NULL
)
2119 else if (strcmp(optarg
, "DMA") == NULL
)
2121 else if (strcmp(optarg
, "U4FT_ACC_NO_PIO") == NULL
)
2123 else if (strcmp(optarg
, "U4FT_ACC_NO_DMA") == NULL
)
2129 if ((errdef
.instance
= strtol(optarg
, &str
, 0)) < 0)
2130 errdef
.instance
= -1;
2131 else if (str
== optarg
)
2135 errdef
.offset
= strtoull(optarg
, &str
, 0);
2138 else if (optind
< argc
&&
2139 (argv
[optind
][0] != '-' ||
2140 (strlen(argv
[optind
]) > 1 &&
2141 isdigit(argv
[optind
][1])))) {
2142 /* -1 indicates the rest of register set */
2143 errdef
.len
= strtoull(argv
[optind
++], 0, 0);
2147 (void) strncpy(errdef
.name
, optarg
, MAXNAMELEN
);
2148 if ((errdef
.namesize
= strlen(errdef
.name
)) == 0)
2152 for (i
= 0; optypes
[i
].str
!= 0; i
++)
2153 if (strcmp(optarg
, optypes
[i
].str
) == 0) {
2154 errdef
.optype
= optypes
[i
].code
;
2157 if (optypes
[i
].str
== 0)
2159 else if (optind
< argc
&&
2160 (argv
[optind
][0] != '-' ||
2161 (strlen(argv
[optind
]) > 1 &&
2162 isdigit(argv
[optind
][1]))))
2164 strtoull(argv
[optind
++], 0, 0);
2168 if ((err
= str_to_bm(optarg
, ptypes
, &tmpui
)) == 0) {
2169 while (optind
< argc
&& *argv
[optind
] != '-')
2170 if ((err
= str_to_bm(argv
[optind
++],
2173 policy
= (uint16_t)tmpui
;
2175 if (err
== 0 && (policy
& BYTEPOLICY
))
2176 errdef
.log
.flags
|= BOFI_LOG_REPIO
;
2179 if (getnameinst(optarg
, &errdef
.instance
, buf
,
2183 (void) strncpy(errdef
.name
, buf
, MAXNAMELEN
);
2186 if ((errdef
.rnumber
= strtol(optarg
, &str
, 0)) < 0)
2187 errdef
.rnumber
= -1;
2188 if (str
== optarg
) err
= EINVAL
;
2191 collecttime
= strtoull(optarg
, &str
, 0);
2193 err
= EINVAL
; /* zero is valid */
2197 max_edef_wait
= strtoul(optarg
, &str
, 0);
2201 else if (optind
< argc
&&
2202 (argv
[optind
][0] != '-' ||
2203 (strlen(argv
[optind
]) > 1 &&
2204 isdigit(argv
[optind
][1]))))
2205 edef_sleep
= strtoull(argv
[optind
++], 0, 0);
2209 if ((optind
< argc
&& *argv
[optind
] == '-') ||
2211 errdef
.log
.flags
|= BOFI_LOG_WRAP
;
2213 if (strchr(argv
[optind
], 'w') != 0)
2214 errdef
.log
.flags
|= BOFI_LOG_WRAP
;
2215 if (strchr(argv
[optind
], 'r') != 0)
2216 errdef
.log
.flags
|= BOFI_LOG_REPIO
;
2217 if (strchr(argv
[optind
], 't') != 0)
2218 errdef
.log
.flags
|= BOFI_LOG_TIMESTAMP
;
2219 if (strstr(argv
[optind
], "~t") != 0)
2220 errdef
.log
.flags
&= ~BOFI_LOG_TIMESTAMP
;
2225 (void) fprintf(errfile
, "usage: %s %s\n",
2229 case '?': /* also picks up missing parameters */
2231 (void) fprintf(errfile
, "usage: %s %s\n",
2237 (void) fprintf(errfile
, "usage: %s %s\n",
2242 break; /* the -e option must be the final option */
2246 if (errdef
.name
[0] == 0) {
2247 msg(0, "%s - invalid name parameter\n", Progname
);
2250 errdef
.namesize
= strlen(errdef
.name
);
2253 policy
|= UNBIASEDPOLICY
;
2254 policy
|= OPERATORSPOLICY
;
2257 if (errdef
.optype
== BOFI_NOP
)
2258 errdef
.optype
= BOFI_XOR
;
2259 if (errdef
.access_type
== BOFI_LOG
) { /* qualify all accesses */
2260 errdef
.access_type
=
2261 (BOFI_LOG
|BOFI_DMA_RW
|BOFI_PIO_RW
|BOFI_INTR
);
2262 atype_is_default
= 1;
2263 } else if (errdef
.access_type
== 0) { /* qualify all accesses */
2264 errdef
.access_type
=
2265 (BOFI_DMA_RW
|BOFI_PIO_RW
|BOFI_INTR
);
2266 atype_is_default
= 1;
2268 atype_is_default
= 0;
2271 if ((errdef
.access_type
& BOFI_LOG
) == 0) {
2272 int fd
, i
, instance
;
2274 struct handle_info
*hdls
, *hp
;
2276 if ((fd
= open(BOFI_DEV
, O_RDWR
)) == -1) {
2277 msg(0, "%s: error opening bofi driver: %s\n",
2278 Progname
, strerror(errno
));
2281 if ((err
= get_hinfo(fd
, errdef
.name
, &hdls
, &cnt
,
2282 errdef
.instance
, errdef
.access_type
, errdef
.rnumber
,
2283 errdef
.offset
, errdef
.len
, 0)) != 0) {
2284 msg(0, "%s: Bad lookup on bofi driver.\n", Progname
);
2287 } else if (cnt
== 0) {
2289 "%s: No handles match request access criteria.\n",
2294 if (errdef
.instance
== -1)
2297 instance
= hdls
->instance
;
2298 for (i
= 0, hp
= hdls
; i
< cnt
; i
++, hp
++) {
2299 if (instance
!= hp
->instance
) {
2305 if (instance
== -1) {
2306 msg(0, "Multiple instances match access criteria"
2307 " (only allowed when logging):\n");
2308 msg(0, "\tinst\taccess\trnumber\toffset\tlength\n");
2309 for (i
= 0, hp
= hdls
; i
< cnt
; i
++, hp
++)
2310 msg(0, "\t%d\t0x%x\t%d\t0x%llx\t0x%llx\n",
2311 hp
->instance
, hp
->access_type
,
2312 hp
->rnumber
, hp
->offset
, hp
->len
);
2314 struct bofi_errstate es
;
2315 int timeleft
= max_edef_wait
;
2317 if (ioctl(fd
, BOFI_ADD_DEF
, &errdef
) == -1) {
2318 perror("th_define - adding errdef failed");
2320 es
.errdef_handle
= errdef
.errdef_handle
;
2321 msg(4, "waiting for edef:"
2322 " %d %s %d %d 0x%llx 0x%llx 0x%x 0x%x"
2323 " 0x%x 0x%x 0x%x 0x%llx\n",
2324 errdef
.namesize
, errdef
.name
,
2325 errdef
.instance
, errdef
.rnumber
,
2326 errdef
.offset
, errdef
.len
,
2327 errdef
.access_type
, errdef
.access_count
,
2328 errdef
.fail_count
, errdef
.acc_chk
,
2329 errdef
.optype
, errdef
.operand
);
2331 set_handler(SIGALRM
); /* handle it */
2335 (void) alarm(edef_sleep
);
2336 if (ioctl(fd
, BOFI_CHK_STATE_W
,
2338 if (errno
!= EINTR
) {
2342 } else if (!do_status
) {
2347 (void) fprintf(outfile
,
2348 "%llu:%llu:%u:%u:%u:"
2350 es
.fail_time
, es
.msg_time
,
2353 es
.acc_chk
, es
.errmsg_count
,
2354 (uint_t
)es
.severity
,
2357 if (es
.acc_chk
== 0 &&
2358 es
.fail_count
== 0 && !do_status
)
2359 print_err_reports(outfile
,
2363 if ((timeleft
-= edef_sleep
) <=
2372 } else if (!do_status
)
2373 print_err_reports(outfile
,
2375 } while (es
.acc_chk
!= 0 || es
.fail_count
!= 0);
2377 msg(2, "done: acc_chk 0x%x fcnt %d\n",
2378 es
.acc_chk
, es
.fail_count
);
2386 test_driver(&errdef
, collecttime
);