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