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