xref: /illumos-gate/usr/src/cmd/busstat/busstat.c (revision bc54f855)
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  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*bc54f855SJohn Levon /*
28*bc54f855SJohn Levon  * Copyright (c) 2018, Joyent, Inc.
29*bc54f855SJohn Levon  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <strings.h>
347c478bd9Sstevel@tonic-gate #include <time.h>
357c478bd9Sstevel@tonic-gate #include <signal.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/stat.h>
387c478bd9Sstevel@tonic-gate #include <sys/time.h>
397c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
407c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
417c478bd9Sstevel@tonic-gate #include <limits.h>
427c478bd9Sstevel@tonic-gate #include <signal.h>
437c478bd9Sstevel@tonic-gate #include <fcntl.h>
447c478bd9Sstevel@tonic-gate #include <unistd.h>
457c478bd9Sstevel@tonic-gate #include <stropts.h>
467c478bd9Sstevel@tonic-gate #include <locale.h>
477c478bd9Sstevel@tonic-gate #include <libintl.h>
487c478bd9Sstevel@tonic-gate #include <libgen.h>
497c478bd9Sstevel@tonic-gate #include <nl_types.h>
507c478bd9Sstevel@tonic-gate #include <kstat.h>
517c478bd9Sstevel@tonic-gate #include <ctype.h>
527c478bd9Sstevel@tonic-gate #include <signal.h>
537c478bd9Sstevel@tonic-gate #include <errno.h>
547c478bd9Sstevel@tonic-gate #include <time.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include "busstat.h"
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /* Global defines */
607c478bd9Sstevel@tonic-gate static int		delta = TRUE;
617c478bd9Sstevel@tonic-gate static int		banner = TRUE;
627c478bd9Sstevel@tonic-gate static int		max_pic_num = 1;
637c478bd9Sstevel@tonic-gate static int		initial_read = TRUE;
647c478bd9Sstevel@tonic-gate static char		*pgmname;
657c478bd9Sstevel@tonic-gate static kstat_ctl_t	*kc;			/* libkstat cookie */
667c478bd9Sstevel@tonic-gate static dev_node_t	*dev_list_head	= NULL;
677c478bd9Sstevel@tonic-gate static dev_node_t	*dev_list_tail	= NULL;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Global flags.
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate static char	curr_dev_name[KSTAT_STRLEN];
737c478bd9Sstevel@tonic-gate static int	curr_inst_num;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static void print_evt(void);
767c478bd9Sstevel@tonic-gate static void print_dev(int, char *);
777c478bd9Sstevel@tonic-gate static void parse_cmd(int);
787c478bd9Sstevel@tonic-gate static void parse_dev_inst(char *);
797c478bd9Sstevel@tonic-gate static void parse_pic_evt(char *);
807c478bd9Sstevel@tonic-gate static void add_dev_node(char *, int);
817c478bd9Sstevel@tonic-gate static void add_all_dev_node(char *);
827c478bd9Sstevel@tonic-gate static void add_evt_node(dev_node_t *);
837c478bd9Sstevel@tonic-gate static void modify_evt_node(dev_node_t *, char *);
847c478bd9Sstevel@tonic-gate static void prune_evt_nodes(dev_node_t *);
857c478bd9Sstevel@tonic-gate static void setup_evts(void);
867c478bd9Sstevel@tonic-gate static void set_evt(dev_node_t *);
877c478bd9Sstevel@tonic-gate static void read_evts(void);
887c478bd9Sstevel@tonic-gate static void read_r_evt_node(dev_node_t *, int, kstat_named_t *);
897c478bd9Sstevel@tonic-gate static void read_w_evt_node(dev_node_t *, int, kstat_named_t *);
907c478bd9Sstevel@tonic-gate static void check_dr_ops(void);
917c478bd9Sstevel@tonic-gate static void remove_dev_node(dev_node_t *);
927c478bd9Sstevel@tonic-gate static dev_node_t *find_dev_node(char *, int, int);
937c478bd9Sstevel@tonic-gate static kstat_t *find_pic_kstat(char *, int, char *);
947c478bd9Sstevel@tonic-gate static int64_t is_num(char *);
957c478bd9Sstevel@tonic-gate static void print_banner(void);
967c478bd9Sstevel@tonic-gate static void print_timestamp(void);
977c478bd9Sstevel@tonic-gate static void usage(void);
987c478bd9Sstevel@tonic-gate static void *safe_malloc(size_t);
997c478bd9Sstevel@tonic-gate static void set_timer(int);
1007c478bd9Sstevel@tonic-gate static void handle_sig(int);
1017c478bd9Sstevel@tonic-gate static int strisnum(const char *);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)1047c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate 	int		c, i;
1077c478bd9Sstevel@tonic-gate 	int		interval = 1;	/* Interval between displays */
1087c478bd9Sstevel@tonic-gate 	int		count = 0;	/* Number of times to sample */
1097c478bd9Sstevel@tonic-gate 	int		write_evts = FALSE;
1107c478bd9Sstevel@tonic-gate 	int		pos = 0;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1137c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
1147c478bd9Sstevel@tonic-gate #endif
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/* For I18N */
1177c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1187c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	pgmname = basename(argv[0]);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	if ((kc = kstat_open()) == NULL) {
1237c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could not "
1247c478bd9Sstevel@tonic-gate 			"open /dev/kstat\n"), pgmname);
1257c478bd9Sstevel@tonic-gate 		exit(1);
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "e:w:r:ahln")) != EOF) {
1297c478bd9Sstevel@tonic-gate 		switch (c) {
1307c478bd9Sstevel@tonic-gate 		case 'a':
1317c478bd9Sstevel@tonic-gate 			delta = FALSE;
1327c478bd9Sstevel@tonic-gate 			break;
1337c478bd9Sstevel@tonic-gate 		case 'e':
1347c478bd9Sstevel@tonic-gate 			(void) print_evt();
1357c478bd9Sstevel@tonic-gate 			break;
1367c478bd9Sstevel@tonic-gate 		case 'h':
1377c478bd9Sstevel@tonic-gate 			usage();
1387c478bd9Sstevel@tonic-gate 			break;
1397c478bd9Sstevel@tonic-gate 		case 'l':
1407c478bd9Sstevel@tonic-gate 			(void) print_dev(argc, argv[argc-1]);
1417c478bd9Sstevel@tonic-gate 			break;
1427c478bd9Sstevel@tonic-gate 		case 'n':
1437c478bd9Sstevel@tonic-gate 			banner = FALSE;
1447c478bd9Sstevel@tonic-gate 			break;
1457c478bd9Sstevel@tonic-gate 		case 'r':
1467c478bd9Sstevel@tonic-gate 			(void) parse_cmd(READ_EVT);
1477c478bd9Sstevel@tonic-gate 			break;
1487c478bd9Sstevel@tonic-gate 		case 'w':
1497c478bd9Sstevel@tonic-gate 			(void) parse_cmd(WRITE_EVT);
1507c478bd9Sstevel@tonic-gate 			write_evts = TRUE;
1517c478bd9Sstevel@tonic-gate 			break;
1527c478bd9Sstevel@tonic-gate 		default:
1537c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: invalid "
1547c478bd9Sstevel@tonic-gate 				"option\n"), pgmname);
1557c478bd9Sstevel@tonic-gate 			usage();
1567c478bd9Sstevel@tonic-gate 			break;
1577c478bd9Sstevel@tonic-gate 		}
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if ((argc == 1) || (dev_list_head == NULL))
1617c478bd9Sstevel@tonic-gate 		usage();
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/*
1647c478bd9Sstevel@tonic-gate 	 * validate remaining operands are numeric.
1657c478bd9Sstevel@tonic-gate 	 */
1667c478bd9Sstevel@tonic-gate 	pos = optind;
1677c478bd9Sstevel@tonic-gate 	while (pos < argc) {
1687c478bd9Sstevel@tonic-gate 		if (strisnum(argv[pos]) == 0) {
1697c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1707c478bd9Sstevel@tonic-gate 				gettext("%s: syntax error\n"),
1717c478bd9Sstevel@tonic-gate 				pgmname);
1727c478bd9Sstevel@tonic-gate 			usage();
1737c478bd9Sstevel@tonic-gate 		}
1747c478bd9Sstevel@tonic-gate 		pos++;
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	if (optind < argc) {
1787c478bd9Sstevel@tonic-gate 		if ((interval = atoi(argv[optind])) == 0) {
1797c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: invalid "
1807c478bd9Sstevel@tonic-gate 				"interval value\n"), pgmname);
1817c478bd9Sstevel@tonic-gate 			exit(1);
1827c478bd9Sstevel@tonic-gate 		}
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 		optind++;
1857c478bd9Sstevel@tonic-gate 		if (optind < argc)
1867c478bd9Sstevel@tonic-gate 			if ((count = atoi(argv[optind])) <= 0) {
1877c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("%s: "
1887c478bd9Sstevel@tonic-gate 					"invalid iteration value.\n"),
1897c478bd9Sstevel@tonic-gate 					    pgmname);
1907c478bd9Sstevel@tonic-gate 				exit(1);
1917c478bd9Sstevel@tonic-gate 			}
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	set_timer(interval);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	/*
1977c478bd9Sstevel@tonic-gate 	 * Set events for the first time.
1987c478bd9Sstevel@tonic-gate 	 */
1997c478bd9Sstevel@tonic-gate 	if (write_evts == TRUE)
2007c478bd9Sstevel@tonic-gate 		setup_evts();
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	if (count > 0) {
2047c478bd9Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
2057c478bd9Sstevel@tonic-gate 			if (banner)
2067c478bd9Sstevel@tonic-gate 				print_banner();
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 			check_dr_ops();
2097c478bd9Sstevel@tonic-gate 			read_evts();
2107c478bd9Sstevel@tonic-gate 			(void) fflush(stdout);
2117c478bd9Sstevel@tonic-gate 			(void) pause();
2127c478bd9Sstevel@tonic-gate 		}
2137c478bd9Sstevel@tonic-gate 	} else {
2147c478bd9Sstevel@tonic-gate 		for (;;) {
2157c478bd9Sstevel@tonic-gate 			if (banner)
2167c478bd9Sstevel@tonic-gate 				print_banner();
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 			check_dr_ops();
2197c478bd9Sstevel@tonic-gate 			read_evts();
2207c478bd9Sstevel@tonic-gate 			(void) fflush(stdout);
2217c478bd9Sstevel@tonic-gate 			(void) pause();
2227c478bd9Sstevel@tonic-gate 		}
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	read_evts();
2267c478bd9Sstevel@tonic-gate 	return (0);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate  * Display all the events that can be set on a device.
2327c478bd9Sstevel@tonic-gate  */
2337c478bd9Sstevel@tonic-gate void
print_evt()2347c478bd9Sstevel@tonic-gate print_evt()
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	kstat_t		*cnt_ksp;
2377c478bd9Sstevel@tonic-gate 	kstat_t		*pic_ksp;
2387c478bd9Sstevel@tonic-gate 	kstat_named_t	*cnt_data;
2397c478bd9Sstevel@tonic-gate 	kstat_named_t	*pic_data;
2407c478bd9Sstevel@tonic-gate 	char		*device = NULL;
2417c478bd9Sstevel@tonic-gate 	char		*value;
2427c478bd9Sstevel@tonic-gate 	int		inst_num = -1;
2437c478bd9Sstevel@tonic-gate 	int		i = 0;
2447c478bd9Sstevel@tonic-gate 	int		j;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	value = optarg;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/*
2497c478bd9Sstevel@tonic-gate 	 * Search through the value string for a numeric char which will
2507c478bd9Sstevel@tonic-gate 	 * be the device instance number, if the user specified one. If
2517c478bd9Sstevel@tonic-gate 	 * the user did not specify an instance then the return value from
2527c478bd9Sstevel@tonic-gate 	 * strscpn will be equal to the string length. In this case we
2537c478bd9Sstevel@tonic-gate 	 * use a default value of -1 for the kstat_lookup which causes
2547c478bd9Sstevel@tonic-gate 	 * the device number to be ignored during the search.
2557c478bd9Sstevel@tonic-gate 	 */
2567c478bd9Sstevel@tonic-gate 	if (((i = strcspn(value, "0123456789")) > 0) && (i != strlen(value))) {
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 		device = safe_malloc(sizeof (char) * i+1);
2597c478bd9Sstevel@tonic-gate 		device[i] = '\0';
2607c478bd9Sstevel@tonic-gate 		(void) strncpy(device, value, i);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 		value = value + i;
2637c478bd9Sstevel@tonic-gate 		inst_num = atoi(value);
2647c478bd9Sstevel@tonic-gate 	}
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	/*
2677c478bd9Sstevel@tonic-gate 	 * No instance specified.
2687c478bd9Sstevel@tonic-gate 	 */
2697c478bd9Sstevel@tonic-gate 	if (device == NULL)
2707c478bd9Sstevel@tonic-gate 		device = value;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * Get the "counters" kstat, so that we can get
2747c478bd9Sstevel@tonic-gate 	 * the names of the "picN" kstats, which hold the
2757c478bd9Sstevel@tonic-gate 	 * event names.
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	if ((cnt_ksp = kstat_lookup(kc, device, inst_num, "counters"))
2787c478bd9Sstevel@tonic-gate 								== NULL) {
2797c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: invalid device "
2807c478bd9Sstevel@tonic-gate 			"name or instance (%s)\n"), pgmname, device);
2817c478bd9Sstevel@tonic-gate 		exit(1);
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
2857c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could not read "
2867c478bd9Sstevel@tonic-gate 			"kstat.\n"), pgmname);
2877c478bd9Sstevel@tonic-gate 		exit(1);
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/*
2937c478bd9Sstevel@tonic-gate 	 * Start at 1 as the first entry in the "counters"
2947c478bd9Sstevel@tonic-gate 	 * kstat is the pcr value/name. We are looking for the
2957c478bd9Sstevel@tonic-gate 	 * name of the "picN" kstats. For each one found store
2967c478bd9Sstevel@tonic-gate 	 * a pointer to it in pic_data[].
2977c478bd9Sstevel@tonic-gate 	 */
2987c478bd9Sstevel@tonic-gate 	if (cnt_ksp->ks_ndata <= 1) {
2997c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: invalid kstat "
3007c478bd9Sstevel@tonic-gate 			"structure.\n"), pgmname);
3017c478bd9Sstevel@tonic-gate 		exit(1);
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	for (i = 1; i < cnt_ksp->ks_ndata; i++) {
3057c478bd9Sstevel@tonic-gate 		if ((pic_ksp = find_pic_kstat(device, inst_num,
3067c478bd9Sstevel@tonic-gate 			cnt_data[i].name)) == NULL) {
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: could not read "
3097c478bd9Sstevel@tonic-gate 				"pic kstat data structure for %s\n"),
3107c478bd9Sstevel@tonic-gate 				    pgmname, cnt_ksp->ks_module);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 			exit(1);
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
3167c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: could not read "
3177c478bd9Sstevel@tonic-gate 				"pic kstat.\n"), pgmname);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 			exit(1);
3207c478bd9Sstevel@tonic-gate 		}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 		pic_data = (kstat_named_t *)pic_ksp->ks_data;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 		(void) printf(gettext("pic%-8d\n"), i-1);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 		for (j = 0; j < pic_ksp->ks_ndata-1; j++) {
3277c478bd9Sstevel@tonic-gate 			(void) printf("%-30s\n", pic_data[j].name);
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 		(void) printf("\n");
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	exit(0);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate  * Display the names and instances of the devices on the system
3397c478bd9Sstevel@tonic-gate  * which can support performance monitoring.
3407c478bd9Sstevel@tonic-gate  */
3417c478bd9Sstevel@tonic-gate void
print_dev(int argc,char * str)3427c478bd9Sstevel@tonic-gate print_dev(int argc, char *str)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	kstat_t	*ksp;
3457c478bd9Sstevel@tonic-gate 	static int first_time = 1;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	if ((argc > 2) || (strcmp(str, "-l") != 0)) {
3487c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: no arguments "
3497c478bd9Sstevel@tonic-gate 			"permitted with -l option.\n"),
3507c478bd9Sstevel@tonic-gate 			    pgmname);
3517c478bd9Sstevel@tonic-gate 		usage();
3527c478bd9Sstevel@tonic-gate 		exit(1);
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/*
3567c478bd9Sstevel@tonic-gate 	 * For each device node, print the node name (device
3577c478bd9Sstevel@tonic-gate 	 * name) and the instance numbers.
3587c478bd9Sstevel@tonic-gate 	 */
3597c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
3607c478bd9Sstevel@tonic-gate 		if ((strcmp(ksp->ks_class, "bus") == 0) &&
3617c478bd9Sstevel@tonic-gate 			(strcmp(ksp->ks_name, "counters") == 0)) {
3627c478bd9Sstevel@tonic-gate 					if (first_time) {
3637c478bd9Sstevel@tonic-gate 						(void) printf(gettext("Busstat "
3647c478bd9Sstevel@tonic-gate 							"Device(s):\n"));
3657c478bd9Sstevel@tonic-gate 						first_time = 0;
3667c478bd9Sstevel@tonic-gate 					}
3677c478bd9Sstevel@tonic-gate 					(void) printf("%s%d ", ksp->ks_module,
3687c478bd9Sstevel@tonic-gate 						ksp->ks_instance);
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	if (first_time)
3737c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: No devices available "
3747c478bd9Sstevel@tonic-gate 			"in system."), pgmname);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	(void) printf("\n");
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	exit(0);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate /*
3827c478bd9Sstevel@tonic-gate  * Parses the cmd line, checks all the values and
3837c478bd9Sstevel@tonic-gate  * creates the appropiate data structures.
3847c478bd9Sstevel@tonic-gate  */
3857c478bd9Sstevel@tonic-gate void
parse_cmd(int mode)3867c478bd9Sstevel@tonic-gate parse_cmd(int mode)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate 	char		*options = optarg, *value;
3897c478bd9Sstevel@tonic-gate 	int		arg_num	= 0;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	while ((value = (char *)strtok(options, ",=")) != NULL) {
3927c478bd9Sstevel@tonic-gate 		/*
3937c478bd9Sstevel@tonic-gate 		 * First arg must be device name.
3947c478bd9Sstevel@tonic-gate 		 */
3957c478bd9Sstevel@tonic-gate 		if (!arg_num) {
3967c478bd9Sstevel@tonic-gate 			parse_dev_inst(value);
3977c478bd9Sstevel@tonic-gate 		} else {
3987c478bd9Sstevel@tonic-gate 			if (mode == READ_EVT) {
3997c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("%s: "
4007c478bd9Sstevel@tonic-gate 					"event names or pic values not "
4017c478bd9Sstevel@tonic-gate 					"permitted with -r option.\n"),
4027c478bd9Sstevel@tonic-gate 					    pgmname);
403*bc54f855SJohn Levon 				usage();
4047c478bd9Sstevel@tonic-gate 				exit(1);
4057c478bd9Sstevel@tonic-gate 			}
4067c478bd9Sstevel@tonic-gate 			/*
4077c478bd9Sstevel@tonic-gate 			 * Now dealing with pic values.
4087c478bd9Sstevel@tonic-gate 			 */
4097c478bd9Sstevel@tonic-gate 			parse_pic_evt(value);
4107c478bd9Sstevel@tonic-gate 		}
4117c478bd9Sstevel@tonic-gate 		/*
4127c478bd9Sstevel@tonic-gate 		 * After first strtok call, must set first arg
4137c478bd9Sstevel@tonic-gate 		 * to null if wish to parse rest of string.
4147c478bd9Sstevel@tonic-gate 		 * See strtok man page.
4157c478bd9Sstevel@tonic-gate 		 */
4167c478bd9Sstevel@tonic-gate 		if (options != NULL)
4177c478bd9Sstevel@tonic-gate 			options = NULL;
4187c478bd9Sstevel@tonic-gate 		arg_num++;
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate  * Parse the device name/instance section of the
4257c478bd9Sstevel@tonic-gate  * command line.
4267c478bd9Sstevel@tonic-gate  */
4277c478bd9Sstevel@tonic-gate void
parse_dev_inst(char * value)4287c478bd9Sstevel@tonic-gate parse_dev_inst(char *value)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	int		i;
4317c478bd9Sstevel@tonic-gate 	char		*device	= NULL;
4327c478bd9Sstevel@tonic-gate 	int		malloc_flag = FALSE;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	if (strlen(value) == 0) {
4357c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: No device name given.\n"),
4367c478bd9Sstevel@tonic-gate 			pgmname);
4377c478bd9Sstevel@tonic-gate 		exit(1);
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/*
4417c478bd9Sstevel@tonic-gate 	 * Break string into device name and
4427c478bd9Sstevel@tonic-gate 	 * instance number (if given).
4437c478bd9Sstevel@tonic-gate 	 */
4447c478bd9Sstevel@tonic-gate 	if ((i = strcspn(value, "0123456789")) > 0) {
4457c478bd9Sstevel@tonic-gate 		if (i != strlen(value)) {
4467c478bd9Sstevel@tonic-gate 			device = safe_malloc(sizeof (char) * i+1);
4477c478bd9Sstevel@tonic-gate 			device[i] = '\0';
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 			(void) strncpy(device, value, i);
4507c478bd9Sstevel@tonic-gate 			malloc_flag = TRUE;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 			value = value + i;
4537c478bd9Sstevel@tonic-gate 		}
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/*
4577c478bd9Sstevel@tonic-gate 	 * No instance was specified so we assume
4587c478bd9Sstevel@tonic-gate 	 * the user wants to use ALL instances.
4597c478bd9Sstevel@tonic-gate 	 */
4607c478bd9Sstevel@tonic-gate 	if (device == NULL) {
4617c478bd9Sstevel@tonic-gate 		if ((device = value) == NULL) {
4627c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: no device "
4637c478bd9Sstevel@tonic-gate 				"specified\n"), pgmname);
4647c478bd9Sstevel@tonic-gate 			exit(1);
4657c478bd9Sstevel@tonic-gate 		}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 		/*
4687c478bd9Sstevel@tonic-gate 		 * Set global flags.
4697c478bd9Sstevel@tonic-gate 		 */
4707c478bd9Sstevel@tonic-gate 		(void) strcpy(curr_dev_name, device);
4717c478bd9Sstevel@tonic-gate 		curr_inst_num = -1;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 		add_all_dev_node(device);
4747c478bd9Sstevel@tonic-gate 		goto clean_up;
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	/*
4787c478bd9Sstevel@tonic-gate 	 * Set global flags.
4797c478bd9Sstevel@tonic-gate 	 */
4807c478bd9Sstevel@tonic-gate 	(void) strcpy(curr_dev_name, device);
4817c478bd9Sstevel@tonic-gate 	curr_inst_num = atoi(value);
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	add_dev_node(device, curr_inst_num);
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate clean_up:
4867c478bd9Sstevel@tonic-gate 	if (malloc_flag) {
4877c478bd9Sstevel@tonic-gate 		free(device);
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate  * Adds new event nodes to existing ones, modifies existing ones, or
4947c478bd9Sstevel@tonic-gate  * prunes existing ones.
4957c478bd9Sstevel@tonic-gate  *
4967c478bd9Sstevel@tonic-gate  * A specific instance call will overwrite an earlier all
4977c478bd9Sstevel@tonic-gate  * instances call, but *not* vice-versa.
4987c478bd9Sstevel@tonic-gate  *
4997c478bd9Sstevel@tonic-gate  * All the state transitions are given below.
5007c478bd9Sstevel@tonic-gate  *
5017c478bd9Sstevel@tonic-gate  *
5027c478bd9Sstevel@tonic-gate  *                       Call Type
5037c478bd9Sstevel@tonic-gate  * STATE |  Specific Instance          All Instances.
5047c478bd9Sstevel@tonic-gate  * ======================================================
5057c478bd9Sstevel@tonic-gate  * INIT  | Change state to       | Change state to ALL,
5067c478bd9Sstevel@tonic-gate  *       | INST, add events      | add events.
5077c478bd9Sstevel@tonic-gate  *       |                       |
5087c478bd9Sstevel@tonic-gate  * INST  | State unchanged,      | No change.
5097c478bd9Sstevel@tonic-gate  *       | Add events.           |
5107c478bd9Sstevel@tonic-gate  *       |                       |
5117c478bd9Sstevel@tonic-gate  * ALL   | Change state to       | State unchanged,
5127c478bd9Sstevel@tonic-gate  *       | INST, replace events. | add events.
5137c478bd9Sstevel@tonic-gate  */
5147c478bd9Sstevel@tonic-gate void
parse_pic_evt(char * value)5157c478bd9Sstevel@tonic-gate parse_pic_evt(char *value)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	dev_node_t	*dev_node;
5187c478bd9Sstevel@tonic-gate 	char		*evt_name;
5197c478bd9Sstevel@tonic-gate 	int		pic_num;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if (strlen(value) <= PIC_STR_LEN) {
5227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: no pic number "
5237c478bd9Sstevel@tonic-gate 			"specified.\n"), pgmname);
5247c478bd9Sstevel@tonic-gate 		exit(1);
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	if (strncmp(value, "pic", PIC_STR_LEN) != 0) {
5287c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: missing pic "
5297c478bd9Sstevel@tonic-gate 			"specifier\n"), pgmname);
5307c478bd9Sstevel@tonic-gate 		usage();
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	/*
5347c478bd9Sstevel@tonic-gate 	 * Step over the 'pic' part of the string to
5357c478bd9Sstevel@tonic-gate 	 * get the pic number.
5367c478bd9Sstevel@tonic-gate 	 */
5377c478bd9Sstevel@tonic-gate 	value = value + PIC_STR_LEN;
5387c478bd9Sstevel@tonic-gate 	pic_num = atoi(value);
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	if ((pic_num == -1) || (pic_num > max_pic_num -1)) {
5417c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: invalid pic "
5427c478bd9Sstevel@tonic-gate 			"number.\n"), pgmname);
5437c478bd9Sstevel@tonic-gate 		exit(1);
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if ((evt_name = (char *)strtok(NULL, "=,")) == NULL) {
5477c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: no event "
5487c478bd9Sstevel@tonic-gate 			"specified.\n"), pgmname);
5497c478bd9Sstevel@tonic-gate 		exit(1);
5507c478bd9Sstevel@tonic-gate 	}
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	/*
5537c478bd9Sstevel@tonic-gate 	 * Dealing with a specific instance.
5547c478bd9Sstevel@tonic-gate 	 */
5557c478bd9Sstevel@tonic-gate 	if (curr_inst_num >= 0) {
5567c478bd9Sstevel@tonic-gate 		if ((dev_node = find_dev_node(curr_dev_name,
5577c478bd9Sstevel@tonic-gate 			curr_inst_num, pic_num)) == NULL) {
5587c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: could not find "
5597c478bd9Sstevel@tonic-gate 				"data structures for %s\n"),
5607c478bd9Sstevel@tonic-gate 				    pgmname, curr_dev_name);
5617c478bd9Sstevel@tonic-gate 			exit(1);
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		if (dev_node->r_w == EVT_READ) {
5657c478bd9Sstevel@tonic-gate 			modify_evt_node(dev_node, evt_name);
5667c478bd9Sstevel@tonic-gate 			dev_node->r_w = EVT_WRITE;
5677c478bd9Sstevel@tonic-gate 			dev_node->state = STATE_INST;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		} else if ((dev_node->r_w == EVT_WRITE) &&
5707c478bd9Sstevel@tonic-gate 			(dev_node->state == STATE_ALL)) {
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 			prune_evt_nodes(dev_node);
5737c478bd9Sstevel@tonic-gate 			modify_evt_node(dev_node, evt_name);
5747c478bd9Sstevel@tonic-gate 			dev_node->state = STATE_INST;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		} else if ((dev_node->r_w == EVT_WRITE) &&
5777c478bd9Sstevel@tonic-gate 			(dev_node->state == STATE_INST)) {
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 			add_evt_node(dev_node);
5807c478bd9Sstevel@tonic-gate 			modify_evt_node(dev_node, evt_name);
5817c478bd9Sstevel@tonic-gate 		}
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 		return;
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	/*
5877c478bd9Sstevel@tonic-gate 	 * Dealing with all instances of a specific device.
5887c478bd9Sstevel@tonic-gate 	 */
5897c478bd9Sstevel@tonic-gate 	dev_node = dev_list_head;
5907c478bd9Sstevel@tonic-gate 	while (dev_node != NULL) {
5917c478bd9Sstevel@tonic-gate 		if ((strcmp(dev_node->name, curr_dev_name) == 0) &&
5927c478bd9Sstevel@tonic-gate 			(dev_node->pic_num == pic_num)) {
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 			if (dev_node->r_w == EVT_READ) {
5957c478bd9Sstevel@tonic-gate 				modify_evt_node(dev_node,
5967c478bd9Sstevel@tonic-gate 					evt_name);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 				dev_node->r_w = EVT_WRITE;
5997c478bd9Sstevel@tonic-gate 				dev_node->state = STATE_ALL;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 			} else if ((dev_node->r_w == EVT_WRITE) &&
6027c478bd9Sstevel@tonic-gate 				(dev_node->state == STATE_ALL)) {
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 				add_evt_node(dev_node);
6057c478bd9Sstevel@tonic-gate 				modify_evt_node(dev_node, evt_name);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 			}
6087c478bd9Sstevel@tonic-gate 		}
6097c478bd9Sstevel@tonic-gate 		dev_node = dev_node->next;
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate /*
6157c478bd9Sstevel@tonic-gate  * Create a dev_node structure for this device if one does not
6167c478bd9Sstevel@tonic-gate  * already exist.
6177c478bd9Sstevel@tonic-gate  */
6187c478bd9Sstevel@tonic-gate void
add_dev_node(char * dev_name,int inst_num)6197c478bd9Sstevel@tonic-gate add_dev_node(char *dev_name, int inst_num)
6207c478bd9Sstevel@tonic-gate {
6217c478bd9Sstevel@tonic-gate 	dev_node_t	*new_dev_node;
6227c478bd9Sstevel@tonic-gate 	kstat_named_t	*cnt_data;
6237c478bd9Sstevel@tonic-gate 	kstat_t		*cnt_ksp;
6247c478bd9Sstevel@tonic-gate 	kstat_t		*pic_ksp;
6257c478bd9Sstevel@tonic-gate 	int		pic_num;
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	if ((cnt_ksp = kstat_lookup(kc, dev_name,
6297c478bd9Sstevel@tonic-gate 		inst_num, "counters")) == NULL) {
6307c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: invalid device "
6317c478bd9Sstevel@tonic-gate 			"name or instance (%s%d)\n"), pgmname,
6327c478bd9Sstevel@tonic-gate 				dev_name, inst_num);
6337c478bd9Sstevel@tonic-gate 		exit(1);
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
6377c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s : could not read counters "
6387c478bd9Sstevel@tonic-gate 			"kstat for device %s.\n"), pgmname, dev_name);
6397c478bd9Sstevel@tonic-gate 		exit(1);
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	if (cnt_ksp->ks_ndata <= 1) {
6457c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s : invalid "
6467c478bd9Sstevel@tonic-gate 			"kstat structure.\n"), pgmname);
6477c478bd9Sstevel@tonic-gate 		exit(1);
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	/*
6517c478bd9Sstevel@tonic-gate 	 * max_pic_num used to format headers correctly
6527c478bd9Sstevel@tonic-gate 	 * for printing.
6537c478bd9Sstevel@tonic-gate 	 */
6547c478bd9Sstevel@tonic-gate 	if (cnt_ksp->ks_ndata-1 > max_pic_num)
6557c478bd9Sstevel@tonic-gate 		max_pic_num = cnt_ksp->ks_ndata-1;
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	/* for each pic... */
6587c478bd9Sstevel@tonic-gate 	for (pic_num = 0; pic_num < cnt_ksp->ks_ndata-1; pic_num++) {
6597c478bd9Sstevel@tonic-gate 		if (find_dev_node(dev_name, inst_num, pic_num) != NULL) {
6607c478bd9Sstevel@tonic-gate 			/* Node already exists */
6617c478bd9Sstevel@tonic-gate 			continue;
6627c478bd9Sstevel@tonic-gate 		}
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 		new_dev_node = safe_malloc(sizeof (dev_node_t));
6657c478bd9Sstevel@tonic-gate 		bzero(new_dev_node, sizeof (dev_node_t));
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 		(void) strcpy(new_dev_node->name, dev_name);
6687c478bd9Sstevel@tonic-gate 		new_dev_node->dev_inst = inst_num;
6697c478bd9Sstevel@tonic-gate 		new_dev_node->pic_num = pic_num;
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 		new_dev_node->cnt_ksp = cnt_ksp;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 		if ((pic_ksp = find_pic_kstat(dev_name, inst_num,
6747c478bd9Sstevel@tonic-gate 			cnt_data[pic_num+1].name)) == NULL) {
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: could not find "
6777c478bd9Sstevel@tonic-gate 				"pic kstat structure for %s.\n"),
6787c478bd9Sstevel@tonic-gate 				    pgmname, cnt_ksp->ks_module);
6797c478bd9Sstevel@tonic-gate 			exit(1);
6807c478bd9Sstevel@tonic-gate 		}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 		new_dev_node->pic_ksp = pic_ksp;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 		add_evt_node(new_dev_node);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 		new_dev_node->state = STATE_INIT;
6877c478bd9Sstevel@tonic-gate 		new_dev_node->r_w = EVT_READ;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 		if (dev_list_head == NULL) {
6907c478bd9Sstevel@tonic-gate 			dev_list_head = new_dev_node;
6917c478bd9Sstevel@tonic-gate 			dev_list_tail = new_dev_node;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 		} else if (find_dev_node(dev_name, inst_num, pic_num) == NULL) {
6947c478bd9Sstevel@tonic-gate 			dev_list_tail->next = new_dev_node;
6957c478bd9Sstevel@tonic-gate 			dev_list_tail = new_dev_node;
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate  * Add all possible instances of a device.
7037c478bd9Sstevel@tonic-gate  */
7047c478bd9Sstevel@tonic-gate void
add_all_dev_node(char * dev_name)7057c478bd9Sstevel@tonic-gate add_all_dev_node(char *dev_name)
7067c478bd9Sstevel@tonic-gate {
7077c478bd9Sstevel@tonic-gate 	kstat_t	*ksp;
7087c478bd9Sstevel@tonic-gate 	int	match = 0;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
7117c478bd9Sstevel@tonic-gate 		if ((strcmp(ksp->ks_class, "bus") == 0) &&
7127c478bd9Sstevel@tonic-gate 			(strcmp(ksp->ks_name, "counters") == 0) &&
7137c478bd9Sstevel@tonic-gate 			(strcmp(ksp->ks_module, dev_name) == 0)) {
7147c478bd9Sstevel@tonic-gate 				match = 1;
7157c478bd9Sstevel@tonic-gate 				add_dev_node(dev_name, ksp->ks_instance);
7167c478bd9Sstevel@tonic-gate 		}
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	if (match == 0) {
7207c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7217c478bd9Sstevel@tonic-gate 			gettext("%s: invalid device name (%s)\n"),
7227c478bd9Sstevel@tonic-gate 			pgmname, dev_name);
7237c478bd9Sstevel@tonic-gate 		exit(1);
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate  * Add an event node to a specified device node.
7307c478bd9Sstevel@tonic-gate  */
7317c478bd9Sstevel@tonic-gate void
add_evt_node(dev_node_t * dev_node)7327c478bd9Sstevel@tonic-gate add_evt_node(dev_node_t *dev_node)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate 	evt_node_t	*new_evt_node;
7357c478bd9Sstevel@tonic-gate 	evt_node_t	*curr_evt_node;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	new_evt_node = safe_malloc(sizeof (evt_node_t));
7387c478bd9Sstevel@tonic-gate 	bzero(new_evt_node, sizeof (evt_node_t));
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	(void) strcpy(new_evt_node->evt_name, "");
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	if (dev_node->evt_node == NULL) {
7437c478bd9Sstevel@tonic-gate 		dev_node->evt_node = new_evt_node;
7447c478bd9Sstevel@tonic-gate 		new_evt_node->next = new_evt_node;
7457c478bd9Sstevel@tonic-gate 		return;
7467c478bd9Sstevel@tonic-gate 	} else {
7477c478bd9Sstevel@tonic-gate 		curr_evt_node = dev_node->evt_node;
7487c478bd9Sstevel@tonic-gate 		while (curr_evt_node->next != dev_node->evt_node)
7497c478bd9Sstevel@tonic-gate 			curr_evt_node = curr_evt_node->next;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 		curr_evt_node->next = new_evt_node;
7527c478bd9Sstevel@tonic-gate 		new_evt_node->next = dev_node->evt_node;
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate /*
7587c478bd9Sstevel@tonic-gate  * Fill in or change the fields of an evt node.
7597c478bd9Sstevel@tonic-gate  */
7607c478bd9Sstevel@tonic-gate void
modify_evt_node(dev_node_t * dev_node,char * evt_name)7617c478bd9Sstevel@tonic-gate modify_evt_node(dev_node_t *dev_node, char *evt_name)
7627c478bd9Sstevel@tonic-gate {
7637c478bd9Sstevel@tonic-gate 	evt_node_t	*evt_node;
7647c478bd9Sstevel@tonic-gate 	kstat_t		*pic_ksp;
7657c478bd9Sstevel@tonic-gate 	kstat_named_t	*pic_data;
7667c478bd9Sstevel@tonic-gate 	int64_t		evt_num = 0;
7677c478bd9Sstevel@tonic-gate 	int		evt_match = 0;
7687c478bd9Sstevel@tonic-gate 	int		i;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	evt_node = dev_node->evt_node;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	/*
7737c478bd9Sstevel@tonic-gate 	 * Find the last event node.
7747c478bd9Sstevel@tonic-gate 	 */
7757c478bd9Sstevel@tonic-gate 	if (evt_node->next != evt_node) {
7767c478bd9Sstevel@tonic-gate 		while (evt_node->next != dev_node->evt_node) {
7777c478bd9Sstevel@tonic-gate 			evt_node = evt_node->next;
7787c478bd9Sstevel@tonic-gate 		}
7797c478bd9Sstevel@tonic-gate 	}
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	evt_node->prev_count = 0;
7827c478bd9Sstevel@tonic-gate 	evt_node->total = 0;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	pic_ksp = dev_node->pic_ksp;
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
7877c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could not read "
7887c478bd9Sstevel@tonic-gate 			"pic kstat.\n"), pgmname);
7897c478bd9Sstevel@tonic-gate 		exit(1);
7907c478bd9Sstevel@tonic-gate 	}
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	pic_data = (kstat_named_t *)dev_node->pic_ksp->ks_data;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	/*
7957c478bd9Sstevel@tonic-gate 	 * The event can either be given as a event name (string) or
7967c478bd9Sstevel@tonic-gate 	 * as a pcr mask. If given as pcr mask, we try to match it
7977c478bd9Sstevel@tonic-gate 	 * to an event name, and use that name. Otherwise we just use
7987c478bd9Sstevel@tonic-gate 	 * the pcr mask value.
7997c478bd9Sstevel@tonic-gate 	 */
8007c478bd9Sstevel@tonic-gate 	if ((evt_num = is_num(evt_name)) == EVT_STR) {
8017c478bd9Sstevel@tonic-gate 		(void) strcpy(evt_node->evt_name, evt_name);
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 		for (i = 0; i < dev_node->pic_ksp->ks_ndata; i++) {
8047c478bd9Sstevel@tonic-gate 			if (strcmp(evt_name, pic_data[i].name) == 0) {
8057c478bd9Sstevel@tonic-gate 				evt_node->evt_pcr_mask = pic_data[i].value.ui64;
8067c478bd9Sstevel@tonic-gate 				return;
8077c478bd9Sstevel@tonic-gate 			}
8087c478bd9Sstevel@tonic-gate 		}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
8117c478bd9Sstevel@tonic-gate 			gettext("%s: %s is not a valid event name.\n"),
8127c478bd9Sstevel@tonic-gate 			pgmname, evt_name);
8137c478bd9Sstevel@tonic-gate 		exit(1);
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	} else {
8167c478bd9Sstevel@tonic-gate 		/*
8177c478bd9Sstevel@tonic-gate 		 * See if the pcr mask given by the user matches that for any
8187c478bd9Sstevel@tonic-gate 		 * existing event.
8197c478bd9Sstevel@tonic-gate 		 */
8207c478bd9Sstevel@tonic-gate 		for (i = 0; i < dev_node->pic_ksp->ks_ndata; i++) {
8217c478bd9Sstevel@tonic-gate 			if (evt_num == pic_data[i].value.ui64) {
8227c478bd9Sstevel@tonic-gate 				(void) strcpy(evt_node->evt_name,
8237c478bd9Sstevel@tonic-gate 					pic_data[i].name);
8247c478bd9Sstevel@tonic-gate 				evt_match = 1;
8257c478bd9Sstevel@tonic-gate 				break;
8267c478bd9Sstevel@tonic-gate 			}
8277c478bd9Sstevel@tonic-gate 		}
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 		if (evt_match == 0)
8307c478bd9Sstevel@tonic-gate 			(void) sprintf(evt_node->evt_name, "%llx", evt_num);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 		evt_node->evt_pcr_mask = evt_num;
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate }
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate /*
8387c478bd9Sstevel@tonic-gate  * Removes all bar one of the evt_nodes that are hanging off the
8397c478bd9Sstevel@tonic-gate  * specified dev_node.
8407c478bd9Sstevel@tonic-gate  */
8417c478bd9Sstevel@tonic-gate void
prune_evt_nodes(dev_node_t * dev_node)8427c478bd9Sstevel@tonic-gate prune_evt_nodes(dev_node_t *dev_node)
8437c478bd9Sstevel@tonic-gate {
8447c478bd9Sstevel@tonic-gate 	evt_node_t	*next_evt_node;
8457c478bd9Sstevel@tonic-gate 	evt_node_t	*curr_evt_node;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	/*
8487c478bd9Sstevel@tonic-gate 	 * Only one evt node, nothing for us to do.
8497c478bd9Sstevel@tonic-gate 	 */
8507c478bd9Sstevel@tonic-gate 	if (dev_node->evt_node->next == dev_node->evt_node) {
8517c478bd9Sstevel@tonic-gate 		return;
8527c478bd9Sstevel@tonic-gate 	}
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	curr_evt_node = dev_node->evt_node->next;
8557c478bd9Sstevel@tonic-gate 	dev_node->evt_node->next = dev_node->evt_node;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	while (curr_evt_node != dev_node->evt_node) {
8587c478bd9Sstevel@tonic-gate 		next_evt_node = curr_evt_node->next;
8597c478bd9Sstevel@tonic-gate 		free(curr_evt_node);
8607c478bd9Sstevel@tonic-gate 		curr_evt_node = next_evt_node;
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate /*
8667c478bd9Sstevel@tonic-gate  * Set the events for each pic on each device instance.
8677c478bd9Sstevel@tonic-gate  */
8687c478bd9Sstevel@tonic-gate void
setup_evts()8697c478bd9Sstevel@tonic-gate setup_evts()
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate 	dev_node_t	*dev_node;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	dev_node = dev_list_head;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	while (dev_node != NULL) {
8767c478bd9Sstevel@tonic-gate 		if (dev_node->r_w == EVT_WRITE)
8777c478bd9Sstevel@tonic-gate 			set_evt(dev_node);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		dev_node = dev_node->next;
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate  * Set the appropiate events. Only called for event nodes
8867c478bd9Sstevel@tonic-gate  * that are marked EVT_WRITE.
8877c478bd9Sstevel@tonic-gate  */
8887c478bd9Sstevel@tonic-gate void
set_evt(dev_node_t * dev_node)8897c478bd9Sstevel@tonic-gate set_evt(dev_node_t *dev_node)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate 	kstat_named_t	*cnt_data;
8927c478bd9Sstevel@tonic-gate 	kstat_named_t	*pic_data;
8937c478bd9Sstevel@tonic-gate 	kstat_t		*cnt_ksp;
8947c478bd9Sstevel@tonic-gate 	kstat_t		*pic_ksp;
8957c478bd9Sstevel@tonic-gate 	evt_node_t	*evt_node;
8967c478bd9Sstevel@tonic-gate 	uint64_t	clear_pcr_mask;
8977c478bd9Sstevel@tonic-gate 	uint64_t	pcr;
8987c478bd9Sstevel@tonic-gate 	int		pic_num;
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	cnt_ksp = dev_node->cnt_ksp;
9017c478bd9Sstevel@tonic-gate 	pic_ksp = dev_node->pic_ksp;
9027c478bd9Sstevel@tonic-gate 	pic_num = dev_node->pic_num;
9037c478bd9Sstevel@tonic-gate 	evt_node = dev_node->evt_node;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	/* Read the "counters" kstat */
9067c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
9077c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could "
9087c478bd9Sstevel@tonic-gate 			"not set event's.\n"), pgmname);
9097c478bd9Sstevel@tonic-gate 		exit(1);
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
9157c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could "
9167c478bd9Sstevel@tonic-gate 			"not set event's.\n"), pgmname);
9177c478bd9Sstevel@tonic-gate 		exit(1);
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	pic_data = (kstat_named_t *)pic_ksp->ks_data;
9217c478bd9Sstevel@tonic-gate 	clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	if ((pic_num < 0) || (pic_num > cnt_ksp->ks_ndata-1)) {
9247c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
9257c478bd9Sstevel@tonic-gate 			gettext("%s: invalid pic #%d.\n"),
9267c478bd9Sstevel@tonic-gate 			pgmname, pic_num);
9277c478bd9Sstevel@tonic-gate 		exit(1);
9287c478bd9Sstevel@tonic-gate 	}
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	/*
9317c478bd9Sstevel@tonic-gate 	 * Store the previous value that is on the pic
9327c478bd9Sstevel@tonic-gate 	 * so that we can calculate the delta value
9337c478bd9Sstevel@tonic-gate 	 * later.
9347c478bd9Sstevel@tonic-gate 	 */
9357c478bd9Sstevel@tonic-gate 	evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	/*
9397c478bd9Sstevel@tonic-gate 	 * Read the current pcr value from device.
9407c478bd9Sstevel@tonic-gate 	 */
9417c478bd9Sstevel@tonic-gate 	pcr = cnt_data[0].value.ui64;
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	/*
9447c478bd9Sstevel@tonic-gate 	 * Clear the section of the pcr which corresponds to the
9457c478bd9Sstevel@tonic-gate 	 * pic we are setting events on. Also clear the pcr value
9467c478bd9Sstevel@tonic-gate 	 * which is stored in the instance node.
9477c478bd9Sstevel@tonic-gate 	 *
9487c478bd9Sstevel@tonic-gate 	 */
9497c478bd9Sstevel@tonic-gate 	pcr = pcr & clear_pcr_mask;
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	/*
9527c478bd9Sstevel@tonic-gate 	 * Set the event.
9537c478bd9Sstevel@tonic-gate 	 */
9547c478bd9Sstevel@tonic-gate 	pcr = pcr | evt_node->evt_pcr_mask;
9557c478bd9Sstevel@tonic-gate 	cnt_data[0].value.ui64 = pcr;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	/*
9587c478bd9Sstevel@tonic-gate 	 * Write the value back to the kstat, to make it
9597c478bd9Sstevel@tonic-gate 	 * visible to the underlying driver.
9607c478bd9Sstevel@tonic-gate 	 */
9617c478bd9Sstevel@tonic-gate 	if (kstat_write(kc, cnt_ksp, NULL) == FAIL) {
9627c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could not set events "
9637c478bd9Sstevel@tonic-gate 					"(setting events requires root "
9647c478bd9Sstevel@tonic-gate 					    "permission).\n"), pgmname);
9657c478bd9Sstevel@tonic-gate 		exit(1);
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate /*
9717c478bd9Sstevel@tonic-gate  * Works through the list of device nodes, reading events
9727c478bd9Sstevel@tonic-gate  * and where appropiate setting new events (multiplexing).
9737c478bd9Sstevel@tonic-gate  */
9747c478bd9Sstevel@tonic-gate void
read_evts()9757c478bd9Sstevel@tonic-gate read_evts()
9767c478bd9Sstevel@tonic-gate {
9777c478bd9Sstevel@tonic-gate 	dev_node_t	*dev_node;
9787c478bd9Sstevel@tonic-gate 	kstat_t		*cnt_ksp;
9797c478bd9Sstevel@tonic-gate 	kstat_named_t	*cnt_data;
9807c478bd9Sstevel@tonic-gate 	char		tmp_str[30];
9817c478bd9Sstevel@tonic-gate 	int		iter = 0;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	dev_node = dev_list_head;
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	while (dev_node != NULL) {
9867c478bd9Sstevel@tonic-gate 		if (iter == 0)
9877c478bd9Sstevel@tonic-gate 			print_timestamp();
9887c478bd9Sstevel@tonic-gate 		/*
9897c478bd9Sstevel@tonic-gate 		 * First read of all the counters is done
9907c478bd9Sstevel@tonic-gate 		 * to establish a baseline for the counts.
9917c478bd9Sstevel@tonic-gate 		 * This data is not printed.
9927c478bd9Sstevel@tonic-gate 		 */
9937c478bd9Sstevel@tonic-gate 		if ((!initial_read) && (iter == 0)) {
9947c478bd9Sstevel@tonic-gate 			(void) snprintf(tmp_str, sizeof (tmp_str), "%s%d",
9957c478bd9Sstevel@tonic-gate 				dev_node->name, dev_node->dev_inst);
9967c478bd9Sstevel@tonic-gate 			(void) printf("%-7s", tmp_str);
9977c478bd9Sstevel@tonic-gate 		}
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 		cnt_ksp = (kstat_t *)dev_node->cnt_ksp;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
10027c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: device %s%d "
10037c478bd9Sstevel@tonic-gate 				"(pic %d) no longer valid.\n"),
10047c478bd9Sstevel@tonic-gate 				    pgmname, dev_node->name,
10057c478bd9Sstevel@tonic-gate 				    dev_node->dev_inst,
10067c478bd9Sstevel@tonic-gate 				    dev_node->pic_num);
10077c478bd9Sstevel@tonic-gate 			remove_dev_node(dev_node);
10087c478bd9Sstevel@tonic-gate 			dev_node = dev_list_head;
10097c478bd9Sstevel@tonic-gate 			continue;
10107c478bd9Sstevel@tonic-gate 		}
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 		cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 		if (dev_node->r_w == EVT_READ) {
10157c478bd9Sstevel@tonic-gate 			read_r_evt_node(dev_node, dev_node->pic_num, cnt_data);
10167c478bd9Sstevel@tonic-gate 			iter++;
10177c478bd9Sstevel@tonic-gate 		} else {
10187c478bd9Sstevel@tonic-gate 			read_w_evt_node(dev_node, dev_node->pic_num, cnt_data);
10197c478bd9Sstevel@tonic-gate 			iter++;
10207c478bd9Sstevel@tonic-gate 		}
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 		if ((!initial_read) && (iter == max_pic_num)) {
10237c478bd9Sstevel@tonic-gate 			iter = 0;
10247c478bd9Sstevel@tonic-gate 			(void) printf("\n");
10257c478bd9Sstevel@tonic-gate 		}
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 		/*
10287c478bd9Sstevel@tonic-gate 		 * If there is more than one event node
10297c478bd9Sstevel@tonic-gate 		 * per-pic then we are multiplexing.
10307c478bd9Sstevel@tonic-gate 		 */
10317c478bd9Sstevel@tonic-gate 		if ((dev_node->evt_node->next != dev_node->evt_node) &&
10327c478bd9Sstevel@tonic-gate 			(!initial_read)) {
10337c478bd9Sstevel@tonic-gate 				dev_node->evt_node = dev_node->evt_node->next;
10347c478bd9Sstevel@tonic-gate 				set_evt(dev_node);
10357c478bd9Sstevel@tonic-gate 		}
10367c478bd9Sstevel@tonic-gate 		dev_node = dev_node->next;
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 	initial_read = FALSE;
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate /*
10437c478bd9Sstevel@tonic-gate  * Read a node that is marked as EVT_READ
10447c478bd9Sstevel@tonic-gate  */
10457c478bd9Sstevel@tonic-gate void
read_r_evt_node(dev_node_t * dev_node,int pic_num,kstat_named_t * cnt_data)10467c478bd9Sstevel@tonic-gate read_r_evt_node(dev_node_t *dev_node, int pic_num, kstat_named_t *cnt_data)
10477c478bd9Sstevel@tonic-gate {
10487c478bd9Sstevel@tonic-gate 	evt_node_t	*evt_node;
10497c478bd9Sstevel@tonic-gate 	kstat_t		*pic_ksp;
10507c478bd9Sstevel@tonic-gate 	kstat_named_t	*pic_data;
10517c478bd9Sstevel@tonic-gate 	uint64_t	pcr_read;
10527c478bd9Sstevel@tonic-gate 	uint64_t	clear_pcr_mask;
10537c478bd9Sstevel@tonic-gate 	uint64_t	delta_count;
10547c478bd9Sstevel@tonic-gate 	int		i;
10557c478bd9Sstevel@tonic-gate 	int		match = 0;
10567c478bd9Sstevel@tonic-gate 	int		evt_blank = 1;
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	evt_node = dev_node->evt_node;
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	pic_ksp = (kstat_t *)dev_node->pic_ksp;
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
10637c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: device %s%d "
10647c478bd9Sstevel@tonic-gate 			"(pic %d) no longer valid.\n"), pgmname,
10657c478bd9Sstevel@tonic-gate 			    dev_node->name, dev_node->dev_inst,
10667c478bd9Sstevel@tonic-gate 			    dev_node->pic_num);
10677c478bd9Sstevel@tonic-gate 		remove_dev_node(dev_node);
10687c478bd9Sstevel@tonic-gate 		return;
10697c478bd9Sstevel@tonic-gate 	}
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	pic_data = (kstat_named_t *)pic_ksp->ks_data;
10727c478bd9Sstevel@tonic-gate 	clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	/*
10757c478bd9Sstevel@tonic-gate 	 * Get PCR value from device. We extract the portion
10767c478bd9Sstevel@tonic-gate 	 * of the PCR relating to the pic we are interested by
10777c478bd9Sstevel@tonic-gate 	 * AND'ing the inverse of the clear mask for this pic.
10787c478bd9Sstevel@tonic-gate 	 *
10797c478bd9Sstevel@tonic-gate 	 * The clear mask is usually used to clear the appropiate
10807c478bd9Sstevel@tonic-gate 	 * section of the PCR before we write events into it. So
10817c478bd9Sstevel@tonic-gate 	 * by using the inverse of the mask, we zero everything
10827c478bd9Sstevel@tonic-gate 	 * *but* the section we are interested in.
10837c478bd9Sstevel@tonic-gate 	 */
10847c478bd9Sstevel@tonic-gate 	pcr_read = cnt_data[0].value.ui64;
10857c478bd9Sstevel@tonic-gate 	pcr_read = pcr_read & ~(clear_pcr_mask);
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	/*
10887c478bd9Sstevel@tonic-gate 	 * If the event name is blank this is the first time that
10897c478bd9Sstevel@tonic-gate 	 * this node has been accessed, so we read the pcr and
10907c478bd9Sstevel@tonic-gate 	 * from that we get the event name if it exists.
10917c478bd9Sstevel@tonic-gate 	 *
10927c478bd9Sstevel@tonic-gate 	 * If the pcr read from the device does not match that
10937c478bd9Sstevel@tonic-gate 	 * stored in the node, then it means that the event has
10947c478bd9Sstevel@tonic-gate 	 * changed from its previous value, so we need to re-read
10957c478bd9Sstevel@tonic-gate 	 * all the values.
10967c478bd9Sstevel@tonic-gate 	 */
10977c478bd9Sstevel@tonic-gate 	if ((strcmp(evt_node->evt_name, "") == 0) ||
10987c478bd9Sstevel@tonic-gate 		(pcr_read != evt_node->evt_pcr_mask)) {
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 		for (i = 0; i < pic_ksp->ks_ndata-1; i++) {
11017c478bd9Sstevel@tonic-gate 			if (pcr_read == pic_data[i].value.ui64) {
11027c478bd9Sstevel@tonic-gate 				match = TRUE;
11037c478bd9Sstevel@tonic-gate 				break;
11047c478bd9Sstevel@tonic-gate 			}
11057c478bd9Sstevel@tonic-gate 		}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 		/*
11087c478bd9Sstevel@tonic-gate 		 * Able to resolve pcr value to a event name.
11097c478bd9Sstevel@tonic-gate 		 */
11107c478bd9Sstevel@tonic-gate 		if (match) {
11117c478bd9Sstevel@tonic-gate 			(void) strcpy(evt_node->evt_name, pic_data[i].name);
11127c478bd9Sstevel@tonic-gate 			evt_node->evt_pcr_mask = pcr_read;
11137c478bd9Sstevel@tonic-gate 			evt_node->total = 0;
11147c478bd9Sstevel@tonic-gate 			evt_node->prev_count =
11157c478bd9Sstevel@tonic-gate 				cnt_data[pic_num+1].value.ui64;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 			if ((evt_blank) && (!initial_read)) {
11187c478bd9Sstevel@tonic-gate 				(void) printf("%s\t%-8d\t",
11197c478bd9Sstevel@tonic-gate 					evt_node->evt_name, 0);
11207c478bd9Sstevel@tonic-gate 				evt_blank = 0;
11217c478bd9Sstevel@tonic-gate 			}
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 		} else {
11247c478bd9Sstevel@tonic-gate 			(void) sprintf(evt_node->evt_name, "0x%llx", pcr_read);
11257c478bd9Sstevel@tonic-gate 			evt_node->evt_pcr_mask = pcr_read;
11267c478bd9Sstevel@tonic-gate 			evt_node->total = 0;
11277c478bd9Sstevel@tonic-gate 			evt_node->prev_count =
11287c478bd9Sstevel@tonic-gate 				cnt_data[pic_num+1].value.ui64;
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 			if ((evt_blank) && (!initial_read)) {
11317c478bd9Sstevel@tonic-gate 				(void) printf("%s\t%-8d\t",
11327c478bd9Sstevel@tonic-gate 					evt_node->evt_name, 0);
11337c478bd9Sstevel@tonic-gate 				evt_blank = 0;
11347c478bd9Sstevel@tonic-gate 			}
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 		}
11377c478bd9Sstevel@tonic-gate 	} else {
11387c478bd9Sstevel@tonic-gate 		/* Deal with wraparound of the counters */
11397c478bd9Sstevel@tonic-gate 		if (cnt_data[pic_num+1].value.ui64 < evt_node->prev_count) {
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 			delta_count = (UINT32_MAX-evt_node->prev_count) +
11427c478bd9Sstevel@tonic-gate 				cnt_data[pic_num+1].value.ui64;
11437c478bd9Sstevel@tonic-gate 		} else {
11447c478bd9Sstevel@tonic-gate 			/* Calcalate delta value */
11457c478bd9Sstevel@tonic-gate 			delta_count = cnt_data[pic_num+1].value.ui64
11467c478bd9Sstevel@tonic-gate 						- evt_node->prev_count;
11477c478bd9Sstevel@tonic-gate 		}
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 		/*
11517c478bd9Sstevel@tonic-gate 		 * Store value so that we can calculate delta next
11527c478bd9Sstevel@tonic-gate 		 * time through.
11537c478bd9Sstevel@tonic-gate 		 */
11547c478bd9Sstevel@tonic-gate 		evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 		/* Update count total */
11577c478bd9Sstevel@tonic-gate 		evt_node->total += delta_count;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 		if (delta) {
11607c478bd9Sstevel@tonic-gate 			(void) printf("%-20s %-9lld   ",
11617c478bd9Sstevel@tonic-gate 				evt_node->evt_name, delta_count);
11627c478bd9Sstevel@tonic-gate 		} else {
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 			(void) printf("%-20s %-9lld   ",
11657c478bd9Sstevel@tonic-gate 				evt_node->evt_name, evt_node->total);
11667c478bd9Sstevel@tonic-gate 		}
11677c478bd9Sstevel@tonic-gate 	}
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate /*
11727c478bd9Sstevel@tonic-gate  * Read event nodes marked as EVT_WRITE
11737c478bd9Sstevel@tonic-gate  */
11747c478bd9Sstevel@tonic-gate void
read_w_evt_node(dev_node_t * dev_node,int pic_num,kstat_named_t * cnt_data)11757c478bd9Sstevel@tonic-gate read_w_evt_node(dev_node_t *dev_node, int pic_num, kstat_named_t *cnt_data)
11767c478bd9Sstevel@tonic-gate {
11777c478bd9Sstevel@tonic-gate 	kstat_t		*pic_ksp;
11787c478bd9Sstevel@tonic-gate 	kstat_named_t	*pic_data;
11797c478bd9Sstevel@tonic-gate 	evt_node_t	*evt_node;
11807c478bd9Sstevel@tonic-gate 	uint64_t	delta_count;
11817c478bd9Sstevel@tonic-gate 	uint64_t	pcr_read;
11827c478bd9Sstevel@tonic-gate 	uint64_t	clear_pcr_mask;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	evt_node = dev_node->evt_node;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	pic_ksp = (kstat_t *)dev_node->pic_ksp;
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
11897c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could not read "
11907c478bd9Sstevel@tonic-gate 			"%s%d\n"), pgmname, dev_node->name,
11917c478bd9Sstevel@tonic-gate 			    dev_node->dev_inst);
11927c478bd9Sstevel@tonic-gate 		remove_dev_node(dev_node);
11937c478bd9Sstevel@tonic-gate 		return;
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	pic_data = (kstat_named_t *)pic_ksp->ks_data;
11977c478bd9Sstevel@tonic-gate 	clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	/*
12007c478bd9Sstevel@tonic-gate 	 * Get PCR value from device. We extract the portion
12017c478bd9Sstevel@tonic-gate 	 * of the PCR relating to the pic we are interested by
12027c478bd9Sstevel@tonic-gate 	 * AND'ing the inverse of the clear mask for this pic.
12037c478bd9Sstevel@tonic-gate 	 *
12047c478bd9Sstevel@tonic-gate 	 * The clear mask is usually used to clear the appropiate
12057c478bd9Sstevel@tonic-gate 	 * section of the PCR before we write events into it. So
12067c478bd9Sstevel@tonic-gate 	 * by using the inverse of the mask, we zero everything
12077c478bd9Sstevel@tonic-gate 	 * *but* the section we are interested in.
12087c478bd9Sstevel@tonic-gate 	 */
12097c478bd9Sstevel@tonic-gate 	pcr_read = cnt_data[0].value.ui64;
12107c478bd9Sstevel@tonic-gate 	pcr_read = pcr_read & ~(clear_pcr_mask);
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	/*
12137c478bd9Sstevel@tonic-gate 	 * If the pcr value from the device does not match the
12147c478bd9Sstevel@tonic-gate 	 * stored value, then the events on at least one of the
12157c478bd9Sstevel@tonic-gate 	 * pics must have been change by another busstat instance.
12167c478bd9Sstevel@tonic-gate 	 *
12177c478bd9Sstevel@tonic-gate 	 * Regard this as a fatal error.
12187c478bd9Sstevel@tonic-gate 	 */
12197c478bd9Sstevel@tonic-gate 	if (pcr_read != evt_node->evt_pcr_mask) {
12207c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: events changed (possibly "
12217c478bd9Sstevel@tonic-gate 			"by another busstat).\n"), pgmname);
12227c478bd9Sstevel@tonic-gate 		exit(2);
12237c478bd9Sstevel@tonic-gate 	}
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	/*
12267c478bd9Sstevel@tonic-gate 	 * Calculate delta, and then store value just read to allow us to
12277c478bd9Sstevel@tonic-gate 	 * calculate delta next time around.
12287c478bd9Sstevel@tonic-gate 	 */
12297c478bd9Sstevel@tonic-gate 	/* Deal with wraparound of the counters */
12307c478bd9Sstevel@tonic-gate 	if (cnt_data[pic_num+1].value.ui64 < evt_node->prev_count) {
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 		delta_count = (UINT32_MAX-evt_node->prev_count) +
12337c478bd9Sstevel@tonic-gate 			cnt_data[pic_num+1].value.ui64;
12347c478bd9Sstevel@tonic-gate 	} else {
12357c478bd9Sstevel@tonic-gate 		/* Calcalate delta value */
12367c478bd9Sstevel@tonic-gate 		delta_count = cnt_data[pic_num+1].value.ui64
12377c478bd9Sstevel@tonic-gate 			- evt_node->prev_count;
12387c478bd9Sstevel@tonic-gate 	}
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	if (initial_read) {
12437c478bd9Sstevel@tonic-gate 		evt_node->total = 0;
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	} else {
12467c478bd9Sstevel@tonic-gate 		/* Update count total */
12477c478bd9Sstevel@tonic-gate 		evt_node->total += delta_count;
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 		if (delta) {
12507c478bd9Sstevel@tonic-gate 			(void) printf("%-20s %-9lld   ",
12517c478bd9Sstevel@tonic-gate 				evt_node->evt_name, delta_count);
12527c478bd9Sstevel@tonic-gate 		} else {
12537c478bd9Sstevel@tonic-gate 			(void) printf("%-20s %-9lld   ",
12547c478bd9Sstevel@tonic-gate 				evt_node->evt_name, evt_node->total);
12557c478bd9Sstevel@tonic-gate 		}
12567c478bd9Sstevel@tonic-gate 	}
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate /*
12617c478bd9Sstevel@tonic-gate  * Check to see if any DR operations have occured, and deal with the
12627c478bd9Sstevel@tonic-gate  * consequences.
12637c478bd9Sstevel@tonic-gate  *
12647c478bd9Sstevel@tonic-gate  * Use the Kstat chain ID to check for DR operations. If the ID has
12657c478bd9Sstevel@tonic-gate  * changed then some kstats on system have been modified, we check
12667c478bd9Sstevel@tonic-gate  * all the data structures to see are they still valid. If they are
12677c478bd9Sstevel@tonic-gate  * not we remove them.
12687c478bd9Sstevel@tonic-gate  */
12697c478bd9Sstevel@tonic-gate void
check_dr_ops()12707c478bd9Sstevel@tonic-gate check_dr_ops()
12717c478bd9Sstevel@tonic-gate {
12727c478bd9Sstevel@tonic-gate 	dev_node_t	*dev_node;
12737c478bd9Sstevel@tonic-gate 	kid_t		new_id;
12747c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
12757c478bd9Sstevel@tonic-gate 	int		match = 0;
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 	if ((new_id = kstat_chain_update(kc)) < 0) {
12787c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could not get "
12797c478bd9Sstevel@tonic-gate 			"kstat chain id\n"), pgmname);
12807c478bd9Sstevel@tonic-gate 		exit(1);
12817c478bd9Sstevel@tonic-gate 	}
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	if (new_id == 0) {
12847c478bd9Sstevel@tonic-gate 		/* Kstat chain has not changed. */
12857c478bd9Sstevel@tonic-gate 		return;
12867c478bd9Sstevel@tonic-gate 	}
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	/*
12897c478bd9Sstevel@tonic-gate 	 * Scan the chain of device nodes, making sure that their associated
12907c478bd9Sstevel@tonic-gate 	 * kstats are still present. If not we remove the appropiate node.
12917c478bd9Sstevel@tonic-gate 	 */
12927c478bd9Sstevel@tonic-gate 	dev_node = dev_list_head;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	while (dev_node != NULL) {
12957c478bd9Sstevel@tonic-gate 		for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
12967c478bd9Sstevel@tonic-gate 			if ((strcmp("bus", ksp->ks_class) == 0) &&
12977c478bd9Sstevel@tonic-gate 				(strcmp("counters", ksp->ks_name) == 0) &&
12987c478bd9Sstevel@tonic-gate 				(strcmp(dev_node->name, ksp->ks_module) == 0) &&
12997c478bd9Sstevel@tonic-gate 				(ksp->ks_instance == dev_node->dev_inst)) {
13007c478bd9Sstevel@tonic-gate 					match = 1;
13017c478bd9Sstevel@tonic-gate 					break;
13027c478bd9Sstevel@tonic-gate 			}
13037c478bd9Sstevel@tonic-gate 		}
13047c478bd9Sstevel@tonic-gate 		if (match == 0) {
13057c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: device %s%d"
13067c478bd9Sstevel@tonic-gate 				" (pic %d) no longer valid.\n"), pgmname,
13077c478bd9Sstevel@tonic-gate 				    dev_node->name, dev_node->dev_inst,
13087c478bd9Sstevel@tonic-gate 				    dev_node->pic_num);
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 			remove_dev_node(dev_node);
13117c478bd9Sstevel@tonic-gate 		}
13127c478bd9Sstevel@tonic-gate 		dev_node = dev_node->next;
13137c478bd9Sstevel@tonic-gate 	}
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate /*
13197c478bd9Sstevel@tonic-gate  * Remove a device node and its associated event nodes.
13207c478bd9Sstevel@tonic-gate  */
13217c478bd9Sstevel@tonic-gate void
remove_dev_node(dev_node_t * dev_node)13227c478bd9Sstevel@tonic-gate remove_dev_node(dev_node_t *dev_node)
13237c478bd9Sstevel@tonic-gate {
13247c478bd9Sstevel@tonic-gate 	dev_node_t	*curr_node;
13257c478bd9Sstevel@tonic-gate 	dev_node_t	*prev_node;
13267c478bd9Sstevel@tonic-gate 	evt_node_t	*curr_evt_node;
13277c478bd9Sstevel@tonic-gate 	evt_node_t	*next_evt_node;
13287c478bd9Sstevel@tonic-gate 	evt_node_t	*start_pos;
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	curr_node = dev_list_head;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	if (curr_node == dev_node) {
13337c478bd9Sstevel@tonic-gate 		dev_list_head = dev_node->next;
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 		if (dev_list_head == NULL) {
13367c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: no "
13377c478bd9Sstevel@tonic-gate 				"devices left to monitor.\n"),
13387c478bd9Sstevel@tonic-gate 				    pgmname);
13397c478bd9Sstevel@tonic-gate 			exit(1);
13407c478bd9Sstevel@tonic-gate 		}
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 		/* Remove each event node first */
13437c478bd9Sstevel@tonic-gate 		start_pos = dev_node->evt_node;
13447c478bd9Sstevel@tonic-gate 		curr_evt_node = start_pos->next;
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 		while (curr_evt_node != start_pos) {
13477c478bd9Sstevel@tonic-gate 			next_evt_node = curr_evt_node->next;
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 			free(curr_evt_node);
13507c478bd9Sstevel@tonic-gate 			curr_evt_node = next_evt_node;
13517c478bd9Sstevel@tonic-gate 		}
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 		free(start_pos);
13547c478bd9Sstevel@tonic-gate 		free(dev_node);
13557c478bd9Sstevel@tonic-gate 		return;
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	/* Find the device node */
13597c478bd9Sstevel@tonic-gate 	prev_node = dev_list_head;
13607c478bd9Sstevel@tonic-gate 	curr_node = prev_node->next;
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	while (curr_node != NULL) {
13637c478bd9Sstevel@tonic-gate 		if (curr_node == dev_node) {
13647c478bd9Sstevel@tonic-gate 			prev_node->next = curr_node->next;
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 			/* Remove each event node first */
13677c478bd9Sstevel@tonic-gate 			start_pos = dev_node->evt_node;
13687c478bd9Sstevel@tonic-gate 			curr_evt_node = start_pos->next;
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 			while (curr_evt_node != start_pos) {
13717c478bd9Sstevel@tonic-gate 				next_evt_node = curr_evt_node->next;
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 				free(curr_evt_node);
13747c478bd9Sstevel@tonic-gate 				curr_evt_node = next_evt_node;
13757c478bd9Sstevel@tonic-gate 			}
13767c478bd9Sstevel@tonic-gate 			free(start_pos);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 			free(dev_node);
13797c478bd9Sstevel@tonic-gate 			return;
13807c478bd9Sstevel@tonic-gate 		}
13817c478bd9Sstevel@tonic-gate 		prev_node = curr_node;
13827c478bd9Sstevel@tonic-gate 		curr_node = curr_node->next;
13837c478bd9Sstevel@tonic-gate 	}
13847c478bd9Sstevel@tonic-gate }
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate /*
13887c478bd9Sstevel@tonic-gate  * Find a device node in the linked list of dev_nodes. Match
13897c478bd9Sstevel@tonic-gate  * is done on device name, and instance number.
13907c478bd9Sstevel@tonic-gate  */
13917c478bd9Sstevel@tonic-gate dev_node_t *
find_dev_node(char * name,int inst_num,int pic_num)13927c478bd9Sstevel@tonic-gate find_dev_node(char *name, int inst_num, int pic_num)
13937c478bd9Sstevel@tonic-gate {
13947c478bd9Sstevel@tonic-gate 	dev_node_t	*curr_node;
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	curr_node = dev_list_head;
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	while (curr_node != NULL) {
13997c478bd9Sstevel@tonic-gate 		if ((strcmp(curr_node->name, name) == 0) &&
14007c478bd9Sstevel@tonic-gate 			(curr_node->dev_inst == inst_num) &&
14017c478bd9Sstevel@tonic-gate 			(curr_node->pic_num == pic_num)) {
14027c478bd9Sstevel@tonic-gate 				return (curr_node);
14037c478bd9Sstevel@tonic-gate 		}
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		curr_node = curr_node->next;
14067c478bd9Sstevel@tonic-gate 	}
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 	return (NULL);
14097c478bd9Sstevel@tonic-gate }
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate /*
14137c478bd9Sstevel@tonic-gate  * Determines whether the string represents a event name
14147c478bd9Sstevel@tonic-gate  * or a numeric value. Numeric value can be dec, hex
14157c478bd9Sstevel@tonic-gate  * or octal. All are converted to long int.
14167c478bd9Sstevel@tonic-gate  */
14177c478bd9Sstevel@tonic-gate int64_t
is_num(char * name)14187c478bd9Sstevel@tonic-gate is_num(char *name)
14197c478bd9Sstevel@tonic-gate {
14207c478bd9Sstevel@tonic-gate 	char	*remainder = NULL;
14217c478bd9Sstevel@tonic-gate 	int64_t	num;
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	num = (int64_t)strtol(name, &remainder, 0);
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	if (name == remainder) {
14267c478bd9Sstevel@tonic-gate 		return (EVT_STR);
14277c478bd9Sstevel@tonic-gate 	} else {
14287c478bd9Sstevel@tonic-gate 		return (num);
14297c478bd9Sstevel@tonic-gate 	}
14307c478bd9Sstevel@tonic-gate }
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate /*
14347c478bd9Sstevel@tonic-gate  * Find a pointer to the specified picN kstat. First
14357c478bd9Sstevel@tonic-gate  * search for the specific kstat, and if that can't
14367c478bd9Sstevel@tonic-gate  * be found search for any picN kstat belonging to this device.
14377c478bd9Sstevel@tonic-gate  */
14387c478bd9Sstevel@tonic-gate kstat_t *
find_pic_kstat(char * dev_name,int inst_num,char * pic)14397c478bd9Sstevel@tonic-gate find_pic_kstat(char *dev_name, int inst_num, char *pic)
14407c478bd9Sstevel@tonic-gate {
14417c478bd9Sstevel@tonic-gate 	kstat_t	*ksp;
14427c478bd9Sstevel@tonic-gate 	kstat_t	*p_ksp;
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	/* Look for specific picN kstat */
14457c478bd9Sstevel@tonic-gate 	if ((p_ksp = kstat_lookup(kc, dev_name, inst_num, pic)) == NULL) {
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 		for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
14487c478bd9Sstevel@tonic-gate 			if ((strcmp(ksp->ks_class, "bus") == 0) &&
14497c478bd9Sstevel@tonic-gate 				(strcmp(ksp->ks_name, pic) == 0) &&
14507c478bd9Sstevel@tonic-gate 				(strcmp(ksp->ks_module, dev_name) == 0)) {
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 						return (ksp);
14537c478bd9Sstevel@tonic-gate 			}
14547c478bd9Sstevel@tonic-gate 		}
14557c478bd9Sstevel@tonic-gate 	}
14567c478bd9Sstevel@tonic-gate 	return (p_ksp);
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate /*
14617c478bd9Sstevel@tonic-gate  * Print column titles.
14627c478bd9Sstevel@tonic-gate  * Can be turned off by -n option.
14637c478bd9Sstevel@tonic-gate  */
14647c478bd9Sstevel@tonic-gate void
print_banner()14657c478bd9Sstevel@tonic-gate print_banner()
14667c478bd9Sstevel@tonic-gate {
14677c478bd9Sstevel@tonic-gate 	int		i;
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	(void) printf("time dev    ");
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	for (i = 0; i < max_pic_num; i++)
14727c478bd9Sstevel@tonic-gate 		(void) printf("event%d               "
14737c478bd9Sstevel@tonic-gate 			"pic%d        ", i, i);
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	(void) printf("\n");
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	banner = FALSE;
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate /*
14827c478bd9Sstevel@tonic-gate  * Print the elapsed time in seconds, since the last call.
14837c478bd9Sstevel@tonic-gate  */
14847c478bd9Sstevel@tonic-gate void
print_timestamp()14857c478bd9Sstevel@tonic-gate print_timestamp()
14867c478bd9Sstevel@tonic-gate {
14877c478bd9Sstevel@tonic-gate 	static hrtime_t	curr_time = 0;
14887c478bd9Sstevel@tonic-gate 	static hrtime_t total_elapsed = 0;
14897c478bd9Sstevel@tonic-gate 	hrtime_t	new_time = 0;
14907c478bd9Sstevel@tonic-gate 	hrtime_t	elapsed = 0;
14917c478bd9Sstevel@tonic-gate 	hrtime_t	rem = 0;
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 	if (initial_read)	{
14947c478bd9Sstevel@tonic-gate 		curr_time = (uint64_t)gethrtime();
14957c478bd9Sstevel@tonic-gate 		return;
14967c478bd9Sstevel@tonic-gate 	}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	new_time = gethrtime();
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	elapsed = (new_time - curr_time)/NANO;
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 	/* Round up time value if necessary */
15037c478bd9Sstevel@tonic-gate 	rem = (new_time - curr_time)%NANO;
15047c478bd9Sstevel@tonic-gate 	if (rem >= NANO/2)
15057c478bd9Sstevel@tonic-gate 		elapsed += 1;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	total_elapsed += elapsed;
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	(void) printf("%-4llu ", total_elapsed);
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 	curr_time = new_time;
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate void
usage()15167c478bd9Sstevel@tonic-gate usage()
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Usage : busstat [-a] [-h] [-l] [-n]\n"
15197c478bd9Sstevel@tonic-gate 		"                [-e device-inst]\n"
15207c478bd9Sstevel@tonic-gate 		"                [-w device-inst "
15217c478bd9Sstevel@tonic-gate 					"[,pic0=<event>] [,picN=<event>] ]\n"
15227c478bd9Sstevel@tonic-gate 		"                [-r device-inst]\n"
15237c478bd9Sstevel@tonic-gate 		"                [ interval [count] ]\n"));
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 	exit(2);
15267c478bd9Sstevel@tonic-gate }
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate void *
safe_malloc(size_t size)15307c478bd9Sstevel@tonic-gate safe_malloc(size_t size)
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate 	void *a;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	if ((a = malloc(size)) == NULL) {
15357c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
15367c478bd9Sstevel@tonic-gate 			gettext("%s: out of memory.\n"), pgmname);
15377c478bd9Sstevel@tonic-gate 		exit(1);
15387c478bd9Sstevel@tonic-gate 	}
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 	return (a);
15417c478bd9Sstevel@tonic-gate }
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate /*
15447c478bd9Sstevel@tonic-gate  * Create and arm the timer.
15457c478bd9Sstevel@tonic-gate  */
15467c478bd9Sstevel@tonic-gate void
set_timer(int interval)15477c478bd9Sstevel@tonic-gate set_timer(int interval)
15487c478bd9Sstevel@tonic-gate {
15497c478bd9Sstevel@tonic-gate 	timer_t		t_id;		/* Timer id */
15507c478bd9Sstevel@tonic-gate 	itimerspec_t	time_struct;
15517c478bd9Sstevel@tonic-gate 	struct sigevent	sig_struct;
15527c478bd9Sstevel@tonic-gate 	struct sigaction act;
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 	bzero(&sig_struct, sizeof (struct sigevent));
15557c478bd9Sstevel@tonic-gate 	bzero(&act, sizeof (struct sigaction));
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	/* Create timer */
15587c478bd9Sstevel@tonic-gate 	sig_struct.sigev_notify = SIGEV_SIGNAL;
15597c478bd9Sstevel@tonic-gate 	sig_struct.sigev_signo = SIGUSR1;
15607c478bd9Sstevel@tonic-gate 	sig_struct.sigev_value.sival_int = 0;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) {
15637c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: Timer creation failed.\n"),
15647c478bd9Sstevel@tonic-gate 			pgmname);
15657c478bd9Sstevel@tonic-gate 		exit(1);
15667c478bd9Sstevel@tonic-gate 	}
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 	act.sa_handler = handle_sig;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	if (sigaction(SIGUSR1, &act, NULL) != 0) {
15717c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: could not setup signal "
15727c478bd9Sstevel@tonic-gate 			"handler"), pgmname);
15737c478bd9Sstevel@tonic-gate 		exit(1);
15747c478bd9Sstevel@tonic-gate 	}
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	time_struct.it_value.tv_sec = interval;
15777c478bd9Sstevel@tonic-gate 	time_struct.it_value.tv_nsec = 0;
15787c478bd9Sstevel@tonic-gate 	time_struct.it_interval.tv_sec = interval;
15797c478bd9Sstevel@tonic-gate 	time_struct.it_interval.tv_nsec = 0;
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	/* Arm timer */
15827c478bd9Sstevel@tonic-gate 	if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) {
15837c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: Setting timer failed.\n"),
15847c478bd9Sstevel@tonic-gate 			pgmname);
15857c478bd9Sstevel@tonic-gate 		exit(1);
15867c478bd9Sstevel@tonic-gate 	}
15877c478bd9Sstevel@tonic-gate }
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate /* ARGSUSED */
15917c478bd9Sstevel@tonic-gate void
handle_sig(int x)15927c478bd9Sstevel@tonic-gate handle_sig(int x)
15937c478bd9Sstevel@tonic-gate {
15947c478bd9Sstevel@tonic-gate }
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate /*
15977c478bd9Sstevel@tonic-gate  * return a boolean value indicating whether or not
15987c478bd9Sstevel@tonic-gate  * a string consists solely of characters which are
15997c478bd9Sstevel@tonic-gate  * digits 0..9
16007c478bd9Sstevel@tonic-gate  */
16017c478bd9Sstevel@tonic-gate int
strisnum(const char * s)16027c478bd9Sstevel@tonic-gate strisnum(const char *s)
16037c478bd9Sstevel@tonic-gate {
16047c478bd9Sstevel@tonic-gate 	for (; *s != '\0'; s++) {
16057c478bd9Sstevel@tonic-gate 		if (*s < '0' || *s > '9')
16067c478bd9Sstevel@tonic-gate 			return (0);
16077c478bd9Sstevel@tonic-gate 	}
16087c478bd9Sstevel@tonic-gate 	return (1);
16097c478bd9Sstevel@tonic-gate }
1610