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 #include <sys/time_impl.h>
29 #include <stdio_ext.h>
36 #include <sys/resource.h>
42 #include <libdevinfo.h>
44 #include <sys/dditypes.h>
45 #include <sys/sunddi.h>
48 #define BOFI_DEV "/devices/pseudo/bofi@0:bofi,ctl"
50 #define GETSTRUCT(s, num) \
51 ((s *) memalign(sizeof (void*), (num) * sizeof (s)))
53 #define MAXEDEFS (0x64) /* controls max no of concurent edefs */
54 #define DFLTLOGSZ (0x4000) /* default size of an access log */
55 #define DFLT_NONPIO_LOGSZ (0x400) /* default size of a log */
56 #define MAXALRMCALL (0x1000ull) /* alarm does not permit big values */
57 #define MIN_REPORT_TIME (5) /* min time to wait for edef status */
58 #define DISTRIB_CUTOFF (3) /* useful when reducing a log */
59 #define myLLMAX (0x7fffffffffffffffll)
60 #define myULLMAX (0xffffffffffffffffull)
63 * default interval to wait between kicking off workload and injecting fault
65 #define DEFAULT_EDEF_SLEEP 3
67 * when generating dma corruptions, it is best to corrupt each double word
68 * individually for control areas - however for data areas this can be
69 * excessive and would generate so many cases we would never finish the run.
70 * So set a cut-off value where we switch from corrupting each double word
71 * separately to corrupting th elot in one go. 0x100 bytes seems a good value
72 * on the drivers we have seen so far.
74 #define DMA_INDIVIDUAL_CORRUPT_CUTOFF 0x100
76 struct collector_def
{
77 struct bofi_errdef ed
; /* definition of the log criteria */
78 struct bofi_errstate es
; /* the current status of the log */
79 struct acc_log_elem
*lp
; /* array of logged accesses */
83 static uint16_t policy
;
85 #define BYTEPOLICY (0xf)
86 #define MULTIPOLICY (0x10)
87 #define SIZEPOLICY (BYTEPOLICY|MULTIPOLICY)
88 #define UNBIASEDPOLICY 0x20
89 #define UNCOMMONPOLICY 0x40
90 #define COMMONPOLICY 0x80
91 #define MEDIANPOLICY 0x100
92 #define MAXIMALPOLICY 0x200
93 #define OPERATORSPOLICY 0x400
94 #define VALIDPOLICY (0x7ff)
102 static coding_t ptypes
[] = {
103 {"onebyte", 0x1}, {"twobyte", 0x2},
104 {"fourbyte", 0x4}, {"eightbyte", 0x8},
105 {"multibyte", 0x10}, {"unbiased", 0x20}, {"uncommon", 0x40},
106 {"common", 0x80}, {"median", 0x100}, {"maximal", 0x200},
107 {"operators", 0x400}, {0, 0}
109 static coding_t atypes
[] = {
110 {"pio_r", BOFI_PIO_R
}, {"pio_w", BOFI_PIO_W
},
111 {"dma_r", BOFI_DMA_R
}, {"dma_w", BOFI_DMA_W
},
112 {"pio", BOFI_PIO_RW
}, {"dma", BOFI_DMA_RW
},
113 {"log", BOFI_LOG
}, {"intr", BOFI_INTR
},
114 {"PIO_R", BOFI_PIO_R
}, {"PIO_W", BOFI_PIO_W
},
115 {"DMA_R", BOFI_DMA_R
}, {"DMA_W", BOFI_DMA_W
},
116 {"PIO", BOFI_PIO_RW
}, {"DMA", BOFI_DMA_RW
},
117 {"LOG", BOFI_LOG
}, {"INTR", BOFI_INTR
}, {0, 0}
119 static coding_t optypes
[] = {
120 {"EQ", BOFI_EQUAL
}, {"AND", BOFI_AND
}, {"OR", BOFI_OR
},
121 {"XOR", BOFI_XOR
}, {"NO", BOFI_NO_TRANSFER
},
122 {"DELAY", BOFI_DELAY_INTR
}, {"LOSE", BOFI_LOSE_INTR
},
123 {"EXTRA", BOFI_EXTRA_INTR
}, {0, 0}
125 static coding_t doptypes
[] = {
126 {"EQ", BOFI_EQUAL
}, {"AND", BOFI_AND
}, {"OR", BOFI_OR
},
127 {"XOR", BOFI_XOR
}, {0, 0}
129 static coding_t ioptypes
[] = {
130 {"DELAY", BOFI_DELAY_INTR
}, {"LOSE", BOFI_LOSE_INTR
},
131 {"EXTRA", BOFI_EXTRA_INTR
}, {0, 0}
134 static const unsigned long long DFLTLOGTIME
= -1ull; /* log forever */
137 * This global controls the generation of errdefs for PIO_W. The default should
138 * be to only perform an access check errdef but not to corrupt writes - this
139 * may trash non-FT platforms.
141 static uint_t atype_is_default
; /* do not corrupt PIO_W by default */
142 static uint_t lsize_is_default
; /* set when the user has not given a size */
144 static uint64_t random_operand
= 0xdeadbeafdeadbeafull
;
145 #define NPIO_DEFAULTS (3) /* number of default corruption values */
146 static longlong_t pio_default_values
[NPIO_DEFAULTS
] = {
147 0x0ull
, /* corresponds to a line going high/low */
148 0x32f1f03232f1f032ull
, /* the value returned when the fake ta is set */
149 (longlong_t
)(~0) /* corresponds to a line going high/low */
152 static uint_t dbglvl
= 0; /* debug this program */
153 static int alarmed
= 0;
154 static int killed
= 0;
157 * name of a script to call before offlining a driver being tested
159 static char **fixup_script
= 0;
160 static int scriptargs
= 0;
164 static int max_edef_wait
= 0;
165 static int edef_sleep
= 0;
166 static int do_status
= 0; /* report edef status in parsable format */
167 static char *user_comment
= 0;
169 static char *Progname
;
170 static FILE *errfile
;
171 static FILE *outfile
;
174 * The th_define utility provides an interface to the bus_ops fault injection
175 * bofi device driver for defining error injection specifications (referred to
176 * as errdefs). An errdef corresponds to a specification of how to corrupt a
177 * device driver's accesses to its hardware. The command line arguments
178 * determine the precise nature of the fault to be injected. If the supplied
179 * arguments define a consistent errdef, the th_define process will store the
180 * errdef with the bofi driver and suspend itself until the criteria given by
181 * the errdef become satisfied (in practice, this will occur when the access
182 * counts go to zero).
184 * When the resulting errdef is activated using the th_manage(1M) user command
185 * utility, the bofi driver will act upon the errdef by matching the number of
186 * hardware accesses - specified in count, that are of the type specified in
187 * acc_types, made by instance number instance - of the driver whose name is
188 * name, (or by the driver instance specified by * path ) to the register set
189 * (or DMA handle) specified by rnumber, that lie within the range offset to
190 * offset + length from the beginning of the register set or DMA handle. It then
191 * applies operator and operand to the next failcount matching accesses.
193 * If acc_types includes LOG, th_define runs in automatic test script generation
194 * mode, and a set of test scripts (written in the Korn shell) is created and
195 * placed in a sub-directory of the current directory with the name
196 * driver.test.<id>. A separate, executable script is generated for each access
197 * handle that matches the logging criteria. The log of accesses is placed at
198 * the top of each script as a record of the session. If the current directory
199 * is not writable, file output is written to standard output. The base name of
200 * each test file is the driver name, and the extension is a number that
201 * discriminates between different access handles. A control script (with the
202 * same name as the created test directory) is generated that will run all the
203 * test scripts sequentially.
205 * Executing the scripts will install, and then activate, the resulting error
206 * definitions. Error definitions are activated sequentially and the driver
207 * instance under test is taken offline and brought back online before each test
208 * (refer to the -e option for more information). By default, logging will apply
209 * to all PIO accesses, interrupts and DMA accesses to and from areas mapped
210 * for both reading and writing, but it can be constrained by specifying
211 * additional acc_types, rnumber, offset and length. Logging will continue for
212 * count matching accesses, with an optional time limit of collect_time seconds.
214 * Either the -n or -P option must be provided. The other options are optional.
215 * If an option (other than the -a option) is specified multiple times, only
216 * the final value for the option is used. If an option is not specified, its
217 * associated value is set to an appropriate default, which will provide
218 * maximal error coverage as described below.
223 msg(uint_t lvl
, char *msg
, ...)
234 count
= vsnprintf(buf
, BUFSZ
, msg
, args
);
238 if (count
>= sizeof (buf
))
241 (void) fprintf(errfile
, "%s", buf
);
247 kill_sighandler(int sig
)
264 (void) sigfillset(&(sa
.sa_mask
));
266 sa
.sa_handler
= kill_sighandler
;
267 if (sigaction(sig
, &sa
, NULL
) != 0)
268 /* install handler */
269 msg(0, "bad sigaction: %s\n", strerror(errno
));
273 * Compare two driver access handles
276 hdl_cmp(const void *p1
, const void *p2
)
278 struct handle_info
*e1
= (struct handle_info
*)p1
;
279 struct handle_info
*e2
= (struct handle_info
*)p2
;
281 if (e1
->instance
< e2
->instance
)
283 else if (e1
->instance
> e2
->instance
)
285 else if (e1
->access_type
< e2
->access_type
)
287 else if (e1
->access_type
> e2
->access_type
)
289 else if (e1
->rnumber
< e2
->rnumber
)
291 else if (e1
->rnumber
> e2
->rnumber
)
293 else if (e1
->len
< e2
->len
)
295 else if (e1
->len
> e2
->len
)
297 else if (e1
->offset
< e2
->offset
)
299 else if (e1
->offset
> e2
->offset
)
301 else if (e1
->addr_cookie
< e2
->addr_cookie
)
303 else if (e1
->addr_cookie
> e2
->addr_cookie
)
310 * Compare two hardware accesses.
313 elem_cmp(const void *p1
, const void *p2
)
315 struct acc_log_elem
*e1
= (struct acc_log_elem
*)p1
;
316 struct acc_log_elem
*e2
= (struct acc_log_elem
*)p2
;
318 if (e1
->access_type
< e2
->access_type
)
320 else if (e1
->access_type
> e2
->access_type
)
322 else if (e1
->offset
< e2
->offset
)
324 else if (e1
->offset
> e2
->offset
)
326 else if (e1
->size
< e2
->size
)
328 else if (e1
->size
> e2
->size
)
335 * Another way of comparing two hardware accesses.
338 log_cmp(const void *p1
, const void *p2
)
340 struct acc_log_elem
*e1
= (struct acc_log_elem
*)p1
;
341 struct acc_log_elem
*e2
= (struct acc_log_elem
*)p2
;
343 int rval
= elem_cmp(p1
, p2
);
346 if (e1
->repcount
< e2
->repcount
)
348 else if (e1
->repcount
> e2
->repcount
)
357 * And a final way of sorting a log (by access type followed by repcount).
360 log_cmp2(const void *p1
, const void *p2
)
362 struct acc_log_elem
*e1
= (struct acc_log_elem
*)p1
;
363 struct acc_log_elem
*e2
= (struct acc_log_elem
*)p2
;
365 if (e1
->access_type
< e2
->access_type
)
367 else if (e1
->access_type
> e2
->access_type
)
369 else if (e1
->repcount
< e2
->repcount
)
371 else if (e1
->repcount
> e2
->repcount
)
378 dump_log(uint_t lvl
, FILE *fp
, struct acc_log_elem
*items
,
379 size_t nitems
, uint_t logflags
)
383 uint_t offset
, allthesame
= 1;
385 if (logflags
& BOFI_LOG_TIMESTAMP
&&
386 getenv("DUMP_FULL_LOG") != 0)
389 for (i
= 1; i
< nitems
; i
++)
390 if (elem_cmp(items
+i
, items
) != 0)
394 "# Logged Accesses:\n# %-4s\t%-12s\t%-4s\t%-18s"
395 " (%-1s)\t%-10s\n\n", "type",
396 (items
->access_type
& BOFI_DMA_RW
) ?
397 "address" : "offset",
398 "size", "value", "repcnt", "time");
400 for (i
= 0; i
< nitems
; i
++, items
++) {
401 offset
= items
->offset
;
404 "# 0x%-2x\t0x%-10x\t%-4d\t0x%-16llx"
405 " (0x%-1x)\t%-8llu\n",
406 items
->access_type
, offset
, items
->size
,
407 items
->value
, items
->repcount
,
408 (logflags
& BOFI_LOG_TIMESTAMP
) ?
409 items
->access_time
: 0ull);
413 "# Access duplicated %d times\n",
418 msg(lvl
, "# 0x%x 0x%x %d 0x%llx(0x%x) %llu\n",
419 items
->access_type
, offset
, items
->size
,
420 items
->value
, items
->repcount
,
421 (logflags
& BOFI_LOG_TIMESTAMP
) ?
422 items
->access_time
: 0ull);
428 str_to_bm(char *optarg
, coding_t
*c
, uint_t
*bm
)
434 msg(2, "str_to_bm: optarg %s\n", optarg
);
435 if (optarg
!= NULL
&& (str
= strtok(optarg
, s
))) {
436 msg(2, "str_to_bm: str %s\n", str
);
438 for (; c
->str
!= 0; c
++)
439 if (strcmp(str
, c
->str
) == 0) {
441 msg(2, "str_to_bm: %s matches\n",
446 } while ((str
= strtok(NULL
, s
)));
449 msg(2, "str_to_bm: done 0x%x\n", *bm
);
455 * Generic routine for commands that apply to a particular instance of
456 * a driver under test (e.g. activate all errdefs defined on an instance).
459 manage_instance(int fd
, char *namep
, int instance
, int cmd
)
461 struct bofi_errctl errctl
;
463 errctl
.namesize
= strlen(namep
);
464 (void) strncpy(errctl
.name
, namep
, MAXNAMELEN
);
465 errctl
.instance
= instance
;
467 msg(8, "manage_instance: %s %d\n", namep
, instance
);
468 if (ioctl(fd
, cmd
, &errctl
) == -1) {
469 msg(0, "bofi ioctl %d failed: %s\n", cmd
, strerror(errno
));
479 struct bofi_errdef
*edp
,
480 struct acc_log_elem
*item
,
484 int fon
, /* corrupt after this many accesses */
485 size_t fcnt
, /* and then fail it fcnt times */
491 "-n %s -i %d -r %d -l 0x%llx 0x%x -a %s -c %d %d -f %d"
496 edp
->offset
+ item
->offset
, /* offset into the regset */
497 item
->size
, /* corrupt addrs from offset to offset+size */
499 fon
, /* corrupt after this many accesses */
500 fcnt
, /* and then fail it fcnt times */
505 (void) fprintf(fp
, " -w %lu %lu\n", nttime
, interval
);
510 define_op_err(FILE *fp
, int *ecnt
, struct bofi_errdef
*edp
,
511 struct acc_log_elem
*item
, ulong_t nttime
, ulong_t interval
, char *type
,
512 int fon
, size_t fcnt
)
519 uint64_t save_offset
;
521 if (item
->access_type
& BOFI_INTR
)
527 * errdefs for dma accesses are too numerous so assume that dma writes
528 * (DDI_DMA_SYNC_FORDEV) create less exposure to potential errors than
529 * do dma reads (DDI_DMA_SYNC_FORCPU).
531 * also by default do not corrupt PIO_W - it may hang a non-FT platform.
533 if (item
->access_type
!= BOFI_DMA_W
&&
534 ((item
->access_type
& BOFI_PIO_W
) == 0 || !atype_is_default
)) {
536 * user has asked for PIO_W
538 for (; ct
->str
!= 0; ct
++) {
543 operand
= random_operand
; /* a random value */
544 random_operand
= lrand48() | ((uint64_t)
548 operand
= 0xaddedabadb00bull
;
557 case BOFI_DELAY_INTR
: /* delay for 1 msec */
560 case BOFI_LOSE_INTR
: /* op not applicable */
563 case BOFI_EXTRA_INTR
: /* extra intrs */
569 if ((item
->access_type
== BOFI_DMA_W
||
570 item
->access_type
== BOFI_DMA_R
) &&
571 item
->size
> sizeof (uint64_t) && item
->size
<
572 DMA_INDIVIDUAL_CORRUPT_CUTOFF
) {
573 save_size
= item
->size
;
574 save_offset
= item
->offset
;
575 for (k
= (item
->size
+
576 sizeof (uint64_t) - 1) &
577 ~(sizeof (uint64_t) - 1);
578 k
> 0; k
-= sizeof (uint64_t)) {
579 item
->size
= sizeof (uint64_t);
580 (void) define_one_error(fp
, edp
,
581 item
, nttime
, interval
, type
, fon
,
582 fcnt
, edp
->acc_chk
, opname
,
584 item
->offset
+= sizeof (uint64_t);
586 item
->size
= save_size
;
587 item
->offset
= save_offset
;
589 (void) define_one_error(fp
, edp
, item
,
590 nttime
, interval
, type
, fon
, fcnt
,
591 edp
->acc_chk
, opname
, operand
);
594 if (op
== BOFI_EQUAL
) {
596 for (cnt
= 0; cnt
< NPIO_DEFAULTS
;
597 cnt
++, *ecnt
= *ecnt
+ 1) {
598 if ((item
->access_type
== BOFI_DMA_W
||
599 item
->access_type
== BOFI_DMA_R
) &&
600 item
->size
> sizeof (uint64_t) &&
602 DMA_INDIVIDUAL_CORRUPT_CUTOFF
) {
603 save_size
= item
->size
;
604 save_offset
= item
->offset
;
605 for (k
= (item
->size
+
606 sizeof (uint64_t) - 1) &
607 ~(sizeof (uint64_t) - 1);
609 k
-= sizeof (uint64_t)) {
612 (void) define_one_error(
623 item
->size
= save_size
;
624 item
->offset
= save_offset
;
626 (void) define_one_error(fp
,
627 edp
, item
, nttime
, interval
,
629 edp
->acc_chk
, opname
,
630 pio_default_values
[cnt
]);
637 if ((item
->access_type
& BOFI_PIO_W
) && !atype_is_default
) {
639 * user has asked for PIO_W
641 (void) define_one_error(fp
, edp
, item
, nttime
, interval
,
642 type
, fon
, fcnt
, edp
->acc_chk
, "NO", 0);
647 * and finally an access check errdef
649 if (item
->access_type
& BOFI_PIO_RW
)
650 (void) define_one_error(fp
, edp
, item
, nttime
, interval
,
651 type
, fon
, fcnt
, 1, "OR", 0);
653 if (item
->access_type
& BOFI_DMA_RW
)
654 (void) define_one_error(fp
, edp
, item
, nttime
, interval
,
655 type
, fon
, fcnt
, 2, "OR", 0);
660 * Convert a collection of log entries into error definitions.
664 define_nerrs(int fd
, FILE *fp
, int *ecnt
, struct bofi_errdef
*edp
,
665 struct acc_log_elem
*items
,
676 struct acc_log_elem
*item
;
680 int cycleiops
, cycledops
;
682 ulong_t ttime
, nttime
, interval
;
685 operand
= edp
->operand
;
686 msg(3, "define_nerrs: nitems %d (ac %d at 0x%x): (%d %d)"
687 " (op 0x%x 0x%llx)\n\n", nitems
, naccess
, items
->access_type
,
688 minac
, maxac
, op
, operand
);
691 * all items are guaranteed have values in the two element set {0, at}
692 * where at is a valid access type (so find the value of at)
694 for (i
= 0, item
= items
, at
= 0; i
< nitems
; i
++, item
++)
695 if (item
->access_type
!= 0) {
696 at
= item
->access_type
;
703 * find the string form of the access type
705 for (i
= 0, type
= 0; atypes
[i
].str
!= 0; i
++) {
706 if (atypes
[i
].code
== at
) {
707 type
= atypes
[i
].str
;
712 msg(0, "Unknown access type returned from bofi\n\t");
713 dump_log(0, 0, item
, 1, BOFI_LOG_TIMESTAMP
);
714 msg(1, "0x%x 0x%x 0x%x 0x%x\n", BOFI_LOG
, BOFI_INTR
,
715 BOFI_DMA_RW
, BOFI_PIO_RW
);
719 msg(1, "define_n: at = 0x%d (%s)\n", at
, type
== 0 ? "null" : type
);
721 * find the string form of the operator
723 for (i
= 0, opname
= 0; optypes
[i
].str
!= 0; i
++) {
724 if (op
== optypes
[i
].code
) {
725 opname
= optypes
[i
].str
;
731 * if not found or inconsistent default to XOR
734 (op
== BOFI_NO_TRANSFER
&&
735 (at
& (BOFI_DMA_RW
|BOFI_PIO_R
))) ||
736 (op
>= BOFI_DELAY_INTR
&& (at
& BOFI_INTR
) == 0)) {
737 opname
= optypes
[3].str
; /* "XOR" */
739 op
= optypes
[3].code
;
743 * if operator and access type are inconsistent choose a sensible
748 if (op
< BOFI_DELAY_INTR
)
750 else if (op
== BOFI_LOSE_INTR
)
754 if (nitems
== 1 && (at
& BOFI_DMA_RW
))
757 * for each access in the list define one or more error definitions
759 for (i
= 0, item
= items
; i
< nitems
; i
++, item
++) {
763 if (item
->access_type
== 0)
767 * base number of errors to inject on 3% of number of
768 * similar accesses seen during LOG phase
770 acnt
= item
->repcount
/ 10 + 1; /* 10% */
771 fcnt
= (acnt
>= 3) ? acnt
/ 3 : 1; /* 3% */
774 * wait for twice the time it took during LOG phase
776 if ((ttime
= (item
->access_time
* 2)) < MIN_REPORT_TIME
)
777 ttime
= MIN_REPORT_TIME
;
778 else if (max_edef_wait
!= 0 && ttime
> max_edef_wait
)
779 ttime
= max_edef_wait
;
781 * if edef_sleep set (-w) the use that, otherwise use default
783 interval
= edef_sleep
? edef_sleep
: DEFAULT_EDEF_SLEEP
;
786 "define_n: item %d limit %d step %d (intr %d) tt(%lu)\n",
787 i
, item
->repcount
, acnt
, intrs
, ttime
);
789 for (j
= 0, fon
= 1, nttime
= ttime
; j
< item
->repcount
;
791 if (policy
& OPERATORSPOLICY
) {
792 define_op_err(fp
, ecnt
, edp
, item
,
793 nttime
, interval
, type
, fon
, fcnt
);
796 op
= ioptypes
[intrs
].code
;
797 opname
= ioptypes
[intrs
++].str
;
799 case BOFI_DELAY_INTR
:
800 /* delay for 1 sec */
804 /* op not applicable */
807 case BOFI_EXTRA_INTR
:
809 /* generate 2 extra intrs */
814 } else if (cycledops
) {
815 op
= doptypes
[intrs
].code
;
816 opname
= doptypes
[intrs
++].str
;
819 random_operand
= lrand48() |
822 break; /* a random value */
824 operand
= 0xaddedabadb00bull
;
827 operand
= 0xd1ab011c0af1a5c0ull
;
836 (void) define_one_error(fp
, edp
, item
,
837 nttime
, interval
, type
, fon
,
838 fcnt
, edp
->acc_chk
, opname
, operand
);
840 if (op
== BOFI_EQUAL
) {
842 for (cnt
= 0; cnt
< NPIO_DEFAULTS
;
843 cnt
++, *ecnt
= *ecnt
+ 1)
844 (void) define_one_error(fp
,
846 interval
, type
, fon
, fcnt
,
847 edp
->acc_chk
, opname
,
848 pio_default_values
[cnt
]);
853 * all non maximal policies should only generate
854 * a single error definition set per access.
856 if (!(policy
& MAXIMALPOLICY
))
859 nttime
= (logtime
- item
->access_time
) *
860 (j
+ acnt
+ fcnt
- 1) / logsize
;
861 if (nttime
< MIN_REPORT_TIME
)
862 nttime
= MIN_REPORT_TIME
;
863 else if (nttime
> max_edef_wait
)
864 nttime
= max_edef_wait
;
866 msg(11, "define_nerrs: %lu %d %d %d %llu\n", nttime
,
867 max_edef_wait
, fon
, fcnt
, item
->access_time
);
869 if (item
->access_type
!= BOFI_INTR
)
878 reduce_log(uint16_t pol
, struct acc_log
*log
, /* input args */
879 struct acc_log_elem
**llp
, size_t *cntp
) /* output args */
882 struct acc_log_elem
*items
, *item
, *elem
;
883 int cnt
, nitems
, acnt
;
884 int i
, j
, k
, lb
, ub
, mina
, maxa
, cutoff
[2], mean
;
886 if (llp
== 0 || cntp
== 0) /* subroutine interface violated */
890 items
= (void *)log
->logbase
;
891 nitems
= log
->entries
;
893 items
= *llp
; /* outputs double up as inputs */
896 /* has the utc time wrapped over ULMAX - unlikely so fix it at 10 */
897 logtime
= (log
->stop_time
>= log
->start_time
) ?
898 log
->stop_time
- log
->start_time
: 10ul;
900 msg(1, "reduce %d: logtime %lu\n", nitems
, logtime
);
902 * Sort the log by access type - do not remove duplicates yet (but do
903 * remove access that do not match the requested log -> errdef policy
904 * (defined by union pu pol). Set the repcount field of each entry to a
905 * unique value (in the control statement of the for loop) - this
906 * ensures that the qsort (following the for loop) will not remove any
909 for (i
= 0, cnt
= 0, elem
= items
; i
< nitems
;
910 elem
->repcount
= i
, i
++, elem
++) {
912 * If interested in the I/O transfer size and this access
913 * does not match the requested size then ignore the access
915 if ((pol
& SIZEPOLICY
) &&
916 (!(pol
& MULTIPOLICY
) || elem
->repcount
== 1) &&
917 /* req for DMA / ddi_rep */
918 (pol
& elem
->size
) == 0)
919 elem
->access_type
= 0;
920 /* these will end up sorted at the head */
923 elem
->size
*= elem
->repcount
;
924 if (log
->flags
& BOFI_LOG_TIMESTAMP
)
925 /* real access time */
926 elem
->access_time
-= log
->start_time
;
929 elem
->access_time
= logtime
* (i
+ 1) / nitems
;
933 qsort((void *)items
, nitems
, sizeof (*items
), log_cmp
);
935 msg(5, "qsorted log raw (nitems %d cnt %d:\n", nitems
, cnt
);
936 dump_log(14, 0, items
, nitems
, log
->flags
);
938 if (cnt
!= nitems
) { /* some items should be ignored */
939 items
+= (nitems
- cnt
); /* ignore these ones */
940 if ((nitems
= cnt
) == 0) {
944 /* the chosen policy has ignored everything */
949 * Now remove duplicate entries based on access type, address and size.
950 * Reuse the repcount field to store the no. of duplicate accesses.
951 * Store the average access time in the single remaining
952 * representative of the duplicate set.
955 for (i
= 1, cnt
= 1, elem
= items
, elem
->repcount
= 1, item
= elem
+ 1;
956 i
< nitems
; i
++, item
++) {
957 if (elem_cmp(elem
, item
) == 0) {
958 elem
->access_time
+= item
->access_time
;
960 } else { /* not a duplicate */
961 elem
->access_time
= logtime
/ elem
->repcount
;
968 elem
->access_time
= logtime
/ elem
->repcount
;
971 * The log is sorted by access type - now resort to order by frequency
972 * of accesses (ie for a given access type uncommon access will come
976 qsort((void *)items
, cnt
, sizeof (*items
), log_cmp2
);
977 msg(4, "qsorted log2: cnt is %d\n", cnt
);
978 dump_log(4, 0, items
, cnt
, log
->flags
);
980 for (i
= 0; i
< cnt
; i
= j
) {
983 * Pick out the set [i, j) consisting of elements with the same
986 for (j
= i
+ 1, acnt
= items
[i
].repcount
; j
< cnt
&&
987 items
[j
].access_type
== items
[i
].access_type
; j
++)
988 acnt
+= items
[j
].repcount
;
990 if (j
- i
== 1) /* never ignore solo accesses of a given type */
993 * Now determine what constitutes uncommon and common accesses:
995 mina
= items
[i
].repcount
;
996 maxa
= items
[j
-1].repcount
;
997 mean
= acnt
/ (j
- i
); /* mean value */
999 if (pol
& (UNCOMMONPOLICY
|MEDIANPOLICY
)) {
1000 cutoff
[0] = (mean
- mina
) / DISTRIB_CUTOFF
+ mina
;
1002 for (ub
= i
; ub
< j
; ub
++)
1003 if (items
[ub
].repcount
> cutoff
[0])
1011 if (pol
& (COMMONPOLICY
|MEDIANPOLICY
)) {
1012 cutoff
[1] = maxa
- (maxa
- mean
) / DISTRIB_CUTOFF
;
1013 for (lb
= j
- 1; lb
>= i
; lb
--)
1014 if (items
[lb
].repcount
< cutoff
[1])
1016 if (!(pol
& (UNCOMMONPOLICY
|MEDIANPOLICY
)))
1020 msg(3, "reduce_log: p 0x%x at %d:0x%x %d:0x%x acnt mina maxa"
1022 " mean %d cutoffs(%d %d) bnds(%d, %d)\n",
1023 pol
, i
, items
[i
].access_type
, j
, items
[j
].access_type
,
1024 acnt
, mina
, maxa
, mean
, cutoff
[0], cutoff
[1], lb
, ub
);
1027 if (!(pol
& MEDIANPOLICY
))
1028 /* delete all the mid accesses */
1029 for (k
= ub
; k
<= lb
; k
++)
1030 items
[k
].access_type
= 0;
1032 if (!(pol
& UNCOMMONPOLICY
))
1033 /* delete uncommon accesses */
1034 for (k
= i
; k
< ub
; k
++)
1035 items
[k
].access_type
= 0;
1036 if (!(pol
& COMMONPOLICY
))
1037 /* delete common accesses */
1038 for (k
= lb
+1; k
< j
; k
++)
1039 items
[k
].access_type
= 0;
1042 msg(4, "reduce_log: returning %d items\n", cnt
);
1043 dump_log(5, 0, items
, cnt
, log
->flags
);
1050 log2errdefs(int fd
, struct bofi_errdef
*edp
, struct acc_log
*log
,
1053 struct acc_log_elem
*items
;
1057 char fname
[_POSIX_PATH_MAX
];
1059 time_t utc
= time(NULL
);
1064 struct stat statbuf
;
1066 items
= (void *)log
->logbase
;
1067 nitems
= log
->entries
;
1068 logtime
= (log
->stop_time
>= log
->start_time
) ?
1069 log
->stop_time
- log
->start_time
: 10ul;
1074 /* ensure that generated errdefs complete in bounded time */
1075 if (max_edef_wait
== 0)
1077 logtime
> MIN_REPORT_TIME
? logtime
: MIN_REPORT_TIME
* 2;
1079 msg(4, "log2errdefs(0x%p, 0x%p, %d, 0x%x):\n",
1080 (void *) edp
, (void *) items
, nitems
, policy
);
1082 (void) snprintf(fname
, sizeof (fname
), "%s.%d", (char *)edp
->name
,
1084 if ((fp
= fopen(fname
, "w")) == 0)
1087 (void) fprintf(fp
, "#!/bin/ksh -p\n\n");
1088 (void) fprintf(fp
, "# %-24s%s\n", "Script creation time:", ctime(&utc
));
1089 (void) fprintf(fp
, "# %-24s%llu\n",
1090 "Activation time:", log
->start_time
);
1091 (void) fprintf(fp
, "# %-24s%llu\n",
1092 "Deactivation time:", log
->stop_time
);
1093 (void) fprintf(fp
, "# %-24s%d\n", "Log size:", nitems
);
1094 (void) fprintf(fp
, "# %-24s", "Errdef policy:");
1095 for (i
= 0; ptypes
[i
].str
!= 0; i
++)
1096 if (policy
& ptypes
[i
].code
)
1097 (void) fprintf(fp
, "%s ", ptypes
[i
].str
);
1098 (void) fprintf(fp
, "\n");
1099 (void) fprintf(fp
, "# %-24s%s\n", "Driver:", (char *)edp
->name
);
1100 (void) fprintf(fp
, "# %-24s%d\n", "Instance:", edp
->instance
);
1101 if (edp
->access_type
& BOFI_PIO_RW
) {
1102 (void) fprintf(fp
, "# %-24s%d\n",
1103 "Register set:", edp
->rnumber
);
1104 (void) fprintf(fp
, "# %-24s0x%llx\n", "Offset:", edp
->offset
);
1105 (void) fprintf(fp
, "# %-24s0x%llx\n", "Length:", edp
->len
);
1106 } else if (edp
->access_type
& BOFI_DMA_RW
) {
1107 (void) fprintf(fp
, "# %-24s%d\n", "DMA handle:", edp
->rnumber
);
1108 (void) fprintf(fp
, "# %-24s0x%llx\n", "Offset:", edp
->offset
);
1109 (void) fprintf(fp
, "# %-24s0x%llx\n", "Length:", edp
->len
);
1110 } else if ((edp
->access_type
& BOFI_INTR
) == 0) {
1111 (void) fprintf(fp
, "# %-24s%d\n",
1112 "Unknown Handle Type:", edp
->rnumber
);
1115 (void) fprintf(fp
, "# %-24s0x%x ( ", "Access type:",
1116 (edp
->access_type
& ~BOFI_LOG
));
1117 if (edp
->access_type
& BOFI_PIO_R
)
1118 (void) fprintf(fp
, "%s ", "pio_r");
1119 if (edp
->access_type
& BOFI_PIO_W
)
1120 (void) fprintf(fp
, "%s ", "pio_w");
1121 if (edp
->access_type
& BOFI_DMA_W
)
1122 (void) fprintf(fp
, "%s ", "dma_w");
1123 if (edp
->access_type
& BOFI_DMA_R
)
1124 (void) fprintf(fp
, "%s ", "dma_r");
1125 if (edp
->access_type
& BOFI_INTR
)
1126 (void) fprintf(fp
, "%s ", "intr");
1127 (void) fprintf(fp
, ")\n\n");
1129 (void) fprintf(fp
, "# %-24s%s\n\n",
1130 "Test Comment:", user_comment
);
1132 dump_log(0, fp
, items
, nitems
, log
->flags
);
1135 if ((err
= reduce_log(policy
, log
, &items
, &nitems
)) < 0 ||
1137 msg(4, "log2errdefs: reduce_log err %d nitems %d\n",
1141 (void) fprintf(fp
, "\nerror() { echo \""
1143 " >&2; exit 2; }\n");
1145 "trap ' ' 16\t# ignore - it is trapped by abort monitor_edef\n");
1147 (void) fprintf(fp
, "\nfixup_script()\n{\n");
1148 if (scriptargs
> 0) {
1149 (void) fprintf(fp
, "\tif [[ $1 -eq 1 ]]\n\tthen\n");
1150 (void) fprintf(fp
, "\t\t# Call a user defined workload\n");
1151 (void) fprintf(fp
, "\t\t# while injecting errors\n\t\t");
1152 for (i
= 0; i
< scriptargs
; i
++)
1153 (void) fprintf(fp
, "%s ", fixup_script
[i
]);
1154 (void) fprintf(fp
, "\n\tfi\n");
1155 (void) fprintf(fp
, "\treturn 0\n");
1157 (void) fprintf(fp
, "\tif [[ $1 -eq 0 ]]\n\tthen\n");
1159 "\t\t# terminate any outstanding workload\n");
1160 (void) fprintf(fp
, "\t\tif [ $script_pid -gt 0 ]; then\n");
1161 (void) fprintf(fp
, "\t\t\tkill $script_pid\n");
1162 (void) fprintf(fp
, "\t\t\tscript_pid=0\n");
1163 (void) fprintf(fp
, "\t\tfi\n");
1164 (void) fprintf(fp
, "\tfi\n");
1165 (void) fprintf(fp
, "\treturn -1\n");
1167 (void) fprintf(fp
, "}\n\n");
1168 (void) fprintf(fp
, "devpath=/devices%s\n\n", devpath
);
1169 (void) fprintf(fp
, "#\n");
1170 (void) fprintf(fp
, "# following text extracted from th_script\n");
1171 (void) fprintf(fp
, "#\n");
1172 if (stat("/usr/lib/th_script", &statbuf
) == -1) {
1173 msg(0, "log2errdefs: stat of /usr/lib/th_script failed\n");
1176 fd
= open("/usr/lib/th_script", O_RDONLY
);
1178 msg(0, "log2errdefs: open of /usr/lib/th_script failed\n");
1181 buffer
= malloc(statbuf
.st_size
);
1183 msg(0, "log2errdefs: malloc for /usr/lib/th_script failed\n");
1186 if (read(fd
, buffer
, statbuf
.st_size
) != statbuf
.st_size
) {
1187 msg(0, "log2errdefs: read of /usr/lib/th_script failed\n");
1190 (void) fwrite(buffer
, statbuf
.st_size
, 1, fp
);
1192 (void) fprintf(fp
, "#\n");
1193 (void) fprintf(fp
, "# end of extracted text\n");
1194 (void) fprintf(fp
, "#\n");
1195 (void) fprintf(fp
, "run_subtest %s %d <<ERRDEFS\n",
1196 (char *)edp
->name
, edp
->instance
);
1198 for (i
= 0; i
< nitems
; i
= j
) {
1200 acc_cnt
= items
[i
].repcount
;
1202 j
< nitems
&& items
[j
].access_type
== items
[i
].access_type
;
1204 acc_cnt
+= items
[j
].repcount
;
1205 msg(1, "l2e: nitems %d i %d j %d at 0x%x\n",
1206 nitems
, i
, j
, items
[i
].access_type
);
1207 if (items
[i
].access_type
!= 0)
1208 (void) define_nerrs(fd
, fp
, &ecnt
, edp
, items
+i
, j
-i
,
1209 acc_cnt
, items
[i
].repcount
, items
[j
-1].repcount
,
1210 logtime
, log
->entries
);
1213 (void) fprintf(fp
, "ERRDEFS\n");
1214 (void) fprintf(fp
, "exit 0\n");
1216 if (fp
!= stdout
&& fp
!= stderr
) {
1217 if (fchmod(fileno(fp
), S_IRWXU
|S_IRGRP
|S_IROTH
))
1218 msg(0, "fchmod failed: %s\n", strerror(errno
));
1219 if (fclose(fp
) != 0)
1220 msg(0, "close of %s failed: %s\n", fname
,
1223 msg(10, "log2errdefs: done\n");
1226 #define LLSZMASK (sizeof (longlong_t) -1)
1230 struct bofi_errdef
*errdef
, /* returned access criteria */
1231 struct bofi_errstate
*errstate
,
1232 struct handle_info
*hdl
, /* handle to match against request */
1233 struct bofi_errdef
*edp
) /* requested access criteria */
1236 errdef
->instance
= hdl
->instance
;
1239 if (hdl
->access_type
== 0)
1242 errdef
->access_type
=
1243 errdef
->access_type
& (hdl
->access_type
|BOFI_LOG
);
1245 /* use a big log for PIO and a small one otherwise */
1246 if (lsize_is_default
&&
1247 (errdef
->access_type
& BOFI_PIO_RW
) == 0) {
1248 errdef
->access_count
= DFLT_NONPIO_LOGSZ
;
1249 errdef
->fail_count
= 0;
1251 errdef
->log
.logsize
= errstate
->log
.logsize
=
1252 errdef
->access_count
+ errdef
->fail_count
- 1;
1253 if (errdef
->log
.logsize
== -1U) {
1254 errdef
->log
.logsize
= errstate
->log
.logsize
= 0;
1256 errdef
->log
.logbase
= errstate
->log
.logbase
=
1257 (caddr_t
)GETSTRUCT(struct acc_log_elem
, errdef
->log
.logsize
);
1259 if (errdef
->log
.logbase
== 0)
1262 errdef
->rnumber
= hdl
->rnumber
;
1263 errdef
->offset
= hdl
->offset
;
1264 errdef
->len
= hdl
->len
;
1266 msg(4, "creating errdef: %d %s %d %d 0x%llx 0x%llx 0x%x 0x%x 0x%x"
1267 " 0x%x 0x%x 0x%llx\n",
1268 errdef
->namesize
, (char *)errdef
->name
,
1269 errdef
->instance
, errdef
->rnumber
,
1270 errdef
->offset
, errdef
->len
,
1271 errdef
->access_type
,
1272 errdef
->access_count
, errdef
->fail_count
,
1273 errdef
->acc_chk
, errdef
->optype
, errdef
->operand
);
1274 if (ioctl(fd
, BOFI_ADD_DEF
, errdef
) == -1) {
1275 perror("th_define - adding errdef failed");
1278 errdef
->optype
= edp
->optype
; /* driver clears it if fcnt is zero */
1279 errstate
->errdef_handle
= errdef
->errdef_handle
;
1284 collect_state(int fd
, int cmd
,
1285 struct bofi_errstate
*errstate
,
1286 struct bofi_errdef
*errdef
,
1290 size_t ls
= errstate
->log
.logsize
;
1292 msg(2, "collect_state: pre: edp->access_type 0x%x (logsize %d)\n",
1293 errdef
->access_type
, errdef
->log
.logsize
);
1296 errstate
->log
.logsize
= 0; /* only copy the driver log once */
1298 msg(10, "collecting state (lsize %d) ...\n",
1299 errstate
->log
.logsize
);
1302 if (ioctl(fd
, cmd
, errstate
) == -1 && errno
!= EINTR
) {
1303 perror("th_define (collect) -"
1304 " waiting for error report failed");
1308 (void) fprintf(outfile
, "Logged %d out of %d accesses"
1309 " (%s %d %d 0x%x %d).\n",
1310 errstate
->log
.entries
, ls
,
1311 (char *)errdef
->name
, errdef
->instance
, errdef
->rnumber
,
1312 errdef
->access_type
, errstate
->log
.wrapcnt
);
1314 (void) msg(1, "\t(ac %d fc %d lf 0x%x wc %d).\n",
1315 errstate
->access_count
, errstate
->fail_count
,
1316 errstate
->log
.flags
, errstate
->log
.wrapcnt
);
1319 if ((errstate
->log
.flags
& BOFI_LOG_WRAP
) &&
1320 errstate
->access_count
> 0)
1322 if (errstate
->access_count
<= 1 &&
1323 errstate
->fail_count
== 0 &&
1324 errstate
->acc_chk
== 0) {
1325 msg(3, "collecting state complete entries %d\n",
1326 errstate
->log
.entries
);
1330 msg(5, "still collecting state: %d, %d, %d\n",
1331 errstate
->access_count
, errstate
->fail_count
,
1333 (void) msg(2, "Log: errno %d size %d entries %d "
1334 "(off 0x%llx len 0x%llx) ac %d\n", errno
,
1335 errstate
->log
.logsize
, errstate
->log
.entries
,
1336 errdef
->offset
, errdef
->len
, errstate
->access_count
);
1338 } while (rval
== 0 && errstate
->log
.entries
< ls
);
1340 /* now grab the log itself */
1341 errstate
->log
.logsize
= ls
;
1342 if (errstate
->log
.entries
!= 0) {
1343 if (ioctl(fd
, BOFI_CHK_STATE
, errstate
) == -1) {
1345 "%s: errorwhile retrieving %d log entries: %s\n",
1346 Progname
, errstate
->log
.entries
, strerror(errno
));
1348 msg(2, "collect_state: post: edp->access_type 0x%x"
1349 " (log entries %d %d) (%llu - %llu)\n",
1350 errdef
->access_type
,
1351 errstate
->log
.entries
, errstate
->access_count
,
1352 errstate
->log
.start_time
, errstate
->log
.stop_time
);
1354 log2errdefs(fd
, errdef
, &(errstate
->log
), devpath
);
1360 print_err_reports(FILE *fp
, struct bofi_errstate
*esp
,
1361 char *fname
, char *cmt
, int id
)
1363 if (fname
!= 0 && *fname
!= 0)
1364 (void) fprintf(fp
, "%sErrdef file %s definition %d:",
1367 (void) fprintf(fp
, "%s", cmt
);
1369 if (esp
->access_count
!= 0) {
1370 (void) fprintf(fp
, " (access count %d).\n", esp
->access_count
);
1372 (void) fprintf(fp
, "\n%s\tremaining fail count %d acc_chk %d\n",
1373 cmt
, esp
->fail_count
, esp
->acc_chk
);
1374 (void) fprintf(fp
, "%s\tfail time 0x%llx error reported time"
1375 " 0x%llx errors reported %d\n", cmt
,
1376 esp
->fail_time
, esp
->msg_time
,
1379 (void) fprintf(fp
, "%s\tmessage \"%s\" severity 0x%x\n",
1380 cmt
, esp
->buffer
, (uint_t
)esp
->severity
);
1385 thr_collect(void *arg
, char *devpath
)
1388 struct collector_def
*hi
= (struct collector_def
*)arg
;
1390 msg(4, "thr_collect: collecting %s inst %d rn %d at = 0x%x.\n",
1391 hi
->ed
.name
, hi
->ed
.instance
,
1392 hi
->ed
.rnumber
, hi
->ed
.access_type
);
1394 if ((fd
= open(BOFI_DEV
, O_RDWR
)) == -1) {
1395 if (errno
== EAGAIN
)
1396 msg(0, "Too many instances of bofi currently open\n");
1398 msg(0, "Error while opening bofi driver: %s",
1402 * Activate the logging errdefs - then collect the results.
1404 (void) manage_instance(fd
, hi
->ed
.name
,
1405 hi
->ed
.instance
, BOFI_START
);
1406 collect_state(fd
, BOFI_CHK_STATE_W
, &hi
->es
, &hi
->ed
, devpath
);
1410 * there is no more work to do on this access handle so clean up / exit.
1412 msg(3, "thr_collect: closing and broadcasting.\n");
1417 * Given an access handle known to the bofi driver see if the user has
1418 * specified access criteria that match that handle. Note: this matching
1419 * algorithm should be kept consistent with the drivers alogorithm.
1422 match_hinfo(struct handle_info
*hp
, int instance
, uint_t access_type
,
1423 int rnumber
, offset_t offset
, offset_t len
)
1426 msg(9, "matching (%d %d) 0x%x %d offset (%llx, %llx) len (%llx %llx)\n",
1427 hp
->instance
, instance
, access_type
, rnumber
,
1428 hp
->offset
, offset
, hp
->len
, len
);
1430 if (instance
!= -1 && hp
->instance
!= instance
)
1432 if ((access_type
& BOFI_DMA_RW
) &&
1433 (hp
->access_type
& BOFI_DMA_RW
) &&
1434 (rnumber
== -1 || hp
->rnumber
== rnumber
))
1436 else if ((access_type
& BOFI_INTR
) &&
1437 (hp
->access_type
& BOFI_INTR
))
1439 else if ((access_type
& BOFI_PIO_RW
) &&
1440 (hp
->access_type
& BOFI_PIO_RW
) &&
1441 (rnumber
== -1 || hp
->rnumber
== rnumber
) &&
1442 (len
== 0 || hp
->offset
< offset
+ len
) &&
1443 (hp
->len
== 0 || hp
->offset
+ hp
->len
> offset
))
1450 * Obtain all the handles created by the driver specified by the name parameter
1451 * that match the remaining arguments. The output parameter nhdls indicates how
1452 * many of the structures pointed to by the output parameter hip match the
1455 * It is the responsibility of the caller to free *hip when *nhdls != 0.
1458 get_hinfo(int fd
, char *name
, struct handle_info
**hip
, size_t *nhdls
,
1459 int instance
, int atype
, int rset
, offset_t offset
, offset_t len
,
1462 struct bofi_get_hdl_info hdli
;
1465 command
= BOFI_GET_HANDLE_INFO
;
1466 hdli
.namesize
= strlen(name
);
1467 (void) strncpy(hdli
.name
, name
, MAXNAMELEN
);
1469 * Initially ask for the number of access handles (not the structures)
1470 * in order to allocate memory
1477 * Ask the bofi driver for all handles created by the driver under test.
1479 if (ioctl(fd
, command
, &hdli
) == -1) {
1481 msg(0, "driver failed to return handles: %s\n",
1484 } else if ((*nhdls
= hdli
.count
) == 0) {
1485 msg(1, "get_hinfo: no registered handles\n");
1486 return (0); /* no handles */
1487 } else if ((*hip
= GETSTRUCT(struct handle_info
, *nhdls
)) == 0) {
1490 struct handle_info
*hp
, **chosen
;
1493 /* Ask for *nhdls handles */
1494 hdli
.hdli
= (caddr_t
)*hip
;
1495 if (ioctl(fd
, command
, &hdli
) == -1) {
1498 msg(0, "BOFI_GET_HANDLE_INFO ioctl returned error %d\n",
1504 if (hdli
.count
< *nhdls
)
1505 *nhdls
= hdli
.count
; /* some handles have gone away */
1507 msg(4, "qsorting %d handles\n", *nhdls
);
1509 /* sort them naturally (NB ordering is not mandatory) */
1510 qsort((void *)*hip
, *nhdls
, sizeof (**hip
), hdl_cmp
);
1512 if ((chosen
= malloc(sizeof (hp
) * *nhdls
)) != NULL
) {
1513 struct handle_info
**ip
;
1514 /* the selected handles */
1515 struct handle_info
*prev
= 0;
1518 for (i
= 0, hp
= *hip
, ip
= chosen
; i
< *nhdls
;
1521 * Remark: unbound handles never match
1522 * (access_type == 0)
1524 if (match_hinfo(hp
, instance
, atype
, rset
,
1525 offset
&0x7fffffff, len
&0x7fffffff)) {
1526 msg(3, "match: 0x%x 0x%llx 0x%llx"
1527 " 0x%llx (0x%llx)\n",
1528 hp
->access_type
, hp
->addr_cookie
,
1529 hp
->offset
, hp
->len
,
1530 (hp
->len
& 0x7fffffff));
1532 (prev
->access_type
& BOFI_DMA_RW
) &&
1533 (hp
->access_type
& BOFI_DMA_RW
) &&
1534 hp
->instance
== prev
->instance
&&
1535 hp
->len
== prev
->len
&&
1540 if ((hp
->access_type
& BOFI_DMA_RW
) &&
1541 (atype
& BOFI_DMA_RW
) !=
1547 msg(3, "match_hinfo: match:"
1548 " 0x%llx (%d %d) (%d %d)"
1549 " (0x%x 0x%x) (0x%llx,"
1553 hp
->instance
, prev
->rnumber
,
1556 hp
->access_type
, prev
->len
,
1559 /* it matches so remember it */
1565 if (*nhdls
!= scnt
) {
1567 * Reuse the alloc'ed memory to return
1568 * only those handles the user has asked for.
1569 * But first prune the handles to get rid of
1570 * overlapping ranges (they are ordered by
1571 * offset and length).
1574 for (i
= 0, hp
= *hip
, ip
= chosen
; i
< scnt
;
1577 (void) memcpy(hp
, *ip
,
1583 for (i
= 0, hp
= *hip
; i
< *nhdls
; i
++, hp
++) {
1584 msg(4, "\t%d 0x%x %d 0x%llx 0x%llx 0x%llx\n",
1585 hp
->instance
, hp
->access_type
, hp
->rnumber
,
1586 hp
->len
, hp
->offset
, hp
->addr_cookie
);
1592 msg(4, "get_info: %s got %d handles\n", name
, *nhdls
);
1599 struct sigaction sa
;
1600 int *ip
, sigs
[] = {SIGINT
, SIGTERM
, 0};
1602 sa
.sa_handler
= kill_sighandler
;
1603 (void) sigemptyset(&sa
.sa_mask
);
1604 for (ip
= sigs
; *ip
; ip
++)
1605 (void) sigaddset(&sa
.sa_mask
, *ip
);
1607 for (ip
= sigs
; *ip
; ip
++)
1608 (void) sigaction(*ip
, &sa
, NULL
);
1616 /* Potentially hungry on resources so up them all to their maximums */
1617 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0)
1618 msg(0, "failed to obtain RLIMIT_NOFILE: %s\n", strerror(errno
));
1620 msg(12, "RLIMIT_NOFILE\t %lu (%lu)\n",
1621 rl
.rlim_cur
, rl
.rlim_max
);
1622 rl
.rlim_cur
= rl
.rlim_max
;
1623 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0)
1624 msg(0, "failed to set RLIMIT_NOFILE: %s\n",
1626 (void) enable_extended_FILE_stdio(-1, -1);
1628 if (getrlimit(RLIMIT_DATA
, &rl
) < 0)
1629 msg(0, "failed to obtain RLIMIT_DATA: %s\n", strerror(errno
));
1631 msg(12, "RLIMIT_DATA\t %lu (%lu)\n", rl
.rlim_cur
, rl
.rlim_max
);
1632 rl
.rlim_cur
= rl
.rlim_max
;
1633 if (setrlimit(RLIMIT_DATA
, &rl
) < 0)
1634 msg(0, "failed to set RLIMIT_DATA: %s\n",
1637 if (getrlimit(RLIMIT_FSIZE
, &rl
) < 0)
1638 msg(0, "failed to obtain RLIMIT_FSIZE: %s\n", strerror(errno
));
1640 msg(12, "RLIMIT_FSIZE\t %lu (%lu)\n", rl
.rlim_cur
, rl
.rlim_max
);
1641 rl
.rlim_cur
= rl
.rlim_max
;
1642 if (setrlimit(RLIMIT_FSIZE
, &rl
) < 0)
1643 msg(0, "failed to set RLIMIT_FSIZE: %s\n",
1649 create_test_file(char *drvname
)
1651 char dirname
[_POSIX_PATH_MAX
];
1652 char testname
[_POSIX_PATH_MAX
];
1654 time_t utc
= time(NULL
);
1656 if (snprintf(dirname
, sizeof (dirname
), "%s.test.%lu",
1657 drvname
, utc
) == -1 ||
1658 snprintf(testname
, sizeof (testname
), "%s.test.%lu",
1659 drvname
, utc
) == -1)
1662 if (mkdir(dirname
, S_IRWXU
|S_IRGRP
|S_IROTH
)) {
1663 msg(0, "Error creating %s: %s\n", dirname
, strerror(errno
));
1666 if (chdir(dirname
)) {
1667 (void) rmdir(dirname
);
1670 if ((fp
= fopen(testname
, "w")) == 0)
1671 return (0); /* leave created directory intact */
1679 char name
[MAXPATHLEN
];
1684 walk_callback(di_node_t node
, void *arg
)
1686 struct walk_arg
*warg
= (struct walk_arg
*)arg
;
1690 driver_name
= di_driver_name(node
);
1691 if (driver_name
!= NULL
) {
1692 if (strcmp(driver_name
, warg
->name
) == 0 &&
1693 di_instance(node
) == warg
->instance
) {
1694 path
= di_devfs_path(node
);
1698 (void) strncpy(warg
->path
, path
, warg
->pathlen
);
1699 return (DI_WALK_TERMINATE
);
1702 return (DI_WALK_CONTINUE
);
1706 getpath(char *path
, int instance
, char *name
, int pathlen
)
1709 struct walk_arg warg
;
1711 warg
.instance
= instance
;
1712 (void) strncpy(warg
.name
, name
, MAXPATHLEN
);
1714 warg
.pathlen
= pathlen
;
1715 if ((node
= di_init("/", DINFOSUBTREE
)) == DI_NODE_NIL
)
1717 if (di_walk_node(node
, DI_WALK_CLDFIRST
, &warg
, walk_callback
) == -1) {
1721 if (warg
.path
== NULL
) {
1730 * Record logsize h/w accesses of type 'edp->access_type' made by instance
1731 * 'edp->instance' of driver 'edp->name' to the register set (or dma handle)
1732 * 'edp->rnumber' that lie within the range 'edp->offset' to
1733 * 'edp->offset' + 'edp->len'.
1734 * Access criteria may be mixed and matched:
1735 * - access types may be combined (PIO read/write, DMA read write or intrs);
1736 * - if 'edp->instance' is -1 all instances are checked for the criteria;
1737 * - if 'edp->rnumber' is -1 all register sets and dma handles are matched;
1738 * - 'offset' and 'len' indicate that only PIO and DMA accesses within the
1739 * range 'edp->offset' to 'edp->len' will be logged. Putting 'edp->offset'
1740 * to zero and 'edp->len' to -1ull gives maximal coverage.
1742 * 'collecttime' is the number of seconds used to log accesses
1743 * (default is infinity).
1746 test_driver(struct bofi_errdef
*edp
,
1747 unsigned long long collecttime
)
1751 struct collector_def
*cdefs
, *cdp
;
1752 struct handle_info
*hdls
, *hdl
;
1756 unsigned long long timechunk
;
1757 FILE *sfp
; /* generated control test file */
1758 char buf
[MAXPATHLEN
];
1759 char devpath
[MAXPATHLEN
];
1760 char *devpathp
= "NULL";
1764 char *name
= (char *)edp
->name
;
1765 uint_t logsize
= edp
->access_count
+ edp
->fail_count
- 1;
1766 int inst
= edp
->instance
;
1767 uint_t atype
= edp
->access_type
;
1768 int rset
= edp
->rnumber
;
1769 offset_t offset
= edp
->offset
;
1770 offset_t len
= edp
->len
;
1772 msg(4, "test_driver: %s %d inst %d 0x%x rset %d %llx %llx\n",
1773 name
, logsize
, inst
, atype
, rset
, offset
, len
);
1776 if (getpath(devpath
, inst
, name
, MAXPATHLEN
) != -1) {
1782 fd
= open(BOFI_DEV
, O_RDWR
);
1784 perror("get_hdl_info - bad open of bofi driver");
1788 (void) snprintf(buf
, sizeof (buf
),
1789 "th_manage /devices%s offline", devpathp
);
1791 (void) snprintf(buf
, sizeof (buf
),
1792 "th_manage /devices%s online", devpathp
);
1794 (void) snprintf(buf
, sizeof (buf
),
1795 "th_manage /devices%s getstate >/dev/null", devpathp
);
1798 if (get_hinfo(fd
, name
, &hdls
, &cnt
,
1799 inst
, atype
, rset
, offset
, len
, 1) != 0) {
1800 msg(0, "driver_test: bad get_info for %d hdls\n", cnt
);
1802 } else if (logsize
== 0 || collecttime
== 0 || cnt
== 0) {
1804 msg(1, "No matching handles.\n");
1807 if ((cdefs
= GETSTRUCT(struct collector_def
, cnt
)) == 0) {
1808 msg(0, "driver_test: can't get memory for %d cdefs\n", cnt
);
1813 if (scriptargs
> 0) {
1814 (void) snprintf(buf
, sizeof (buf
),
1815 "DRIVER_PATH=/devices%s DRIVER_INSTANCE=%d"
1816 " DRIVER_UNCONFIGURE=0 DRIVER_CONFIGURE=1",
1817 devpathp
, drv_inst
);
1818 for (i
= 0; i
< scriptargs
; i
++) {
1819 (void) strcat(buf
, " ");
1820 (void) strcat(buf
, fixup_script
[i
]);
1822 (void) strcat(buf
, " &");
1824 (void) snprintf(buf
, sizeof (buf
),
1825 "while : ; do th_manage /devices%s online;"
1826 " th_manage /devices%s getstate >/dev/null;"
1827 " th_manage /devices%s offline;done &"
1828 " echo $! >/tmp/bofi.pid",
1829 devpathp
, devpathp
, devpathp
);
1832 (void) snprintf(buf
, sizeof (buf
), "sleep %d",
1833 edef_sleep
? edef_sleep
: DEFAULT_EDEF_SLEEP
);
1837 (void) fprintf(outfile
,
1838 "Logging accesses to instances ");
1839 for (i
= 0, inst
= -1, hdl
= hdls
; i
< cnt
;
1841 if (inst
!= hdl
->instance
) {
1842 inst
= hdl
->instance
;
1843 (void) fprintf(outfile
, "%d ", inst
);
1846 (void) fprintf(outfile
, " (%d logs of size 0x%x).\n\t"
1847 "(Use th_manage ... clear_errdefs to terminate"
1848 " logging)\n", cnt
, logsize
);
1850 sfp
= create_test_file(name
);
1852 * Install a logging errdef for each matching handle,
1853 * and then create a child to collect the log.
1854 * The child is responsible for activating the log.
1856 for (i
= 0, cdp
= cdefs
, hdl
= hdls
, nchildren
= 0;
1857 i
< cnt
; i
++, cdp
++, hdl
++) {
1858 if (add_edef(fd
, &cdp
->ed
, &cdp
->es
, hdl
, edp
) != 0) {
1862 cdp
->lp
= (void *)cdp
->ed
.log
.logbase
;
1863 msg(1, "test_driver: thr_create:"
1864 " lsize 0x%x 0x%x at 0x%x\n",
1865 cdp
->es
.log
.logsize
,
1866 cdp
->ed
.log
.logsize
,
1867 cdp
->ed
.access_type
);
1868 if ((pid
= fork()) == -1) {
1869 msg(0, "fork failed for handle"
1870 " %d: %s\n", i
, strerror(errno
));
1871 cdp
->pid
= 0; /* ignore */
1872 } else if (pid
== 0) {
1873 thr_collect(cdp
, devpathp
);
1881 if (nchildren
!= 0) {
1883 (void) fprintf(sfp
, "#!/bin/ksh -p\n\n");
1885 "\n# Test control script generated using:\n#");
1886 for (i
= 0; i
< pargc
; i
++)
1887 (void) fprintf(sfp
, " %s", pargv
[i
]);
1888 (void) fprintf(sfp
, "\n\n");
1889 (void) fprintf(sfp
, "\nrun_tests()\n{\n");
1890 for (i
= 0, cdp
= cdefs
; i
< cnt
; i
++, cdp
++)
1893 "\tif [ -x ./%s.%d ]\n\tthen\n",
1894 name
, (int)cdp
->pid
);
1896 "\t\techo \"Starting test"
1899 (void) fprintf(sfp
, "\t\t./%s.%d\n",
1900 name
, (int)cdp
->pid
);
1901 (void) fprintf(sfp
, "\t\techo \""
1902 "Test %d (id %d) complete\"\n",
1904 (void) fprintf(sfp
, "\tfi\n");
1906 (void) fprintf(sfp
, "}\n\nrun_tests\n");
1907 if (fchmod(fileno(sfp
), S_IRWXU
|S_IRGRP
|S_IROTH
))
1908 msg(0, "fchmod on control script failed: %s\n",
1910 if (fclose(sfp
) != 0)
1911 msg(0, "Error closing control script: %s\n",
1915 set_handler(SIGALRM
); /* handle it */
1917 * The user may want to terminate logging before the log fills
1918 * so use a timer to signal the logging children to handle this
1921 timechunk
= collecttime
/ MAXALRMCALL
;
1922 collecttime
= collecttime
- timechunk
* MAXALRMCALL
;
1924 msg(2, "logging for (0x%llx 0x%llx)\n", timechunk
, collecttime
);
1926 (void) alarm(collecttime
); /* odd bit of collect time */
1928 /* wait for the log to fill or deadline satisfied */
1930 pid
= wait(&statloc
);
1931 for (i
= 0, nchildren
= 0, cdp
= cdefs
;
1932 i
< cnt
; i
++, cdp
++)
1933 if (cdp
->pid
== pid
)
1935 for (i
= 0, nchildren
= 0, cdp
= cdefs
;
1936 i
< cnt
; i
++, cdp
++)
1944 if (timechunk
-- > 0) {
1946 * prepare for the next timeslice by
1947 * rearming the clock
1949 if (alarm(MAXALRMCALL
) == 0)
1953 * must have been a user abort
1964 (void) fprintf(outfile
, "Logging complete.\n");
1967 if (scriptargs
> 0) {
1968 (void) snprintf(buf
, sizeof (buf
),
1969 "DRIVER_PATH=/devices%s DRIVER_INSTANCE=%d"
1970 " DRIVER_UNCONFIGURE=1 DRIVER_CONFIGURE=0",
1971 devpathp
, drv_inst
);
1972 for (i
= 0; i
< scriptargs
; i
++) {
1973 (void) strcat(buf
, " ");
1974 (void) strcat(buf
, fixup_script
[i
]);
1978 (void) system("kill `cat /tmp/bofi.pid`");
1981 msg(2, "test_driver: terminating\n");
1985 getnameinst(char *orig_path
, int *instance
, char *name
, int namelen
)
1990 if ((node
= di_init(&orig_path
[8], DINFOSUBTREE
|DINFOMINOR
)) ==
1993 if ((binding_name
= di_driver_name(node
)) == NULL
)
1995 *instance
= di_instance(node
);
1996 (void) strncpy(name
, binding_name
, namelen
);
2001 static char syntax
[] =
2002 " [ -n name [ -i instance ] | -P path ]\n"
2003 " [ -a acc_types ] [ -r rnumber ]\n"
2004 " [ -l offset [ length ] ] [ -c count [ failcount ] ]\n"
2005 " [ -o operator [ operand ] ] [ -f acc_chk ]\n"
2006 " [ -w max_wait_period [ report_interval ] ]\n"
2008 " [ -n name [ -i instance ] | -P path ]\n"
2009 " -a LOG [ acc_types ] [ -r rnumber]\n"
2010 " [ -l offset [ length ] ] [ -c count [ failcount ] ]\n"
2011 " [ -s collect_time ] [ -p policy ] [ -x flags ]\n"
2012 " [ -C ] [-e fixup_script ]\n"
2017 main(int argc
, char *argv
[])
2019 extern char *optarg
;
2022 char c
; /* for parsing getopts */
2023 int nopts
= 0; /* for backward compatibility */
2026 /* use a maximal set of defaults for logging or injecting */
2027 struct bofi_errdef errdef
= {
2028 0, /* length of driver name */
2029 {0}, /* driver name */
2030 -1, /* monitor all instances */
2031 -1, /* monitor all register sets and DMA handles */
2032 (offset_t
)0, /* monitor from start of reg. set or DMA hd */
2033 myLLMAX
, /* monitor whole reg set or DMA hdl(no LLMAX) */
2034 0, /* qualify all */
2035 DFLTLOGSZ
, /* default no. of accesses before corrupting */
2036 0u, /* default no. of accesses to corrupt */
2037 0u, /* no check access corruption */
2038 BOFI_NOP
, /* no corruption operator by default */
2039 myULLMAX
, /* default operand */
2040 {0, 0, BOFI_LOG_TIMESTAMP
, /* timestamp by default */
2041 0, 0, 0, 0}, /* no logging by default */
2045 /* specify the default no of seconds for which to monitor */
2046 unsigned long long collecttime
= DFLTLOGTIME
;
2048 char *str
; /* temporary variable */
2049 long tmpl
; /* another one */
2053 char buf
[MAXPATHLEN
];
2055 Progname
= (char *)strrchr(*argv
, '/');
2056 Progname
= (Progname
== NULL
) ? *argv
: Progname
+ 1;
2061 lsize_is_default
= 1;
2065 while ((c
= getopt(argc
, argv
, "a:c:C:dD:e:f:h:i:l:n:o:p:P:r:s:tw:x"))
2070 msg(2, "option a: optarg %s optind %d argc %d\n",
2071 optarg
, optind
, argc
);
2072 if ((err
= str_to_bm(optarg
, atypes
,
2073 &errdef
.access_type
)) == 0)
2074 while (optind
< argc
&& *argv
[optind
] != '-') {
2075 if ((err
= str_to_bm(argv
[optind
++],
2076 atypes
, &errdef
.access_type
)))
2081 lsize_is_default
= 0;
2083 errdef
.access_count
= strtoul(optarg
, &str
, 0);
2086 else if (optind
< argc
&& (argv
[optind
][0] != '-' ||
2087 (strlen(argv
[optind
]) > 1 &&
2088 isdigit(argv
[optind
][1]))))
2090 strtoull(argv
[optind
++], 0, 0);
2093 user_comment
= optarg
;
2094 if (optind
< argc
&& argv
[optind
][0] != '-')
2098 dbglvl
= strtoul(optarg
, &str
, 0);
2103 fixup_script
= &argv
[optind
- 1];
2105 while (optind
< argc
) {
2111 tmpl
= strtol(optarg
, &str
, 0);
2114 errdef
.acc_chk
= tmpl
;
2115 else if (strcmp(optarg
, "PIO") == 0)
2117 else if (strcmp(optarg
, "DMA") == 0)
2119 else if (strcmp(optarg
, "U4FT_ACC_NO_PIO") == 0)
2121 else if (strcmp(optarg
, "U4FT_ACC_NO_DMA") == 0)
2127 if ((errdef
.instance
= strtol(optarg
, &str
, 0)) < 0)
2128 errdef
.instance
= -1;
2129 else if (str
== optarg
)
2133 errdef
.offset
= strtoull(optarg
, &str
, 0);
2136 else if (optind
< argc
&&
2137 (argv
[optind
][0] != '-' ||
2138 (strlen(argv
[optind
]) > 1 &&
2139 isdigit(argv
[optind
][1])))) {
2140 /* -1 indicates the rest of register set */
2141 errdef
.len
= strtoull(argv
[optind
++], 0, 0);
2145 (void) strncpy(errdef
.name
, optarg
, MAXNAMELEN
);
2146 if ((errdef
.namesize
= strlen(errdef
.name
)) == 0)
2150 for (i
= 0; optypes
[i
].str
!= 0; i
++)
2151 if (strcmp(optarg
, optypes
[i
].str
) == 0) {
2152 errdef
.optype
= optypes
[i
].code
;
2155 if (optypes
[i
].str
== 0)
2157 else if (optind
< argc
&&
2158 (argv
[optind
][0] != '-' ||
2159 (strlen(argv
[optind
]) > 1 &&
2160 isdigit(argv
[optind
][1]))))
2162 strtoull(argv
[optind
++], 0, 0);
2166 if ((err
= str_to_bm(optarg
, ptypes
, &tmpui
)) == 0) {
2167 while (optind
< argc
&& *argv
[optind
] != '-')
2168 if ((err
= str_to_bm(argv
[optind
++],
2171 policy
= (uint16_t)tmpui
;
2173 if (err
== 0 && (policy
& BYTEPOLICY
))
2174 errdef
.log
.flags
|= BOFI_LOG_REPIO
;
2177 if (getnameinst(optarg
, &errdef
.instance
, buf
,
2181 (void) strncpy(errdef
.name
, buf
, MAXNAMELEN
);
2184 if ((errdef
.rnumber
= strtol(optarg
, &str
, 0)) < 0)
2185 errdef
.rnumber
= -1;
2186 if (str
== optarg
) err
= EINVAL
;
2189 collecttime
= strtoull(optarg
, &str
, 0);
2191 err
= EINVAL
; /* zero is valid */
2195 max_edef_wait
= strtoul(optarg
, &str
, 0);
2199 else if (optind
< argc
&&
2200 (argv
[optind
][0] != '-' ||
2201 (strlen(argv
[optind
]) > 1 &&
2202 isdigit(argv
[optind
][1]))))
2203 edef_sleep
= strtoull(argv
[optind
++], 0, 0);
2207 if ((optind
< argc
&& *argv
[optind
] == '-') ||
2209 errdef
.log
.flags
|= BOFI_LOG_WRAP
;
2211 if (strchr(argv
[optind
], 'w') != 0)
2212 errdef
.log
.flags
|= BOFI_LOG_WRAP
;
2213 if (strchr(argv
[optind
], 'r') != 0)
2214 errdef
.log
.flags
|= BOFI_LOG_REPIO
;
2215 if (strchr(argv
[optind
], 't') != 0)
2216 errdef
.log
.flags
|= BOFI_LOG_TIMESTAMP
;
2217 if (strstr(argv
[optind
], "~t") != 0)
2218 errdef
.log
.flags
&= ~BOFI_LOG_TIMESTAMP
;
2223 (void) fprintf(errfile
, "usage: %s %s\n",
2227 case '?': /* also picks up missing parameters */
2229 (void) fprintf(errfile
, "usage: %s %s\n",
2235 (void) fprintf(errfile
, "usage: %s %s\n",
2240 break; /* the -e option must be the final option */
2244 if (errdef
.name
[0] == 0) {
2245 msg(0, "%s - invalid name parameter\n", Progname
);
2248 errdef
.namesize
= strlen(errdef
.name
);
2251 policy
|= UNBIASEDPOLICY
;
2252 policy
|= OPERATORSPOLICY
;
2255 if (errdef
.optype
== BOFI_NOP
)
2256 errdef
.optype
= BOFI_XOR
;
2257 if (errdef
.access_type
== BOFI_LOG
) { /* qualify all accesses */
2258 errdef
.access_type
=
2259 (BOFI_LOG
|BOFI_DMA_RW
|BOFI_PIO_RW
|BOFI_INTR
);
2260 atype_is_default
= 1;
2261 } else if (errdef
.access_type
== 0) { /* qualify all accesses */
2262 errdef
.access_type
=
2263 (BOFI_DMA_RW
|BOFI_PIO_RW
|BOFI_INTR
);
2264 atype_is_default
= 1;
2266 atype_is_default
= 0;
2269 if ((errdef
.access_type
& BOFI_LOG
) == 0) {
2270 int fd
, i
, instance
;
2272 struct handle_info
*hdls
, *hp
;
2274 if ((fd
= open(BOFI_DEV
, O_RDWR
)) == -1) {
2275 msg(0, "%s: error opening bofi driver: %s\n",
2276 Progname
, strerror(errno
));
2279 if ((err
= get_hinfo(fd
, errdef
.name
, &hdls
, &cnt
,
2280 errdef
.instance
, errdef
.access_type
, errdef
.rnumber
,
2281 errdef
.offset
, errdef
.len
, 0)) != 0) {
2282 msg(0, "%s: Bad lookup on bofi driver.\n", Progname
);
2285 } else if (cnt
== 0) {
2287 "%s: No handles match request access criteria.\n",
2292 if (errdef
.instance
== -1)
2295 instance
= hdls
->instance
;
2296 for (i
= 0, hp
= hdls
; i
< cnt
; i
++, hp
++) {
2297 if (instance
!= hp
->instance
) {
2303 if (instance
== -1) {
2304 msg(0, "Multiple instances match access criteria"
2305 " (only allowed when logging):\n");
2306 msg(0, "\tinst\taccess\trnumber\toffset\tlength\n");
2307 for (i
= 0, hp
= hdls
; i
< cnt
; i
++, hp
++)
2308 msg(0, "\t%d\t0x%x\t%d\t0x%llx\t0x%llx\n",
2309 hp
->instance
, hp
->access_type
,
2310 hp
->rnumber
, hp
->offset
, hp
->len
);
2312 struct bofi_errstate es
;
2313 int timeleft
= max_edef_wait
;
2315 if (ioctl(fd
, BOFI_ADD_DEF
, &errdef
) == -1) {
2316 perror("th_define - adding errdef failed");
2318 es
.errdef_handle
= errdef
.errdef_handle
;
2319 msg(4, "waiting for edef:"
2320 " %d %s %d %d 0x%llx 0x%llx 0x%x 0x%x"
2321 " 0x%x 0x%x 0x%x 0x%llx\n",
2322 errdef
.namesize
, errdef
.name
,
2323 errdef
.instance
, errdef
.rnumber
,
2324 errdef
.offset
, errdef
.len
,
2325 errdef
.access_type
, errdef
.access_count
,
2326 errdef
.fail_count
, errdef
.acc_chk
,
2327 errdef
.optype
, errdef
.operand
);
2329 set_handler(SIGALRM
); /* handle it */
2333 (void) alarm(edef_sleep
);
2334 if (ioctl(fd
, BOFI_CHK_STATE_W
,
2336 if (errno
!= EINTR
) {
2340 } else if (!do_status
) {
2345 (void) fprintf(outfile
,
2346 "%llu:%llu:%u:%u:%u:"
2348 es
.fail_time
, es
.msg_time
,
2351 es
.acc_chk
, es
.errmsg_count
,
2352 (uint_t
)es
.severity
,
2355 if (es
.acc_chk
== 0 &&
2356 es
.fail_count
== 0 && !do_status
)
2357 print_err_reports(outfile
,
2361 if ((timeleft
-= edef_sleep
) <=
2370 } else if (!do_status
)
2371 print_err_reports(outfile
,
2373 } while (es
.acc_chk
!= 0 || es
.fail_count
!= 0);
2375 msg(2, "done: acc_chk 0x%x fcnt %d\n",
2376 es
.acc_chk
, es
.fail_count
);
2384 test_driver(&errdef
, collecttime
);