1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate /*
31*0Sstevel@tonic-gate  * devctl - device control utility
32*0Sstevel@tonic-gate  *
33*0Sstevel@tonic-gate  * to compile:
34*0Sstevel@tonic-gate  * cc -o devctl -ldevice -ldevinfo devctl.c
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  * usage: devctl [-v] command [device/bus pathname]
37*0Sstevel@tonic-gate  *
38*0Sstevel@tonic-gate  * Commands:
39*0Sstevel@tonic-gate  * 	list		- list all controllers exporting the devctl interface
40*0Sstevel@tonic-gate  *	online		- online a device
41*0Sstevel@tonic-gate  *	offline		- offline a device
42*0Sstevel@tonic-gate  *	remove  	- remove a device from the device tree
43*0Sstevel@tonic-gate  * 	quiesce		- quiesce the bus
44*0Sstevel@tonic-gate  *	unquiesce	- resume bus activity
45*0Sstevel@tonic-gate  *	configure	- configure a bus's child devices
46*0Sstevel@tonic-gate  *	unconfigure	- unconfigure a bus's child devices
47*0Sstevel@tonic-gate  *	bus-reset	- reset a bus
48*0Sstevel@tonic-gate  *	dev-reset	- reset a device
49*0Sstevel@tonic-gate  * 	bus-getstate	- return the current state of the bus
50*0Sstevel@tonic-gate  *	dev-getstate	- return the current state of the device
51*0Sstevel@tonic-gate  *	bus-devcreate	- create a new device, bus specific
52*0Sstevel@tonic-gate  *	dev-raisepower		- power up a device via pm_raise_power() (pm)
53*0Sstevel@tonic-gate  *	dev-idlecomp		- idle a device's component 0 (pm)
54*0Sstevel@tonic-gate  *	dev-busycomp		- busy a device's component 0 (pm)
55*0Sstevel@tonic-gate  *	dev-testbusy		- test a device's component 0's busy state (pm)
56*0Sstevel@tonic-gate  *	dev-changepowerhigh	- power up a device via pm_power_has_changed()
57*0Sstevel@tonic-gate  *				  (pm)
58*0Sstevel@tonic-gate  *	dev-changepowerlow	- power off a device via pm_power_has_changed()
59*0Sstevel@tonic-gate  *				  (pm)
60*0Sstevel@tonic-gate  *	dev-failsuspend		- fail DDI_SUSPEND (pm)
61*0Sstevel@tonic-gate  *	dev-changeonresume	- issue pm_power_has_changed() vs,
62*0Sstevel@tonic-gate  *				  pm_raise_power() on device resume (pm)
63*0Sstevel@tonic-gate  *	dev-nolowerpower	- don't call pm_lower_power() on detach (pm)
64*0Sstevel@tonic-gate  *	dev-promprintf		- issue a prom_printf() call (pm)
65*0Sstevel@tonic-gate  *	bus-raisepower		- power up a bus via pm_raise_power() (pm)
66*0Sstevel@tonic-gate  *	bus-idlecomp		- idle a bus' component (pm)
67*0Sstevel@tonic-gate  *	bus-busycomp		- busy a bus' component (pm)
68*0Sstevel@tonic-gate  *	bus-testbusy		- test a bus' component busy state (pm)
69*0Sstevel@tonic-gate  *	bus-changepowerhigh	- power up a bus via pm_power_has_changed() (pm)
70*0Sstevel@tonic-gate  *	bus-changepowerlow	- power off a bus via pm_power_has_changed()
71*0Sstevel@tonic-gate  *				  (pm)
72*0Sstevel@tonic-gate  *	bus-failsuspend		- fail DDI_SUSPEND (pm)
73*0Sstevel@tonic-gate  *	bus-teststrict		- test is bus driver is  strict or involved (pm)
74*0Sstevel@tonic-gate  *	bus-noinvol		- mark idle twice when child detaches
75*0Sstevel@tonic-gate  *
76*0Sstevel@tonic-gate  *
77*0Sstevel@tonic-gate  * Returns:
78*0Sstevel@tonic-gate  *	- Success
79*0Sstevel@tonic-gate  *	- Operation not supported by device
80*0Sstevel@tonic-gate  *	- No Permission
81*0Sstevel@tonic-gate  *	- No Such Device
82*0Sstevel@tonic-gate  *
83*0Sstevel@tonic-gate  * Examples:
84*0Sstevel@tonic-gate  *	devctl list - list all controllers exporting a :devctl node
85*0Sstevel@tonic-gate  *	devctl offline /dev/dsk/c0t3d0s0  - offline disk
86*0Sstevel@tonic-gate  *	devctl dev-getstate  /devices/sbus@1f,0/espdma@e,8400000/esp@e,8800000\
87*0Sstevel@tonic-gate  * sd@3,0
88*0Sstevel@tonic-gate  *
89*0Sstevel@tonic-gate  */
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate #include <stdio.h>
92*0Sstevel@tonic-gate #include <string.h>
93*0Sstevel@tonic-gate #include <unistd.h>
94*0Sstevel@tonic-gate #include <stdlib.h>
95*0Sstevel@tonic-gate #include <sys/types.h>
96*0Sstevel@tonic-gate #include <sys/errno.h>
97*0Sstevel@tonic-gate #include <sys/stat.h>
98*0Sstevel@tonic-gate #include <sys/param.h>
99*0Sstevel@tonic-gate #include <libdevice.h>
100*0Sstevel@tonic-gate #include <libdevinfo.h>
101*0Sstevel@tonic-gate #include <sys/sunddi.h>
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate typedef struct cmds {
104*0Sstevel@tonic-gate 	char *cmdname;
105*0Sstevel@tonic-gate 	int (*cmdf)(devctl_hdl_t);
106*0Sstevel@tonic-gate } cmds_t;
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate extern int errno;
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate static void setprogname(char *name);
111*0Sstevel@tonic-gate static void print_bus_state(char *devname, uint_t state);
112*0Sstevel@tonic-gate static void print_dev_state(char *devname, uint_t state);
113*0Sstevel@tonic-gate static int dev_getstate(devctl_hdl_t);
114*0Sstevel@tonic-gate static int bus_getstate(devctl_hdl_t);
115*0Sstevel@tonic-gate static int bus_devcreate(devctl_hdl_t);
116*0Sstevel@tonic-gate static void run_list_ctlrs(void);
117*0Sstevel@tonic-gate static struct cmds *dc_cmd();
118*0Sstevel@tonic-gate static int nexif(di_node_t din, di_minor_t dim, void *arg);
119*0Sstevel@tonic-gate static void *s_malloc(size_t);
120*0Sstevel@tonic-gate static void *s_realloc(void *, size_t);
121*0Sstevel@tonic-gate static char *s_strdup(char *);
122*0Sstevel@tonic-gate static int dev_pm_testbusy(devctl_hdl_t);
123*0Sstevel@tonic-gate static int bus_pm_teststrict(devctl_hdl_t);
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate static char *devctl_device;
126*0Sstevel@tonic-gate static char *orig_path;
127*0Sstevel@tonic-gate static char *devctl_cmdname;
128*0Sstevel@tonic-gate static char *progname;
129*0Sstevel@tonic-gate static int  verbose;
130*0Sstevel@tonic-gate static int  debug;
131*0Sstevel@tonic-gate static char *dev_name;
132*0Sstevel@tonic-gate static char **dev_props;
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate static const char *usage = "%s [-v] list | online | offline | remove |\n"
135*0Sstevel@tonic-gate 	"\tquiesce | unquiesce | configure | unconfigure |\n"
136*0Sstevel@tonic-gate 	"\t{bus,dev}-reset {bus,dev}-getstate | {bus,dev}-raisepower |\n"
137*0Sstevel@tonic-gate 	"\t{bus,dev}-idlecomp | {bus,dev}-busycomp |\n"
138*0Sstevel@tonic-gate 	"\t{bus,dev}-changepowerhigh | {bus,dev}-changepowerlow |\n"
139*0Sstevel@tonic-gate 	"\t{bus,dev}-testbusy | {bus,dev}-failsuspend | dev-changeonresume |\n"
140*0Sstevel@tonic-gate 	"\tdev-promprintf | dev-nolowerpower | bus-teststrict |\n"
141*0Sstevel@tonic-gate 	"\tbus-noinvol [/dev/... | /devices/...]\n";
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate static struct cmds device_cmds[] = {
144*0Sstevel@tonic-gate 	{"online", devctl_device_online},
145*0Sstevel@tonic-gate 	{"offline", devctl_device_offline},
146*0Sstevel@tonic-gate 	{"remove", devctl_device_remove},
147*0Sstevel@tonic-gate 	{"dev-reset", devctl_device_reset},
148*0Sstevel@tonic-gate 	{"dev-getstate", dev_getstate},
149*0Sstevel@tonic-gate 	{"dev-raisepower", devctl_pm_raisepower},
150*0Sstevel@tonic-gate 	{"dev-busycomp", devctl_pm_busycomponent},
151*0Sstevel@tonic-gate 	{"dev-idlecomp", devctl_pm_idlecomponent},
152*0Sstevel@tonic-gate 	{"dev-testbusy", dev_pm_testbusy},
153*0Sstevel@tonic-gate 	{"dev-changepowerlow", devctl_pm_changepowerlow},
154*0Sstevel@tonic-gate 	{"dev-changepowerhigh", devctl_pm_changepowerhigh},
155*0Sstevel@tonic-gate 	{"dev-failsuspend", devctl_pm_failsuspend},
156*0Sstevel@tonic-gate 	{"dev-changeonresume", devctl_pm_device_changeonresume},
157*0Sstevel@tonic-gate 	{"dev-promprintf", devctl_pm_device_promprintf},
158*0Sstevel@tonic-gate 	{"dev-nolowerpower", devctl_pm_device_no_lower_power},
159*0Sstevel@tonic-gate 	{NULL, NULL},
160*0Sstevel@tonic-gate };
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate static struct cmds bus_cmds[] = {
163*0Sstevel@tonic-gate 	{"quiesce", devctl_bus_quiesce},
164*0Sstevel@tonic-gate 	{"unquiesce", devctl_bus_unquiesce},
165*0Sstevel@tonic-gate 	{"bus-reset", devctl_bus_reset},
166*0Sstevel@tonic-gate 	{"configure", devctl_bus_configure},
167*0Sstevel@tonic-gate 	{"unconfigure", devctl_bus_unconfigure},
168*0Sstevel@tonic-gate 	{"bus-getstate", bus_getstate},
169*0Sstevel@tonic-gate 	{"bus-devcreate", bus_devcreate},
170*0Sstevel@tonic-gate 	{"bus-raisepower", devctl_pm_raisepower},
171*0Sstevel@tonic-gate 	{"bus-busycomp", devctl_pm_busycomponent},
172*0Sstevel@tonic-gate 	{"bus-idlecomp", devctl_pm_idlecomponent},
173*0Sstevel@tonic-gate 	{"bus-changepowerlow", devctl_pm_changepowerlow},
174*0Sstevel@tonic-gate 	{"bus-changepowerhigh", devctl_pm_changepowerhigh},
175*0Sstevel@tonic-gate 	{"bus-testbusy", dev_pm_testbusy},
176*0Sstevel@tonic-gate 	{"bus-failsuspend", devctl_pm_failsuspend},
177*0Sstevel@tonic-gate 	{"bus-teststrict", bus_pm_teststrict},
178*0Sstevel@tonic-gate 	{"bus-noinvol", devctl_pm_bus_no_invol},
179*0Sstevel@tonic-gate 	{NULL, NULL},
180*0Sstevel@tonic-gate };
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate void
185*0Sstevel@tonic-gate main(int argc, char *argv[])
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	int	c;
188*0Sstevel@tonic-gate 	int 	rv;
189*0Sstevel@tonic-gate 	int	pathlen;
190*0Sstevel@tonic-gate 	struct cmds *dcmd;
191*0Sstevel@tonic-gate 	devctl_hdl_t dcp;
192*0Sstevel@tonic-gate 	struct stat stat_buf;
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	setprogname(argv[0]);
195*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "vd")) != -1)  {
196*0Sstevel@tonic-gate 		switch (c)  {
197*0Sstevel@tonic-gate 		case 'v':
198*0Sstevel@tonic-gate 			++verbose;
199*0Sstevel@tonic-gate 			break;
200*0Sstevel@tonic-gate 		case 'd':
201*0Sstevel@tonic-gate 			++debug;
202*0Sstevel@tonic-gate 			(void) putenv("LIBDEVICE_DEBUG");
203*0Sstevel@tonic-gate 			break;
204*0Sstevel@tonic-gate 		default:
205*0Sstevel@tonic-gate 			(void) fprintf(stderr, usage, progname);
206*0Sstevel@tonic-gate 			exit(1);
207*0Sstevel@tonic-gate 			/*NOTREACHED*/
208*0Sstevel@tonic-gate 		}
209*0Sstevel@tonic-gate 	}
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	if (optind == argc) {
212*0Sstevel@tonic-gate 		(void) fprintf(stderr, usage, progname);
213*0Sstevel@tonic-gate 		exit(-1);
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	devctl_cmdname = argv[optind++];
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	if (strcmp(devctl_cmdname, "list") == 0) {
219*0Sstevel@tonic-gate 		run_list_ctlrs();
220*0Sstevel@tonic-gate 		exit(0);
221*0Sstevel@tonic-gate 	}
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	/*
224*0Sstevel@tonic-gate 	 * any command other than "list" requires a device path
225*0Sstevel@tonic-gate 	 */
226*0Sstevel@tonic-gate 	if (((optind + 1) > argc)) {
227*0Sstevel@tonic-gate 		(void) fprintf(stderr, usage, progname);
228*0Sstevel@tonic-gate 		exit(-1);
229*0Sstevel@tonic-gate 	}
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	orig_path = s_strdup(argv[optind]);
232*0Sstevel@tonic-gate 	devctl_device = s_malloc(MAXPATHLEN);
233*0Sstevel@tonic-gate 	(void) strcpy(devctl_device, orig_path);
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	/*
236*0Sstevel@tonic-gate 	 * Additional properties follow for bus-devcreate
237*0Sstevel@tonic-gate 	 */
238*0Sstevel@tonic-gate 	if ((optind + 1 < argc) &&
239*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "bus-devcreate") == 0) {
240*0Sstevel@tonic-gate 		int i;
241*0Sstevel@tonic-gate 		optind++;
242*0Sstevel@tonic-gate 		dev_name = s_strdup(argv[optind]);
243*0Sstevel@tonic-gate 		i = argc - optind;
244*0Sstevel@tonic-gate 		dev_props = s_malloc(i * sizeof (char *));
245*0Sstevel@tonic-gate 		while (--i) {
246*0Sstevel@tonic-gate 			dev_props[i - 1] = s_strdup(argv[optind + i]);
247*0Sstevel@tonic-gate 		}
248*0Sstevel@tonic-gate 	}
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	/*
251*0Sstevel@tonic-gate 	 * if the device is a logical name, get the physical name
252*0Sstevel@tonic-gate 	 */
253*0Sstevel@tonic-gate 	if (lstat(orig_path, &stat_buf) == 0) {
254*0Sstevel@tonic-gate 		if ((stat_buf.st_mode & S_IFLNK) == S_IFLNK) {
255*0Sstevel@tonic-gate 			if ((pathlen = readlink(orig_path, devctl_device,
256*0Sstevel@tonic-gate 			    MAXPATHLEN)) == -1)  {
257*0Sstevel@tonic-gate 				(void) fprintf(stderr,
258*0Sstevel@tonic-gate 					"devctl: readlink(%s) - %s\n",
259*0Sstevel@tonic-gate 					orig_path, strerror(errno));
260*0Sstevel@tonic-gate 				exit(-1);
261*0Sstevel@tonic-gate 			}
262*0Sstevel@tonic-gate 			devctl_device[pathlen] = '\0';
263*0Sstevel@tonic-gate 		}
264*0Sstevel@tonic-gate 	}
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if ((dcmd = dc_cmd(device_cmds, devctl_cmdname)) == NULL) {
267*0Sstevel@tonic-gate 		dcmd = dc_cmd(bus_cmds, devctl_cmdname);
268*0Sstevel@tonic-gate 		if (dcmd == NULL) {
269*0Sstevel@tonic-gate 			(void) fprintf(stderr, "unrecognized command (%s)\n",
270*0Sstevel@tonic-gate 			    devctl_cmdname);
271*0Sstevel@tonic-gate 			(void) fprintf(stderr, usage, progname);
272*0Sstevel@tonic-gate 			exit(1);
273*0Sstevel@tonic-gate 		} else if (strcmp(devctl_cmdname, "bus-raisepower") == 0 ||
274*0Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-changepowerlow") == 0 ||
275*0Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-changepowerhigh") == 0 ||
276*0Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-idlecomp") == 0 ||
277*0Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-busycomp") == 0 ||
278*0Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-testbusy") == 0 ||
279*0Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-failsuspend") == 0 ||
280*0Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-teststrict") == 0 ||
281*0Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-noinvol") == 0) {
282*0Sstevel@tonic-gate 			dcp = devctl_pm_bus_acquire(devctl_device, 0);
283*0Sstevel@tonic-gate 			if (dcp == NULL) {
284*0Sstevel@tonic-gate 				(void) fprintf(stderr,
285*0Sstevel@tonic-gate 				    "devctl: device_pm_bus_acquire %s - %s\n",
286*0Sstevel@tonic-gate 				    devctl_device, strerror(errno));
287*0Sstevel@tonic-gate 				exit(-1);
288*0Sstevel@tonic-gate 			}
289*0Sstevel@tonic-gate 		} else {
290*0Sstevel@tonic-gate 			dcp = devctl_bus_acquire(devctl_device, 0);
291*0Sstevel@tonic-gate 			if (dcp == NULL) {
292*0Sstevel@tonic-gate 				(void) fprintf(stderr, "devctl: bus_acquire "
293*0Sstevel@tonic-gate 				    "%s - %s\n",
294*0Sstevel@tonic-gate 				    devctl_device, strerror(errno));
295*0Sstevel@tonic-gate 				exit(-1);
296*0Sstevel@tonic-gate 			}
297*0Sstevel@tonic-gate 		}
298*0Sstevel@tonic-gate 	} else if (strcmp(devctl_cmdname, "dev-raisepower") == 0 ||
299*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-changepowerlow") == 0 ||
300*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-changepowerhigh") == 0 ||
301*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-idlecomp") == 0 ||
302*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-busycomp") == 0 ||
303*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-testbusy") == 0 ||
304*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-failsuspend") == 0 ||
305*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-changeonresume") == 0 ||
306*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-promprintf") == 0 ||
307*0Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-nolowerpower") == 0) {
308*0Sstevel@tonic-gate 		dcp = devctl_pm_dev_acquire(devctl_device, 0);
309*0Sstevel@tonic-gate 		if (dcp == NULL) {
310*0Sstevel@tonic-gate 			(void) fprintf(stderr,
311*0Sstevel@tonic-gate 				"devctl: device_pm_dev_acquire %s - %s\n",
312*0Sstevel@tonic-gate 				devctl_device, strerror(errno));
313*0Sstevel@tonic-gate 			exit(-1);
314*0Sstevel@tonic-gate 		}
315*0Sstevel@tonic-gate 	} else {
316*0Sstevel@tonic-gate 		dcp = devctl_device_acquire(devctl_device, 0);
317*0Sstevel@tonic-gate 		if (dcp == NULL) {
318*0Sstevel@tonic-gate 			(void) fprintf(stderr,
319*0Sstevel@tonic-gate 				"devctl: device_acquire %s - %s\n",
320*0Sstevel@tonic-gate 				devctl_device, strerror(errno));
321*0Sstevel@tonic-gate 			exit(-1);
322*0Sstevel@tonic-gate 		}
323*0Sstevel@tonic-gate 	}
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	if (verbose)
326*0Sstevel@tonic-gate 		(void) printf("devctl: cmd (%s) device (%s)\n",
327*0Sstevel@tonic-gate 		    devctl_cmdname, orig_path);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	(void) fflush(NULL);	/* get output out of the way */
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	rv = (dcmd->cmdf)(dcp);
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	if (rv == -1) {
334*0Sstevel@tonic-gate 		perror("devctl");
335*0Sstevel@tonic-gate 		exit(-1);
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate 	exit(0);
338*0Sstevel@tonic-gate } /* main */
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate static int
341*0Sstevel@tonic-gate dev_pm_testbusy(devctl_hdl_t dcp)
342*0Sstevel@tonic-gate {
343*0Sstevel@tonic-gate 	int rv;
344*0Sstevel@tonic-gate 	uint_t *busyp;
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	busyp = s_malloc(sizeof (uint_t));
347*0Sstevel@tonic-gate 	rv = devctl_pm_testbusy(dcp, busyp);
348*0Sstevel@tonic-gate 	if (rv != -1)
349*0Sstevel@tonic-gate 		(void) printf("%s: busy state %d\n", orig_path, *busyp);
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	return (0);
352*0Sstevel@tonic-gate }
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate static int
355*0Sstevel@tonic-gate bus_pm_teststrict(devctl_hdl_t dcp)
356*0Sstevel@tonic-gate {
357*0Sstevel@tonic-gate 	int rv;
358*0Sstevel@tonic-gate 	uint_t *strict;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	strict = s_malloc(sizeof (uint_t));
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	rv = devctl_pm_bus_teststrict(dcp, strict);
363*0Sstevel@tonic-gate 	if (rv != -1)
364*0Sstevel@tonic-gate 		(void) printf("%s: strict %d\n", orig_path, *strict);
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	return (0);
367*0Sstevel@tonic-gate }
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate static int
370*0Sstevel@tonic-gate dev_getstate(devctl_hdl_t dcp)
371*0Sstevel@tonic-gate {
372*0Sstevel@tonic-gate 	int rv;
373*0Sstevel@tonic-gate 	uint_t state;
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	rv = devctl_device_getstate(dcp, &state);
376*0Sstevel@tonic-gate 	if (rv != -1)
377*0Sstevel@tonic-gate 		print_dev_state(orig_path, state);
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	return (0);
380*0Sstevel@tonic-gate }
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate static int
383*0Sstevel@tonic-gate bus_getstate(devctl_hdl_t dcp)
384*0Sstevel@tonic-gate {
385*0Sstevel@tonic-gate 	int rv;
386*0Sstevel@tonic-gate 	uint_t state;
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	rv = devctl_bus_getstate(dcp, &state);
389*0Sstevel@tonic-gate 	if (rv != -1)
390*0Sstevel@tonic-gate 		print_bus_state(orig_path, state);
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	return (0);
393*0Sstevel@tonic-gate }
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate /*
396*0Sstevel@tonic-gate  * Only string property is supported now.
397*0Sstevel@tonic-gate  * Will add more later.
398*0Sstevel@tonic-gate  */
399*0Sstevel@tonic-gate static void
400*0Sstevel@tonic-gate add_prop(devctl_ddef_t ddef_hdl, char *prop_str)
401*0Sstevel@tonic-gate {
402*0Sstevel@tonic-gate 	char *pname, *pval, *tmp;
403*0Sstevel@tonic-gate 	char **strs = NULL;
404*0Sstevel@tonic-gate 	int nstr;
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	tmp = strchr(prop_str, '=');
407*0Sstevel@tonic-gate 	if (tmp == NULL) {
408*0Sstevel@tonic-gate 		(void) fprintf(stderr, "invalid property %s", prop_str);
409*0Sstevel@tonic-gate 		exit(-1);
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	(void) printf("prop string: %s\n", prop_str);
413*0Sstevel@tonic-gate 	pname = prop_str;
414*0Sstevel@tonic-gate 	*tmp++ = '\0';
415*0Sstevel@tonic-gate 	if (*tmp != '"') {
416*0Sstevel@tonic-gate 		(void) devctl_ddef_string(ddef_hdl, pname, tmp);
417*0Sstevel@tonic-gate 		return;
418*0Sstevel@tonic-gate 	}
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	nstr = 0;
421*0Sstevel@tonic-gate 	while (*tmp != '\0') {
422*0Sstevel@tonic-gate 		pval = tmp + 1;
423*0Sstevel@tonic-gate 		tmp = strchr(pval, '"');
424*0Sstevel@tonic-gate 		if (tmp == NULL) {
425*0Sstevel@tonic-gate 			(void) fprintf(stderr, "missing quote in %s", tmp);
426*0Sstevel@tonic-gate 			exit(-1);
427*0Sstevel@tonic-gate 		}
428*0Sstevel@tonic-gate 		nstr++;
429*0Sstevel@tonic-gate 		strs = (char **)s_realloc(strs, nstr * sizeof (char *));
430*0Sstevel@tonic-gate 		strs[nstr - 1] = pval;
431*0Sstevel@tonic-gate 		*tmp++ = '\0';
432*0Sstevel@tonic-gate 		(void) printf("string[%d] = %s\n", nstr - 1, pval);
433*0Sstevel@tonic-gate 		if (*tmp)
434*0Sstevel@tonic-gate 			tmp = strchr(tmp, '"');
435*0Sstevel@tonic-gate 		if (tmp == NULL) {
436*0Sstevel@tonic-gate 			(void) fprintf(stderr, "string not ending with quote");
437*0Sstevel@tonic-gate 			exit(-1);
438*0Sstevel@tonic-gate 		}
439*0Sstevel@tonic-gate 	}
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	(void) devctl_ddef_string_array(ddef_hdl, pname, nstr, strs);
442*0Sstevel@tonic-gate 	free(strs);
443*0Sstevel@tonic-gate }
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate static int
446*0Sstevel@tonic-gate bus_devcreate(devctl_hdl_t bus_dcp)
447*0Sstevel@tonic-gate {
448*0Sstevel@tonic-gate 	int rv;
449*0Sstevel@tonic-gate 	char **propp = dev_props;
450*0Sstevel@tonic-gate 	devctl_ddef_t ddef_hdl = NULL;
451*0Sstevel@tonic-gate 	devctl_hdl_t dev_hdl = NULL;
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	ddef_hdl = devctl_ddef_alloc(dev_name, 0);
454*0Sstevel@tonic-gate 	if (dev_props == NULL) {
455*0Sstevel@tonic-gate 		(void) fprintf(stderr, "dev-create: missing device props\n");
456*0Sstevel@tonic-gate 		return (-1);
457*0Sstevel@tonic-gate 	}
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	while (*propp) {
460*0Sstevel@tonic-gate 		add_prop(ddef_hdl, *propp);
461*0Sstevel@tonic-gate 		propp++;
462*0Sstevel@tonic-gate 	}
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 	if (devctl_bus_dev_create(bus_dcp, ddef_hdl, 0, &dev_hdl)) {
465*0Sstevel@tonic-gate 		(void) fprintf(stderr,
466*0Sstevel@tonic-gate 		    "bus-devcreate: failed to create device node\n");
467*0Sstevel@tonic-gate 		rv = -1;
468*0Sstevel@tonic-gate 	} else if (devctl_get_pathname(dev_hdl, devctl_device, MAXPATHLEN)
469*0Sstevel@tonic-gate 	    == NULL) {
470*0Sstevel@tonic-gate 		(void) fprintf(stderr,
471*0Sstevel@tonic-gate 		    "bus-devcreate: failed to get device path\n");
472*0Sstevel@tonic-gate 		rv = -1;
473*0Sstevel@tonic-gate 	} else {
474*0Sstevel@tonic-gate 		(void) printf("created device %s\n", devctl_device);
475*0Sstevel@tonic-gate 		rv = 0;
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	devctl_ddef_free(ddef_hdl);
479*0Sstevel@tonic-gate 	if (dev_hdl)
480*0Sstevel@tonic-gate 		devctl_release(dev_hdl);
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	return (rv);
483*0Sstevel@tonic-gate }
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate static void
486*0Sstevel@tonic-gate print_bus_state(char *devname, uint_t state)
487*0Sstevel@tonic-gate {
488*0Sstevel@tonic-gate 	(void) printf("\t%s: ", devname);
489*0Sstevel@tonic-gate 	if (state == BUS_QUIESCED)
490*0Sstevel@tonic-gate 		(void) printf("Quiesced");
491*0Sstevel@tonic-gate 	else if (state == BUS_ACTIVE)
492*0Sstevel@tonic-gate 		(void) printf("Active");
493*0Sstevel@tonic-gate 	else if (state == BUS_SHUTDOWN)
494*0Sstevel@tonic-gate 		(void) printf("Shutdown");
495*0Sstevel@tonic-gate 	(void) printf("\n");
496*0Sstevel@tonic-gate }
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate static void
499*0Sstevel@tonic-gate print_dev_state(char *devname, uint_t state)
500*0Sstevel@tonic-gate {
501*0Sstevel@tonic-gate 	(void) printf("\t%s: ", devname);
502*0Sstevel@tonic-gate 	if (state & DEVICE_ONLINE) {
503*0Sstevel@tonic-gate 		(void) printf("Online");
504*0Sstevel@tonic-gate 		if (state & DEVICE_BUSY)
505*0Sstevel@tonic-gate 			(void) printf(" Busy");
506*0Sstevel@tonic-gate 		if (state & DEVICE_DOWN)
507*0Sstevel@tonic-gate 			(void) printf(" Down");
508*0Sstevel@tonic-gate 	} else {
509*0Sstevel@tonic-gate 		if (state & DEVICE_OFFLINE) {
510*0Sstevel@tonic-gate 			(void) printf("Offline");
511*0Sstevel@tonic-gate 			if (state & DEVICE_DOWN)
512*0Sstevel@tonic-gate 				(void) printf(" Down");
513*0Sstevel@tonic-gate 		}
514*0Sstevel@tonic-gate 	}
515*0Sstevel@tonic-gate 	(void) printf("\n");
516*0Sstevel@tonic-gate }
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate static void
519*0Sstevel@tonic-gate setprogname(char *name)
520*0Sstevel@tonic-gate {
521*0Sstevel@tonic-gate 	register char *p;
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	if (p = strrchr(name, '/'))
524*0Sstevel@tonic-gate 		progname = p + 1;
525*0Sstevel@tonic-gate 	else
526*0Sstevel@tonic-gate 		progname = name;
527*0Sstevel@tonic-gate }
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate static struct cmds *
530*0Sstevel@tonic-gate dc_cmd(struct cmds *cmd_tbl, char *devctl_cmdname)
531*0Sstevel@tonic-gate {
532*0Sstevel@tonic-gate 	int i;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	for (i = 0; cmd_tbl[i].cmdname != NULL; i++) {
535*0Sstevel@tonic-gate 		if (strcasecmp(cmd_tbl[i].cmdname, devctl_cmdname) == 0)
536*0Sstevel@tonic-gate 			return (&cmd_tbl[i]);
537*0Sstevel@tonic-gate 	}
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	return (NULL);
540*0Sstevel@tonic-gate }
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate /*
543*0Sstevel@tonic-gate  * list all nexus drivers exporting the :devctl minor device
544*0Sstevel@tonic-gate  */
545*0Sstevel@tonic-gate static void
546*0Sstevel@tonic-gate run_list_ctlrs(void)
547*0Sstevel@tonic-gate {
548*0Sstevel@tonic-gate 	di_node_t dinode;
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate 	if ((dinode = di_init("/", DINFOSUBTREE|DINFOMINOR)) == NULL) {
551*0Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: di_init() failed\n",
552*0Sstevel@tonic-gate 		    progname);
553*0Sstevel@tonic-gate 		exit(-1);
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 	(void) di_walk_minor(dinode, DDI_NT_NEXUS, NULL, 0, &nexif);
556*0Sstevel@tonic-gate 	di_fini(dinode);
557*0Sstevel@tonic-gate 	exit(0);
558*0Sstevel@tonic-gate }
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate /*ARGSUSED*/
561*0Sstevel@tonic-gate static int
562*0Sstevel@tonic-gate nexif(di_node_t din, di_minor_t dim, void *arg)
563*0Sstevel@tonic-gate {
564*0Sstevel@tonic-gate 	char *devname;
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	if ((devname = di_devfs_path(din)) != NULL) {
567*0Sstevel@tonic-gate 		(void) printf("%s%d: /devices%s\n", di_driver_name(din),
568*0Sstevel@tonic-gate 		    di_instance(din), devname);
569*0Sstevel@tonic-gate 		di_devfs_path_free(devname);
570*0Sstevel@tonic-gate 	}
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
573*0Sstevel@tonic-gate }
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate void *
576*0Sstevel@tonic-gate s_malloc(size_t len)
577*0Sstevel@tonic-gate {
578*0Sstevel@tonic-gate 	void *buf = malloc(len);
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	if (buf == NULL) {
581*0Sstevel@tonic-gate 		perror("s_malloc failed");
582*0Sstevel@tonic-gate 		exit(-1);
583*0Sstevel@tonic-gate 	}
584*0Sstevel@tonic-gate 	return (buf);
585*0Sstevel@tonic-gate }
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate void *
588*0Sstevel@tonic-gate s_realloc(void *ptr, size_t len)
589*0Sstevel@tonic-gate {
590*0Sstevel@tonic-gate 	void *buf = realloc(ptr, len);
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 	if (buf == NULL) {
593*0Sstevel@tonic-gate 		perror("s_realloc failed");
594*0Sstevel@tonic-gate 		exit(-1);
595*0Sstevel@tonic-gate 	}
596*0Sstevel@tonic-gate 	return (buf);
597*0Sstevel@tonic-gate }
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate char *
600*0Sstevel@tonic-gate s_strdup(char *str)
601*0Sstevel@tonic-gate {
602*0Sstevel@tonic-gate 	char *buf = strdup(str);
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	if (buf == NULL) {
605*0Sstevel@tonic-gate 		perror("s_malloc failed");
606*0Sstevel@tonic-gate 		exit(-1);
607*0Sstevel@tonic-gate 	}
608*0Sstevel@tonic-gate 	return (buf);
609*0Sstevel@tonic-gate }
610