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
5*540db9a9SStephen Hanson * Common Development and Distribution License (the "License").
6*540db9a9SStephen Hanson * 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 */
21d9638e54Smws
227c478bd9Sstevel@tonic-gate /*
23*540db9a9SStephen Hanson * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * The "program" executed by the injector consists of a tree of commands.
297c478bd9Sstevel@tonic-gate * Routines in this file build and execute said command tree.
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate #include <inj.h>
367c478bd9Sstevel@tonic-gate #include <inj_event.h>
377c478bd9Sstevel@tonic-gate #include <inj_lex.h>
387c478bd9Sstevel@tonic-gate #include <inj_err.h>
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate * Command tree construction
427c478bd9Sstevel@tonic-gate */
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate static inj_list_t inj_cmds;
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate void
inj_cmds_add(inj_cmd_t * cmd)477c478bd9Sstevel@tonic-gate inj_cmds_add(inj_cmd_t *cmd)
487c478bd9Sstevel@tonic-gate {
497c478bd9Sstevel@tonic-gate inj_list_append(&inj_cmds, cmd);
507c478bd9Sstevel@tonic-gate }
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate inj_list_t *
inj_cmds_get(void)537c478bd9Sstevel@tonic-gate inj_cmds_get(void)
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate return (&inj_cmds);
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate inj_randelem_t *
inj_rand_create(inj_defn_t * ev,uint_t prob)597c478bd9Sstevel@tonic-gate inj_rand_create(inj_defn_t *ev, uint_t prob)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate inj_randelem_t *re = inj_zalloc(sizeof (inj_randelem_t));
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate re->re_event = ev;
647c478bd9Sstevel@tonic-gate re->re_prob = prob;
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate return (re);
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate inj_randelem_t *
inj_rand_add(inj_randelem_t * list,inj_randelem_t * new)707c478bd9Sstevel@tonic-gate inj_rand_add(inj_randelem_t *list, inj_randelem_t *new)
717c478bd9Sstevel@tonic-gate {
727c478bd9Sstevel@tonic-gate new->re_next = list;
737c478bd9Sstevel@tonic-gate return (new);
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_rand(inj_randelem_t * rlist)777c478bd9Sstevel@tonic-gate inj_cmd_rand(inj_randelem_t *rlist)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate inj_randelem_t *r;
807c478bd9Sstevel@tonic-gate inj_cmd_t *cmd;
817c478bd9Sstevel@tonic-gate uint_t prob, tmpprob;
827c478bd9Sstevel@tonic-gate int nelems, i;
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate prob = 0;
857c478bd9Sstevel@tonic-gate for (i = 0, r = rlist; r != NULL; r = r->re_next, i++)
867c478bd9Sstevel@tonic-gate prob += r->re_prob;
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate if (prob != 100) {
897c478bd9Sstevel@tonic-gate yyerror("probabilities don't sum to 100\n");
907c478bd9Sstevel@tonic-gate return (NULL);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate nelems = i;
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate cmd = inj_zalloc(sizeof (inj_cmd_t));
967c478bd9Sstevel@tonic-gate cmd->cmd_type = CMD_RANDOM;
977c478bd9Sstevel@tonic-gate cmd->cmd_num = nelems;
987c478bd9Sstevel@tonic-gate cmd->cmd_rand = inj_alloc(sizeof (inj_randelem_t *) * nelems);
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate prob = 0;
1017c478bd9Sstevel@tonic-gate for (r = rlist, i = 0; i < nelems; i++, r = r->re_next) {
1027c478bd9Sstevel@tonic-gate tmpprob = r->re_prob;
1037c478bd9Sstevel@tonic-gate r->re_prob = prob;
1047c478bd9Sstevel@tonic-gate prob += tmpprob;
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate cmd->cmd_rand[i] = r;
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate return (cmd);
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_repeat(inj_cmd_t * repcmd,uint_t num)1137c478bd9Sstevel@tonic-gate inj_cmd_repeat(inj_cmd_t *repcmd, uint_t num)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t));
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate cmd->cmd_type = CMD_REPEAT;
1187c478bd9Sstevel@tonic-gate cmd->cmd_num = num;
1197c478bd9Sstevel@tonic-gate cmd->cmd_subcmd = repcmd;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate return (cmd);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_send(inj_defn_t * ev)1257c478bd9Sstevel@tonic-gate inj_cmd_send(inj_defn_t *ev)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t));
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate cmd->cmd_type = CMD_SEND_EVENT;
1307c478bd9Sstevel@tonic-gate cmd->cmd_event = ev;
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate return (cmd);
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_sleep(uint_t secs)1367c478bd9Sstevel@tonic-gate inj_cmd_sleep(uint_t secs)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t));
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate cmd->cmd_type = CMD_SLEEP;
1417c478bd9Sstevel@tonic-gate cmd->cmd_num = secs;
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate return (cmd);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_addhrt(hrtime_t delta)1477c478bd9Sstevel@tonic-gate inj_cmd_addhrt(hrtime_t delta)
1487c478bd9Sstevel@tonic-gate {
149d9638e54Smws const char *class = "resource.fm.fmd.clock.addhrtime";
1507c478bd9Sstevel@tonic-gate inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t));
1517c478bd9Sstevel@tonic-gate inj_defn_t *ev = inj_zalloc(sizeof (inj_defn_t));
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate ev->defn_name = class;
1547c478bd9Sstevel@tonic-gate ev->defn_lineno = yylineno;
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate if ((errno = nvlist_alloc(&ev->defn_nvl, NV_UNIQUE_NAME, 0)) != 0)
1577c478bd9Sstevel@tonic-gate die("failed to allocate nvl for %s event", class);
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate if ((errno = nvlist_add_string(ev->defn_nvl, FM_CLASS, class)) != 0 ||
1607c478bd9Sstevel@tonic-gate (errno = nvlist_add_uint8(ev->defn_nvl, FM_VERSION, 1)) != 0 ||
1617c478bd9Sstevel@tonic-gate (errno = nvlist_add_int64(ev->defn_nvl, "delta", delta)) != 0)
1627c478bd9Sstevel@tonic-gate die("failed to build nvl for %s event", class);
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate cmd->cmd_type = CMD_SEND_EVENT;
1657c478bd9Sstevel@tonic-gate cmd->cmd_event = ev;
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate return (cmd);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_endhrt(void)1717c478bd9Sstevel@tonic-gate inj_cmd_endhrt(void)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate return (inj_cmd_addhrt(-1LL)); /* clock underflow causes end of time */
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate static uint64_t
inj_ena(void)1777c478bd9Sstevel@tonic-gate inj_ena(void)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate return (((gethrtime() & ENA_FMT1_TIME_MASK) <<
1807c478bd9Sstevel@tonic-gate ENA_FMT1_TIME_SHFT) | (FM_ENA_FMT1 & ENA_FORMAT_MASK));
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate static void
cmd_run_send(const inj_mode_ops_t * mode,void * hdl,inj_defn_t * ev)1847c478bd9Sstevel@tonic-gate cmd_run_send(const inj_mode_ops_t *mode, void *hdl, inj_defn_t *ev)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate if (!quiet) {
1877c478bd9Sstevel@tonic-gate (void) printf("sending event %s ... ", ev->defn_name);
1887c478bd9Sstevel@tonic-gate (void) fflush(stdout);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate
191*540db9a9SStephen Hanson if ((errno = nvlist_add_boolean_value(ev->defn_nvl, "__injected",
192*540db9a9SStephen Hanson 1)) != 0)
193*540db9a9SStephen Hanson warn("failed to add __injected to %s", ev->defn_name);
194*540db9a9SStephen Hanson
1957c478bd9Sstevel@tonic-gate if (ev->defn_decl && (ev->defn_decl->decl_flags & DECL_F_AUTOENA) &&
1967c478bd9Sstevel@tonic-gate (errno = nvlist_add_uint64(ev->defn_nvl, "ena", inj_ena())) != 0)
1977c478bd9Sstevel@tonic-gate warn("failed to add ena to %s", ev->defn_name);
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate if (verbose) {
2007c478bd9Sstevel@tonic-gate nvlist_print(stdout, ev->defn_nvl);
2017c478bd9Sstevel@tonic-gate (void) printf("\n");
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate mode->mo_send(hdl, ev->defn_nvl);
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate if (!quiet)
2077c478bd9Sstevel@tonic-gate (void) printf("done\n");
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate static void
cmd_run_random(const inj_mode_ops_t * mode,void * hdl,inj_cmd_t * cmd)2117c478bd9Sstevel@tonic-gate cmd_run_random(const inj_mode_ops_t *mode, void *hdl, inj_cmd_t *cmd)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate uint_t num = lrand48() % 100;
2147c478bd9Sstevel@tonic-gate int i;
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate for (i = 1; i < cmd->cmd_num; i++) {
2177c478bd9Sstevel@tonic-gate if (cmd->cmd_rand[i]->re_prob > num)
2187c478bd9Sstevel@tonic-gate break;
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate cmd_run_send(mode, hdl, cmd->cmd_rand[i - 1]->re_event);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate static void
cmd_run(const inj_mode_ops_t * mode,void * hdl,inj_cmd_t * cmd)2257c478bd9Sstevel@tonic-gate cmd_run(const inj_mode_ops_t *mode, void *hdl, inj_cmd_t *cmd)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate switch (cmd->cmd_type) {
2287c478bd9Sstevel@tonic-gate case CMD_SEND_EVENT:
2297c478bd9Sstevel@tonic-gate cmd_run_send(mode, hdl, cmd->cmd_event);
2307c478bd9Sstevel@tonic-gate break;
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate case CMD_SLEEP:
2337c478bd9Sstevel@tonic-gate (void) printf("sleeping for %d sec%s ... ",
2347c478bd9Sstevel@tonic-gate cmd->cmd_num, cmd->cmd_num > 1 ? "s" : "");
2357c478bd9Sstevel@tonic-gate (void) fflush(stdout);
2367c478bd9Sstevel@tonic-gate (void) sleep(cmd->cmd_num);
2377c478bd9Sstevel@tonic-gate (void) printf("done\n");
2387c478bd9Sstevel@tonic-gate break;
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate case CMD_RANDOM:
2417c478bd9Sstevel@tonic-gate cmd_run_random(mode, hdl, cmd);
2427c478bd9Sstevel@tonic-gate break;
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate default:
2457c478bd9Sstevel@tonic-gate warn("ignoring unknown command type: %d\n", cmd->cmd_type);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate void
inj_program_run(inj_list_t * prog,const inj_mode_ops_t * mode,void * mode_arg)2507c478bd9Sstevel@tonic-gate inj_program_run(inj_list_t *prog, const inj_mode_ops_t *mode, void *mode_arg)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate void *hdl = mode->mo_open(mode_arg);
2537c478bd9Sstevel@tonic-gate inj_cmd_t *cmd;
2547c478bd9Sstevel@tonic-gate int i;
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate for (cmd = inj_list_next(prog); cmd != NULL; cmd = inj_list_next(cmd)) {
2577c478bd9Sstevel@tonic-gate if (cmd->cmd_type == CMD_REPEAT) {
2587c478bd9Sstevel@tonic-gate for (i = 1; i <= cmd->cmd_num; i++) {
2597c478bd9Sstevel@tonic-gate if (verbose) {
2607c478bd9Sstevel@tonic-gate (void) printf("(repeat %d of %d)\n",
2617c478bd9Sstevel@tonic-gate i, cmd->cmd_num);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate cmd_run(mode, hdl, cmd->cmd_subcmd);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate } else
2667c478bd9Sstevel@tonic-gate cmd_run(mode, hdl, cmd);
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate mode->mo_close(hdl);
2707c478bd9Sstevel@tonic-gate }
271