xref: /illumos-gate/usr/src/cmd/th_tools/th_define.c (revision ef150c2b)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22e5ba14ffSstephh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/time_impl.h>
277c478bd9Sstevel@tonic-gate #include <sys/wait.h>
287c478bd9Sstevel@tonic-gate #include <stdio.h>
29004388ebScasper #include <stdio_ext.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <stdarg.h>
327c478bd9Sstevel@tonic-gate #include <ctype.h>
337c478bd9Sstevel@tonic-gate #include <time.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <sys/resource.h>
377c478bd9Sstevel@tonic-gate #include <limits.h>
387c478bd9Sstevel@tonic-gate #include <string.h>
397c478bd9Sstevel@tonic-gate #include <unistd.h>
407c478bd9Sstevel@tonic-gate #include <errno.h>
417c478bd9Sstevel@tonic-gate #include <signal.h>
427c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
437c478bd9Sstevel@tonic-gate #define	_KERNEL
447c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
457c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
467c478bd9Sstevel@tonic-gate #include <sys/bofi.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #define	BOFI_DEV	"/devices/pseudo/bofi@0:bofi,ctl"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #define	GETSTRUCT(s, num)	\
517c478bd9Sstevel@tonic-gate 	((s *) memalign(sizeof (void*), (num) * sizeof (s)))
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #define	MAXEDEFS	(0x64)		/* controls max no of concurent edefs */
547c478bd9Sstevel@tonic-gate #define	DFLTLOGSZ	(0x4000)	/* default size of an access log */
557c478bd9Sstevel@tonic-gate #define	DFLT_NONPIO_LOGSZ	(0x400)	/* default size of a log */
567c478bd9Sstevel@tonic-gate #define	MAXALRMCALL	(0x1000ull)	/* alarm does not permit big values */
577c478bd9Sstevel@tonic-gate #define	MIN_REPORT_TIME	(5)		/* min time to wait for edef status */
587c478bd9Sstevel@tonic-gate #define	DISTRIB_CUTOFF	(3)		/* useful when reducing a log */
597c478bd9Sstevel@tonic-gate #define	myLLMAX		(0x7fffffffffffffffll)
607c478bd9Sstevel@tonic-gate #define	myULLMAX	(0xffffffffffffffffull)
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * default interval to wait between kicking off workload and injecting fault
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate #define	DEFAULT_EDEF_SLEEP 3
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * when generating dma corruptions, it is best to corrupt each double word
687c478bd9Sstevel@tonic-gate  * individually for control areas - however for data areas this can be
697c478bd9Sstevel@tonic-gate  * excessive and would generate so many cases we would never finish the run.
707c478bd9Sstevel@tonic-gate  * So set a cut-off value where we switch from corrupting each double word
717c478bd9Sstevel@tonic-gate  * separately to corrupting th elot in one go. 0x100 bytes seems a good value
727c478bd9Sstevel@tonic-gate  * on the drivers we have seen so far.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate #define	DMA_INDIVIDUAL_CORRUPT_CUTOFF 0x100
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate struct collector_def {
777c478bd9Sstevel@tonic-gate 	struct bofi_errdef ed;		/* definition of the log criteria */
787c478bd9Sstevel@tonic-gate 	struct bofi_errstate es;	/* the current status of the log */
797c478bd9Sstevel@tonic-gate 	struct acc_log_elem *lp;	/* array of logged accesses */
807c478bd9Sstevel@tonic-gate 	pid_t pid;
817c478bd9Sstevel@tonic-gate };
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate static uint16_t policy;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #define	BYTEPOLICY	(0xf)
867c478bd9Sstevel@tonic-gate #define	MULTIPOLICY	(0x10)
877c478bd9Sstevel@tonic-gate #define	SIZEPOLICY	(BYTEPOLICY|MULTIPOLICY)
887c478bd9Sstevel@tonic-gate #define	UNBIASEDPOLICY	0x20
897c478bd9Sstevel@tonic-gate #define	UNCOMMONPOLICY	0x40
907c478bd9Sstevel@tonic-gate #define	COMMONPOLICY	0x80
917c478bd9Sstevel@tonic-gate #define	MEDIANPOLICY	0x100
927c478bd9Sstevel@tonic-gate #define	MAXIMALPOLICY	0x200
937c478bd9Sstevel@tonic-gate #define	OPERATORSPOLICY	0x400
947c478bd9Sstevel@tonic-gate #define	VALIDPOLICY	(0x7ff)
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate typedef
977c478bd9Sstevel@tonic-gate struct coding {
987c478bd9Sstevel@tonic-gate 	char	*str;
997c478bd9Sstevel@tonic-gate 	uint_t	code;
1007c478bd9Sstevel@tonic-gate } coding_t;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static coding_t ptypes[] = {
1037c478bd9Sstevel@tonic-gate 	{"onebyte", 0x1}, {"twobyte", 0x2},
1047c478bd9Sstevel@tonic-gate 	{"fourbyte", 0x4}, {"eightbyte", 0x8},
1057c478bd9Sstevel@tonic-gate 	{"multibyte", 0x10}, {"unbiased", 0x20}, {"uncommon", 0x40},
1067c478bd9Sstevel@tonic-gate 	{"common", 0x80}, {"median", 0x100}, {"maximal", 0x200},
1077c478bd9Sstevel@tonic-gate 	{"operators", 0x400},  {0, 0}
1087c478bd9Sstevel@tonic-gate };
1097c478bd9Sstevel@tonic-gate static coding_t atypes[] = {
1107c478bd9Sstevel@tonic-gate 	{"pio_r", BOFI_PIO_R}, {"pio_w", BOFI_PIO_W},
1117c478bd9Sstevel@tonic-gate 	{"dma_r", BOFI_DMA_R}, {"dma_w", BOFI_DMA_W},
1127c478bd9Sstevel@tonic-gate 	{"pio", BOFI_PIO_RW}, {"dma", BOFI_DMA_RW},
1137c478bd9Sstevel@tonic-gate 	{"log", BOFI_LOG}, {"intr", BOFI_INTR},
1147c478bd9Sstevel@tonic-gate 	{"PIO_R", BOFI_PIO_R}, {"PIO_W", BOFI_PIO_W},
1157c478bd9Sstevel@tonic-gate 	{"DMA_R", BOFI_DMA_R}, {"DMA_W", BOFI_DMA_W},
1167c478bd9Sstevel@tonic-gate 	{"PIO", BOFI_PIO_RW}, {"DMA", BOFI_DMA_RW},
1177c478bd9Sstevel@tonic-gate 	{"LOG", BOFI_LOG}, {"INTR", BOFI_INTR}, {0, 0}
1187c478bd9Sstevel@tonic-gate };
1197c478bd9Sstevel@tonic-gate static coding_t optypes[] = {
1207c478bd9Sstevel@tonic-gate 	{"EQ", BOFI_EQUAL}, {"AND", BOFI_AND}, {"OR", BOFI_OR},
1217c478bd9Sstevel@tonic-gate 	{"XOR", BOFI_XOR}, {"NO", BOFI_NO_TRANSFER},
1227c478bd9Sstevel@tonic-gate 	{"DELAY", BOFI_DELAY_INTR}, {"LOSE", BOFI_LOSE_INTR},
1237c478bd9Sstevel@tonic-gate 	{"EXTRA", BOFI_EXTRA_INTR}, {0, 0}
1247c478bd9Sstevel@tonic-gate };
1257c478bd9Sstevel@tonic-gate static coding_t doptypes[] = {
1267c478bd9Sstevel@tonic-gate 	{"EQ", BOFI_EQUAL}, {"AND", BOFI_AND}, {"OR", BOFI_OR},
1277c478bd9Sstevel@tonic-gate 	{"XOR", BOFI_XOR}, {0, 0}
1287c478bd9Sstevel@tonic-gate };
1297c478bd9Sstevel@tonic-gate static coding_t ioptypes[] = {
1307c478bd9Sstevel@tonic-gate 	{"DELAY", BOFI_DELAY_INTR}, {"LOSE", BOFI_LOSE_INTR},
1317c478bd9Sstevel@tonic-gate 	{"EXTRA", BOFI_EXTRA_INTR}, {0, 0}
1327c478bd9Sstevel@tonic-gate };
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate static const unsigned long long	DFLTLOGTIME	= -1ull; /* log forever */
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate  * This global controls the generation of errdefs for PIO_W. The default should
1387c478bd9Sstevel@tonic-gate  * be to only perform an access check errdef but not to corrupt writes - this
1397c478bd9Sstevel@tonic-gate  * may trash non-FT platforms.
1407c478bd9Sstevel@tonic-gate  */
1417c478bd9Sstevel@tonic-gate static uint_t atype_is_default;	/* do not corrupt PIO_W by default */
1427c478bd9Sstevel@tonic-gate static uint_t lsize_is_default;	/* set when the user has not given a size */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate static uint64_t random_operand = 0xdeadbeafdeadbeafull;
1457c478bd9Sstevel@tonic-gate #define	NPIO_DEFAULTS	(3)	/* number of default corruption values */
1467c478bd9Sstevel@tonic-gate static longlong_t pio_default_values[NPIO_DEFAULTS] = {
1477c478bd9Sstevel@tonic-gate 	0x0ull,			/* corresponds to a line going high/low */
1487c478bd9Sstevel@tonic-gate 	0x32f1f03232f1f032ull,	/* the value returned when the fake ta is set */
1497c478bd9Sstevel@tonic-gate 	(longlong_t)(~0)	/* corresponds to a line going high/low */
1507c478bd9Sstevel@tonic-gate };
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate static uint_t dbglvl		= 0;	/* debug this program */
1537c478bd9Sstevel@tonic-gate static int alarmed		= 0;
1547c478bd9Sstevel@tonic-gate static int killed		= 0;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate  * name of a script to call before offlining a driver being tested
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static char **fixup_script = 0;
1607c478bd9Sstevel@tonic-gate static int	scriptargs = 0;
1617c478bd9Sstevel@tonic-gate static char **pargv;
1627c478bd9Sstevel@tonic-gate static int	pargc;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate static int	max_edef_wait = 0;
1657c478bd9Sstevel@tonic-gate static int	edef_sleep = 0;
1667c478bd9Sstevel@tonic-gate static int	do_status = 0;	/* report edef status in parsable format */
1677c478bd9Sstevel@tonic-gate static char *user_comment = 0;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate static char *Progname;
1707c478bd9Sstevel@tonic-gate static FILE *errfile;
1717c478bd9Sstevel@tonic-gate static FILE *outfile;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate  * The th_define utility provides an interface to the bus_ops fault injection
1757c478bd9Sstevel@tonic-gate  * bofi device driver for defining error injection specifications (referred to
1767c478bd9Sstevel@tonic-gate  * as errdefs). An errdef corresponds to a specification of how to corrupt a
1777c478bd9Sstevel@tonic-gate  * device driver's accesses to its hardware. The command line arguments
1787c478bd9Sstevel@tonic-gate  * determine the precise nature of the fault to be injected. If the supplied
1797c478bd9Sstevel@tonic-gate  * arguments define a consistent errdef, the th_define process will store the
1807c478bd9Sstevel@tonic-gate  * errdef with the bofi driver and suspend itself until the criteria given by
1817c478bd9Sstevel@tonic-gate  * the errdef become satisfied (in practice, this will occur when the access
1827c478bd9Sstevel@tonic-gate  * counts go to zero).
1837c478bd9Sstevel@tonic-gate  *
184bbf21555SRichard Lowe  * When the resulting errdef is activated using the th_manage(8) user command
1857c478bd9Sstevel@tonic-gate  * utility, the bofi driver will act upon the errdef by matching the number of
1867c478bd9Sstevel@tonic-gate  * hardware accesses - specified in count, that are of the type specified in
1877c478bd9Sstevel@tonic-gate  * acc_types, made by instance number instance - of the driver whose name is
1887c478bd9Sstevel@tonic-gate  * name, (or by the driver instance specified by * path ) to the register set
1897c478bd9Sstevel@tonic-gate  * (or DMA handle) specified by rnumber, that lie within the range offset to
1907c478bd9Sstevel@tonic-gate  * offset + length from the beginning of the register set or DMA handle. It then
1917c478bd9Sstevel@tonic-gate  * applies operator and operand to the next failcount matching accesses.
1927c478bd9Sstevel@tonic-gate  *
1937c478bd9Sstevel@tonic-gate  * If acc_types includes LOG, th_define runs in automatic test script generation
1947c478bd9Sstevel@tonic-gate  * mode, and a set of test scripts (written in the Korn shell) is created and
1957c478bd9Sstevel@tonic-gate  * placed in a sub-directory of the current directory with the name
1967c478bd9Sstevel@tonic-gate  * driver.test.<id>. A separate, executable script is generated for each access
1977c478bd9Sstevel@tonic-gate  * handle that matches the logging criteria. The log of accesses is placed at
1987c478bd9Sstevel@tonic-gate  * the top of each script as a record of the session. If the current directory
1997c478bd9Sstevel@tonic-gate  * is not writable, file output is written to standard output. The base name of
2007c478bd9Sstevel@tonic-gate  * each test file is the driver name, and the extension is a number that
2017c478bd9Sstevel@tonic-gate  * discriminates between different access handles. A control script (with the
2027c478bd9Sstevel@tonic-gate  * same name as the created test directory) is generated that will run all the
2037c478bd9Sstevel@tonic-gate  * test scripts sequentially.
2047c478bd9Sstevel@tonic-gate  *
2057c478bd9Sstevel@tonic-gate  * Executing the scripts will install, and then activate, the resulting error
2067c478bd9Sstevel@tonic-gate  * definitions. Error definitions are activated sequentially and the driver
2077c478bd9Sstevel@tonic-gate  * instance under test is taken offline and brought back online before each test
2087c478bd9Sstevel@tonic-gate  * (refer to the -e option for more information). By default, logging will apply
2097c478bd9Sstevel@tonic-gate  * to all PIO accesses, interrupts and DMA accesses to and from areas mapped
2107c478bd9Sstevel@tonic-gate  * for both reading and writing, but it can be constrained by specifying
2117c478bd9Sstevel@tonic-gate  * additional acc_types, rnumber, offset and length. Logging will continue for
2127c478bd9Sstevel@tonic-gate  * count matching accesses, with an optional time limit of collect_time seconds.
2137c478bd9Sstevel@tonic-gate  *
2147c478bd9Sstevel@tonic-gate  * Either the -n or -P option must be provided. The other options are optional.
2157c478bd9Sstevel@tonic-gate  * If an option (other than the -a option) is specified multiple times, only
2167c478bd9Sstevel@tonic-gate  * the final value for the option is used. If an option is not specified, its
2177c478bd9Sstevel@tonic-gate  * associated value is set to an appropriate default, which will provide
2187c478bd9Sstevel@tonic-gate  * maximal error coverage as described below.
2197c478bd9Sstevel@tonic-gate  */
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
2227c478bd9Sstevel@tonic-gate static void
msg(uint_t lvl,char * msg,...)2237c478bd9Sstevel@tonic-gate msg(uint_t lvl, char *msg, ...)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate #define	BUFSZ	128
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if (lvl <= dbglvl) {
2287c478bd9Sstevel@tonic-gate 		int count;
2297c478bd9Sstevel@tonic-gate 		va_list args;
2307c478bd9Sstevel@tonic-gate 		char buf[BUFSZ];
2317c478bd9Sstevel@tonic-gate 		int	pos = 0;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 		va_start(args, msg);
2347c478bd9Sstevel@tonic-gate 		count = vsnprintf(buf, BUFSZ, msg, args);
2357c478bd9Sstevel@tonic-gate 		va_end(args);
2367c478bd9Sstevel@tonic-gate 		if (count > 0) {
2377c478bd9Sstevel@tonic-gate 			count += pos;
2387c478bd9Sstevel@tonic-gate 			if (count >= sizeof (buf))
2397c478bd9Sstevel@tonic-gate 				count = BUFSZ - 1;
2407c478bd9Sstevel@tonic-gate 			buf[count] = '\0';
2417c478bd9Sstevel@tonic-gate 			(void) fprintf(errfile, "%s", buf);
2427c478bd9Sstevel@tonic-gate 		}
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate static void
kill_sighandler(int sig)2477c478bd9Sstevel@tonic-gate kill_sighandler(int sig)
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate 	switch (sig) {
2507c478bd9Sstevel@tonic-gate 		case SIGALRM:
2517c478bd9Sstevel@tonic-gate 			alarmed = 1;
2527c478bd9Sstevel@tonic-gate 			break;
2537c478bd9Sstevel@tonic-gate 		default:
2547c478bd9Sstevel@tonic-gate 			killed = 1;
2557c478bd9Sstevel@tonic-gate 			break;
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate static void
set_handler(int sig)2607c478bd9Sstevel@tonic-gate set_handler(int sig)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate 	struct sigaction sa;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	(void) sigfillset(&(sa.sa_mask));
2657c478bd9Sstevel@tonic-gate 	sa.sa_flags = 0;
2667c478bd9Sstevel@tonic-gate 	sa.sa_handler = kill_sighandler;
2677c478bd9Sstevel@tonic-gate 	if (sigaction(sig, &sa, NULL) != 0)
2687c478bd9Sstevel@tonic-gate 		/* install handler */
2697c478bd9Sstevel@tonic-gate 		msg(0, "bad sigaction: %s\n", strerror(errno));
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate  * Compare two driver access handles
2747c478bd9Sstevel@tonic-gate  */
2757c478bd9Sstevel@tonic-gate static int
hdl_cmp(const void * p1,const void * p2)2767c478bd9Sstevel@tonic-gate hdl_cmp(const void *p1, const void *p2)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate 	struct handle_info *e1 = (struct handle_info *)p1;
2797c478bd9Sstevel@tonic-gate 	struct handle_info *e2 = (struct handle_info *)p2;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	if (e1->instance < e2->instance)
2827c478bd9Sstevel@tonic-gate 		return (-1);
2837c478bd9Sstevel@tonic-gate 	else if (e1->instance > e2->instance)
2847c478bd9Sstevel@tonic-gate 		return (1);
2857c478bd9Sstevel@tonic-gate 	else if (e1->access_type < e2->access_type)
2867c478bd9Sstevel@tonic-gate 		return (-1);
2877c478bd9Sstevel@tonic-gate 	else if (e1->access_type > e2->access_type)
2887c478bd9Sstevel@tonic-gate 		return (1);
2897c478bd9Sstevel@tonic-gate 	else if (e1->rnumber < e2->rnumber)
2907c478bd9Sstevel@tonic-gate 		return (-1);
2917c478bd9Sstevel@tonic-gate 	else if (e1->rnumber > e2->rnumber)
2927c478bd9Sstevel@tonic-gate 		return (1);
2937c478bd9Sstevel@tonic-gate 	else if (e1->len < e2->len)
2947c478bd9Sstevel@tonic-gate 		return (-1);
2957c478bd9Sstevel@tonic-gate 	else if (e1->len > e2->len)
2967c478bd9Sstevel@tonic-gate 		return (1);
2977c478bd9Sstevel@tonic-gate 	else if (e1->offset < e2->offset)
2987c478bd9Sstevel@tonic-gate 		return (-1);
2997c478bd9Sstevel@tonic-gate 	else if (e1->offset > e2->offset)
3007c478bd9Sstevel@tonic-gate 		return (1);
3017c478bd9Sstevel@tonic-gate 	else if (e1->addr_cookie < e2->addr_cookie)
3027c478bd9Sstevel@tonic-gate 		return (-1);
3037c478bd9Sstevel@tonic-gate 	else if (e1->addr_cookie > e2->addr_cookie)
3047c478bd9Sstevel@tonic-gate 		return (1);
3057c478bd9Sstevel@tonic-gate 	else
3067c478bd9Sstevel@tonic-gate 		return (0);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate  * Compare two hardware accesses.
3117c478bd9Sstevel@tonic-gate  */
3127c478bd9Sstevel@tonic-gate static int
elem_cmp(const void * p1,const void * p2)3137c478bd9Sstevel@tonic-gate elem_cmp(const void *p1, const void *p2)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	struct acc_log_elem *e1 = (struct acc_log_elem *)p1;
3167c478bd9Sstevel@tonic-gate 	struct acc_log_elem *e2 = (struct acc_log_elem *)p2;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	if (e1->access_type < e2->access_type)
3197c478bd9Sstevel@tonic-gate 		return (-1);
3207c478bd9Sstevel@tonic-gate 	else if (e1->access_type > e2->access_type)
3217c478bd9Sstevel@tonic-gate 		return (1);
3227c478bd9Sstevel@tonic-gate 	else if (e1->offset < e2->offset)
3237c478bd9Sstevel@tonic-gate 		return (-1);
3247c478bd9Sstevel@tonic-gate 	else if (e1->offset > e2->offset)
3257c478bd9Sstevel@tonic-gate 		return (1);
3267c478bd9Sstevel@tonic-gate 	else if (e1->size < e2->size)
3277c478bd9Sstevel@tonic-gate 		return (-1);
3287c478bd9Sstevel@tonic-gate 	else if (e1->size > e2->size)
3297c478bd9Sstevel@tonic-gate 		return (1);
3307c478bd9Sstevel@tonic-gate 	else
3317c478bd9Sstevel@tonic-gate 		return (0);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate /*
3357c478bd9Sstevel@tonic-gate  * Another way of comparing two hardware accesses.
3367c478bd9Sstevel@tonic-gate  */
3377c478bd9Sstevel@tonic-gate static int
log_cmp(const void * p1,const void * p2)3387c478bd9Sstevel@tonic-gate log_cmp(const void *p1, const void *p2)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate 	struct acc_log_elem *e1 = (struct acc_log_elem *)p1;
3417c478bd9Sstevel@tonic-gate 	struct acc_log_elem *e2 = (struct acc_log_elem *)p2;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	int rval = elem_cmp(p1, p2);
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	if (rval == 0)
3467c478bd9Sstevel@tonic-gate 		if (e1->repcount < e2->repcount)
3477c478bd9Sstevel@tonic-gate 			return (-1);
3487c478bd9Sstevel@tonic-gate 		else if (e1->repcount > e2->repcount)
3497c478bd9Sstevel@tonic-gate 			return (1);
3507c478bd9Sstevel@tonic-gate 		else
3517c478bd9Sstevel@tonic-gate 			return (0);
3527c478bd9Sstevel@tonic-gate 	else
3537c478bd9Sstevel@tonic-gate 		return (rval);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate  * And a final way of sorting a log (by access type followed by repcount).
3587c478bd9Sstevel@tonic-gate  */
3597c478bd9Sstevel@tonic-gate static int
log_cmp2(const void * p1,const void * p2)3607c478bd9Sstevel@tonic-gate log_cmp2(const void *p1, const void *p2)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate 	struct acc_log_elem *e1 = (struct acc_log_elem *)p1;
3637c478bd9Sstevel@tonic-gate 	struct acc_log_elem *e2 = (struct acc_log_elem *)p2;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (e1->access_type < e2->access_type)
3667c478bd9Sstevel@tonic-gate 		return (-1);
3677c478bd9Sstevel@tonic-gate 	else if (e1->access_type > e2->access_type)
3687c478bd9Sstevel@tonic-gate 		return (1);
3697c478bd9Sstevel@tonic-gate 	else if (e1->repcount < e2->repcount)
3707c478bd9Sstevel@tonic-gate 		return (-1);
3717c478bd9Sstevel@tonic-gate 	else if (e1->repcount > e2->repcount)
3727c478bd9Sstevel@tonic-gate 		return (1);
3737c478bd9Sstevel@tonic-gate 	else
3747c478bd9Sstevel@tonic-gate 		return (0);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate static void
dump_log(uint_t lvl,FILE * fp,struct acc_log_elem * items,size_t nitems,uint_t logflags)3787c478bd9Sstevel@tonic-gate dump_log(uint_t lvl, FILE *fp, struct acc_log_elem *items,
3790afbf539SToomas Soome     size_t nitems, uint_t logflags)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	if (lvl <= dbglvl) {
3827c478bd9Sstevel@tonic-gate 		int i;
3837c478bd9Sstevel@tonic-gate 		uint_t offset, allthesame = 1;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		if (logflags & BOFI_LOG_TIMESTAMP &&
386e5ba14ffSstephh 		    getenv("DUMP_FULL_LOG") != 0)
3877c478bd9Sstevel@tonic-gate 			allthesame = 0;
3887c478bd9Sstevel@tonic-gate 		else
3897c478bd9Sstevel@tonic-gate 			for (i = 1; i < nitems; i++)
3907c478bd9Sstevel@tonic-gate 				if (elem_cmp(items+i, items) != 0)
3917c478bd9Sstevel@tonic-gate 					allthesame = 0;
3927c478bd9Sstevel@tonic-gate 		if (fp != 0)
3937c478bd9Sstevel@tonic-gate 			(void) fprintf(fp,
3947c478bd9Sstevel@tonic-gate 			    "# Logged Accesses:\n# %-4s\t%-12s\t%-4s\t%-18s"
3957c478bd9Sstevel@tonic-gate 			    " (%-1s)\t%-10s\n\n", "type",
3967c478bd9Sstevel@tonic-gate 			    (items->access_type & BOFI_DMA_RW) ?
3977c478bd9Sstevel@tonic-gate 			    "address" : "offset",
3987c478bd9Sstevel@tonic-gate 			    "size", "value", "repcnt", "time");
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 		for (i = 0; i < nitems; i++, items++) {
4017c478bd9Sstevel@tonic-gate 			offset = items->offset;
4027c478bd9Sstevel@tonic-gate 			if (fp != 0) {
4037c478bd9Sstevel@tonic-gate 				(void) fprintf(fp,
4047c478bd9Sstevel@tonic-gate 				    "# 0x%-2x\t0x%-10x\t%-4d\t0x%-16llx"
4057c478bd9Sstevel@tonic-gate 				    " (0x%-1x)\t%-8llu\n",
4067c478bd9Sstevel@tonic-gate 				    items->access_type, offset, items->size,
4077c478bd9Sstevel@tonic-gate 				    items->value, items->repcount,
4087c478bd9Sstevel@tonic-gate 				    (logflags & BOFI_LOG_TIMESTAMP) ?
4097c478bd9Sstevel@tonic-gate 				    items->access_time : 0ull);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 				if (allthesame) {
4127c478bd9Sstevel@tonic-gate 					(void) fprintf(fp,
4137c478bd9Sstevel@tonic-gate 					    "# Access duplicated %d times\n",
4147c478bd9Sstevel@tonic-gate 					    nitems);
4157c478bd9Sstevel@tonic-gate 					break;
4167c478bd9Sstevel@tonic-gate 				}
4177c478bd9Sstevel@tonic-gate 			} else
4187c478bd9Sstevel@tonic-gate 				msg(lvl, "# 0x%x 0x%x %d 0x%llx(0x%x) %llu\n",
4197c478bd9Sstevel@tonic-gate 				    items->access_type, offset, items->size,
4207c478bd9Sstevel@tonic-gate 				    items->value, items->repcount,
4217c478bd9Sstevel@tonic-gate 				    (logflags & BOFI_LOG_TIMESTAMP) ?
4227c478bd9Sstevel@tonic-gate 				    items->access_time : 0ull);
4237c478bd9Sstevel@tonic-gate 		}
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate static int
str_to_bm(char * optarg,coding_t * c,uint_t * bm)4287c478bd9Sstevel@tonic-gate str_to_bm(char *optarg, coding_t *c, uint_t *bm)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	char *str;
4317c478bd9Sstevel@tonic-gate 	char *s = "\t\n ";
4327c478bd9Sstevel@tonic-gate 	int err = EINVAL;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	msg(2, "str_to_bm: optarg %s\n", optarg);
4357c478bd9Sstevel@tonic-gate 	if (optarg != NULL && (str = strtok(optarg, s))) {
4367c478bd9Sstevel@tonic-gate 		msg(2, "str_to_bm: str %s\n", str);
4377c478bd9Sstevel@tonic-gate 		do {
4387c478bd9Sstevel@tonic-gate 			for (; c->str != 0; c++)
4397c478bd9Sstevel@tonic-gate 				if (strcmp(str, c->str) == 0) {
4407c478bd9Sstevel@tonic-gate 					*bm |= c->code;
4417c478bd9Sstevel@tonic-gate 					msg(2, "str_to_bm: %s matches\n",
4427c478bd9Sstevel@tonic-gate 					    c->str);
4437c478bd9Sstevel@tonic-gate 					err = 0;
4447c478bd9Sstevel@tonic-gate 					break;
4457c478bd9Sstevel@tonic-gate 				}
4467c478bd9Sstevel@tonic-gate 		} while ((str = strtok(NULL, s)));
4477c478bd9Sstevel@tonic-gate 	} else
4487c478bd9Sstevel@tonic-gate 		return (EINVAL);
4497c478bd9Sstevel@tonic-gate 	msg(2, "str_to_bm: done 0x%x\n", *bm);
4507c478bd9Sstevel@tonic-gate 	return (err);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate  * Generic routine for commands that apply to a particular instance of
4567c478bd9Sstevel@tonic-gate  * a driver under test (e.g. activate all errdefs defined on an instance).
4577c478bd9Sstevel@tonic-gate  */
4587c478bd9Sstevel@tonic-gate static int
manage_instance(int fd,char * namep,int instance,int cmd)4597c478bd9Sstevel@tonic-gate manage_instance(int fd, char *namep, int instance, int cmd)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	struct bofi_errctl errctl;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	errctl.namesize = strlen(namep);
4647c478bd9Sstevel@tonic-gate 	(void) strncpy(errctl.name, namep, MAXNAMELEN);
4657c478bd9Sstevel@tonic-gate 	errctl.instance = instance;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	msg(8, "manage_instance: %s %d\n", namep, instance);
4687c478bd9Sstevel@tonic-gate 	if (ioctl(fd, cmd, &errctl) == -1) {
4697c478bd9Sstevel@tonic-gate 		msg(0, "bofi ioctl %d failed: %s\n", cmd, strerror(errno));
4707c478bd9Sstevel@tonic-gate 		return (-1);
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 	return (0);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate static int
define_one_error(FILE * fp,struct bofi_errdef * edp,struct acc_log_elem * item,ulong_t nttime,ulong_t interval,char * type,int fon,size_t fcnt,uint_t acc_chk,char * opname,uint64_t operand)4777c478bd9Sstevel@tonic-gate define_one_error(
4787c478bd9Sstevel@tonic-gate 	FILE *fp,
4797c478bd9Sstevel@tonic-gate 	struct bofi_errdef *edp,
4807c478bd9Sstevel@tonic-gate 	struct acc_log_elem *item,
4817c478bd9Sstevel@tonic-gate 	ulong_t	nttime,
4827c478bd9Sstevel@tonic-gate 	ulong_t interval,
4837c478bd9Sstevel@tonic-gate 	char	*type,
4847c478bd9Sstevel@tonic-gate 	int fon,	/* corrupt after this many accesses */
4857c478bd9Sstevel@tonic-gate 	size_t fcnt,	/* and then fail it fcnt times */
4867c478bd9Sstevel@tonic-gate 	uint_t	acc_chk,
4877c478bd9Sstevel@tonic-gate 	char	*opname,
4887c478bd9Sstevel@tonic-gate 	uint64_t	operand)
4897c478bd9Sstevel@tonic-gate {
4907c478bd9Sstevel@tonic-gate 	(void) fprintf(fp,
4917c478bd9Sstevel@tonic-gate 	    "-n %s -i %d -r %d -l 0x%llx 0x%x -a %s -c %d %d -f %d"
4927c478bd9Sstevel@tonic-gate 	    " -o %s 0x%llx",
4937c478bd9Sstevel@tonic-gate 	    (char *)edp->name,
4947c478bd9Sstevel@tonic-gate 	    edp->instance,
4957c478bd9Sstevel@tonic-gate 	    edp->rnumber,
4967c478bd9Sstevel@tonic-gate 	    edp->offset + item->offset,	/* offset into the regset */
4977c478bd9Sstevel@tonic-gate 	    item->size,	/* corrupt addrs from offset to offset+size */
4987c478bd9Sstevel@tonic-gate 	    type,
4997c478bd9Sstevel@tonic-gate 	    fon,	/* corrupt after this many accesses */
5007c478bd9Sstevel@tonic-gate 	    fcnt,	/* and then fail it fcnt times */
5017c478bd9Sstevel@tonic-gate 	    acc_chk,
5027c478bd9Sstevel@tonic-gate 	    opname,
5037c478bd9Sstevel@tonic-gate 	    operand);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, " -w %lu %lu\n", nttime, interval);
5067c478bd9Sstevel@tonic-gate 	return (0);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate static void
define_op_err(FILE * fp,int * ecnt,struct bofi_errdef * edp,struct acc_log_elem * item,ulong_t nttime,ulong_t interval,char * type,int fon,size_t fcnt)5107c478bd9Sstevel@tonic-gate define_op_err(FILE *fp, int *ecnt, struct bofi_errdef *edp,
5110afbf539SToomas Soome     struct acc_log_elem *item, ulong_t nttime, ulong_t interval, char *type,
5120afbf539SToomas Soome     int fon, size_t fcnt)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	coding_t *ct;
5157c478bd9Sstevel@tonic-gate 	char	*opname;
5167c478bd9Sstevel@tonic-gate 	uint_t	op;
5177c478bd9Sstevel@tonic-gate 	uint64_t	operand;
5187c478bd9Sstevel@tonic-gate 	int k, save_size;
5197c478bd9Sstevel@tonic-gate 	uint64_t save_offset;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if (item->access_type & BOFI_INTR)
5227c478bd9Sstevel@tonic-gate 		ct = &ioptypes[0];
5237c478bd9Sstevel@tonic-gate 	else
5247c478bd9Sstevel@tonic-gate 		ct = &doptypes[0];
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	/*
5277c478bd9Sstevel@tonic-gate 	 * errdefs for dma accesses are too numerous so assume that dma writes
5287c478bd9Sstevel@tonic-gate 	 * (DDI_DMA_SYNC_FORDEV) create less exposure to potential errors than
5297c478bd9Sstevel@tonic-gate 	 * do dma reads (DDI_DMA_SYNC_FORCPU).
5307c478bd9Sstevel@tonic-gate 	 *
5317c478bd9Sstevel@tonic-gate 	 * also by default do not corrupt PIO_W - it may hang a non-FT platform.
5327c478bd9Sstevel@tonic-gate 	 */
5337c478bd9Sstevel@tonic-gate 	if (item->access_type != BOFI_DMA_W &&
5347c478bd9Sstevel@tonic-gate 	    ((item->access_type & BOFI_PIO_W) == 0 || !atype_is_default)) {
5357c478bd9Sstevel@tonic-gate 		/*
5367c478bd9Sstevel@tonic-gate 		 * user has asked for PIO_W
5377c478bd9Sstevel@tonic-gate 		 */
5387c478bd9Sstevel@tonic-gate 		for (; ct->str != 0; ct++) {
5397c478bd9Sstevel@tonic-gate 			op = ct->code;
5407c478bd9Sstevel@tonic-gate 			opname = ct->str;
5417c478bd9Sstevel@tonic-gate 			switch (op) {
5427c478bd9Sstevel@tonic-gate 			case BOFI_EQUAL:
5437c478bd9Sstevel@tonic-gate 				operand = random_operand; /* a random value */
5447c478bd9Sstevel@tonic-gate 				random_operand = lrand48() | ((uint64_t)
5457c478bd9Sstevel@tonic-gate 				    (lrand48()) << 32);
5467c478bd9Sstevel@tonic-gate 				break;
5477c478bd9Sstevel@tonic-gate 			case BOFI_AND:
5487c478bd9Sstevel@tonic-gate 				operand = 0xaddedabadb00bull;
5497c478bd9Sstevel@tonic-gate 				break;
5507c478bd9Sstevel@tonic-gate 			case BOFI_OR:
5517c478bd9Sstevel@tonic-gate 				operand = 0x1;
5527c478bd9Sstevel@tonic-gate 				break;
5537c478bd9Sstevel@tonic-gate 			case BOFI_XOR:
5547c478bd9Sstevel@tonic-gate 			default:
5557c478bd9Sstevel@tonic-gate 				operand = myULLMAX;
5567c478bd9Sstevel@tonic-gate 				break;
5577c478bd9Sstevel@tonic-gate 			case BOFI_DELAY_INTR: /* delay for 1 msec */
5587c478bd9Sstevel@tonic-gate 				operand = 1000000;
5597c478bd9Sstevel@tonic-gate 				break;
5607c478bd9Sstevel@tonic-gate 			case BOFI_LOSE_INTR: /* op not applicable */
5617c478bd9Sstevel@tonic-gate 				operand = 0;
5627c478bd9Sstevel@tonic-gate 				break;
5637c478bd9Sstevel@tonic-gate 			case BOFI_EXTRA_INTR: /* extra intrs */
5647c478bd9Sstevel@tonic-gate 				operand = 0xfff;
5657c478bd9Sstevel@tonic-gate 				break;
5667c478bd9Sstevel@tonic-gate 			}
5677c478bd9Sstevel@tonic-gate 			*ecnt = *ecnt + 1;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 			if ((item->access_type == BOFI_DMA_W ||
5707c478bd9Sstevel@tonic-gate 			    item->access_type == BOFI_DMA_R) &&
5717c478bd9Sstevel@tonic-gate 			    item->size > sizeof (uint64_t) && item->size <
5727c478bd9Sstevel@tonic-gate 			    DMA_INDIVIDUAL_CORRUPT_CUTOFF) {
5737c478bd9Sstevel@tonic-gate 				save_size = item->size;
5747c478bd9Sstevel@tonic-gate 				save_offset = item->offset;
5757c478bd9Sstevel@tonic-gate 				for (k = (item->size +
5767c478bd9Sstevel@tonic-gate 				    sizeof (uint64_t) - 1) &
5777c478bd9Sstevel@tonic-gate 				    ~(sizeof (uint64_t) - 1);
5787c478bd9Sstevel@tonic-gate 				    k > 0; k -= sizeof (uint64_t)) {
5797c478bd9Sstevel@tonic-gate 					item->size = sizeof (uint64_t);
5807c478bd9Sstevel@tonic-gate 					(void) define_one_error(fp, edp,
5817c478bd9Sstevel@tonic-gate 					    item, nttime, interval, type, fon,
5827c478bd9Sstevel@tonic-gate 					    fcnt, edp->acc_chk, opname,
5837c478bd9Sstevel@tonic-gate 					    operand);
5847c478bd9Sstevel@tonic-gate 					item->offset += sizeof (uint64_t);
5857c478bd9Sstevel@tonic-gate 				}
5867c478bd9Sstevel@tonic-gate 				item->size = save_size;
5877c478bd9Sstevel@tonic-gate 				item->offset = save_offset;
5887c478bd9Sstevel@tonic-gate 			} else {
5897c478bd9Sstevel@tonic-gate 				(void) define_one_error(fp, edp, item,
5907c478bd9Sstevel@tonic-gate 				    nttime, interval, type, fon, fcnt,
5917c478bd9Sstevel@tonic-gate 				    edp->acc_chk, opname, operand);
5927c478bd9Sstevel@tonic-gate 			}
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 			if (op == BOFI_EQUAL) {
5957c478bd9Sstevel@tonic-gate 				uint_t cnt;
5967c478bd9Sstevel@tonic-gate 				for (cnt = 0; cnt < NPIO_DEFAULTS;
5977c478bd9Sstevel@tonic-gate 				    cnt++, *ecnt = *ecnt + 1) {
5987c478bd9Sstevel@tonic-gate 					if ((item->access_type == BOFI_DMA_W ||
5997c478bd9Sstevel@tonic-gate 					    item->access_type == BOFI_DMA_R) &&
6007c478bd9Sstevel@tonic-gate 					    item->size > sizeof (uint64_t) &&
6017c478bd9Sstevel@tonic-gate 					    item->size <
6027c478bd9Sstevel@tonic-gate 					    DMA_INDIVIDUAL_CORRUPT_CUTOFF) {
6037c478bd9Sstevel@tonic-gate 						save_size = item->size;
6047c478bd9Sstevel@tonic-gate 						save_offset = item->offset;
6057c478bd9Sstevel@tonic-gate 						for (k = (item->size +
6067c478bd9Sstevel@tonic-gate 						    sizeof (uint64_t) - 1) &
6077c478bd9Sstevel@tonic-gate 						    ~(sizeof (uint64_t) - 1);
6087c478bd9Sstevel@tonic-gate 						    k > 0;
6097c478bd9Sstevel@tonic-gate 						    k -= sizeof (uint64_t)) {
6107c478bd9Sstevel@tonic-gate 							item->size =
6117c478bd9Sstevel@tonic-gate 							    sizeof (uint64_t);
6127c478bd9Sstevel@tonic-gate 							(void) define_one_error(
6137c478bd9Sstevel@tonic-gate 							    fp, edp, item,
6147c478bd9Sstevel@tonic-gate 							    nttime, interval,
6157c478bd9Sstevel@tonic-gate 							    type, fon, fcnt,
6167c478bd9Sstevel@tonic-gate 							    edp->acc_chk,
6177c478bd9Sstevel@tonic-gate 							    opname,
6187c478bd9Sstevel@tonic-gate 							    pio_default_values
6197c478bd9Sstevel@tonic-gate 							    [cnt]);
6207c478bd9Sstevel@tonic-gate 							item->offset +=
6217c478bd9Sstevel@tonic-gate 							    sizeof (uint64_t);
6227c478bd9Sstevel@tonic-gate 						}
6237c478bd9Sstevel@tonic-gate 						item->size = save_size;
6247c478bd9Sstevel@tonic-gate 						item->offset = save_offset;
6257c478bd9Sstevel@tonic-gate 					} else {
6267c478bd9Sstevel@tonic-gate 						(void) define_one_error(fp,
6277c478bd9Sstevel@tonic-gate 						    edp, item, nttime, interval,
6287c478bd9Sstevel@tonic-gate 						    type, fon, fcnt,
6297c478bd9Sstevel@tonic-gate 						    edp->acc_chk, opname,
6307c478bd9Sstevel@tonic-gate 						    pio_default_values[cnt]);
6317c478bd9Sstevel@tonic-gate 					}
6327c478bd9Sstevel@tonic-gate 				}
6337c478bd9Sstevel@tonic-gate 			}
6347c478bd9Sstevel@tonic-gate 		}
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	if ((item->access_type & BOFI_PIO_W) && !atype_is_default) {
6387c478bd9Sstevel@tonic-gate 		/*
6397c478bd9Sstevel@tonic-gate 		 * user has asked for PIO_W
6407c478bd9Sstevel@tonic-gate 		 */
6417c478bd9Sstevel@tonic-gate 		(void) define_one_error(fp, edp, item, nttime, interval,
6427c478bd9Sstevel@tonic-gate 		    type, fon, fcnt, edp->acc_chk, "NO", 0);
6437c478bd9Sstevel@tonic-gate 		*ecnt = *ecnt + 1;
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/*
6477c478bd9Sstevel@tonic-gate 	 * and finally an access check errdef
6487c478bd9Sstevel@tonic-gate 	 */
6497c478bd9Sstevel@tonic-gate 	if (item->access_type & BOFI_PIO_RW)
6507c478bd9Sstevel@tonic-gate 		(void) define_one_error(fp, edp, item, nttime, interval,
6517c478bd9Sstevel@tonic-gate 		    type, fon, fcnt, 1, "OR", 0);
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	if (item->access_type & BOFI_DMA_RW)
6547c478bd9Sstevel@tonic-gate 		(void) define_one_error(fp, edp, item, nttime, interval,
6557c478bd9Sstevel@tonic-gate 		    type, fon, fcnt, 2, "OR", 0);
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate }
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate /*
6607c478bd9Sstevel@tonic-gate  * Convert a collection of log entries into error definitions.
6617c478bd9Sstevel@tonic-gate  */
6627c478bd9Sstevel@tonic-gate /* ARGSUSED */
6637c478bd9Sstevel@tonic-gate static int
define_nerrs(int fd,FILE * fp,int * ecnt,struct bofi_errdef * edp,struct acc_log_elem * items,size_t nitems,uint_t naccess,uint_t minac,uint_t maxac,ulong_t logtime,ulong_t logsize)6647c478bd9Sstevel@tonic-gate define_nerrs(int fd, FILE *fp, int *ecnt, struct bofi_errdef *edp,
6650afbf539SToomas Soome     struct acc_log_elem *items, size_t nitems, uint_t naccess, uint_t minac,
6660afbf539SToomas Soome     uint_t maxac, ulong_t logtime, ulong_t logsize)
6677c478bd9Sstevel@tonic-gate {
6687c478bd9Sstevel@tonic-gate 	char	*type;
6697c478bd9Sstevel@tonic-gate 	uint_t	at;
6707c478bd9Sstevel@tonic-gate 	int	i;
6717c478bd9Sstevel@tonic-gate 	struct acc_log_elem	*item;
6727c478bd9Sstevel@tonic-gate 	char	*opname;
6737c478bd9Sstevel@tonic-gate 	uint_t	op;
6747c478bd9Sstevel@tonic-gate 	uint64_t	operand;
6757c478bd9Sstevel@tonic-gate 	int	cycleiops, cycledops;
6767c478bd9Sstevel@tonic-gate 	int	intrs = 0;
6777c478bd9Sstevel@tonic-gate 	ulong_t	ttime, nttime, interval;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	op = edp->optype;
6807c478bd9Sstevel@tonic-gate 	operand = edp->operand;
6817c478bd9Sstevel@tonic-gate 	msg(3, "define_nerrs: nitems %d (ac %d at 0x%x): (%d %d)"
6827c478bd9Sstevel@tonic-gate 	    " (op 0x%x 0x%llx)\n\n", nitems, naccess, items->access_type,
6837c478bd9Sstevel@tonic-gate 	    minac, maxac, op, operand);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	/*
6867c478bd9Sstevel@tonic-gate 	 * all items are guaranteed have values in the two element set {0, at}
6877c478bd9Sstevel@tonic-gate 	 * where at is a valid access type (so find the value of at)
6887c478bd9Sstevel@tonic-gate 	 */
6897c478bd9Sstevel@tonic-gate 	for (i = 0, item = items, at = 0; i < nitems; i++, item++)
6907c478bd9Sstevel@tonic-gate 		if (item->access_type != 0) {
6917c478bd9Sstevel@tonic-gate 			at = item->access_type;
6927c478bd9Sstevel@tonic-gate 			break;
6937c478bd9Sstevel@tonic-gate 		}
6947c478bd9Sstevel@tonic-gate 	if (at == 0)
6957c478bd9Sstevel@tonic-gate 		return (-1);
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	/*
6987c478bd9Sstevel@tonic-gate 	 * find the string form of the access type
6997c478bd9Sstevel@tonic-gate 	 */
7007c478bd9Sstevel@tonic-gate 	for (i = 0, type = 0; atypes[i].str != 0; i++) {
7017c478bd9Sstevel@tonic-gate 		if (atypes[i].code == at) {
7027c478bd9Sstevel@tonic-gate 			type = atypes[i].str;
7037c478bd9Sstevel@tonic-gate 			break;
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 	if (type == 0) {
7077c478bd9Sstevel@tonic-gate 		msg(0, "Unknown access type returned from bofi\n\t");
7087c478bd9Sstevel@tonic-gate 		dump_log(0, 0, item, 1, BOFI_LOG_TIMESTAMP);
7097c478bd9Sstevel@tonic-gate 		msg(1, "0x%x 0x%x 0x%x 0x%x\n", BOFI_LOG, BOFI_INTR,
7107c478bd9Sstevel@tonic-gate 		    BOFI_DMA_RW, BOFI_PIO_RW);
7117c478bd9Sstevel@tonic-gate 		return (-1);
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	msg(1, "define_n: at = 0x%d (%s)\n", at, type == 0 ? "null" : type);
7157c478bd9Sstevel@tonic-gate 	/*
7167c478bd9Sstevel@tonic-gate 	 * find the string form of the operator
7177c478bd9Sstevel@tonic-gate 	 */
7187c478bd9Sstevel@tonic-gate 	for (i = 0, opname = 0; optypes[i].str != 0; i++) {
7197c478bd9Sstevel@tonic-gate 		if (op == optypes[i].code) {
7207c478bd9Sstevel@tonic-gate 			opname = optypes[i].str;
7217c478bd9Sstevel@tonic-gate 			break;
7227c478bd9Sstevel@tonic-gate 		}
7237c478bd9Sstevel@tonic-gate 	}
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/*
7267c478bd9Sstevel@tonic-gate 	 * if not found or inconsistent default to XOR
7277c478bd9Sstevel@tonic-gate 	 */
7287c478bd9Sstevel@tonic-gate 	if (opname == 0 ||
7297c478bd9Sstevel@tonic-gate 	    (op == BOFI_NO_TRANSFER &&
7307c478bd9Sstevel@tonic-gate 	    (at & (BOFI_DMA_RW|BOFI_PIO_R))) ||
7317c478bd9Sstevel@tonic-gate 	    (op >= BOFI_DELAY_INTR && (at & BOFI_INTR) == 0)) {
7327c478bd9Sstevel@tonic-gate 		opname = optypes[3].str;	/* "XOR" */
7337c478bd9Sstevel@tonic-gate 		operand = myULLMAX;
7347c478bd9Sstevel@tonic-gate 		op = optypes[3].code;
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	/*
7387c478bd9Sstevel@tonic-gate 	 * if operator and access type are inconsistent choose a sensible
7397c478bd9Sstevel@tonic-gate 	 * default
7407c478bd9Sstevel@tonic-gate 	 */
7417c478bd9Sstevel@tonic-gate 	cycleiops = 0;
7427c478bd9Sstevel@tonic-gate 	if (at & BOFI_INTR)
7437c478bd9Sstevel@tonic-gate 		if (op < BOFI_DELAY_INTR)
7447c478bd9Sstevel@tonic-gate 			cycleiops = 1;
7457c478bd9Sstevel@tonic-gate 		else if (op == BOFI_LOSE_INTR)
7467c478bd9Sstevel@tonic-gate 			operand = 0;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	cycledops = 0;
7497c478bd9Sstevel@tonic-gate 	if (nitems == 1 && (at & BOFI_DMA_RW))
7507c478bd9Sstevel@tonic-gate 		cycledops = 1;
7517c478bd9Sstevel@tonic-gate 	/*
7527c478bd9Sstevel@tonic-gate 	 * for each access in the list define one or more error definitions
7537c478bd9Sstevel@tonic-gate 	 */
7547c478bd9Sstevel@tonic-gate 	for (i = 0, item = items; i < nitems; i++, item++) {
7557c478bd9Sstevel@tonic-gate 		size_t acnt, fcnt;
7567c478bd9Sstevel@tonic-gate 		int j, fon;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 		if (item->access_type == 0)
7597c478bd9Sstevel@tonic-gate 			continue;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 		/*
7627c478bd9Sstevel@tonic-gate 		 * base number of errors to inject on 3% of number of
7637c478bd9Sstevel@tonic-gate 		 * similar accesses seen during LOG phase
7647c478bd9Sstevel@tonic-gate 		 */
7657c478bd9Sstevel@tonic-gate 		acnt = item->repcount / 10 + 1; /* 10% */
7667c478bd9Sstevel@tonic-gate 		fcnt = (acnt >= 3) ? acnt / 3 : 1; /* 3% */
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 		/*
7697c478bd9Sstevel@tonic-gate 		 * wait for twice the time it took during LOG phase
7707c478bd9Sstevel@tonic-gate 		 */
7717c478bd9Sstevel@tonic-gate 		if ((ttime = (item->access_time * 2)) < MIN_REPORT_TIME)
7727c478bd9Sstevel@tonic-gate 			ttime = MIN_REPORT_TIME;
7737c478bd9Sstevel@tonic-gate 		else if (max_edef_wait != 0 && ttime > max_edef_wait)
7747c478bd9Sstevel@tonic-gate 			ttime = max_edef_wait;
7757c478bd9Sstevel@tonic-gate 		/*
7767c478bd9Sstevel@tonic-gate 		 * if edef_sleep set (-w) the use that, otherwise use default
7777c478bd9Sstevel@tonic-gate 		 */
7787c478bd9Sstevel@tonic-gate 		interval = edef_sleep ? edef_sleep : DEFAULT_EDEF_SLEEP;
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		msg(10,
7817c478bd9Sstevel@tonic-gate 		    "define_n: item %d limit %d step %d (intr %d) tt(%lu)\n",
7827c478bd9Sstevel@tonic-gate 		    i, item->repcount, acnt, intrs, ttime);
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 		for (j = 0, fon = 1, nttime = ttime; j < item->repcount;
7857c478bd9Sstevel@tonic-gate 		    j += acnt) {
7867c478bd9Sstevel@tonic-gate 			if (policy & OPERATORSPOLICY) {
7877c478bd9Sstevel@tonic-gate 				define_op_err(fp, ecnt, edp, item,
7887c478bd9Sstevel@tonic-gate 				    nttime, interval, type, fon, fcnt);
7897c478bd9Sstevel@tonic-gate 			} else {
7907c478bd9Sstevel@tonic-gate 				if (cycleiops) {
7917c478bd9Sstevel@tonic-gate 					op = ioptypes[intrs].code;
7927c478bd9Sstevel@tonic-gate 					opname = ioptypes[intrs++].str;
7937c478bd9Sstevel@tonic-gate 					switch (op) {
7947c478bd9Sstevel@tonic-gate 					case BOFI_DELAY_INTR:
7957c478bd9Sstevel@tonic-gate 						/* delay for 1 sec */
7967c478bd9Sstevel@tonic-gate 						operand = 1000000;
7977c478bd9Sstevel@tonic-gate 						break;
7987c478bd9Sstevel@tonic-gate 					case BOFI_LOSE_INTR:
7997c478bd9Sstevel@tonic-gate 						/* op not applicable */
8007c478bd9Sstevel@tonic-gate 						operand = 0;
8017c478bd9Sstevel@tonic-gate 						break;
8027c478bd9Sstevel@tonic-gate 					case BOFI_EXTRA_INTR:
8037c478bd9Sstevel@tonic-gate 					default:
8047c478bd9Sstevel@tonic-gate 						/* generate 2 extra intrs */
8057c478bd9Sstevel@tonic-gate 						operand = 0xfff;
8067c478bd9Sstevel@tonic-gate 						break;
8077c478bd9Sstevel@tonic-gate 					}
8087c478bd9Sstevel@tonic-gate 					intrs %= 3;
8097c478bd9Sstevel@tonic-gate 				} else if (cycledops) {
8107c478bd9Sstevel@tonic-gate 					op = doptypes[intrs].code;
8117c478bd9Sstevel@tonic-gate 					opname = doptypes[intrs++].str;
8127c478bd9Sstevel@tonic-gate 					switch (op) {
8137c478bd9Sstevel@tonic-gate 					case BOFI_EQUAL:
8147c478bd9Sstevel@tonic-gate 						random_operand = lrand48() |
8157c478bd9Sstevel@tonic-gate 						    ((uint64_t)
8167c478bd9Sstevel@tonic-gate 						    (lrand48()) << 32);
8177c478bd9Sstevel@tonic-gate 						break; /* a random value */
8187c478bd9Sstevel@tonic-gate 					case BOFI_AND:
8197c478bd9Sstevel@tonic-gate 						operand = 0xaddedabadb00bull;
8207c478bd9Sstevel@tonic-gate 						break;
8217c478bd9Sstevel@tonic-gate 					case BOFI_OR:
8227c478bd9Sstevel@tonic-gate 						operand = 0xd1ab011c0af1a5c0ull;
8237c478bd9Sstevel@tonic-gate 						break;
8247c478bd9Sstevel@tonic-gate 					case BOFI_XOR:
8257c478bd9Sstevel@tonic-gate 					default:
8267c478bd9Sstevel@tonic-gate 						operand = myULLMAX;
8277c478bd9Sstevel@tonic-gate 						break;
8287c478bd9Sstevel@tonic-gate 					}
8297c478bd9Sstevel@tonic-gate 					intrs %= 4;
8307c478bd9Sstevel@tonic-gate 				}
8317c478bd9Sstevel@tonic-gate 				(void) define_one_error(fp, edp, item,
8327c478bd9Sstevel@tonic-gate 				    nttime, interval, type, fon,
8337c478bd9Sstevel@tonic-gate 				    fcnt, edp->acc_chk, opname, operand);
8347c478bd9Sstevel@tonic-gate 				*ecnt = *ecnt + 1;
8357c478bd9Sstevel@tonic-gate 				if (op == BOFI_EQUAL) {
8367c478bd9Sstevel@tonic-gate 					uint_t cnt;
8377c478bd9Sstevel@tonic-gate 					for (cnt = 0; cnt < NPIO_DEFAULTS;
8387c478bd9Sstevel@tonic-gate 					    cnt++, *ecnt = *ecnt + 1)
8397c478bd9Sstevel@tonic-gate 						(void) define_one_error(fp,
8407c478bd9Sstevel@tonic-gate 						    edp, item, nttime,
8417c478bd9Sstevel@tonic-gate 						    interval, type, fon, fcnt,
8427c478bd9Sstevel@tonic-gate 						    edp->acc_chk, opname,
8437c478bd9Sstevel@tonic-gate 						    pio_default_values[cnt]);
8447c478bd9Sstevel@tonic-gate 				}
8457c478bd9Sstevel@tonic-gate 			}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 			/*
8487c478bd9Sstevel@tonic-gate 			 * all non maximal policies should only generate
8497c478bd9Sstevel@tonic-gate 			 * a single error definition set per access.
8507c478bd9Sstevel@tonic-gate 			 */
8517c478bd9Sstevel@tonic-gate 			if (!(policy & MAXIMALPOLICY))
8527c478bd9Sstevel@tonic-gate 				break;
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 			nttime = (logtime - item->access_time) *
8557c478bd9Sstevel@tonic-gate 			    (j + acnt + fcnt - 1) / logsize;
8567c478bd9Sstevel@tonic-gate 			if (nttime < MIN_REPORT_TIME)
8577c478bd9Sstevel@tonic-gate 				nttime = MIN_REPORT_TIME;
8587c478bd9Sstevel@tonic-gate 			else if (nttime > max_edef_wait)
8597c478bd9Sstevel@tonic-gate 				nttime = max_edef_wait;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 			msg(11, "define_nerrs: %lu %d %d %d %llu\n", nttime,
8627c478bd9Sstevel@tonic-gate 			    max_edef_wait, fon, fcnt, item->access_time);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 			if (item->access_type != BOFI_INTR)
8657c478bd9Sstevel@tonic-gate 				fon += j;
8667c478bd9Sstevel@tonic-gate 		}
8677c478bd9Sstevel@tonic-gate 	}
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	return (0);
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate static int
reduce_log(uint16_t pol,struct acc_log * log,struct acc_log_elem ** llp,size_t * cntp)8737c478bd9Sstevel@tonic-gate reduce_log(uint16_t pol, struct acc_log *log,		/* input args */
8740afbf539SToomas Soome     struct acc_log_elem **llp, size_t *cntp)		/* output args */
8757c478bd9Sstevel@tonic-gate {
8767c478bd9Sstevel@tonic-gate 	ulong_t logtime;
8777c478bd9Sstevel@tonic-gate 	struct acc_log_elem *items, *item, *elem;
8787c478bd9Sstevel@tonic-gate 	int cnt, nitems, acnt;
8797c478bd9Sstevel@tonic-gate 	int i, j, k, lb, ub, mina, maxa, cutoff[2], mean;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	if (llp == 0 || cntp == 0)	/* subroutine interface violated */
8827c478bd9Sstevel@tonic-gate 		return (-1);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	if (*llp == 0) {
8857c478bd9Sstevel@tonic-gate 		items = (void *)log->logbase;
8867c478bd9Sstevel@tonic-gate 		nitems = log->entries;
8877c478bd9Sstevel@tonic-gate 	} else {
8887c478bd9Sstevel@tonic-gate 		items = *llp;	/* outputs double up as inputs */
8897c478bd9Sstevel@tonic-gate 		nitems = *cntp;
8907c478bd9Sstevel@tonic-gate 	}
8917c478bd9Sstevel@tonic-gate 	/* has the utc time wrapped over ULMAX - unlikely so fix it at 10 */
8927c478bd9Sstevel@tonic-gate 	logtime = (log->stop_time >= log->start_time) ?
8937c478bd9Sstevel@tonic-gate 	    log->stop_time - log->start_time : 10ul;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	msg(1, "reduce %d: logtime %lu\n", nitems, logtime);
8967c478bd9Sstevel@tonic-gate 	/*
8977c478bd9Sstevel@tonic-gate 	 * Sort the log by access type - do not remove duplicates yet (but do
8987c478bd9Sstevel@tonic-gate 	 * remove access that do not match the requested log -> errdef policy
8997c478bd9Sstevel@tonic-gate 	 * (defined by union pu pol). Set the repcount field of each entry to a
9007c478bd9Sstevel@tonic-gate 	 * unique value (in the control statement of the for loop) - this
9017c478bd9Sstevel@tonic-gate 	 * ensures that the qsort (following the for loop) will not remove any
9027c478bd9Sstevel@tonic-gate 	 * entries.
9037c478bd9Sstevel@tonic-gate 	 */
9047c478bd9Sstevel@tonic-gate 	for (i = 0, cnt = 0, elem = items; i < nitems;
9057c478bd9Sstevel@tonic-gate 	    elem->repcount = i, i++, elem++) {
9067c478bd9Sstevel@tonic-gate 		/*
9077c478bd9Sstevel@tonic-gate 		 * If interested in the I/O transfer size and this access
9087c478bd9Sstevel@tonic-gate 		 * does not match the requested size then ignore the access
9097c478bd9Sstevel@tonic-gate 		 */
9107c478bd9Sstevel@tonic-gate 		if ((pol & SIZEPOLICY) &&
9117c478bd9Sstevel@tonic-gate 		    (!(pol & MULTIPOLICY) || elem->repcount == 1) &&
9127c478bd9Sstevel@tonic-gate 		    /* req for DMA / ddi_rep */
9137c478bd9Sstevel@tonic-gate 		    (pol & elem->size) == 0)
9147c478bd9Sstevel@tonic-gate 			elem->access_type = 0;
9157c478bd9Sstevel@tonic-gate 			/* these will end up sorted at the head */
9167c478bd9Sstevel@tonic-gate 		else {
9177c478bd9Sstevel@tonic-gate 			cnt += 1;
9187c478bd9Sstevel@tonic-gate 			elem->size *= elem->repcount;
9197c478bd9Sstevel@tonic-gate 			if (log->flags & BOFI_LOG_TIMESTAMP)
9207c478bd9Sstevel@tonic-gate 				/* real access time */
9217c478bd9Sstevel@tonic-gate 				elem->access_time -= log->start_time;
9227c478bd9Sstevel@tonic-gate 			else
9237c478bd9Sstevel@tonic-gate 				/* linear fit */
9247c478bd9Sstevel@tonic-gate 				elem->access_time = logtime * (i + 1) / nitems;
9257c478bd9Sstevel@tonic-gate 		}
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	qsort((void *)items, nitems, sizeof (*items), log_cmp);
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	msg(5, "qsorted log raw (nitems %d cnt %d:\n", nitems, cnt);
9317c478bd9Sstevel@tonic-gate 	dump_log(14, 0, items, nitems, log->flags);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	if (cnt != nitems) {	/* some items should be ignored */
9347c478bd9Sstevel@tonic-gate 		items += (nitems - cnt);	/* ignore these ones */
9357c478bd9Sstevel@tonic-gate 		if ((nitems = cnt) == 0) {
9367c478bd9Sstevel@tonic-gate 			*cntp = 0;
9377c478bd9Sstevel@tonic-gate 			*llp = 0;
9387c478bd9Sstevel@tonic-gate 			return (0);
9397c478bd9Sstevel@tonic-gate 			/* the chosen policy has ignored everything */
9407c478bd9Sstevel@tonic-gate 		}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 	/*
9447c478bd9Sstevel@tonic-gate 	 * Now remove duplicate entries based on access type, address and size.
9457c478bd9Sstevel@tonic-gate 	 * Reuse the repcount field to store the no. of duplicate accesses.
9467c478bd9Sstevel@tonic-gate 	 * Store the average access time in the single remaining
9477c478bd9Sstevel@tonic-gate 	 * representative of the duplicate set.
9487c478bd9Sstevel@tonic-gate 	 */
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	for (i = 1, cnt = 1, elem = items, elem->repcount = 1, item = elem + 1;
9517c478bd9Sstevel@tonic-gate 	    i < nitems; i++, item++) {
9527c478bd9Sstevel@tonic-gate 		if (elem_cmp(elem, item) == 0) {
9537c478bd9Sstevel@tonic-gate 			elem->access_time += item->access_time;
9547c478bd9Sstevel@tonic-gate 			elem->repcount++;
9557c478bd9Sstevel@tonic-gate 		} else {	/* not a duplicate */
9567c478bd9Sstevel@tonic-gate 			elem->access_time = logtime / elem->repcount;
9577c478bd9Sstevel@tonic-gate 			elem++;
9587c478bd9Sstevel@tonic-gate 			*elem = *item;
9597c478bd9Sstevel@tonic-gate 			cnt++;
9607c478bd9Sstevel@tonic-gate 			elem->repcount = 1;
9617c478bd9Sstevel@tonic-gate 		}
9627c478bd9Sstevel@tonic-gate 	}
9637c478bd9Sstevel@tonic-gate 	elem->access_time = logtime / elem->repcount;
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	/*
9667c478bd9Sstevel@tonic-gate 	 * The log is sorted by access type - now resort to order by frequency
9677c478bd9Sstevel@tonic-gate 	 * of accesses (ie for a given access type uncommon access will come
9687c478bd9Sstevel@tonic-gate 	 * first.
9697c478bd9Sstevel@tonic-gate 	 */
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	qsort((void *)items, cnt, sizeof (*items), log_cmp2);
9727c478bd9Sstevel@tonic-gate 	msg(4, "qsorted log2: cnt is %d\n", cnt);
9737c478bd9Sstevel@tonic-gate 	dump_log(4, 0, items, cnt, log->flags);
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i = j) {
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 		/*
9787c478bd9Sstevel@tonic-gate 		 * Pick out the set [i, j) consisting of elements with the same
9797c478bd9Sstevel@tonic-gate 		 * access type
9807c478bd9Sstevel@tonic-gate 		 */
9817c478bd9Sstevel@tonic-gate 		for (j = i + 1, acnt = items[i].repcount; j < cnt &&
9827c478bd9Sstevel@tonic-gate 		    items[j].access_type == items[i].access_type; j++)
9837c478bd9Sstevel@tonic-gate 			acnt += items[j].repcount;
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 		if (j - i == 1)	/* never ignore solo accesses of a given type */
9867c478bd9Sstevel@tonic-gate 			continue;
9877c478bd9Sstevel@tonic-gate 		/*
9887c478bd9Sstevel@tonic-gate 		 * Now determine what constitutes uncommon and common accesses:
9897c478bd9Sstevel@tonic-gate 		 */
9907c478bd9Sstevel@tonic-gate 		mina = items[i].repcount;
9917c478bd9Sstevel@tonic-gate 		maxa = items[j-1].repcount;
9927c478bd9Sstevel@tonic-gate 		mean = acnt / (j - i); /* mean value */
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 		if (pol & (UNCOMMONPOLICY|MEDIANPOLICY)) {
9957c478bd9Sstevel@tonic-gate 			cutoff[0] = (mean - mina) / DISTRIB_CUTOFF + mina;
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 			for (ub = i; ub < j; ub++)
9987c478bd9Sstevel@tonic-gate 				if (items[ub].repcount > cutoff[0])
9997c478bd9Sstevel@tonic-gate 					break;
10007c478bd9Sstevel@tonic-gate 			lb = j - 1;
10017c478bd9Sstevel@tonic-gate 		} else {
10027c478bd9Sstevel@tonic-gate 			lb = i;
10037c478bd9Sstevel@tonic-gate 			ub = j-1;
10047c478bd9Sstevel@tonic-gate 		}
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 		if (pol & (COMMONPOLICY|MEDIANPOLICY)) {
10077c478bd9Sstevel@tonic-gate 			cutoff[1] = maxa - (maxa - mean) / DISTRIB_CUTOFF;
10087c478bd9Sstevel@tonic-gate 			for (lb = j - 1; lb >= i; lb--)
10097c478bd9Sstevel@tonic-gate 				if (items[lb].repcount < cutoff[1])
10107c478bd9Sstevel@tonic-gate 					break;
10117c478bd9Sstevel@tonic-gate 			if (!(pol & (UNCOMMONPOLICY|MEDIANPOLICY)))
10127c478bd9Sstevel@tonic-gate 				ub = i;
10137c478bd9Sstevel@tonic-gate 		}
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 		msg(3, "reduce_log: p 0x%x at %d:0x%x %d:0x%x acnt mina maxa"
10167c478bd9Sstevel@tonic-gate 		    " (%d %d %d)"
10177c478bd9Sstevel@tonic-gate 		    " mean %d cutoffs(%d %d) bnds(%d, %d)\n",
10187c478bd9Sstevel@tonic-gate 		    pol, i, items[i].access_type, j, items[j].access_type,
10197c478bd9Sstevel@tonic-gate 		    acnt, mina, maxa, mean, cutoff[0], cutoff[1], lb, ub);
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 		if (ub <= lb)
10227c478bd9Sstevel@tonic-gate 			if (!(pol & MEDIANPOLICY))
10237c478bd9Sstevel@tonic-gate 				/* delete all the mid accesses */
10247c478bd9Sstevel@tonic-gate 				for (k = ub; k <= lb; k++)
10257c478bd9Sstevel@tonic-gate 					items[k].access_type = 0;
10267c478bd9Sstevel@tonic-gate 			else {
10277c478bd9Sstevel@tonic-gate 				if (!(pol & UNCOMMONPOLICY))
10287c478bd9Sstevel@tonic-gate 					/* delete uncommon accesses */
10297c478bd9Sstevel@tonic-gate 					for (k = i; k < ub; k++)
10307c478bd9Sstevel@tonic-gate 						items[k].access_type = 0;
10317c478bd9Sstevel@tonic-gate 				if (!(pol & COMMONPOLICY))
10327c478bd9Sstevel@tonic-gate 					/* delete common accesses */
10337c478bd9Sstevel@tonic-gate 					for (k = lb+1; k < j; k++)
10347c478bd9Sstevel@tonic-gate 						items[k].access_type = 0;
10357c478bd9Sstevel@tonic-gate 			}
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 	msg(4, "reduce_log: returning %d items\n", cnt);
10387c478bd9Sstevel@tonic-gate 	dump_log(5, 0, items, cnt, log->flags);
10397c478bd9Sstevel@tonic-gate 	*cntp = cnt;
10407c478bd9Sstevel@tonic-gate 	*llp = items;
10417c478bd9Sstevel@tonic-gate 	return (0);
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate static void
log2errdefs(int fd,struct bofi_errdef * edp,struct acc_log * log,char * devpath)10457c478bd9Sstevel@tonic-gate log2errdefs(int fd, struct bofi_errdef *edp, struct acc_log *log,
10460afbf539SToomas Soome     char *devpath)
10477c478bd9Sstevel@tonic-gate {
10487c478bd9Sstevel@tonic-gate 	struct acc_log_elem	*items;
10497c478bd9Sstevel@tonic-gate 	size_t			nitems;
10507c478bd9Sstevel@tonic-gate 	int			i, j;
10517c478bd9Sstevel@tonic-gate 	uint_t			acc_cnt;
10527c478bd9Sstevel@tonic-gate 	char			fname[_POSIX_PATH_MAX];
10537c478bd9Sstevel@tonic-gate 	FILE			*fp = 0;
10547c478bd9Sstevel@tonic-gate 	time_t			utc = time(NULL);
10557c478bd9Sstevel@tonic-gate 	int			ecnt = 0;
10567c478bd9Sstevel@tonic-gate 	int			err;
10577c478bd9Sstevel@tonic-gate 	ulong_t			logtime;
10587c478bd9Sstevel@tonic-gate 	char			*buffer;
10597c478bd9Sstevel@tonic-gate 	struct stat		statbuf;
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	items = (void *)log->logbase;
10627c478bd9Sstevel@tonic-gate 	nitems = log->entries;
10637c478bd9Sstevel@tonic-gate 	logtime = (log->stop_time >= log->start_time) ?
10647c478bd9Sstevel@tonic-gate 	    log->stop_time - log->start_time : 10ul;
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	if (nitems == 0)
10677c478bd9Sstevel@tonic-gate 		return;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	/* ensure that generated errdefs complete in bounded time */
10707c478bd9Sstevel@tonic-gate 	if (max_edef_wait == 0)
10717c478bd9Sstevel@tonic-gate 		max_edef_wait =
10727c478bd9Sstevel@tonic-gate 		    logtime > MIN_REPORT_TIME ? logtime : MIN_REPORT_TIME * 2;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	msg(4, "log2errdefs(0x%p, 0x%p, %d, 0x%x):\n",
10757c478bd9Sstevel@tonic-gate 	    (void *) edp, (void *) items, nitems, policy);
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	(void) snprintf(fname, sizeof (fname), "%s.%d", (char *)edp->name,
10787c478bd9Sstevel@tonic-gate 	    (int)getpid());
10797c478bd9Sstevel@tonic-gate 	if ((fp = fopen(fname, "w")) == 0)
10807c478bd9Sstevel@tonic-gate 		fp = outfile;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "#!/bin/ksh -p\n\n");
10837c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# %-24s%s\n", "Script creation time:", ctime(&utc));
10847c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# %-24s%llu\n",
10857c478bd9Sstevel@tonic-gate 	    "Activation time:", log->start_time);
10867c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# %-24s%llu\n",
10877c478bd9Sstevel@tonic-gate 	    "Deactivation time:", log->stop_time);
10887c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# %-24s%d\n", "Log size:", nitems);
10897c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# %-24s", "Errdef policy:");
10907c478bd9Sstevel@tonic-gate 	for (i = 0; ptypes[i].str != 0; i++)
10917c478bd9Sstevel@tonic-gate 		if (policy & ptypes[i].code)
10927c478bd9Sstevel@tonic-gate 			(void) fprintf(fp, "%s ", ptypes[i].str);
10937c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "\n");
10947c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# %-24s%s\n", "Driver:", (char *)edp->name);
10957c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# %-24s%d\n", "Instance:", edp->instance);
10967c478bd9Sstevel@tonic-gate 	if (edp->access_type & BOFI_PIO_RW) {
10977c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "# %-24s%d\n",
10987c478bd9Sstevel@tonic-gate 		    "Register set:", edp->rnumber);
10997c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "# %-24s0x%llx\n", "Offset:", edp->offset);
11007c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "# %-24s0x%llx\n", "Length:", edp->len);
11017c478bd9Sstevel@tonic-gate 	} else if (edp->access_type & BOFI_DMA_RW) {
11027c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "# %-24s%d\n", "DMA handle:", edp->rnumber);
11037c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "# %-24s0x%llx\n", "Offset:", edp->offset);
11047c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "# %-24s0x%llx\n", "Length:", edp->len);
11057c478bd9Sstevel@tonic-gate 	} else if ((edp->access_type & BOFI_INTR) == 0) {
11067c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "# %-24s%d\n",
11077c478bd9Sstevel@tonic-gate 		    "Unknown Handle Type:", edp->rnumber);
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# %-24s0x%x ( ", "Access type:",
11117c478bd9Sstevel@tonic-gate 	    (edp->access_type & ~BOFI_LOG));
11127c478bd9Sstevel@tonic-gate 	if (edp->access_type & BOFI_PIO_R)
11137c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s ", "pio_r");
11147c478bd9Sstevel@tonic-gate 	if (edp->access_type & BOFI_PIO_W)
11157c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s ", "pio_w");
11167c478bd9Sstevel@tonic-gate 	if (edp->access_type & BOFI_DMA_W)
11177c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s ", "dma_w");
11187c478bd9Sstevel@tonic-gate 	if (edp->access_type & BOFI_DMA_R)
11197c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s ", "dma_r");
11207c478bd9Sstevel@tonic-gate 	if (edp->access_type & BOFI_INTR)
11217c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s ", "intr");
11227c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, ")\n\n");
11237c478bd9Sstevel@tonic-gate 	if (user_comment)
11247c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "# %-24s%s\n\n",
11257c478bd9Sstevel@tonic-gate 		    "Test Comment:", user_comment);
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	dump_log(0, fp, items, nitems, log->flags);
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	items = 0;
11307c478bd9Sstevel@tonic-gate 	if ((err = reduce_log(policy, log, &items, &nitems)) < 0 ||
11317c478bd9Sstevel@tonic-gate 	    nitems == 0) {
11327c478bd9Sstevel@tonic-gate 		msg(4, "log2errdefs: reduce_log err %d nitems %d\n",
11337c478bd9Sstevel@tonic-gate 		    err, nitems);
11347c478bd9Sstevel@tonic-gate 		return;
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "\nerror() { echo \""
11377c478bd9Sstevel@tonic-gate 	    "${0##*/}: $@\""
11387c478bd9Sstevel@tonic-gate 	    " >&2; exit 2; }\n");
11397c478bd9Sstevel@tonic-gate 	(void) fprintf(fp,
11407c478bd9Sstevel@tonic-gate 	    "trap ' ' 16\t# ignore - it is trapped by abort monitor_edef\n");
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "\nfixup_script()\n{\n");
11437c478bd9Sstevel@tonic-gate 	if (scriptargs > 0) {
11447c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\tif [[ $1 -eq 1 ]]\n\tthen\n");
11457c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\t\t# Call a user defined workload\n");
11467c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\t\t# while injecting errors\n\t\t");
11477c478bd9Sstevel@tonic-gate 		for (i = 0; i < scriptargs; i++)
11487c478bd9Sstevel@tonic-gate 			(void) fprintf(fp, "%s ", fixup_script[i]);
11497c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\n\tfi\n");
11507c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\treturn 0\n");
11517c478bd9Sstevel@tonic-gate 	} else {
11527c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\tif [[ $1 -eq 0 ]]\n\tthen\n");
11537c478bd9Sstevel@tonic-gate 		(void) fprintf(fp,
11547c478bd9Sstevel@tonic-gate 		    "\t\t# terminate any outstanding workload\n");
11557c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\t\tif [ $script_pid -gt 0 ]; then\n");
11567c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\t\t\tkill $script_pid\n");
11577c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\t\t\tscript_pid=0\n");
11587c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\t\tfi\n");
11597c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\tfi\n");
11607c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\treturn -1\n");
11617c478bd9Sstevel@tonic-gate 	}
11627c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "}\n\n");
11637c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "devpath=/devices%s\n\n", devpath);
11647c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "#\n");
11657c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# following text extracted from th_script\n");
11667c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "#\n");
11677c478bd9Sstevel@tonic-gate 	if (stat("/usr/lib/th_script", &statbuf) == -1) {
11687c478bd9Sstevel@tonic-gate 		msg(0, "log2errdefs: stat of /usr/lib/th_script failed\n");
11697c478bd9Sstevel@tonic-gate 		return;
11707c478bd9Sstevel@tonic-gate 	}
11717c478bd9Sstevel@tonic-gate 	fd = open("/usr/lib/th_script", O_RDONLY);
11727c478bd9Sstevel@tonic-gate 	if (fd == -1) {
11737c478bd9Sstevel@tonic-gate 		msg(0, "log2errdefs: open of /usr/lib/th_script failed\n");
11747c478bd9Sstevel@tonic-gate 		return;
11757c478bd9Sstevel@tonic-gate 	}
11767c478bd9Sstevel@tonic-gate 	buffer = malloc(statbuf.st_size);
11777c478bd9Sstevel@tonic-gate 	if (!buffer) {
11787c478bd9Sstevel@tonic-gate 		msg(0, "log2errdefs: malloc for /usr/lib/th_script failed\n");
11797c478bd9Sstevel@tonic-gate 		return;
11807c478bd9Sstevel@tonic-gate 	}
11817c478bd9Sstevel@tonic-gate 	if (read(fd, buffer, statbuf.st_size) != statbuf.st_size) {
11827c478bd9Sstevel@tonic-gate 		msg(0, "log2errdefs: read of /usr/lib/th_script failed\n");
11837c478bd9Sstevel@tonic-gate 		return;
11847c478bd9Sstevel@tonic-gate 	}
11857c478bd9Sstevel@tonic-gate 	(void) fwrite(buffer, statbuf.st_size, 1, fp);
11867c478bd9Sstevel@tonic-gate 	(void) close(fd);
11877c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "#\n");
11887c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "# end of extracted text\n");
11897c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "#\n");
11907c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "run_subtest %s %d <<ERRDEFS\n",
11917c478bd9Sstevel@tonic-gate 	    (char *)edp->name, edp->instance);
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	for (i = 0; i < nitems; i = j) {
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 		acc_cnt = items[i].repcount;
11967c478bd9Sstevel@tonic-gate 		for (j = i + 1;
11977c478bd9Sstevel@tonic-gate 		    j < nitems && items[j].access_type == items[i].access_type;
11987c478bd9Sstevel@tonic-gate 		    j++)
11997c478bd9Sstevel@tonic-gate 			acc_cnt += items[j].repcount;
12007c478bd9Sstevel@tonic-gate 		msg(1, "l2e: nitems %d i %d j %d at 0x%x\n",
12017c478bd9Sstevel@tonic-gate 		    nitems, i, j, items[i].access_type);
12027c478bd9Sstevel@tonic-gate 		if (items[i].access_type != 0)
12037c478bd9Sstevel@tonic-gate 			(void) define_nerrs(fd, fp, &ecnt, edp, items+i, j-i,
12047c478bd9Sstevel@tonic-gate 			    acc_cnt, items[i].repcount, items[j-1].repcount,
12057c478bd9Sstevel@tonic-gate 			    logtime, log->entries);
12067c478bd9Sstevel@tonic-gate 	}
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "ERRDEFS\n");
12097c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "exit 0\n");
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	if (fp != stdout && fp != stderr) {
12127c478bd9Sstevel@tonic-gate 		if (fchmod(fileno(fp), S_IRWXU|S_IRGRP|S_IROTH))
12137c478bd9Sstevel@tonic-gate 			msg(0, "fchmod failed: %s\n", strerror(errno));
12147c478bd9Sstevel@tonic-gate 		if (fclose(fp) != 0)
12157c478bd9Sstevel@tonic-gate 			msg(0, "close of %s failed: %s\n", fname,
12167c478bd9Sstevel@tonic-gate 			    strerror(errno));
12177c478bd9Sstevel@tonic-gate 	}
12187c478bd9Sstevel@tonic-gate 	msg(10, "log2errdefs: done\n");
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate #define	LLSZMASK (sizeof (longlong_t) -1)
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate static int
add_edef(int fd,struct bofi_errdef * errdef,struct bofi_errstate * errstate,struct handle_info * hdl,struct bofi_errdef * edp)12240afbf539SToomas Soome add_edef(
12250afbf539SToomas Soome 	int fd,
12267c478bd9Sstevel@tonic-gate 	struct bofi_errdef *errdef,	/* returned access criteria */
12277c478bd9Sstevel@tonic-gate 	struct bofi_errstate *errstate,
12287c478bd9Sstevel@tonic-gate 	struct handle_info *hdl,	/* handle to match against request */
12297c478bd9Sstevel@tonic-gate 	struct bofi_errdef *edp)	/* requested access criteria */
12307c478bd9Sstevel@tonic-gate {
12317c478bd9Sstevel@tonic-gate 	*errdef = *edp;
12327c478bd9Sstevel@tonic-gate 	errdef->instance = hdl->instance;
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	if (hdl->access_type == 0)
12367c478bd9Sstevel@tonic-gate 		return (EINVAL);
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	errdef->access_type =
12397c478bd9Sstevel@tonic-gate 	    errdef->access_type & (hdl->access_type|BOFI_LOG);
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	/* use a big log for PIO and a small one otherwise */
12427c478bd9Sstevel@tonic-gate 	if (lsize_is_default &&
12437c478bd9Sstevel@tonic-gate 	    (errdef->access_type & BOFI_PIO_RW) == 0) {
12447c478bd9Sstevel@tonic-gate 		errdef->access_count = DFLT_NONPIO_LOGSZ;
12457c478bd9Sstevel@tonic-gate 		errdef->fail_count = 0;
12467c478bd9Sstevel@tonic-gate 	}
12477c478bd9Sstevel@tonic-gate 	errdef->log.logsize = errstate->log.logsize =
12487c478bd9Sstevel@tonic-gate 	    errdef->access_count + errdef->fail_count - 1;
12497c478bd9Sstevel@tonic-gate 	if (errdef->log.logsize == -1U) {
12507c478bd9Sstevel@tonic-gate 		errdef->log.logsize = errstate->log.logsize = 0;
12517c478bd9Sstevel@tonic-gate 	}
12527c478bd9Sstevel@tonic-gate 	errdef->log.logbase = errstate->log.logbase =
12537c478bd9Sstevel@tonic-gate 	    (caddr_t)GETSTRUCT(struct acc_log_elem, errdef->log.logsize);
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	if (errdef->log.logbase == 0)
12567c478bd9Sstevel@tonic-gate 		return (EAGAIN);
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	errdef->rnumber = hdl->rnumber;
12597c478bd9Sstevel@tonic-gate 	errdef->offset = hdl->offset;
12607c478bd9Sstevel@tonic-gate 	errdef->len = hdl->len;
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	msg(4, "creating errdef: %d %s %d %d 0x%llx 0x%llx 0x%x 0x%x 0x%x"
12637c478bd9Sstevel@tonic-gate 	    " 0x%x 0x%x 0x%llx\n",
12647c478bd9Sstevel@tonic-gate 	    errdef->namesize, (char *)errdef->name,
12657c478bd9Sstevel@tonic-gate 	    errdef->instance, errdef->rnumber,
12667c478bd9Sstevel@tonic-gate 	    errdef->offset, errdef->len,
12677c478bd9Sstevel@tonic-gate 	    errdef->access_type,
12687c478bd9Sstevel@tonic-gate 	    errdef->access_count, errdef->fail_count,
12697c478bd9Sstevel@tonic-gate 	    errdef->acc_chk, errdef->optype, errdef->operand);
12707c478bd9Sstevel@tonic-gate 	if (ioctl(fd, BOFI_ADD_DEF, errdef) == -1) {
12717c478bd9Sstevel@tonic-gate 		perror("th_define - adding errdef failed");
12727c478bd9Sstevel@tonic-gate 		return (errno);
12737c478bd9Sstevel@tonic-gate 	}
12747c478bd9Sstevel@tonic-gate 	errdef->optype = edp->optype; /* driver clears it if fcnt is zero */
12757c478bd9Sstevel@tonic-gate 	errstate->errdef_handle = errdef->errdef_handle;
12767c478bd9Sstevel@tonic-gate 	return (0);
12777c478bd9Sstevel@tonic-gate }
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate static void
collect_state(int fd,int cmd,struct bofi_errstate * errstate,struct bofi_errdef * errdef,char * devpath)12800afbf539SToomas Soome collect_state(int fd, int cmd, struct bofi_errstate *errstate,
12810afbf539SToomas Soome     struct bofi_errdef *errdef, char *devpath)
12827c478bd9Sstevel@tonic-gate {
12837c478bd9Sstevel@tonic-gate 	int rval;
12847c478bd9Sstevel@tonic-gate 	size_t ls = errstate->log.logsize;
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	msg(2, "collect_state: pre: edp->access_type 0x%x (logsize %d)\n",
1287e5ba14ffSstephh 	    errdef->access_type, errdef->log.logsize);
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	do {
12907c478bd9Sstevel@tonic-gate 		errstate->log.logsize = 0; /* only copy the driver log once */
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 		msg(10, "collecting state (lsize %d) ...\n",
12937c478bd9Sstevel@tonic-gate 		    errstate->log.logsize);
12947c478bd9Sstevel@tonic-gate 		errno = 0;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 		if (ioctl(fd, cmd, errstate) == -1 && errno != EINTR) {
12977c478bd9Sstevel@tonic-gate 			perror("th_define (collect) -"
12987c478bd9Sstevel@tonic-gate 			    " waiting for error report failed");
12997c478bd9Sstevel@tonic-gate 			break;
13007c478bd9Sstevel@tonic-gate 		}
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 		(void) fprintf(outfile, "Logged %d out of %d accesses"
13037c478bd9Sstevel@tonic-gate 		    " (%s %d %d 0x%x %d).\n",
13047c478bd9Sstevel@tonic-gate 		    errstate->log.entries, ls,
13057c478bd9Sstevel@tonic-gate 		    (char *)errdef->name, errdef->instance, errdef->rnumber,
13067c478bd9Sstevel@tonic-gate 		    errdef->access_type, errstate->log.wrapcnt);
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 		(void) msg(1, "\t(ac %d fc %d lf 0x%x wc %d).\n",
13097c478bd9Sstevel@tonic-gate 		    errstate->access_count, errstate->fail_count,
13107c478bd9Sstevel@tonic-gate 		    errstate->log.flags, errstate->log.wrapcnt);
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 		rval = errno;
13137c478bd9Sstevel@tonic-gate 		if ((errstate->log.flags & BOFI_LOG_WRAP) &&
13147c478bd9Sstevel@tonic-gate 		    errstate->access_count > 0)
13157c478bd9Sstevel@tonic-gate 			continue;
13167c478bd9Sstevel@tonic-gate 		if (errstate->access_count <= 1 &&
13177c478bd9Sstevel@tonic-gate 		    errstate->fail_count == 0 &&
13187c478bd9Sstevel@tonic-gate 		    errstate->acc_chk == 0) {
13197c478bd9Sstevel@tonic-gate 			msg(3, "collecting state complete entries %d\n",
13207c478bd9Sstevel@tonic-gate 			    errstate->log.entries);
13217c478bd9Sstevel@tonic-gate 			break;
13227c478bd9Sstevel@tonic-gate 		}
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 		msg(5, "still collecting state: %d, %d, %d\n",
13257c478bd9Sstevel@tonic-gate 		    errstate->access_count, errstate->fail_count,
13267c478bd9Sstevel@tonic-gate 		    errstate->acc_chk);
13277c478bd9Sstevel@tonic-gate 		(void) msg(2, "Log: errno %d size %d entries %d "
13287c478bd9Sstevel@tonic-gate 		    "(off 0x%llx len 0x%llx) ac %d\n", errno,
13297c478bd9Sstevel@tonic-gate 		    errstate->log.logsize, errstate->log.entries,
13307c478bd9Sstevel@tonic-gate 		    errdef->offset, errdef->len, errstate->access_count);
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	} while (rval == 0 && errstate->log.entries < ls);
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	/* now grab the log itself */
13357c478bd9Sstevel@tonic-gate 	errstate->log.logsize = ls;
13367c478bd9Sstevel@tonic-gate 	if (errstate->log.entries != 0) {
13377c478bd9Sstevel@tonic-gate 		if (ioctl(fd, BOFI_CHK_STATE, errstate) == -1) {
13387c478bd9Sstevel@tonic-gate 			msg(0,
13397c478bd9Sstevel@tonic-gate 			    "%s: errorwhile retrieving %d log entries: %s\n",
13407c478bd9Sstevel@tonic-gate 			    Progname, errstate->log.entries, strerror(errno));
13417c478bd9Sstevel@tonic-gate 		} else {
13427c478bd9Sstevel@tonic-gate 			msg(2, "collect_state: post: edp->access_type 0x%x"
13437c478bd9Sstevel@tonic-gate 			    " (log entries %d %d) (%llu - %llu)\n",
13447c478bd9Sstevel@tonic-gate 			    errdef->access_type,
13457c478bd9Sstevel@tonic-gate 			    errstate->log.entries, errstate->access_count,
13467c478bd9Sstevel@tonic-gate 			    errstate->log.start_time, errstate->log.stop_time);
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 			log2errdefs(fd, errdef, &(errstate->log), devpath);
13497c478bd9Sstevel@tonic-gate 		}
13507c478bd9Sstevel@tonic-gate 	}
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate static void
print_err_reports(FILE * fp,struct bofi_errstate * esp,char * fname,char * cmt,int id)13547c478bd9Sstevel@tonic-gate print_err_reports(FILE *fp, struct bofi_errstate *esp,
13550afbf539SToomas Soome     char *fname, char *cmt, int id)
13567c478bd9Sstevel@tonic-gate {
13577c478bd9Sstevel@tonic-gate 	if (fname != 0 && *fname != 0)
13587c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%sErrdef file %s definition %d:",
13597c478bd9Sstevel@tonic-gate 		    cmt, fname, id);
13607c478bd9Sstevel@tonic-gate 	else
13617c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s", cmt);
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	if (esp->access_count != 0) {
13647c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, " (access count %d).\n", esp->access_count);
13657c478bd9Sstevel@tonic-gate 	} else {
13667c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\n%s\tremaining fail count %d acc_chk %d\n",
13677c478bd9Sstevel@tonic-gate 		    cmt, esp->fail_count, esp->acc_chk);
13687c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s\tfail time 0x%llx error reported time"
13697c478bd9Sstevel@tonic-gate 		    " 0x%llx errors reported %d\n", cmt,
13707c478bd9Sstevel@tonic-gate 		    esp->fail_time, esp->msg_time,
13717c478bd9Sstevel@tonic-gate 		    esp->errmsg_count);
13727c478bd9Sstevel@tonic-gate 		if (esp->msg_time)
13737c478bd9Sstevel@tonic-gate 			(void) fprintf(fp, "%s\tmessage \"%s\" severity 0x%x\n",
13747c478bd9Sstevel@tonic-gate 			    cmt, esp->buffer, (uint_t)esp->severity);
13757c478bd9Sstevel@tonic-gate 	}
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate static void
thr_collect(void * arg,char * devpath)13797c478bd9Sstevel@tonic-gate thr_collect(void *arg, char *devpath)
13807c478bd9Sstevel@tonic-gate {
13817c478bd9Sstevel@tonic-gate 	int fd;
13827c478bd9Sstevel@tonic-gate 	struct collector_def *hi = (struct collector_def *)arg;
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	msg(4, "thr_collect: collecting %s inst %d rn %d at = 0x%x.\n",
13857c478bd9Sstevel@tonic-gate 	    hi->ed.name, hi->ed.instance,
13867c478bd9Sstevel@tonic-gate 	    hi->ed.rnumber, hi->ed.access_type);
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	if ((fd = open(BOFI_DEV, O_RDWR)) == -1) {
13897c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN)
13907c478bd9Sstevel@tonic-gate 			msg(0, "Too many instances of bofi currently open\n");
13917c478bd9Sstevel@tonic-gate 		else
13927c478bd9Sstevel@tonic-gate 			msg(0, "Error while opening bofi driver: %s",
13937c478bd9Sstevel@tonic-gate 			    strerror(errno));
13947c478bd9Sstevel@tonic-gate 	} else {
13957c478bd9Sstevel@tonic-gate 		/*
13967c478bd9Sstevel@tonic-gate 		 * Activate the logging errdefs - then collect the results.
13977c478bd9Sstevel@tonic-gate 		 */
13987c478bd9Sstevel@tonic-gate 		(void) manage_instance(fd, hi->ed.name,
13997c478bd9Sstevel@tonic-gate 		    hi->ed.instance, BOFI_START);
14007c478bd9Sstevel@tonic-gate 		collect_state(fd, BOFI_CHK_STATE_W, &hi->es, &hi->ed, devpath);
14017c478bd9Sstevel@tonic-gate 	}
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	/*
14047c478bd9Sstevel@tonic-gate 	 * there is no more work to do on this access handle so clean up / exit.
14057c478bd9Sstevel@tonic-gate 	 */
14067c478bd9Sstevel@tonic-gate 	msg(3, "thr_collect: closing and broadcasting.\n");
14077c478bd9Sstevel@tonic-gate 	exit(0);
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate /*
14117c478bd9Sstevel@tonic-gate  * Given an access handle known to the bofi driver see if the user has
14127c478bd9Sstevel@tonic-gate  * specified access criteria that match that handle. Note: this matching
14137c478bd9Sstevel@tonic-gate  * algorithm should be kept consistent with the drivers alogorithm.
14147c478bd9Sstevel@tonic-gate  */
14157c478bd9Sstevel@tonic-gate static int
match_hinfo(struct handle_info * hp,int instance,uint_t access_type,int rnumber,offset_t offset,offset_t len)14167c478bd9Sstevel@tonic-gate match_hinfo(struct handle_info *hp, int instance, uint_t access_type,
14170afbf539SToomas Soome     int rnumber, offset_t offset, offset_t len)
14187c478bd9Sstevel@tonic-gate {
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	msg(9, "matching (%d %d) 0x%x %d offset (%llx, %llx) len (%llx %llx)\n",
14217c478bd9Sstevel@tonic-gate 	    hp->instance, instance, access_type, rnumber,
14227c478bd9Sstevel@tonic-gate 	    hp->offset, offset, hp->len, len);
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	if (instance != -1 && hp->instance != instance)
14257c478bd9Sstevel@tonic-gate 		return (0);
14267c478bd9Sstevel@tonic-gate 	if ((access_type & BOFI_DMA_RW) &&
14277c478bd9Sstevel@tonic-gate 	    (hp->access_type & BOFI_DMA_RW) &&
1428e5ba14ffSstephh 	    (rnumber == -1 || hp->rnumber == rnumber))
14297c478bd9Sstevel@tonic-gate 		return (1);
14307c478bd9Sstevel@tonic-gate 	else if ((access_type & BOFI_INTR) &&
14317c478bd9Sstevel@tonic-gate 	    (hp->access_type & BOFI_INTR))
14327c478bd9Sstevel@tonic-gate 		return (1);
14337c478bd9Sstevel@tonic-gate 	else if ((access_type & BOFI_PIO_RW) &&
14347c478bd9Sstevel@tonic-gate 	    (hp->access_type & BOFI_PIO_RW) &&
14357c478bd9Sstevel@tonic-gate 	    (rnumber == -1 || hp->rnumber == rnumber) &&
14367c478bd9Sstevel@tonic-gate 	    (len == 0 || hp->offset < offset + len) &&
14377c478bd9Sstevel@tonic-gate 	    (hp->len == 0 || hp->offset + hp->len > offset))
14387c478bd9Sstevel@tonic-gate 		return (1);
14397c478bd9Sstevel@tonic-gate 	else
14407c478bd9Sstevel@tonic-gate 		return (0);
14417c478bd9Sstevel@tonic-gate }
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate /*
14447c478bd9Sstevel@tonic-gate  * Obtain all the handles created by the driver specified by the name parameter
14457c478bd9Sstevel@tonic-gate  * that match the remaining arguments. The output parameter nhdls indicates how
14467c478bd9Sstevel@tonic-gate  * many of the structures pointed to by the output parameter hip match the
14477c478bd9Sstevel@tonic-gate  * specification.
14487c478bd9Sstevel@tonic-gate  *
14497c478bd9Sstevel@tonic-gate  * It is the responsibility of the caller to free *hip when *nhdls != 0.
14507c478bd9Sstevel@tonic-gate  */
14517c478bd9Sstevel@tonic-gate static int
get_hinfo(int fd,char * name,struct handle_info ** hip,size_t * nhdls,int instance,int atype,int rset,offset_t offset,offset_t len,int new_semantics)14527c478bd9Sstevel@tonic-gate get_hinfo(int fd, char *name, struct handle_info **hip, size_t *nhdls,
14537c478bd9Sstevel@tonic-gate     int instance, int atype, int rset, offset_t offset, offset_t len,
14547c478bd9Sstevel@tonic-gate     int new_semantics)
14557c478bd9Sstevel@tonic-gate {
14567c478bd9Sstevel@tonic-gate 	struct bofi_get_hdl_info hdli;
14577c478bd9Sstevel@tonic-gate 	int command;
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	command = BOFI_GET_HANDLE_INFO;
14607c478bd9Sstevel@tonic-gate 	hdli.namesize = strlen(name);
14617c478bd9Sstevel@tonic-gate 	(void) strncpy(hdli.name, name, MAXNAMELEN);
14627c478bd9Sstevel@tonic-gate 	/*
14637c478bd9Sstevel@tonic-gate 	 * Initially ask for the number of access handles (not the structures)
14647c478bd9Sstevel@tonic-gate 	 * in order to allocate memory
14657c478bd9Sstevel@tonic-gate 	 */
14667c478bd9Sstevel@tonic-gate 	hdli.hdli = 0;
14677c478bd9Sstevel@tonic-gate 	*hip = 0;
14687c478bd9Sstevel@tonic-gate 	hdli.count = 0;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	/*
14717c478bd9Sstevel@tonic-gate 	 * Ask the bofi driver for all handles created by the driver under test.
14727c478bd9Sstevel@tonic-gate 	 */
14737c478bd9Sstevel@tonic-gate 	if (ioctl(fd, command, &hdli) == -1) {
14747c478bd9Sstevel@tonic-gate 		*nhdls = 0;
14757c478bd9Sstevel@tonic-gate 		msg(0, "driver failed to return handles: %s\n",
14767c478bd9Sstevel@tonic-gate 		    strerror(errno));
14777c478bd9Sstevel@tonic-gate 		return (errno);
14787c478bd9Sstevel@tonic-gate 	} else if ((*nhdls = hdli.count) == 0) {
14797c478bd9Sstevel@tonic-gate 		msg(1, "get_hinfo: no registered handles\n");
14807c478bd9Sstevel@tonic-gate 		return (0);	/* no handles */
14817c478bd9Sstevel@tonic-gate 	} else if ((*hip = GETSTRUCT(struct handle_info, *nhdls)) == 0) {
14827c478bd9Sstevel@tonic-gate 		return (EAGAIN);
14837c478bd9Sstevel@tonic-gate 	} else {
14847c478bd9Sstevel@tonic-gate 		struct handle_info *hp, **chosen;
14857c478bd9Sstevel@tonic-gate 		int i;
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate 		/* Ask for *nhdls handles */
14887c478bd9Sstevel@tonic-gate 		hdli.hdli = (caddr_t)*hip;
14897c478bd9Sstevel@tonic-gate 		if (ioctl(fd, command, &hdli) == -1) {
14907c478bd9Sstevel@tonic-gate 			int err = errno;
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 			msg(0, "BOFI_GET_HANDLE_INFO ioctl returned error %d\n",
14937c478bd9Sstevel@tonic-gate 			    err);
14947c478bd9Sstevel@tonic-gate 			free(*hip);
14957c478bd9Sstevel@tonic-gate 			return (err);
14967c478bd9Sstevel@tonic-gate 		}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 		if (hdli.count < *nhdls)
14997c478bd9Sstevel@tonic-gate 			*nhdls = hdli.count; /* some handles have gone away */
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 		msg(4, "qsorting %d handles\n", *nhdls);
15027c478bd9Sstevel@tonic-gate 		if (*nhdls > 1)
15037c478bd9Sstevel@tonic-gate 			/* sort them naturally (NB ordering is not mandatory) */
15047c478bd9Sstevel@tonic-gate 			qsort((void *)*hip, *nhdls, sizeof (**hip), hdl_cmp);
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 		if ((chosen = malloc(sizeof (hp) * *nhdls)) != NULL) {
15077c478bd9Sstevel@tonic-gate 			struct handle_info **ip;
15087c478bd9Sstevel@tonic-gate 			/* the selected handles */
15097c478bd9Sstevel@tonic-gate 			struct handle_info *prev = 0;
15107c478bd9Sstevel@tonic-gate 			int scnt = 0;
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 			for (i = 0, hp = *hip, ip = chosen; i < *nhdls;
15137c478bd9Sstevel@tonic-gate 			    i++, hp++) {
15147c478bd9Sstevel@tonic-gate 				/*
15157c478bd9Sstevel@tonic-gate 				 * Remark: unbound handles never match
15167c478bd9Sstevel@tonic-gate 				 * (access_type == 0)
15177c478bd9Sstevel@tonic-gate 				 */
15187c478bd9Sstevel@tonic-gate 				if (match_hinfo(hp, instance, atype, rset,
15197c478bd9Sstevel@tonic-gate 				    offset&0x7fffffff, len&0x7fffffff)) {
15207c478bd9Sstevel@tonic-gate 					msg(3, "match: 0x%x 0x%llx 0x%llx"
15217c478bd9Sstevel@tonic-gate 					    " 0x%llx (0x%llx)\n",
15227c478bd9Sstevel@tonic-gate 					    hp->access_type, hp->addr_cookie,
15237c478bd9Sstevel@tonic-gate 					    hp->offset, hp->len,
15247c478bd9Sstevel@tonic-gate 					    (hp->len & 0x7fffffff));
15257c478bd9Sstevel@tonic-gate 					if (prev &&
15267c478bd9Sstevel@tonic-gate 					    (prev->access_type & BOFI_DMA_RW) &&
15277c478bd9Sstevel@tonic-gate 					    (hp->access_type & BOFI_DMA_RW) &&
15287c478bd9Sstevel@tonic-gate 					    hp->instance == prev->instance &&
15297c478bd9Sstevel@tonic-gate 					    hp->len == prev->len &&
15307c478bd9Sstevel@tonic-gate 					    hp->addr_cookie ==
15317c478bd9Sstevel@tonic-gate 					    prev->addr_cookie)
15327c478bd9Sstevel@tonic-gate 						continue;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 					if ((hp->access_type & BOFI_DMA_RW) &&
15357c478bd9Sstevel@tonic-gate 					    (atype & BOFI_DMA_RW) !=
15367c478bd9Sstevel@tonic-gate 					    hp->access_type)
15377c478bd9Sstevel@tonic-gate 						if (new_semantics)
15387c478bd9Sstevel@tonic-gate 							continue;
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 					if (prev)
15417c478bd9Sstevel@tonic-gate 						msg(3, "match_hinfo: match:"
15427c478bd9Sstevel@tonic-gate 						    " 0x%llx (%d %d) (%d %d)"
15437c478bd9Sstevel@tonic-gate 						    " (0x%x 0x%x) (0x%llx,"
15447c478bd9Sstevel@tonic-gate 						    " 0x%llx)\n",
15457c478bd9Sstevel@tonic-gate 						    hp->addr_cookie,
15467c478bd9Sstevel@tonic-gate 						    prev->instance,
15477c478bd9Sstevel@tonic-gate 						    hp->instance, prev->rnumber,
15487c478bd9Sstevel@tonic-gate 						    hp->rnumber,
15497c478bd9Sstevel@tonic-gate 						    prev->access_type,
15507c478bd9Sstevel@tonic-gate 						    hp->access_type, prev->len,
15517c478bd9Sstevel@tonic-gate 						    hp->len);
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 					/* it matches so remember it */
15547c478bd9Sstevel@tonic-gate 					prev = *ip++ = hp;
15557c478bd9Sstevel@tonic-gate 					scnt += 1;
15567c478bd9Sstevel@tonic-gate 				}
15577c478bd9Sstevel@tonic-gate 			}
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 			if (*nhdls != scnt) {
15607c478bd9Sstevel@tonic-gate 				/*
15617c478bd9Sstevel@tonic-gate 				 * Reuse the alloc'ed memory to return
15627c478bd9Sstevel@tonic-gate 				 * only those handles the user has asked for.
15637c478bd9Sstevel@tonic-gate 				 * But first prune the handles to get rid of
15647c478bd9Sstevel@tonic-gate 				 * overlapping ranges (they are ordered by
15657c478bd9Sstevel@tonic-gate 				 * offset and length).
15667c478bd9Sstevel@tonic-gate 				 */
15677c478bd9Sstevel@tonic-gate 				*nhdls = scnt;
15687c478bd9Sstevel@tonic-gate 				for (i = 0, hp = *hip, ip = chosen; i < scnt;
15697c478bd9Sstevel@tonic-gate 				    i++, ip++, hp++)
15707c478bd9Sstevel@tonic-gate 					if (hp != *ip)
15717c478bd9Sstevel@tonic-gate 						(void) memcpy(hp, *ip,
15727c478bd9Sstevel@tonic-gate 						    sizeof (*hp));
15737c478bd9Sstevel@tonic-gate 			}
15747c478bd9Sstevel@tonic-gate 			free(chosen);
15757c478bd9Sstevel@tonic-gate 		}
15767c478bd9Sstevel@tonic-gate 
15777c478bd9Sstevel@tonic-gate 		for (i = 0, hp = *hip; i < *nhdls; i++, hp++) {
15787c478bd9Sstevel@tonic-gate 			msg(4, "\t%d 0x%x %d 0x%llx 0x%llx 0x%llx\n",
15797c478bd9Sstevel@tonic-gate 			    hp->instance, hp->access_type, hp->rnumber,
15807c478bd9Sstevel@tonic-gate 			    hp->len, hp->offset, hp->addr_cookie);
15817c478bd9Sstevel@tonic-gate 		}
15827c478bd9Sstevel@tonic-gate 	}
15837c478bd9Sstevel@tonic-gate 	if (*nhdls == 0 && *hip)
15847c478bd9Sstevel@tonic-gate 		free(*hip);
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	msg(4, "get_info: %s got %d handles\n", name, *nhdls);
15877c478bd9Sstevel@tonic-gate 	return (0);
15887c478bd9Sstevel@tonic-gate }
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate static void
init_sigs()15917c478bd9Sstevel@tonic-gate init_sigs()
15927c478bd9Sstevel@tonic-gate {
15937c478bd9Sstevel@tonic-gate 	struct sigaction sa;
15947c478bd9Sstevel@tonic-gate 	int *ip, sigs[] = {SIGINT, SIGTERM, 0};
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	sa.sa_handler = kill_sighandler;
15977c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sa.sa_mask);
15987c478bd9Sstevel@tonic-gate 	for (ip = sigs; *ip; ip++)
15997c478bd9Sstevel@tonic-gate 		(void) sigaddset(&sa.sa_mask, *ip);
16007c478bd9Sstevel@tonic-gate 	sa.sa_flags = 0;
16017c478bd9Sstevel@tonic-gate 	for (ip = sigs; *ip; ip++)
16027c478bd9Sstevel@tonic-gate 		(void) sigaction(*ip, &sa, NULL);
16037c478bd9Sstevel@tonic-gate }
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate static void
up_resources()16067c478bd9Sstevel@tonic-gate up_resources()
16077c478bd9Sstevel@tonic-gate {
16087c478bd9Sstevel@tonic-gate 	struct rlimit rl;
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	/* Potentially hungry on resources so up them all to their maximums */
16117c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
16127c478bd9Sstevel@tonic-gate 		msg(0, "failed to obtain RLIMIT_NOFILE: %s\n", strerror(errno));
16137c478bd9Sstevel@tonic-gate 	else {
16147c478bd9Sstevel@tonic-gate 		msg(12, "RLIMIT_NOFILE\t %lu (%lu)\n",
16157c478bd9Sstevel@tonic-gate 		    rl.rlim_cur, rl.rlim_max);
16167c478bd9Sstevel@tonic-gate 		rl.rlim_cur = rl.rlim_max;
16177c478bd9Sstevel@tonic-gate 		if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
16187c478bd9Sstevel@tonic-gate 			msg(0, "failed to set RLIMIT_NOFILE: %s\n",
16197c478bd9Sstevel@tonic-gate 			    strerror(errno));
1620004388ebScasper 		(void) enable_extended_FILE_stdio(-1, -1);
16217c478bd9Sstevel@tonic-gate 	}
16227c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_DATA, &rl) < 0)
16237c478bd9Sstevel@tonic-gate 		msg(0, "failed to obtain RLIMIT_DATA: %s\n", strerror(errno));
16247c478bd9Sstevel@tonic-gate 	else {
16257c478bd9Sstevel@tonic-gate 		msg(12, "RLIMIT_DATA\t %lu (%lu)\n", rl.rlim_cur, rl.rlim_max);
16267c478bd9Sstevel@tonic-gate 		rl.rlim_cur = rl.rlim_max;
16277c478bd9Sstevel@tonic-gate 		if (setrlimit(RLIMIT_DATA, &rl) < 0)
16287c478bd9Sstevel@tonic-gate 			msg(0, "failed to set RLIMIT_DATA: %s\n",
16297c478bd9Sstevel@tonic-gate 			    strerror(errno));
16307c478bd9Sstevel@tonic-gate 	}
16317c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_FSIZE, &rl) < 0)
16327c478bd9Sstevel@tonic-gate 		msg(0, "failed to obtain RLIMIT_FSIZE: %s\n", strerror(errno));
16337c478bd9Sstevel@tonic-gate 	else {
16347c478bd9Sstevel@tonic-gate 		msg(12, "RLIMIT_FSIZE\t %lu (%lu)\n", rl.rlim_cur, rl.rlim_max);
16357c478bd9Sstevel@tonic-gate 		rl.rlim_cur = rl.rlim_max;
16367c478bd9Sstevel@tonic-gate 		if (setrlimit(RLIMIT_FSIZE, &rl) < 0)
16377c478bd9Sstevel@tonic-gate 			msg(0, "failed to set RLIMIT_FSIZE: %s\n",
16387c478bd9Sstevel@tonic-gate 			    strerror(errno));
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate static FILE *
create_test_file(char * drvname)16437c478bd9Sstevel@tonic-gate create_test_file(char *drvname)
16447c478bd9Sstevel@tonic-gate {
16457c478bd9Sstevel@tonic-gate 	char dirname[_POSIX_PATH_MAX];
16467c478bd9Sstevel@tonic-gate 	char testname[_POSIX_PATH_MAX];
16477c478bd9Sstevel@tonic-gate 	FILE *fp = 0;
16487c478bd9Sstevel@tonic-gate 	time_t utc = time(NULL);
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	if (snprintf(dirname, sizeof (dirname), "%s.test.%lu",
16517c478bd9Sstevel@tonic-gate 	    drvname, utc) == -1 ||
16527c478bd9Sstevel@tonic-gate 	    snprintf(testname, sizeof (testname), "%s.test.%lu",
16537c478bd9Sstevel@tonic-gate 	    drvname, utc) == -1)
16547c478bd9Sstevel@tonic-gate 		return (0);
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IROTH)) {
16577c478bd9Sstevel@tonic-gate 		msg(0, "Error creating %s: %s\n", dirname, strerror(errno));
16587c478bd9Sstevel@tonic-gate 		return (0);
16597c478bd9Sstevel@tonic-gate 	}
16607c478bd9Sstevel@tonic-gate 	if (chdir(dirname)) {
16617c478bd9Sstevel@tonic-gate 		(void) rmdir(dirname);
16627c478bd9Sstevel@tonic-gate 		return (0);
16637c478bd9Sstevel@tonic-gate 	}
16647c478bd9Sstevel@tonic-gate 	if ((fp = fopen(testname, "w")) == 0)
16657c478bd9Sstevel@tonic-gate 		return (0);	/* leave created directory intact */
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 	return (fp);
16687c478bd9Sstevel@tonic-gate }
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate struct walk_arg {
16717c478bd9Sstevel@tonic-gate 	char *path;
16727c478bd9Sstevel@tonic-gate 	int instance;
16737c478bd9Sstevel@tonic-gate 	char name[MAXPATHLEN];
16747c478bd9Sstevel@tonic-gate 	int pathlen;
16757c478bd9Sstevel@tonic-gate };
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate static int
walk_callback(di_node_t node,void * arg)16787c478bd9Sstevel@tonic-gate walk_callback(di_node_t node, void *arg)
16797c478bd9Sstevel@tonic-gate {
16807c478bd9Sstevel@tonic-gate 	struct walk_arg *warg = (struct walk_arg *)arg;
16817c478bd9Sstevel@tonic-gate 	char *driver_name;
16827c478bd9Sstevel@tonic-gate 	char *path;
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	driver_name = di_driver_name(node);
16857c478bd9Sstevel@tonic-gate 	if (driver_name != NULL) {
16860afbf539SToomas Soome 		if (strcmp(driver_name, warg->name) == 0 &&
16877c478bd9Sstevel@tonic-gate 		    di_instance(node) == warg->instance) {
16887c478bd9Sstevel@tonic-gate 			path = di_devfs_path(node);
16897c478bd9Sstevel@tonic-gate 			if (path == NULL)
16907c478bd9Sstevel@tonic-gate 				warg->path = NULL;
16917c478bd9Sstevel@tonic-gate 			else
16927c478bd9Sstevel@tonic-gate 				(void) strncpy(warg->path, path, warg->pathlen);
16937c478bd9Sstevel@tonic-gate 			return (DI_WALK_TERMINATE);
16947c478bd9Sstevel@tonic-gate 		}
16957c478bd9Sstevel@tonic-gate 	}
16967c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
16977c478bd9Sstevel@tonic-gate }
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate static int
getpath(char * path,int instance,char * name,int pathlen)17007c478bd9Sstevel@tonic-gate getpath(char *path, int instance, char *name, int pathlen)
17017c478bd9Sstevel@tonic-gate {
17027c478bd9Sstevel@tonic-gate 	di_node_t node;
17037c478bd9Sstevel@tonic-gate 	struct walk_arg warg;
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	warg.instance = instance;
17067c478bd9Sstevel@tonic-gate 	(void) strncpy(warg.name, name, MAXPATHLEN);
17077c478bd9Sstevel@tonic-gate 	warg.path = path;
17087c478bd9Sstevel@tonic-gate 	warg.pathlen = pathlen;
17097c478bd9Sstevel@tonic-gate 	if ((node = di_init("/", DINFOSUBTREE)) == DI_NODE_NIL)
17107c478bd9Sstevel@tonic-gate 		return (-1);
17117c478bd9Sstevel@tonic-gate 	if (di_walk_node(node, DI_WALK_CLDFIRST, &warg, walk_callback) == -1) {
17127c478bd9Sstevel@tonic-gate 		di_fini(node);
17137c478bd9Sstevel@tonic-gate 		return (-1);
17147c478bd9Sstevel@tonic-gate 	}
17157c478bd9Sstevel@tonic-gate 	if (warg.path == NULL) {
17167c478bd9Sstevel@tonic-gate 		di_fini(node);
17177c478bd9Sstevel@tonic-gate 		return (-1);
17187c478bd9Sstevel@tonic-gate 	}
17197c478bd9Sstevel@tonic-gate 	di_fini(node);
17207c478bd9Sstevel@tonic-gate 	return (0);
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate /*
17247c478bd9Sstevel@tonic-gate  * Record logsize h/w accesses of type 'edp->access_type' made by instance
17257c478bd9Sstevel@tonic-gate  * 'edp->instance' of driver 'edp->name' to the register set (or dma handle)
17267c478bd9Sstevel@tonic-gate  * 'edp->rnumber' that lie within the range 'edp->offset' to
17277c478bd9Sstevel@tonic-gate  * 'edp->offset' + 'edp->len'.
17287c478bd9Sstevel@tonic-gate  * Access criteria may be mixed and matched:
17297c478bd9Sstevel@tonic-gate  * -	access types may be combined (PIO read/write, DMA read write or intrs);
17307c478bd9Sstevel@tonic-gate  * -	if 'edp->instance' is -1 all instances are checked for the criteria;
17317c478bd9Sstevel@tonic-gate  * -	if 'edp->rnumber' is -1 all register sets and dma handles are matched;
17327c478bd9Sstevel@tonic-gate  * -	'offset' and 'len' indicate that only PIO and DMA accesses within the
17337c478bd9Sstevel@tonic-gate  *	range 'edp->offset' to 'edp->len' will be logged. Putting 'edp->offset'
17347c478bd9Sstevel@tonic-gate  *      to zero and 'edp->len' to -1ull gives maximal coverage.
17357c478bd9Sstevel@tonic-gate  *
17367c478bd9Sstevel@tonic-gate  * 'collecttime' is the number of seconds used to log accesses
17377c478bd9Sstevel@tonic-gate  *		(default is infinity).
17387c478bd9Sstevel@tonic-gate  */
17397c478bd9Sstevel@tonic-gate static void
test_driver(struct bofi_errdef * edp,unsigned long long collecttime)17407c478bd9Sstevel@tonic-gate test_driver(struct bofi_errdef *edp,
17410afbf539SToomas Soome     unsigned long long collecttime)
17427c478bd9Sstevel@tonic-gate {
17437c478bd9Sstevel@tonic-gate 	pid_t pid;
17447c478bd9Sstevel@tonic-gate 	int statloc;
17457c478bd9Sstevel@tonic-gate 	struct collector_def *cdefs, *cdp;
17467c478bd9Sstevel@tonic-gate 	struct handle_info *hdls, *hdl;
17477c478bd9Sstevel@tonic-gate 	int i, fd;
17487c478bd9Sstevel@tonic-gate 	size_t cnt;
17497c478bd9Sstevel@tonic-gate 	size_t nchildren;
17507c478bd9Sstevel@tonic-gate 	unsigned long long timechunk;
17517c478bd9Sstevel@tonic-gate 	FILE *sfp;	/* generated control test file */
17527c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
17537c478bd9Sstevel@tonic-gate 	char devpath[MAXPATHLEN];
17547c478bd9Sstevel@tonic-gate 	char *devpathp = "NULL";
17557c478bd9Sstevel@tonic-gate 	int drv_inst;
17567c478bd9Sstevel@tonic-gate 	int got_it = 0;
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	char *name = (char *)edp->name;
17597c478bd9Sstevel@tonic-gate 	uint_t logsize = edp->access_count + edp->fail_count - 1;
17607c478bd9Sstevel@tonic-gate 	int inst = edp->instance;
17617c478bd9Sstevel@tonic-gate 	uint_t atype = edp->access_type;
17627c478bd9Sstevel@tonic-gate 	int rset = edp->rnumber;
17637c478bd9Sstevel@tonic-gate 	offset_t offset = edp->offset;
17647c478bd9Sstevel@tonic-gate 	offset_t len = edp->len;
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 	msg(4, "test_driver: %s %d inst %d 0x%x rset %d %llx %llx\n",
17677c478bd9Sstevel@tonic-gate 	    name, logsize, inst, atype, rset, offset, len);
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	drv_inst = inst;
17707c478bd9Sstevel@tonic-gate 	if (getpath(devpath, inst, name, MAXPATHLEN) != -1) {
17717c478bd9Sstevel@tonic-gate 		devpathp = devpath;
17727c478bd9Sstevel@tonic-gate 		got_it = 1;
17737c478bd9Sstevel@tonic-gate 	}
17747c478bd9Sstevel@tonic-gate 	if (logsize == -1U)
17757c478bd9Sstevel@tonic-gate 		logsize = 0;
17767c478bd9Sstevel@tonic-gate 	fd = open(BOFI_DEV, O_RDWR);
17777c478bd9Sstevel@tonic-gate 	if (fd == -1) {
17787c478bd9Sstevel@tonic-gate 		perror("get_hdl_info - bad open of bofi driver");
17797c478bd9Sstevel@tonic-gate 		return;
17807c478bd9Sstevel@tonic-gate 	}
17817c478bd9Sstevel@tonic-gate 	if (got_it) {
17827c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf),
17837c478bd9Sstevel@tonic-gate 		    "th_manage /devices%s offline", devpathp);
17847c478bd9Sstevel@tonic-gate 		(void) system(buf);
17857c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf),
17867c478bd9Sstevel@tonic-gate 		    "th_manage /devices%s online", devpathp);
17877c478bd9Sstevel@tonic-gate 		(void) system(buf);
17887c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf),
17897c478bd9Sstevel@tonic-gate 		    "th_manage /devices%s getstate >/dev/null", devpathp);
17907c478bd9Sstevel@tonic-gate 		(void) system(buf);
17917c478bd9Sstevel@tonic-gate 	}
17927c478bd9Sstevel@tonic-gate 	if (get_hinfo(fd, name, &hdls, &cnt,
17937c478bd9Sstevel@tonic-gate 	    inst, atype, rset, offset, len, 1) != 0) {
17947c478bd9Sstevel@tonic-gate 		msg(0, "driver_test: bad get_info for %d hdls\n", cnt);
17957c478bd9Sstevel@tonic-gate 		return;
17967c478bd9Sstevel@tonic-gate 	} else if (logsize == 0 || collecttime == 0 || cnt == 0) {
17977c478bd9Sstevel@tonic-gate 		if (cnt == 0)
17987c478bd9Sstevel@tonic-gate 			msg(1, "No matching handles.\n");
17997c478bd9Sstevel@tonic-gate 		return;
18007c478bd9Sstevel@tonic-gate 	}
18017c478bd9Sstevel@tonic-gate 	if ((cdefs = GETSTRUCT(struct collector_def, cnt)) == 0) {
18027c478bd9Sstevel@tonic-gate 		msg(0, "driver_test: can't get memory for %d cdefs\n", cnt);
18037c478bd9Sstevel@tonic-gate 		return;
18047c478bd9Sstevel@tonic-gate 	}
18057c478bd9Sstevel@tonic-gate 	up_resources();
18067c478bd9Sstevel@tonic-gate 	if (got_it) {
18077c478bd9Sstevel@tonic-gate 		if (scriptargs > 0) {
18087c478bd9Sstevel@tonic-gate 			(void) snprintf(buf, sizeof (buf),
18097c478bd9Sstevel@tonic-gate 			    "DRIVER_PATH=/devices%s DRIVER_INSTANCE=%d"
18107c478bd9Sstevel@tonic-gate 			    " DRIVER_UNCONFIGURE=0 DRIVER_CONFIGURE=1",
18117c478bd9Sstevel@tonic-gate 			    devpathp, drv_inst);
18127c478bd9Sstevel@tonic-gate 			for (i = 0; i < scriptargs; i++) {
18137c478bd9Sstevel@tonic-gate 				(void) strcat(buf, " ");
18147c478bd9Sstevel@tonic-gate 				(void) strcat(buf, fixup_script[i]);
18157c478bd9Sstevel@tonic-gate 			}
18167c478bd9Sstevel@tonic-gate 			(void) strcat(buf, " &");
18177c478bd9Sstevel@tonic-gate 		} else {
18187c478bd9Sstevel@tonic-gate 			(void) snprintf(buf, sizeof (buf),
18197c478bd9Sstevel@tonic-gate 			    "while : ; do th_manage /devices%s online;"
18207c478bd9Sstevel@tonic-gate 			    " th_manage /devices%s getstate >/dev/null;"
18217c478bd9Sstevel@tonic-gate 			    " th_manage /devices%s offline;done &"
18227c478bd9Sstevel@tonic-gate 			    " echo $! >/tmp/bofi.pid",
18237c478bd9Sstevel@tonic-gate 			    devpathp, devpathp, devpathp);
18247c478bd9Sstevel@tonic-gate 		}
18257c478bd9Sstevel@tonic-gate 		(void) system(buf);
18267c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "sleep %d",
18277c478bd9Sstevel@tonic-gate 		    edef_sleep ? edef_sleep : DEFAULT_EDEF_SLEEP);
18287c478bd9Sstevel@tonic-gate 		(void) system(buf);
18297c478bd9Sstevel@tonic-gate 	}
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	(void) fprintf(outfile,
18327c478bd9Sstevel@tonic-gate 	    "Logging accesses to instances ");
18337c478bd9Sstevel@tonic-gate 	for (i = 0, inst = -1, hdl = hdls; i < cnt;
18347c478bd9Sstevel@tonic-gate 	    i++, hdl++) {
18357c478bd9Sstevel@tonic-gate 		if (inst != hdl->instance) {
18367c478bd9Sstevel@tonic-gate 			inst = hdl->instance;
18377c478bd9Sstevel@tonic-gate 			(void) fprintf(outfile, "%d ", inst);
18387c478bd9Sstevel@tonic-gate 		}
18397c478bd9Sstevel@tonic-gate 	}
18407c478bd9Sstevel@tonic-gate 	(void) fprintf(outfile, " (%d logs of size 0x%x).\n\t"
18417c478bd9Sstevel@tonic-gate 	    "(Use th_manage ... clear_errdefs to terminate"
18427c478bd9Sstevel@tonic-gate 	    " logging)\n", cnt, logsize);
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 	sfp = create_test_file(name);
18457c478bd9Sstevel@tonic-gate 	/*
18467c478bd9Sstevel@tonic-gate 	 * Install a logging errdef for each matching handle,
18477c478bd9Sstevel@tonic-gate 	 * and then create a child to collect the log.
18487c478bd9Sstevel@tonic-gate 	 * The child is responsible for activating the log.
18497c478bd9Sstevel@tonic-gate 	 */
18507c478bd9Sstevel@tonic-gate 	for (i = 0, cdp = cdefs, hdl = hdls, nchildren = 0;
18517c478bd9Sstevel@tonic-gate 	    i < cnt; i++, cdp++, hdl++) {
18527c478bd9Sstevel@tonic-gate 		if (add_edef(fd, &cdp->ed, &cdp->es, hdl, edp) != 0) {
18537c478bd9Sstevel@tonic-gate 			cdp->lp = 0;
18547c478bd9Sstevel@tonic-gate 			cdp->pid = 0;
18557c478bd9Sstevel@tonic-gate 		} else {
18567c478bd9Sstevel@tonic-gate 			cdp->lp = (void *)cdp->ed.log.logbase;
18577c478bd9Sstevel@tonic-gate 			msg(1, "test_driver: thr_create:"
18587c478bd9Sstevel@tonic-gate 			    " lsize 0x%x 0x%x at 0x%x\n",
18597c478bd9Sstevel@tonic-gate 			    cdp->es.log.logsize,
18607c478bd9Sstevel@tonic-gate 			    cdp->ed.log.logsize,
18617c478bd9Sstevel@tonic-gate 			    cdp->ed.access_type);
18627c478bd9Sstevel@tonic-gate 			if ((pid = fork()) == -1) {
18637c478bd9Sstevel@tonic-gate 				msg(0, "fork failed for handle"
18647c478bd9Sstevel@tonic-gate 				    " %d: %s\n", i, strerror(errno));
18657c478bd9Sstevel@tonic-gate 				cdp->pid = 0;	/* ignore */
18667c478bd9Sstevel@tonic-gate 			} else if (pid == 0) {
18677c478bd9Sstevel@tonic-gate 				thr_collect(cdp, devpathp);
18687c478bd9Sstevel@tonic-gate 			} else {
18697c478bd9Sstevel@tonic-gate 				cdp->pid = pid;
18707c478bd9Sstevel@tonic-gate 				nchildren += 1;
18717c478bd9Sstevel@tonic-gate 			}
18727c478bd9Sstevel@tonic-gate 		}
18737c478bd9Sstevel@tonic-gate 	}
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	if (nchildren != 0) {
18767c478bd9Sstevel@tonic-gate 		if (sfp) {
18777c478bd9Sstevel@tonic-gate 			(void) fprintf(sfp, "#!/bin/ksh -p\n\n");
18787c478bd9Sstevel@tonic-gate 			(void) fprintf(sfp,
18797c478bd9Sstevel@tonic-gate 			    "\n# Test control script generated using:\n#");
18807c478bd9Sstevel@tonic-gate 			for (i = 0; i < pargc; i++)
18817c478bd9Sstevel@tonic-gate 				(void) fprintf(sfp, " %s", pargv[i]);
18827c478bd9Sstevel@tonic-gate 			(void) fprintf(sfp, "\n\n");
18837c478bd9Sstevel@tonic-gate 			(void) fprintf(sfp, "\nrun_tests()\n{\n");
18847c478bd9Sstevel@tonic-gate 			for (i = 0, cdp = cdefs; i < cnt; i++, cdp++)
18857c478bd9Sstevel@tonic-gate 				if (cdp->pid) {
18867c478bd9Sstevel@tonic-gate 					(void) fprintf(sfp,
18877c478bd9Sstevel@tonic-gate 					    "\tif [ -x ./%s.%d ]\n\tthen\n",
18887c478bd9Sstevel@tonic-gate 					    name, (int)cdp->pid);
18897c478bd9Sstevel@tonic-gate 					(void) fprintf(sfp,
18907c478bd9Sstevel@tonic-gate 					    "\t\techo \"Starting test"
18917c478bd9Sstevel@tonic-gate 					    " %d (id %d)\"\n",
18927c478bd9Sstevel@tonic-gate 					    i, (int)cdp->pid);
18937c478bd9Sstevel@tonic-gate 					(void) fprintf(sfp, "\t\t./%s.%d\n",
18947c478bd9Sstevel@tonic-gate 					    name, (int)cdp->pid);
18957c478bd9Sstevel@tonic-gate 					(void) fprintf(sfp, "\t\techo \""
18967c478bd9Sstevel@tonic-gate 					    "Test %d (id %d) complete\"\n",
18977c478bd9Sstevel@tonic-gate 					    i, (int)cdp->pid);
18987c478bd9Sstevel@tonic-gate 					(void) fprintf(sfp, "\tfi\n");
18997c478bd9Sstevel@tonic-gate 				}
19007c478bd9Sstevel@tonic-gate 			(void) fprintf(sfp, "}\n\nrun_tests\n");
19017c478bd9Sstevel@tonic-gate 			if (fchmod(fileno(sfp), S_IRWXU|S_IRGRP|S_IROTH))
19027c478bd9Sstevel@tonic-gate 				msg(0, "fchmod on control script failed: %s\n",
19037c478bd9Sstevel@tonic-gate 				    strerror(errno));
19047c478bd9Sstevel@tonic-gate 			if (fclose(sfp) != 0)
19057c478bd9Sstevel@tonic-gate 				msg(0, "Error closing control script: %s\n",
19067c478bd9Sstevel@tonic-gate 				    strerror(errno));
19077c478bd9Sstevel@tonic-gate 		}
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 		set_handler(SIGALRM);	/* handle it */
19107c478bd9Sstevel@tonic-gate 		/*
19117c478bd9Sstevel@tonic-gate 		 * The user may want to terminate logging before the log fills
19127c478bd9Sstevel@tonic-gate 		 * so use a timer to signal the logging children to handle this
19137c478bd9Sstevel@tonic-gate 		 * case.
19147c478bd9Sstevel@tonic-gate 		 */
19157c478bd9Sstevel@tonic-gate 		timechunk = collecttime / MAXALRMCALL;
19167c478bd9Sstevel@tonic-gate 		collecttime = collecttime - timechunk * MAXALRMCALL;
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 		msg(2, "logging for (0x%llx 0x%llx)\n", timechunk, collecttime);
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 		(void) alarm(collecttime); /* odd bit of collect time */
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 		/* wait for the log to fill or deadline satisfied */
19237c478bd9Sstevel@tonic-gate 		for (;;) {
19247c478bd9Sstevel@tonic-gate 			pid = wait(&statloc);
19257c478bd9Sstevel@tonic-gate 			for (i = 0, nchildren = 0, cdp = cdefs;
19267c478bd9Sstevel@tonic-gate 			    i < cnt; i++, cdp++)
19277c478bd9Sstevel@tonic-gate 				if (cdp->pid == pid)
19287c478bd9Sstevel@tonic-gate 					cdp->pid = 0;
19297c478bd9Sstevel@tonic-gate 			for (i = 0, nchildren = 0, cdp = cdefs;
19307c478bd9Sstevel@tonic-gate 			    i < cnt; i++, cdp++)
19317c478bd9Sstevel@tonic-gate 				if (cdp->pid)
19327c478bd9Sstevel@tonic-gate 					nchildren++;
19337c478bd9Sstevel@tonic-gate 			if (nchildren == 0)
19347c478bd9Sstevel@tonic-gate 				break;
19357c478bd9Sstevel@tonic-gate 			if (killed)
19367c478bd9Sstevel@tonic-gate 				break;
19377c478bd9Sstevel@tonic-gate 			if (alarmed) {
19387c478bd9Sstevel@tonic-gate 				if (timechunk-- > 0) {
19397c478bd9Sstevel@tonic-gate 					/*
19407c478bd9Sstevel@tonic-gate 					 * prepare for the next timeslice by
19417c478bd9Sstevel@tonic-gate 					 * rearming the clock
19427c478bd9Sstevel@tonic-gate 					 */
19437c478bd9Sstevel@tonic-gate 					if (alarm(MAXALRMCALL) == 0)
19447c478bd9Sstevel@tonic-gate 						alarmed = 0;
19457c478bd9Sstevel@tonic-gate 					else {
19467c478bd9Sstevel@tonic-gate 						/*
19477c478bd9Sstevel@tonic-gate 						 * must have been a user abort
19487c478bd9Sstevel@tonic-gate 						 * (via SIGALRM)
19497c478bd9Sstevel@tonic-gate 						 */
19507c478bd9Sstevel@tonic-gate 						(void) alarm(0);
19517c478bd9Sstevel@tonic-gate 						break;
19527c478bd9Sstevel@tonic-gate 					}
19537c478bd9Sstevel@tonic-gate 				} else
19547c478bd9Sstevel@tonic-gate 					break;
19557c478bd9Sstevel@tonic-gate 			}
19567c478bd9Sstevel@tonic-gate 		}
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 		(void) fprintf(outfile, "Logging complete.\n");
19597c478bd9Sstevel@tonic-gate 	}
19607c478bd9Sstevel@tonic-gate 	if (got_it) {
19617c478bd9Sstevel@tonic-gate 		if (scriptargs > 0) {
19627c478bd9Sstevel@tonic-gate 			(void) snprintf(buf, sizeof (buf),
19637c478bd9Sstevel@tonic-gate 			    "DRIVER_PATH=/devices%s DRIVER_INSTANCE=%d"
19647c478bd9Sstevel@tonic-gate 			    " DRIVER_UNCONFIGURE=1 DRIVER_CONFIGURE=0",
19657c478bd9Sstevel@tonic-gate 			    devpathp, drv_inst);
19667c478bd9Sstevel@tonic-gate 			for (i = 0; i < scriptargs; i++) {
19677c478bd9Sstevel@tonic-gate 				(void) strcat(buf, " ");
19687c478bd9Sstevel@tonic-gate 				(void) strcat(buf, fixup_script[i]);
19697c478bd9Sstevel@tonic-gate 			}
19707c478bd9Sstevel@tonic-gate 			(void) system(buf);
19717c478bd9Sstevel@tonic-gate 		} else {
19727c478bd9Sstevel@tonic-gate 			(void) system("kill `cat /tmp/bofi.pid`");
19737c478bd9Sstevel@tonic-gate 		}
19747c478bd9Sstevel@tonic-gate 	}
19757c478bd9Sstevel@tonic-gate 	msg(2, "test_driver: terminating\n");
19767c478bd9Sstevel@tonic-gate }
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate static int
getnameinst(char * orig_path,int * instance,char * name,int namelen)19797c478bd9Sstevel@tonic-gate getnameinst(char *orig_path, int *instance, char *name, int namelen)
19807c478bd9Sstevel@tonic-gate {
19817c478bd9Sstevel@tonic-gate 	di_node_t node;
19827c478bd9Sstevel@tonic-gate 	char *binding_name;
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 	if ((node = di_init(&orig_path[8], DINFOSUBTREE|DINFOMINOR)) ==
19857c478bd9Sstevel@tonic-gate 	    DI_NODE_NIL)
19867c478bd9Sstevel@tonic-gate 		return (-1);
19877c478bd9Sstevel@tonic-gate 	if ((binding_name = di_driver_name(node)) == NULL)
19887c478bd9Sstevel@tonic-gate 		return (-1);
19897c478bd9Sstevel@tonic-gate 	*instance = di_instance(node);
19907c478bd9Sstevel@tonic-gate 	(void) strncpy(name, binding_name, namelen);
19917c478bd9Sstevel@tonic-gate 	di_fini(node);
19927c478bd9Sstevel@tonic-gate 	return (0);
19937c478bd9Sstevel@tonic-gate }
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate static char syntax[] =
19967c478bd9Sstevel@tonic-gate 	"          [ -n name [ -i instance ] | -P path ]\n"
19977c478bd9Sstevel@tonic-gate 	"          [ -a acc_types ] [ -r rnumber ]\n"
19987c478bd9Sstevel@tonic-gate 	"          [ -l offset [ length ] ] [ -c count [ failcount ] ]\n"
19997c478bd9Sstevel@tonic-gate 	"          [ -o operator [ operand ] ] [ -f acc_chk  ]\n"
20007c478bd9Sstevel@tonic-gate 	"          [ -w max_wait_period [ report_interval ] ]\n"
20017c478bd9Sstevel@tonic-gate 	"     or\n"
20027c478bd9Sstevel@tonic-gate 	"          [ -n name [ -i instance ] | -P path ]\n"
20037c478bd9Sstevel@tonic-gate 	"          -a  LOG  [  acc_types ]  [ -r rnumber]\n"
20047c478bd9Sstevel@tonic-gate 	"          [ -l offset [ length ] ] [ -c count [ failcount ] ]\n"
20057c478bd9Sstevel@tonic-gate 	"          [ -s collect_time ] [ -p policy ] [ -x flags ]\n"
20067c478bd9Sstevel@tonic-gate 	"          [ -C ] [-e fixup_script ]\n"
20077c478bd9Sstevel@tonic-gate 	"     or\n"
20087c478bd9Sstevel@tonic-gate 	"          -h";
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])20117c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
20127c478bd9Sstevel@tonic-gate {
20137c478bd9Sstevel@tonic-gate 	extern char *optarg;
20147c478bd9Sstevel@tonic-gate 	extern int optind;
20157c478bd9Sstevel@tonic-gate 
2016*ef150c2bSRichard Lowe 	int	c;		/* for parsing getopts */
20177c478bd9Sstevel@tonic-gate 	int	nopts = 0;	/* for backward compatibility */
20187c478bd9Sstevel@tonic-gate 	int	err = 0;
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	/* use a maximal set of defaults for logging or injecting */
20217c478bd9Sstevel@tonic-gate 	struct bofi_errdef errdef = {
20227c478bd9Sstevel@tonic-gate 		0,		/* length of driver name */
20237c478bd9Sstevel@tonic-gate 		{0},		/* driver name */
20247c478bd9Sstevel@tonic-gate 		-1,		/* monitor all instances */
20257c478bd9Sstevel@tonic-gate 		-1,		/* monitor all register sets and DMA handles */
20267c478bd9Sstevel@tonic-gate 		(offset_t)0,	/* monitor from start of reg. set or DMA hd */
20277c478bd9Sstevel@tonic-gate 		myLLMAX,	/* monitor whole reg set or DMA hdl(no LLMAX) */
20287c478bd9Sstevel@tonic-gate 		0,		/* qualify all */
20297c478bd9Sstevel@tonic-gate 		DFLTLOGSZ,	/* default no. of accesses before corrupting */
20307c478bd9Sstevel@tonic-gate 		0u,		/* default no. of accesses to corrupt */
20317c478bd9Sstevel@tonic-gate 		0u,		/* no check access corruption */
20327c478bd9Sstevel@tonic-gate 		BOFI_NOP,	/* no corruption operator by default */
20337c478bd9Sstevel@tonic-gate 		myULLMAX,	/* default operand */
20347c478bd9Sstevel@tonic-gate 		{0, 0, BOFI_LOG_TIMESTAMP, /* timestamp by default */
20357c478bd9Sstevel@tonic-gate 		0, 0, 0, 0},	/* no logging by default */
20367c478bd9Sstevel@tonic-gate 		0};
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 	/* specify the default no of seconds for which to monitor */
20407c478bd9Sstevel@tonic-gate 	unsigned long long	collecttime = DFLTLOGTIME;
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate 	char	*str;	/* temporary variable */
20437c478bd9Sstevel@tonic-gate 	long	tmpl;	/* another one */
20447c478bd9Sstevel@tonic-gate 	int		i;
20457c478bd9Sstevel@tonic-gate 	uint_t	tmpui;
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN];
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 	Progname = (char *)strrchr(*argv, '/');
20507c478bd9Sstevel@tonic-gate 	Progname = (Progname == NULL) ? *argv : Progname + 1;
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	errfile = stderr;
20537c478bd9Sstevel@tonic-gate 	outfile = stdout;
20547c478bd9Sstevel@tonic-gate 	policy = 0;
20557c478bd9Sstevel@tonic-gate 	lsize_is_default = 1;
20567c478bd9Sstevel@tonic-gate 	pargv = argv;
20577c478bd9Sstevel@tonic-gate 	pargc = argc;
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "a:c:C:dD:e:f:h:i:l:n:o:p:P:r:s:tw:x"))
20607c478bd9Sstevel@tonic-gate 	    != EOF) {
20617c478bd9Sstevel@tonic-gate 		nopts++;
20627c478bd9Sstevel@tonic-gate 		switch (c) {
20637c478bd9Sstevel@tonic-gate 		case 'a':
20647c478bd9Sstevel@tonic-gate 			msg(2, "option a: optarg %s optind %d argc %d\n",
20657c478bd9Sstevel@tonic-gate 			    optarg, optind, argc);
20667c478bd9Sstevel@tonic-gate 			if ((err = str_to_bm(optarg, atypes,
20677c478bd9Sstevel@tonic-gate 			    &errdef.access_type)) == 0)
20687c478bd9Sstevel@tonic-gate 				while (optind < argc && *argv[optind] != '-') {
20697c478bd9Sstevel@tonic-gate 					if ((err = str_to_bm(argv[optind++],
20707c478bd9Sstevel@tonic-gate 					    atypes, &errdef.access_type)))
20717c478bd9Sstevel@tonic-gate 						break;
20727c478bd9Sstevel@tonic-gate 				}
20737c478bd9Sstevel@tonic-gate 			break;
20747c478bd9Sstevel@tonic-gate 		case 'c':
20757c478bd9Sstevel@tonic-gate 			lsize_is_default = 0;
20767c478bd9Sstevel@tonic-gate 			/* zero is valid */
20777c478bd9Sstevel@tonic-gate 			errdef.access_count = strtoul(optarg, &str, 0);
20787c478bd9Sstevel@tonic-gate 			if (str == optarg)
20797c478bd9Sstevel@tonic-gate 				err = EINVAL;
20807c478bd9Sstevel@tonic-gate 			else if (optind < argc && (argv[optind][0] != '-' ||
20817c478bd9Sstevel@tonic-gate 			    (strlen(argv[optind]) > 1 &&
20827c478bd9Sstevel@tonic-gate 			    isdigit(argv[optind][1]))))
20837c478bd9Sstevel@tonic-gate 				errdef.fail_count =
20847c478bd9Sstevel@tonic-gate 				    strtoull(argv[optind++], 0, 0);
20857c478bd9Sstevel@tonic-gate 			break;
20867c478bd9Sstevel@tonic-gate 		case 'C':
20877c478bd9Sstevel@tonic-gate 			user_comment = optarg;
20887c478bd9Sstevel@tonic-gate 			if (optind < argc && argv[optind][0] != '-')
20897c478bd9Sstevel@tonic-gate 				err = EINVAL;
20907c478bd9Sstevel@tonic-gate 			break;
20917c478bd9Sstevel@tonic-gate 		case 'D':
20927c478bd9Sstevel@tonic-gate 			dbglvl = strtoul(optarg, &str, 0);
20937c478bd9Sstevel@tonic-gate 			break;
20947c478bd9Sstevel@tonic-gate 		case 'e':
20957c478bd9Sstevel@tonic-gate 			fixup_script = 0;
20967c478bd9Sstevel@tonic-gate 			scriptargs = 0;
20977c478bd9Sstevel@tonic-gate 			fixup_script = &argv[optind - 1];
20987c478bd9Sstevel@tonic-gate 			scriptargs += 1;
20997c478bd9Sstevel@tonic-gate 			while (optind < argc) {
21007c478bd9Sstevel@tonic-gate 				optind += 1;
21017c478bd9Sstevel@tonic-gate 				scriptargs += 1;
21027c478bd9Sstevel@tonic-gate 			}
21037c478bd9Sstevel@tonic-gate 			break;
21047c478bd9Sstevel@tonic-gate 		case 'f':
21057c478bd9Sstevel@tonic-gate 			tmpl = strtol(optarg, &str, 0);
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 			if (str != optarg)
21087c478bd9Sstevel@tonic-gate 				errdef.acc_chk = tmpl;
21090afbf539SToomas Soome 			else if (strcmp(optarg, "PIO") == 0)
21107c478bd9Sstevel@tonic-gate 				errdef.acc_chk = 1;
21110afbf539SToomas Soome 			else if (strcmp(optarg, "DMA") == 0)
21127c478bd9Sstevel@tonic-gate 				errdef.acc_chk = 2;
21130afbf539SToomas Soome 			else if (strcmp(optarg, "U4FT_ACC_NO_PIO") == 0)
21147c478bd9Sstevel@tonic-gate 				errdef.acc_chk = 1;
21150afbf539SToomas Soome 			else if (strcmp(optarg, "U4FT_ACC_NO_DMA") == 0)
21167c478bd9Sstevel@tonic-gate 				errdef.acc_chk = 2;
21177c478bd9Sstevel@tonic-gate 			else
21187c478bd9Sstevel@tonic-gate 				err = EINVAL;
21197c478bd9Sstevel@tonic-gate 			break;
21207c478bd9Sstevel@tonic-gate 		case 'i':
21217c478bd9Sstevel@tonic-gate 			if ((errdef.instance = strtol(optarg, &str, 0)) < 0)
21227c478bd9Sstevel@tonic-gate 				errdef.instance = -1;
21237c478bd9Sstevel@tonic-gate 			else if (str == optarg)
21247c478bd9Sstevel@tonic-gate 				err = EINVAL;
21257c478bd9Sstevel@tonic-gate 			break;
21267c478bd9Sstevel@tonic-gate 		case 'l':
21277c478bd9Sstevel@tonic-gate 			errdef.offset = strtoull(optarg, &str, 0);
21287c478bd9Sstevel@tonic-gate 			if (str == optarg)
21297c478bd9Sstevel@tonic-gate 				err = EINVAL;
21307c478bd9Sstevel@tonic-gate 			else if (optind < argc &&
21317c478bd9Sstevel@tonic-gate 			    (argv[optind][0] != '-' ||
21327c478bd9Sstevel@tonic-gate 			    (strlen(argv[optind]) > 1 &&
21337c478bd9Sstevel@tonic-gate 			    isdigit(argv[optind][1])))) {
21347c478bd9Sstevel@tonic-gate 				/* -1 indicates the rest of register set */
21357c478bd9Sstevel@tonic-gate 				errdef.len = strtoull(argv[optind++], 0, 0);
21367c478bd9Sstevel@tonic-gate 			}
21377c478bd9Sstevel@tonic-gate 			break;
21387c478bd9Sstevel@tonic-gate 		case 'n':
21397c478bd9Sstevel@tonic-gate 			(void) strncpy(errdef.name, optarg, MAXNAMELEN);
21407c478bd9Sstevel@tonic-gate 			if ((errdef.namesize = strlen(errdef.name)) == 0)
21417c478bd9Sstevel@tonic-gate 				err = EINVAL;
21427c478bd9Sstevel@tonic-gate 			break;
21437c478bd9Sstevel@tonic-gate 		case 'o':
21447c478bd9Sstevel@tonic-gate 			for (i = 0; optypes[i].str != 0; i++)
21457c478bd9Sstevel@tonic-gate 				if (strcmp(optarg, optypes[i].str) == 0) {
21467c478bd9Sstevel@tonic-gate 					errdef.optype = optypes[i].code;
21477c478bd9Sstevel@tonic-gate 					break;
21487c478bd9Sstevel@tonic-gate 				}
21497c478bd9Sstevel@tonic-gate 			if (optypes[i].str == 0)
21507c478bd9Sstevel@tonic-gate 				err = EINVAL;
21517c478bd9Sstevel@tonic-gate 			else if (optind < argc &&
21527c478bd9Sstevel@tonic-gate 			    (argv[optind][0] != '-' ||
21537c478bd9Sstevel@tonic-gate 			    (strlen(argv[optind]) > 1 &&
21547c478bd9Sstevel@tonic-gate 			    isdigit(argv[optind][1]))))
21557c478bd9Sstevel@tonic-gate 				errdef.operand =
21567c478bd9Sstevel@tonic-gate 				    strtoull(argv[optind++], 0, 0);
21577c478bd9Sstevel@tonic-gate 			break;
21587c478bd9Sstevel@tonic-gate 		case 'p':
21597c478bd9Sstevel@tonic-gate 			tmpui = 0x0u;
21607c478bd9Sstevel@tonic-gate 			if ((err = str_to_bm(optarg, ptypes, &tmpui)) == 0) {
21617c478bd9Sstevel@tonic-gate 				while (optind < argc && *argv[optind] != '-')
21627c478bd9Sstevel@tonic-gate 					if ((err = str_to_bm(argv[optind++],
21637c478bd9Sstevel@tonic-gate 					    ptypes, &tmpui)))
21647c478bd9Sstevel@tonic-gate 						break;
21657c478bd9Sstevel@tonic-gate 				policy = (uint16_t)tmpui;
21667c478bd9Sstevel@tonic-gate 			}
21677c478bd9Sstevel@tonic-gate 			if (err == 0 && (policy & BYTEPOLICY))
21687c478bd9Sstevel@tonic-gate 				errdef.log.flags |= BOFI_LOG_REPIO;
21697c478bd9Sstevel@tonic-gate 			break;
21707c478bd9Sstevel@tonic-gate 		case 'P':
21717c478bd9Sstevel@tonic-gate 			if (getnameinst(optarg, &errdef.instance, buf,
21727c478bd9Sstevel@tonic-gate 			    MAXPATHLEN) == -1)
21737c478bd9Sstevel@tonic-gate 				err = EINVAL;
21747c478bd9Sstevel@tonic-gate 			else
21757c478bd9Sstevel@tonic-gate 				(void) strncpy(errdef.name, buf, MAXNAMELEN);
21767c478bd9Sstevel@tonic-gate 			break;
21777c478bd9Sstevel@tonic-gate 		case 'r':
21787c478bd9Sstevel@tonic-gate 			if ((errdef.rnumber = strtol(optarg, &str, 0)) < 0)
21797c478bd9Sstevel@tonic-gate 				errdef.rnumber = -1;
21807c478bd9Sstevel@tonic-gate 			if (str == optarg) err = EINVAL;
21817c478bd9Sstevel@tonic-gate 			break;
21827c478bd9Sstevel@tonic-gate 		case 's':
21837c478bd9Sstevel@tonic-gate 			collecttime = strtoull(optarg, &str, 0);
21847c478bd9Sstevel@tonic-gate 			if (str == optarg)
21857c478bd9Sstevel@tonic-gate 				err = EINVAL;	/* zero is valid */
21867c478bd9Sstevel@tonic-gate 			break;
21877c478bd9Sstevel@tonic-gate 		case 'w':
21887c478bd9Sstevel@tonic-gate 			do_status = 1;
21897c478bd9Sstevel@tonic-gate 			max_edef_wait = strtoul(optarg, &str, 0);
21907c478bd9Sstevel@tonic-gate 			/* zero is valid */
21917c478bd9Sstevel@tonic-gate 			if (str == optarg)
21927c478bd9Sstevel@tonic-gate 				err = EINVAL;
21937c478bd9Sstevel@tonic-gate 			else if (optind < argc &&
21947c478bd9Sstevel@tonic-gate 			    (argv[optind][0] != '-' ||
21957c478bd9Sstevel@tonic-gate 			    (strlen(argv[optind]) > 1 &&
21967c478bd9Sstevel@tonic-gate 			    isdigit(argv[optind][1]))))
21977c478bd9Sstevel@tonic-gate 				edef_sleep = strtoull(argv[optind++], 0, 0);
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 			break;
22007c478bd9Sstevel@tonic-gate 		case 'x':
22017c478bd9Sstevel@tonic-gate 			if ((optind < argc && *argv[optind] == '-') ||
22027c478bd9Sstevel@tonic-gate 			    optind == argc)
22037c478bd9Sstevel@tonic-gate 				errdef.log.flags |= BOFI_LOG_WRAP;
22047c478bd9Sstevel@tonic-gate 			else {
22057c478bd9Sstevel@tonic-gate 				if (strchr(argv[optind], 'w') != 0)
22067c478bd9Sstevel@tonic-gate 					errdef.log.flags |= BOFI_LOG_WRAP;
22077c478bd9Sstevel@tonic-gate 				if (strchr(argv[optind], 'r') != 0)
22087c478bd9Sstevel@tonic-gate 					errdef.log.flags |= BOFI_LOG_REPIO;
22097c478bd9Sstevel@tonic-gate 				if (strchr(argv[optind], 't') != 0)
22107c478bd9Sstevel@tonic-gate 					errdef.log.flags |= BOFI_LOG_TIMESTAMP;
22117c478bd9Sstevel@tonic-gate 				if (strstr(argv[optind], "~t") != 0)
22127c478bd9Sstevel@tonic-gate 					errdef.log.flags &= ~BOFI_LOG_TIMESTAMP;
22137c478bd9Sstevel@tonic-gate 				optind++;
22147c478bd9Sstevel@tonic-gate 			}
22157c478bd9Sstevel@tonic-gate 			break;
22167c478bd9Sstevel@tonic-gate 		case 'h':
22177c478bd9Sstevel@tonic-gate 			(void) fprintf(errfile, "usage: %s %s\n",
22187c478bd9Sstevel@tonic-gate 			    Progname, syntax);
22197c478bd9Sstevel@tonic-gate 			exit(0);
22207c478bd9Sstevel@tonic-gate 			break;
22217c478bd9Sstevel@tonic-gate 		case '?':	/* also picks up missing parameters */
22227c478bd9Sstevel@tonic-gate 		default:
22237c478bd9Sstevel@tonic-gate 			(void) fprintf(errfile, "usage: %s %s\n",
22247c478bd9Sstevel@tonic-gate 			    Progname, syntax);
22257c478bd9Sstevel@tonic-gate 			exit(2);
22267c478bd9Sstevel@tonic-gate 		}
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 		if (err) {
22297c478bd9Sstevel@tonic-gate 			(void) fprintf(errfile, "usage: %s %s\n",
22307c478bd9Sstevel@tonic-gate 			    Progname, syntax);
22317c478bd9Sstevel@tonic-gate 			exit(2);
22327c478bd9Sstevel@tonic-gate 		}
22337c478bd9Sstevel@tonic-gate 		if (c == 'e')
22347c478bd9Sstevel@tonic-gate 			break;	/* the -e option must be the final option */
22357c478bd9Sstevel@tonic-gate 	}
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 	if (errdef.name[0] == 0) {
22397c478bd9Sstevel@tonic-gate 		msg(0, "%s - invalid name parameter\n", Progname);
22407c478bd9Sstevel@tonic-gate 		exit(1);
22417c478bd9Sstevel@tonic-gate 	}
22427c478bd9Sstevel@tonic-gate 	errdef.namesize = strlen(errdef.name);
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	if (policy == 0) {
22457c478bd9Sstevel@tonic-gate 		policy |= UNBIASEDPOLICY;
22467c478bd9Sstevel@tonic-gate 		policy |= OPERATORSPOLICY;
22477c478bd9Sstevel@tonic-gate 	}
22487c478bd9Sstevel@tonic-gate 
22497c478bd9Sstevel@tonic-gate 	if (errdef.optype == BOFI_NOP)
22507c478bd9Sstevel@tonic-gate 		errdef.optype = BOFI_XOR;
22517c478bd9Sstevel@tonic-gate 	if (errdef.access_type == BOFI_LOG) { /* qualify all accesses */
22527c478bd9Sstevel@tonic-gate 		errdef.access_type =
22537c478bd9Sstevel@tonic-gate 		    (BOFI_LOG|BOFI_DMA_RW|BOFI_PIO_RW|BOFI_INTR);
22547c478bd9Sstevel@tonic-gate 		atype_is_default = 1;
22557c478bd9Sstevel@tonic-gate 	} else if (errdef.access_type == 0) { /* qualify all accesses */
22567c478bd9Sstevel@tonic-gate 		errdef.access_type =
22577c478bd9Sstevel@tonic-gate 		    (BOFI_DMA_RW|BOFI_PIO_RW|BOFI_INTR);
22587c478bd9Sstevel@tonic-gate 		atype_is_default = 1;
22597c478bd9Sstevel@tonic-gate 	} else
22607c478bd9Sstevel@tonic-gate 		atype_is_default = 0;
22617c478bd9Sstevel@tonic-gate 
22627c478bd9Sstevel@tonic-gate 	init_sigs();
22637c478bd9Sstevel@tonic-gate 	if ((errdef.access_type & BOFI_LOG) == 0) {
22647c478bd9Sstevel@tonic-gate 		int fd, i, instance;
22657c478bd9Sstevel@tonic-gate 		size_t cnt;
22667c478bd9Sstevel@tonic-gate 		struct handle_info *hdls, *hp;
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 		if ((fd = open(BOFI_DEV, O_RDWR)) == -1) {
22697c478bd9Sstevel@tonic-gate 			msg(0, "%s: error opening bofi driver: %s\n",
22707c478bd9Sstevel@tonic-gate 			    Progname, strerror(errno));
22717c478bd9Sstevel@tonic-gate 			exit(1);
22727c478bd9Sstevel@tonic-gate 		}
22737c478bd9Sstevel@tonic-gate 		if ((err = get_hinfo(fd, errdef.name, &hdls, &cnt,
22747c478bd9Sstevel@tonic-gate 		    errdef.instance, errdef.access_type, errdef.rnumber,
22757c478bd9Sstevel@tonic-gate 		    errdef.offset, errdef.len, 0)) != 0) {
22767c478bd9Sstevel@tonic-gate 			msg(0, "%s: Bad lookup on bofi driver.\n", Progname);
22777c478bd9Sstevel@tonic-gate 			(void) close(fd);
22787c478bd9Sstevel@tonic-gate 			exit(1);
22797c478bd9Sstevel@tonic-gate 		} else if (cnt == 0) {
22807c478bd9Sstevel@tonic-gate 			msg(0,
22817c478bd9Sstevel@tonic-gate 			    "%s: No handles match request access criteria.\n",
22827c478bd9Sstevel@tonic-gate 			    Progname);
22837c478bd9Sstevel@tonic-gate 			(void) close(fd);
22847c478bd9Sstevel@tonic-gate 			exit(1);
22857c478bd9Sstevel@tonic-gate 		}
22867c478bd9Sstevel@tonic-gate 		if (errdef.instance == -1)
22877c478bd9Sstevel@tonic-gate 			instance = -1;
22887c478bd9Sstevel@tonic-gate 		else {
22897c478bd9Sstevel@tonic-gate 			instance = hdls->instance;
22907c478bd9Sstevel@tonic-gate 			for (i = 0, hp = hdls; i < cnt; i++, hp++) {
22917c478bd9Sstevel@tonic-gate 				if (instance != hp->instance) {
22927c478bd9Sstevel@tonic-gate 					instance = -1;
22937c478bd9Sstevel@tonic-gate 					break;
22947c478bd9Sstevel@tonic-gate 				}
22957c478bd9Sstevel@tonic-gate 			}
22967c478bd9Sstevel@tonic-gate 		}
22977c478bd9Sstevel@tonic-gate 		if (instance == -1) {
22987c478bd9Sstevel@tonic-gate 			msg(0, "Multiple instances match access criteria"
22997c478bd9Sstevel@tonic-gate 			    " (only allowed when logging):\n");
23007c478bd9Sstevel@tonic-gate 			msg(0, "\tinst\taccess\trnumber\toffset\tlength\n");
23017c478bd9Sstevel@tonic-gate 			for (i = 0, hp = hdls; i < cnt; i++, hp++)
23027c478bd9Sstevel@tonic-gate 				msg(0, "\t%d\t0x%x\t%d\t0x%llx\t0x%llx\n",
23037c478bd9Sstevel@tonic-gate 				    hp->instance, hp->access_type,
23047c478bd9Sstevel@tonic-gate 				    hp->rnumber, hp->offset, hp->len);
23057c478bd9Sstevel@tonic-gate 		} else {
23067c478bd9Sstevel@tonic-gate 			struct bofi_errstate es;
23077c478bd9Sstevel@tonic-gate 			int timeleft = max_edef_wait;
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 			if (ioctl(fd, BOFI_ADD_DEF, &errdef) == -1) {
23107c478bd9Sstevel@tonic-gate 				perror("th_define - adding errdef failed");
23117c478bd9Sstevel@tonic-gate 			} else {
23127c478bd9Sstevel@tonic-gate 				es.errdef_handle = errdef.errdef_handle;
23137c478bd9Sstevel@tonic-gate 				msg(4, "waiting for edef:"
23147c478bd9Sstevel@tonic-gate 				    " %d %s %d %d 0x%llx 0x%llx 0x%x 0x%x"
23157c478bd9Sstevel@tonic-gate 				    " 0x%x 0x%x 0x%x 0x%llx\n",
23167c478bd9Sstevel@tonic-gate 				    errdef.namesize, errdef.name,
23177c478bd9Sstevel@tonic-gate 				    errdef.instance, errdef.rnumber,
23187c478bd9Sstevel@tonic-gate 				    errdef.offset, errdef.len,
23197c478bd9Sstevel@tonic-gate 				    errdef.access_type, errdef.access_count,
23207c478bd9Sstevel@tonic-gate 				    errdef.fail_count, errdef.acc_chk,
23217c478bd9Sstevel@tonic-gate 				    errdef.optype, errdef.operand);
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate 				set_handler(SIGALRM);	/* handle it */
23247c478bd9Sstevel@tonic-gate 
23257c478bd9Sstevel@tonic-gate 				do {
23267c478bd9Sstevel@tonic-gate 					if (do_status)
23277c478bd9Sstevel@tonic-gate 						(void) alarm(edef_sleep);
23287c478bd9Sstevel@tonic-gate 					if (ioctl(fd, BOFI_CHK_STATE_W,
23297c478bd9Sstevel@tonic-gate 					    &es) == -1) {
23307c478bd9Sstevel@tonic-gate 						if (errno != EINTR) {
23317c478bd9Sstevel@tonic-gate 							perror("bad"
23327c478bd9Sstevel@tonic-gate 							    " BOFI_CHK_STATE");
23337c478bd9Sstevel@tonic-gate 							break;
23347c478bd9Sstevel@tonic-gate 						} else if (!do_status) {
23357c478bd9Sstevel@tonic-gate 							break;
23367c478bd9Sstevel@tonic-gate 						}
23377c478bd9Sstevel@tonic-gate 					}
23387c478bd9Sstevel@tonic-gate 					if (do_status)
23397c478bd9Sstevel@tonic-gate 						(void) fprintf(outfile,
23407c478bd9Sstevel@tonic-gate 						    "%llu:%llu:%u:%u:%u:"
23417c478bd9Sstevel@tonic-gate 						    "%u:%d:\"%s\"\n",
23427c478bd9Sstevel@tonic-gate 						    es.fail_time, es.msg_time,
23437c478bd9Sstevel@tonic-gate 						    es.access_count,
23447c478bd9Sstevel@tonic-gate 						    es.fail_count,
23457c478bd9Sstevel@tonic-gate 						    es.acc_chk, es.errmsg_count,
23467c478bd9Sstevel@tonic-gate 						    (uint_t)es.severity,
23477c478bd9Sstevel@tonic-gate 						    (es.msg_time) ?
23487c478bd9Sstevel@tonic-gate 						    es.buffer : "");
23497c478bd9Sstevel@tonic-gate 					if (es.acc_chk == 0 &&
23507c478bd9Sstevel@tonic-gate 					    es.fail_count == 0 && !do_status)
23517c478bd9Sstevel@tonic-gate 						print_err_reports(outfile,
23527c478bd9Sstevel@tonic-gate 						    &es, "", "", -1);
23537c478bd9Sstevel@tonic-gate 					else if (alarmed) {
23547c478bd9Sstevel@tonic-gate 						alarmed = 0;
23557c478bd9Sstevel@tonic-gate 						if ((timeleft -= edef_sleep) <=
23567c478bd9Sstevel@tonic-gate 						    0) {
2357e5ba14ffSstephh 							if (do_status)
2358e5ba14ffSstephh 								break;
2359e5ba14ffSstephh 							print_err_reports(
2360e5ba14ffSstephh 							    outfile, &es, "",
2361e5ba14ffSstephh 							    "", -1);
23627c478bd9Sstevel@tonic-gate 							break;
23637c478bd9Sstevel@tonic-gate 						}
23647c478bd9Sstevel@tonic-gate 					} else if (!do_status)
23657c478bd9Sstevel@tonic-gate 						print_err_reports(outfile,
23667c478bd9Sstevel@tonic-gate 						    &es, "", "", -1);
23677c478bd9Sstevel@tonic-gate 				} while (es.acc_chk != 0 || es.fail_count != 0);
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 				msg(2, "done: acc_chk 0x%x fcnt %d\n",
23707c478bd9Sstevel@tonic-gate 				    es.acc_chk, es.fail_count);
23717c478bd9Sstevel@tonic-gate 			}
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 			(void) close(fd);
23747c478bd9Sstevel@tonic-gate 		}
23757c478bd9Sstevel@tonic-gate 		free(hdls);
23767c478bd9Sstevel@tonic-gate 		return (0);
23777c478bd9Sstevel@tonic-gate 	}
23787c478bd9Sstevel@tonic-gate 	test_driver(&errdef, collecttime);
23797c478bd9Sstevel@tonic-gate 	return (0);
23807c478bd9Sstevel@tonic-gate }
2381