th_define.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/time_impl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <libdevinfo.h>
#define _KERNEL
#include <sys/dditypes.h>
#define myLLMAX (0x7fffffffffffffffll)
#define myULLMAX (0xffffffffffffffffull)
/*
* default interval to wait between kicking off workload and injecting fault
*/
#define DEFAULT_EDEF_SLEEP 3
/*
* when generating dma corruptions, it is best to corrupt each double word
* individually for control areas - however for data areas this can be
* excessive and would generate so many cases we would never finish the run.
* So set a cut-off value where we switch from corrupting each double word
* separately to corrupting th elot in one go. 0x100 bytes seems a good value
* on the drivers we have seen so far.
*/
#define DMA_INDIVIDUAL_CORRUPT_CUTOFF 0x100
struct collector_def {
};
#define BYTEPOLICY (0xf)
#define MULTIPOLICY (0x10)
#define UNBIASEDPOLICY 0x20
#define UNCOMMONPOLICY 0x40
#define COMMONPOLICY 0x80
#define MEDIANPOLICY 0x100
#define MAXIMALPOLICY 0x200
#define OPERATORSPOLICY 0x400
#define VALIDPOLICY (0x7ff)
typedef
struct coding {
char *str;
} coding_t;
{"onebyte", 0x1}, {"twobyte", 0x2},
{"fourbyte", 0x4}, {"eightbyte", 0x8},
{"multibyte", 0x10}, {"unbiased", 0x20}, {"uncommon", 0x40},
{"common", 0x80}, {"median", 0x100}, {"maximal", 0x200},
{"operators", 0x400}, {0, 0}
};
};
{"EXTRA", BOFI_EXTRA_INTR}, {0, 0}
};
{"XOR", BOFI_XOR}, {0, 0}
};
{"EXTRA", BOFI_EXTRA_INTR}, {0, 0}
};
/*
* This global controls the generation of errdefs for PIO_W. The default should
* be to only perform an access check errdef but not to corrupt writes - this
* may trash non-FT platforms.
*/
0x32f1f03232f1f032ull, /* the value returned when the fake ta is set */
(longlong_t)(~0) /* corresponds to a line going high/low */
};
static int alarmed = 0;
static int killed = 0;
/*
* name of a script to call before offlining a driver being tested
*/
static char **fixup_script = 0;
static int scriptargs = 0;
static char **pargv;
static int pargc;
static int max_edef_wait = 0;
static int edef_sleep = 0;
static int do_status = 0; /* report edef status in parsable format */
static char *user_comment = 0;
static char *Progname;
/*
* The th_define utility provides an interface to the bus_ops fault injection
* bofi device driver for defining error injection specifications (referred to
* as errdefs). An errdef corresponds to a specification of how to corrupt a
* device driver's accesses to its hardware. The command line arguments
* determine the precise nature of the fault to be injected. If the supplied
* arguments define a consistent errdef, the th_define process will store the
* errdef with the bofi driver and suspend itself until the criteria given by
* the errdef become satisfied (in practice, this will occur when the access
* counts go to zero).
*
* When the resulting errdef is activated using the th_manage(1M) user command
* utility, the bofi driver will act upon the errdef by matching the number of
* hardware accesses - specified in count, that are of the type specified in
* acc_types, made by instance number instance - of the driver whose name is
* name, (or by the driver instance specified by * path ) to the register set
* (or DMA handle) specified by rnumber, that lie within the range offset to
* offset + length from the beginning of the register set or DMA handle. It then
* applies operator and operand to the next failcount matching accesses.
*
* If acc_types includes LOG, th_define runs in automatic test script generation
* mode, and a set of test scripts (written in the Korn shell) is created and
* placed in a sub-directory of the current directory with the name
* driver.test.<id>. A separate, executable script is generated for each access
* handle that matches the logging criteria. The log of accesses is placed at
* the top of each script as a record of the session. If the current directory
* is not writable, file output is written to standard output. The base name of
* each test file is the driver name, and the extension is a number that
* discriminates between different access handles. A control script (with the
* same name as the created test directory) is generated that will run all the
* test scripts sequentially.
*
* Executing the scripts will install, and then activate, the resulting error
* definitions. Error definitions are activated sequentially and the driver
* instance under test is taken offline and brought back online before each test
* (refer to the -e option for more information). By default, logging will apply
* to all PIO accesses, interrupts and DMA accesses to and from areas mapped
* for both reading and writing, but it can be constrained by specifying
* additional acc_types, rnumber, offset and length. Logging will continue for
* count matching accesses, with an optional time limit of collect_time seconds.
*
* Either the -n or -P option must be provided. The other options are optional.
* If an option (other than the -a option) is specified multiple times, only
* the final value for the option is used. If an option is not specified, its
* associated value is set to an appropriate default, which will provide
* maximal error coverage as described below.
*/
/*PRINTFLIKE2*/
static void
{
#define BUFSZ 128
int count;
int pos = 0;
if (count > 0) {
}
}
}
static void
kill_sighandler(int sig)
{
switch (sig) {
case SIGALRM:
alarmed = 1;
break;
default:
killed = 1;
break;
}
}
static void
set_handler(int sig)
{
/* install handler */
}
/*
* Compare two driver access handles
*/
static int
{
return (-1);
return (1);
return (-1);
return (1);
return (-1);
return (1);
return (-1);
return (1);
return (-1);
return (1);
return (-1);
return (1);
else
return (0);
}
/*
* Compare two hardware accesses.
*/
static int
{
return (-1);
return (1);
return (-1);
return (1);
return (-1);
return (1);
else
return (0);
}
/*
* Another way of comparing two hardware accesses.
*/
static int
{
if (rval == 0)
return (-1);
return (1);
else
return (0);
else
return (rval);
}
/*
* And a final way of sorting a log (by access type followed by repcount).
*/
static int
{
return (-1);
return (1);
return (-1);
return (1);
else
return (0);
}
static void
{
int i;
if (logflags & BOFI_LOG_TIMESTAMP &&
getenv("DUMP_FULL_LOG") != 0)
allthesame = 0;
else
for (i = 1; i < nitems; i++)
allthesame = 0;
if (fp != 0)
"# Logged Accesses:\n# %-4s\t%-12s\t%-4s\t%-18s"
" (%-1s)\t%-10s\n\n", "type",
"address" : "offset",
"size", "value", "repcnt", "time");
if (fp != 0) {
"# 0x%-2x\t0x%-10x\t%-4d\t0x%-16llx"
" (0x%-1x)\t%-8llu\n",
(logflags & BOFI_LOG_TIMESTAMP) ?
if (allthesame) {
"# Access duplicated %d times\n",
nitems);
break;
}
} else
(logflags & BOFI_LOG_TIMESTAMP) ?
}
}
}
static int
{
char *str;
char *s = "\t\n ";
do {
for (; c->str != 0; c++)
c->str);
err = 0;
break;
}
} else
return (EINVAL);
return (err);
}
/*
* Generic routine for commands that apply to a particular instance of
* a driver under test (e.g. activate all errdefs defined on an instance).
*/
static int
{
struct bofi_errctl errctl;
return (-1);
}
return (0);
}
static int
struct bofi_errdef *edp,
struct acc_log_elem *item,
char *type,
int fon, /* corrupt after this many accesses */
char *opname,
{
"-n %s -i %d -r %d -l 0x%llx 0x%x -a %s -c %d %d -f %d"
" -o %s 0x%llx",
type,
fon, /* corrupt after this many accesses */
fcnt, /* and then fail it fcnt times */
operand);
return (0);
}
static void
{
char *opname;
int k, save_size;
else
/*
* errdefs for dma accesses are too numerous so assume that dma writes
* (DDI_DMA_SYNC_FORDEV) create less exposure to potential errors than
* do dma reads (DDI_DMA_SYNC_FORCPU).
*
* also by default do not corrupt PIO_W - it may hang a non-FT platform.
*/
/*
* user has asked for PIO_W
*/
switch (op) {
case BOFI_EQUAL:
(lrand48()) << 32);
break;
case BOFI_AND:
operand = 0xaddedabadb00bull;
break;
case BOFI_OR:
operand = 0x1;
break;
case BOFI_XOR:
default:
break;
case BOFI_DELAY_INTR: /* delay for 1 msec */
operand = 1000000;
break;
case BOFI_LOSE_INTR: /* op not applicable */
operand = 0;
break;
case BOFI_EXTRA_INTR: /* extra intrs */
operand = 0xfff;
break;
}
sizeof (uint64_t) - 1) &
~(sizeof (uint64_t) - 1);
k > 0; k -= sizeof (uint64_t)) {
operand);
}
} else {
}
if (op == BOFI_EQUAL) {
sizeof (uint64_t) - 1) &
~(sizeof (uint64_t) - 1);
k > 0;
k -= sizeof (uint64_t)) {
sizeof (uint64_t);
(void) define_one_error(
[cnt]);
sizeof (uint64_t);
}
} else {
(void) define_one_error(fp,
}
}
}
}
}
/*
* user has asked for PIO_W
*/
}
/*
* and finally an access check errdef
*/
}
/*
* Convert a collection of log entries into error definitions.
*/
/* ARGSUSED */
static int
struct acc_log_elem *items,
{
char *type;
int i;
struct acc_log_elem *item;
char *opname;
int intrs = 0;
/*
* all items are guaranteed have values in the two element set {0, at}
* where at is a valid access type (so find the value of at)
*/
if (item->access_type != 0) {
break;
}
if (at == 0)
return (-1);
/*
* find the string form of the access type
*/
break;
}
}
if (type == 0) {
msg(0, "Unknown access type returned from bofi\n\t");
return (-1);
}
/*
* find the string form of the operator
*/
break;
}
}
/*
* if not found or inconsistent default to XOR
*/
if (opname == 0 ||
(op == BOFI_NO_TRANSFER &&
}
/*
* if operator and access type are inconsistent choose a sensible
* default
*/
cycleiops = 0;
if (op < BOFI_DELAY_INTR)
cycleiops = 1;
else if (op == BOFI_LOSE_INTR)
operand = 0;
cycledops = 0;
cycledops = 1;
/*
* for each access in the list define one or more error definitions
*/
int j, fon;
if (item->access_type == 0)
continue;
/*
* base number of errors to inject on 3% of number of
* similar accesses seen during LOG phase
*/
/*
* wait for twice the time it took during LOG phase
*/
/*
* if edef_sleep set (-w) the use that, otherwise use default
*/
msg(10,
"define_n: item %d limit %d step %d (intr %d) tt(%lu)\n",
j += acnt) {
if (policy & OPERATORSPOLICY) {
} else {
if (cycleiops) {
switch (op) {
case BOFI_DELAY_INTR:
/* delay for 1 sec */
operand = 1000000;
break;
case BOFI_LOSE_INTR:
/* op not applicable */
operand = 0;
break;
case BOFI_EXTRA_INTR:
default:
/* generate 2 extra intrs */
operand = 0xfff;
break;
}
intrs %= 3;
} else if (cycledops) {
switch (op) {
case BOFI_EQUAL:
random_operand = lrand48() |
((uint64_t)
(lrand48()) << 32);
break; /* a random value */
case BOFI_AND:
operand = 0xaddedabadb00bull;
break;
case BOFI_OR:
operand = 0xd1ab011c0af1a5c0ull;
break;
case BOFI_XOR:
default:
break;
}
intrs %= 4;
}
if (op == BOFI_EQUAL) {
(void) define_one_error(fp,
}
}
/*
* all non maximal policies should only generate
* a single error definition set per access.
*/
if (!(policy & MAXIMALPOLICY))
break;
if (nttime < MIN_REPORT_TIME)
else if (nttime > max_edef_wait)
fon += j;
}
}
return (0);
}
static int
{
return (-1);
if (*llp == 0) {
} else {
}
/* has the utc time wrapped over ULMAX - unlikely so fix it at 10 */
/*
* Sort the log by access type - do not remove duplicates yet (but do
* remove access that do not match the requested log -> errdef policy
* (defined by union pu pol). Set the repcount field of each entry to a
* unique value (in the control statement of the for loop) - this
* ensures that the qsort (following the for loop) will not remove any
* entries.
*/
/*
* If interested in the I/O transfer size and this access
* does not match the requested size then ignore the access
*/
if ((pol & SIZEPOLICY) &&
/* req for DMA / ddi_rep */
elem->access_type = 0;
/* these will end up sorted at the head */
else {
cnt += 1;
/* real access time */
else
/* linear fit */
}
}
*cntp = 0;
*llp = 0;
return (0);
/* the chosen policy has ignored everything */
}
}
/*
* Now remove duplicate entries based on access type, address and size.
* Reuse the repcount field to store the no. of duplicate accesses.
* Store the average access time in the single remaining
* representative of the duplicate set.
*/
} else { /* not a duplicate */
elem++;
cnt++;
}
}
/*
* The log is sorted by access type - now resort to order by frequency
* of accesses (ie for a given access type uncommon access will come
* first.
*/
for (i = 0; i < cnt; i = j) {
/*
* Pick out the set [i, j) consisting of elements with the same
* access type
*/
if (j - i == 1) /* never ignore solo accesses of a given type */
continue;
/*
* Now determine what constitutes uncommon and common accesses:
*/
break;
lb = j - 1;
} else {
lb = i;
ub = j-1;
}
break;
ub = i;
}
" (%d %d %d)"
" mean %d cutoffs(%d %d) bnds(%d, %d)\n",
if (!(pol & MEDIANPOLICY))
/* delete all the mid accesses */
items[k].access_type = 0;
else {
if (!(pol & UNCOMMONPOLICY))
/* delete uncommon accesses */
for (k = i; k < ub; k++)
items[k].access_type = 0;
if (!(pol & COMMONPOLICY))
/* delete common accesses */
for (k = lb+1; k < j; k++)
items[k].access_type = 0;
}
}
return (0);
}
static void
char *devpath)
{
struct acc_log_elem *items;
int i, j;
char fname[_POSIX_PATH_MAX];
int ecnt = 0;
int err;
char *buffer;
if (nitems == 0)
return;
/* ensure that generated errdefs complete in bounded time */
if (max_edef_wait == 0)
(int)getpid());
}
if (user_comment)
"Test Comment:", user_comment);
items = 0;
nitems == 0) {
return;
}
"${0##*/}: $@\""
" >&2; exit 2; }\n");
"trap ' ' 16\t# ignore - it is trapped by abort monitor_edef\n");
if (scriptargs > 0) {
for (i = 0; i < scriptargs; i++)
} else {
"\t\t# terminate any outstanding workload\n");
}
return;
}
if (fd == -1) {
return;
}
if (!buffer) {
return;
}
return;
}
for (i = 0; i < nitems; i = j) {
for (j = i + 1;
j++)
if (items[i].access_type != 0)
}
}
}
static int
struct bofi_errstate *errstate,
{
if (hdl->access_type == 0)
return (EINVAL);
/* use a big log for PIO and a small one otherwise */
if (lsize_is_default &&
errdef->fail_count = 0;
}
}
return (EAGAIN);
" 0x%x 0x%x 0x%llx\n",
perror("th_define - adding errdef failed");
return (errno);
}
return (0);
}
static void
struct bofi_errstate *errstate,
struct bofi_errdef *errdef,
char *devpath)
{
int rval;
do {
errno = 0;
perror("th_define (collect) -"
" waiting for error report failed");
break;
}
" (%s %d %d 0x%x %d).\n",
errstate->access_count > 0)
continue;
errstate->fail_count == 0 &&
break;
}
"(off 0x%llx len 0x%llx) ac %d\n", errno,
/* now grab the log itself */
msg(0,
"%s: errorwhile retrieving %d log entries: %s\n",
} else {
" (log entries %d %d) (%llu - %llu)\n",
}
}
}
static void
{
else
if (esp->access_count != 0) {
} else {
" 0x%llx errors reported %d\n", cmt,
esp->errmsg_count);
}
}
static void
{
int fd;
msg(0, "Too many instances of bofi currently open\n");
else
msg(0, "Error while opening bofi driver: %s",
} else {
/*
* Activate the logging errdefs - then collect the results.
*/
}
/*
* there is no more work to do on this access handle so clean up / exit.
*/
exit(0);
}
/*
* Given an access handle known to the bofi driver see if the user has
* specified access criteria that match that handle. Note: this matching
* algorithm should be kept consistent with the drivers alogorithm.
*/
static int
{
return (0);
if ((access_type & BOFI_DMA_RW) &&
return (1);
else if ((access_type & BOFI_INTR) &&
return (1);
else if ((access_type & BOFI_PIO_RW) &&
return (1);
else
return (0);
}
/*
* Obtain all the handles created by the driver specified by the name parameter
* that match the remaining arguments. The output parameter nhdls indicates how
* many of the structures pointed to by the output parameter hip match the
* specification.
*
* It is the responsibility of the caller to free *hip when *nhdls != 0.
*/
static int
int new_semantics)
{
struct bofi_get_hdl_info hdli;
int command;
/*
* Initially ask for the number of access handles (not the structures)
* in order to allocate memory
*/
*hip = 0;
/*
* Ask the bofi driver for all handles created by the driver under test.
*/
*nhdls = 0;
msg(0, "driver failed to return handles: %s\n",
return (errno);
return (0); /* no handles */
return (EAGAIN);
} else {
int i;
/* Ask for *nhdls handles */
msg(0, "BOFI_GET_HANDLE_INFO ioctl returned error %d\n",
err);
return (err);
}
if (*nhdls > 1)
/* sort them naturally (NB ordering is not mandatory) */
struct handle_info **ip;
/* the selected handles */
struct handle_info *prev = 0;
int scnt = 0;
i++, hp++) {
/*
* Remark: unbound handles never match
* (access_type == 0)
*/
" 0x%llx (0x%llx)\n",
if (prev &&
hp->addr_cookie ==
continue;
(atype & BOFI_DMA_RW) !=
if (new_semantics)
continue;
if (prev)
" 0x%llx (%d %d) (%d %d)"
" (0x%x 0x%x) (0x%llx,"
" 0x%llx)\n",
/* it matches so remember it */
scnt += 1;
}
}
/*
* Reuse the alloc'ed memory to return
* only those handles the user has asked for.
* But first prune the handles to get rid of
* overlapping ranges (they are ordered by
* offset and length).
*/
sizeof (*hp));
}
}
}
}
return (0);
}
static void
{
}
static void
{
/* Potentially hungry on resources so up them all to their maximums */
else {
msg(0, "failed to set RLIMIT_NOFILE: %s\n",
}
else {
msg(0, "failed to set RLIMIT_DATA: %s\n",
}
else {
msg(0, "failed to set RLIMIT_FSIZE: %s\n",
}
}
static FILE *
create_test_file(char *drvname)
{
char dirname[_POSIX_PATH_MAX];
char testname[_POSIX_PATH_MAX];
return (0);
return (0);
}
return (0);
}
return (0); /* leave created directory intact */
return (fp);
}
struct walk_arg {
char *path;
int instance;
char name[MAXPATHLEN];
int pathlen;
};
static int
{
char *driver_name;
char *path;
if (driver_name != NULL) {
else
return (DI_WALK_TERMINATE);
}
}
return (DI_WALK_CONTINUE);
}
static int
{
return (-1);
return (-1);
}
return (-1);
}
return (0);
}
/*
* Record logsize h/w accesses of type 'edp->access_type' made by instance
* 'edp->instance' of driver 'edp->name' to the register set (or dma handle)
* 'edp->rnumber' that lie within the range 'edp->offset' to
* 'edp->offset' + 'edp->len'.
* Access criteria may be mixed and matched:
* - if 'edp->instance' is -1 all instances are checked for the criteria;
* - if 'edp->rnumber' is -1 all register sets and dma handles are matched;
* - 'offset' and 'len' indicate that only PIO and DMA accesses within the
* range 'edp->offset' to 'edp->len' will be logged. Putting 'edp->offset'
* to zero and 'edp->len' to -1ull gives maximal coverage.
*
* 'collecttime' is the number of seconds used to log accesses
* (default is infinity).
*/
static void
unsigned long long collecttime)
{
int statloc;
int i, fd;
unsigned long long timechunk;
char buf[MAXPATHLEN];
char devpath[MAXPATHLEN];
char *devpathp = "NULL";
int drv_inst;
int got_it = 0;
got_it = 1;
}
if (logsize == -1U)
logsize = 0;
if (fd == -1) {
perror("get_hdl_info - bad open of bofi driver");
return;
}
if (got_it) {
"th_manage /devices%s offline", devpathp);
"th_manage /devices%s online", devpathp);
}
return;
if (cnt == 0)
return;
}
return;
}
up_resources();
if (got_it) {
if (scriptargs > 0) {
"DRIVER_PATH=/devices%s DRIVER_INSTANCE=%d"
" DRIVER_UNCONFIGURE=0 DRIVER_CONFIGURE=1",
for (i = 0; i < scriptargs; i++) {
}
} else {
"while : ; do th_manage /devices%s online;"
" th_manage /devices%s offline;done &"
}
}
"Logging accesses to instances ");
i++, hdl++) {
}
}
"(Use th_manage ... clear_errdefs to terminate"
/*
* Install a logging errdef for each matching handle,
* and then create a child to collect the log.
* The child is responsible for activating the log.
*/
} else {
" lsize 0x%x 0x%x at 0x%x\n",
msg(0, "fork failed for handle"
} else if (pid == 0) {
} else {
nchildren += 1;
}
}
}
if (nchildren != 0) {
if (sfp) {
"\n# Test control script generated using:\n#");
for (i = 0; i < pargc; i++)
"\tif [ -x ./%s.%d ]\n\tthen\n",
"\t\techo \"Starting test"
" %d (id %d)\"\n",
"Test %d (id %d) complete\"\n",
}
msg(0, "fchmod on control script failed: %s\n",
msg(0, "Error closing control script: %s\n",
}
/*
* The user may want to terminate logging before the log fills
* so use a timer to signal the logging children to handle this
* case.
*/
/* wait for the log to fill or deadline satisfied */
for (;;) {
nchildren++;
if (nchildren == 0)
break;
if (killed)
break;
if (alarmed) {
if (timechunk-- > 0) {
/*
* prepare for the next timeslice by
* rearming the clock
*/
if (alarm(MAXALRMCALL) == 0)
alarmed = 0;
else {
/*
* must have been a user abort
* (via SIGALRM)
*/
(void) alarm(0);
break;
}
} else
break;
}
}
}
if (got_it) {
if (scriptargs > 0) {
"DRIVER_PATH=/devices%s DRIVER_INSTANCE=%d"
" DRIVER_UNCONFIGURE=1 DRIVER_CONFIGURE=0",
for (i = 0; i < scriptargs; i++) {
}
} else {
}
}
}
static int
{
char *binding_name;
return (-1);
return (-1);
return (0);
}
static char syntax[] =
" [ -n name [ -i instance ] | -P path ]\n"
" [ -a acc_types ] [ -r rnumber ]\n"
" [ -l offset [ length ] ] [ -c count [ failcount ] ]\n"
" [ -o operator [ operand ] ] [ -f acc_chk ]\n"
" [ -w max_wait_period [ report_interval ] ]\n"
" or\n"
" [ -n name [ -i instance ] | -P path ]\n"
" -a LOG [ acc_types ] [ -r rnumber]\n"
" [ -l offset [ length ] ] [ -c count [ failcount ] ]\n"
" [ -s collect_time ] [ -p policy ] [ -x flags ]\n"
" [ -C ] [-e fixup_script ]\n"
" or\n"
" -h";
int
{
extern char *optarg;
extern int optind;
char c; /* for parsing getopts */
int nopts = 0; /* for backward compatibility */
int err = 0;
/* use a maximal set of defaults for logging or injecting */
struct bofi_errdef errdef = {
0, /* length of driver name */
{0}, /* driver name */
-1, /* monitor all instances */
-1, /* monitor all register sets and DMA handles */
(offset_t)0, /* monitor from start of reg. set or DMA hd */
myLLMAX, /* monitor whole reg set or DMA hdl(no LLMAX) */
0, /* qualify all */
DFLTLOGSZ, /* default no. of accesses before corrupting */
0u, /* default no. of accesses to corrupt */
0u, /* no check access corruption */
BOFI_NOP, /* no corruption operator by default */
myULLMAX, /* default operand */
{0, 0, BOFI_LOG_TIMESTAMP, /* timestamp by default */
0, 0, 0, 0}, /* no logging by default */
0};
/* specify the default no of seconds for which to monitor */
unsigned long long collecttime = DFLTLOGTIME;
char *str; /* temporary variable */
long tmpl; /* another one */
int i;
char buf[MAXPATHLEN];
policy = 0;
lsize_is_default = 1;
!= EOF) {
nopts++;
switch (c) {
case 'a':
&errdef.access_type)) == 0)
break;
}
break;
case 'c':
lsize_is_default = 0;
/* zero is valid */
break;
case 'C':
break;
case 'D':
break;
case 'e':
fixup_script = 0;
scriptargs = 0;
scriptargs += 1;
optind += 1;
scriptargs += 1;
}
break;
case 'f':
else
break;
case 'i':
break;
case 'l':
/* -1 indicates the rest of register set */
}
break;
case 'n':
break;
case 'o':
break;
}
break;
case 'p':
tmpui = 0x0u;
break;
}
break;
case 'P':
MAXPATHLEN) == -1)
else
break;
case 'r':
break;
case 's':
break;
case 'w':
do_status = 1;
/* zero is valid */
break;
case 'x':
else {
optind++;
}
break;
case 'h':
exit(0);
break;
case '?': /* also picks up missing parameters */
default:
exit(2);
}
if (err) {
exit(2);
}
if (c == 'e')
break; /* the -e option must be the final option */
}
exit(1);
}
if (policy == 0) {
policy |= UNBIASEDPOLICY;
}
atype_is_default = 1;
atype_is_default = 1;
} else
atype_is_default = 0;
init_sigs();
msg(0, "%s: error opening bofi driver: %s\n",
exit(1);
}
exit(1);
} else if (cnt == 0) {
msg(0,
"%s: No handles match request access criteria.\n",
Progname);
exit(1);
}
instance = -1;
else {
instance = -1;
break;
}
}
}
if (instance == -1) {
msg(0, "Multiple instances match access criteria"
" (only allowed when logging):\n");
msg(0, "\tinst\taccess\trnumber\toffset\tlength\n");
msg(0, "\t%d\t0x%x\t%d\t0x%llx\t0x%llx\n",
} else {
struct bofi_errstate es;
int timeleft = max_edef_wait;
perror("th_define - adding errdef failed");
} else {
" %d %s %d %d 0x%llx 0x%llx 0x%x 0x%x"
" 0x%x 0x%x 0x%x 0x%llx\n",
do {
if (do_status)
(void) alarm(edef_sleep);
&es) == -1) {
perror("bad"
" BOFI_CHK_STATE");
break;
} else if (!do_status) {
break;
}
}
if (do_status)
"%llu:%llu:%u:%u:%u:"
"%u:%d:\"%s\"\n",
else if (alarmed) {
alarmed = 0;
if ((timeleft -= edef_sleep) <=
0) {
if (!do_status)
&es, "",
"", -1);
break;
}
} else if (!do_status)
}
}
return (0);
}
return (0);
}