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