4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
27 * devctl - device control utility
30 * cc -o devctl -ldevice -ldevinfo devctl.c
32 * usage: devctl [-v] command [device/bus pathname]
35 * list - list all controllers exporting the devctl interface
36 * online - online a device
37 * offline - offline a device
38 * remove - remove a device from the device tree
39 * quiesce - quiesce the bus
40 * unquiesce - resume bus activity
41 * configure - configure a bus's child devices
42 * unconfigure - unconfigure a bus's child devices
43 * bus-reset - reset a bus
44 * dev-reset - reset a device
45 * bus-getstate - return the current state of the bus
46 * dev-getstate - return the current state of the device
47 * bus-devcreate - create a new device, bus specific
48 * dev-raisepower - power up a device via pm_raise_power() (pm)
49 * dev-idlecomp - idle a device's component 0 (pm)
50 * dev-busycomp - busy a device's component 0 (pm)
51 * dev-testbusy - test a device's component 0's busy state (pm)
52 * dev-changepowerhigh - power up a device via pm_power_has_changed()
54 * dev-changepowerlow - power off a device via pm_power_has_changed()
56 * dev-failsuspend - fail DDI_SUSPEND (pm)
57 * dev-changeonresume - issue pm_power_has_changed() vs,
58 * pm_raise_power() on device resume (pm)
59 * dev-nolowerpower - don't call pm_lower_power() on detach (pm)
60 * dev-promprintf - issue a prom_printf() call (pm)
61 * bus-raisepower - power up a bus via pm_raise_power() (pm)
62 * bus-idlecomp - idle a bus' component (pm)
63 * bus-busycomp - busy a bus' component (pm)
64 * bus-testbusy - test a bus' component busy state (pm)
65 * bus-changepowerhigh - power up a bus via pm_power_has_changed() (pm)
66 * bus-changepowerlow - power off a bus via pm_power_has_changed()
68 * bus-failsuspend - fail DDI_SUSPEND (pm)
69 * bus-teststrict - test is bus driver is strict or involved (pm)
70 * bus-noinvol - mark idle twice when child detaches
75 * - Operation not supported by device
80 * devctl list - list all controllers exporting a :devctl node
81 * devctl offline /dev/dsk/c0t3d0s0 - offline disk
82 * devctl dev-getstate /devices/sbus@1f,0/espdma@e,8400000/esp@e,8800000\
91 #include <sys/types.h>
92 #include <sys/errno.h>
94 #include <sys/param.h>
95 #include <libdevice.h>
96 #include <libdevinfo.h>
97 #include <sys/sunddi.h>
101 int (*cmdf
)(devctl_hdl_t
);
106 static void setpname(char *name
);
107 static void print_bus_state(char *devname
, uint_t state
);
108 static void print_dev_state(char *devname
, uint_t state
);
109 static int dev_getstate(devctl_hdl_t
);
110 static int bus_getstate(devctl_hdl_t
);
111 static int bus_devcreate(devctl_hdl_t
);
112 static void run_list_ctlrs(void);
113 static struct cmds
*dc_cmd();
114 static int nexif(di_node_t din
, di_minor_t dim
, void *arg
);
115 static void *s_malloc(size_t);
116 static void *s_realloc(void *, size_t);
117 static char *s_strdup(char *);
118 static int dev_pm_testbusy(devctl_hdl_t
);
119 static int bus_pm_teststrict(devctl_hdl_t
);
121 static char *devctl_device
;
122 static char *orig_path
;
123 static char *devctl_cmdname
;
124 static char *progname
;
127 static char *dev_name
;
128 static char **dev_props
;
130 static const char *usage
= "%s [-v] list | online | offline | remove |\n"
131 "\tquiesce | unquiesce | configure | unconfigure |\n"
132 "\t{bus,dev}-reset {bus,dev}-getstate | {bus,dev}-raisepower |\n"
133 "\t{bus,dev}-idlecomp | {bus,dev}-busycomp |\n"
134 "\t{bus,dev}-changepowerhigh | {bus,dev}-changepowerlow |\n"
135 "\t{bus,dev}-testbusy | {bus,dev}-failsuspend | dev-changeonresume |\n"
136 "\tdev-promprintf | dev-nolowerpower | bus-teststrict |\n"
137 "\tbus-noinvol [/dev/... | /devices/...]\n";
139 static struct cmds device_cmds
[] = {
140 {"online", devctl_device_online
},
141 {"offline", devctl_device_offline
},
142 {"remove", devctl_device_remove
},
143 {"dev-reset", devctl_device_reset
},
144 {"dev-getstate", dev_getstate
},
145 {"dev-raisepower", devctl_pm_raisepower
},
146 {"dev-busycomp", devctl_pm_busycomponent
},
147 {"dev-idlecomp", devctl_pm_idlecomponent
},
148 {"dev-testbusy", dev_pm_testbusy
},
149 {"dev-changepowerlow", devctl_pm_changepowerlow
},
150 {"dev-changepowerhigh", devctl_pm_changepowerhigh
},
151 {"dev-failsuspend", devctl_pm_failsuspend
},
152 {"dev-changeonresume", devctl_pm_device_changeonresume
},
153 {"dev-promprintf", devctl_pm_device_promprintf
},
154 {"dev-nolowerpower", devctl_pm_device_no_lower_power
},
158 static struct cmds bus_cmds
[] = {
159 {"quiesce", devctl_bus_quiesce
},
160 {"unquiesce", devctl_bus_unquiesce
},
161 {"bus-reset", devctl_bus_reset
},
162 {"configure", devctl_bus_configure
},
163 {"unconfigure", devctl_bus_unconfigure
},
164 {"bus-getstate", bus_getstate
},
165 {"bus-devcreate", bus_devcreate
},
166 {"bus-raisepower", devctl_pm_raisepower
},
167 {"bus-busycomp", devctl_pm_busycomponent
},
168 {"bus-idlecomp", devctl_pm_idlecomponent
},
169 {"bus-changepowerlow", devctl_pm_changepowerlow
},
170 {"bus-changepowerhigh", devctl_pm_changepowerhigh
},
171 {"bus-testbusy", dev_pm_testbusy
},
172 {"bus-failsuspend", devctl_pm_failsuspend
},
173 {"bus-teststrict", bus_pm_teststrict
},
174 {"bus-noinvol", devctl_pm_bus_no_invol
},
181 main(int argc
, char *argv
[])
188 struct stat stat_buf
;
191 while ((c
= getopt(argc
, argv
, "vd")) != -1) {
198 (void) putenv("LIBDEVICE_DEBUG");
201 (void) fprintf(stderr
, usage
, progname
);
207 if (optind
== argc
) {
208 (void) fprintf(stderr
, usage
, progname
);
212 devctl_cmdname
= argv
[optind
++];
214 if (strcmp(devctl_cmdname
, "list") == 0) {
220 * any command other than "list" requires a device path
222 if (((optind
+ 1) > argc
)) {
223 (void) fprintf(stderr
, usage
, progname
);
227 orig_path
= s_strdup(argv
[optind
]);
228 devctl_device
= s_malloc(MAXPATHLEN
);
229 (void) strcpy(devctl_device
, orig_path
);
232 * Additional properties follow for bus-devcreate
234 if ((optind
+ 1 < argc
) &&
235 strcmp(devctl_cmdname
, "bus-devcreate") == 0) {
238 dev_name
= s_strdup(argv
[optind
]);
240 dev_props
= s_malloc(i
* sizeof (char *));
242 dev_props
[i
- 1] = s_strdup(argv
[optind
+ i
]);
247 * if the device is a logical name, get the physical name
249 if (lstat(orig_path
, &stat_buf
) == 0) {
250 if (S_ISLNK(stat_buf
.st_mode
)) {
251 if ((pathlen
= readlink(orig_path
, devctl_device
,
252 MAXPATHLEN
)) == -1) {
253 (void) fprintf(stderr
,
254 "devctl: readlink(%s) - %s\n",
255 orig_path
, strerror(errno
));
258 devctl_device
[pathlen
] = '\0';
262 if ((dcmd
= dc_cmd(device_cmds
, devctl_cmdname
)) == NULL
) {
263 dcmd
= dc_cmd(bus_cmds
, devctl_cmdname
);
265 (void) fprintf(stderr
, "unrecognized command (%s)\n",
267 (void) fprintf(stderr
, usage
, progname
);
269 } else if (strcmp(devctl_cmdname
, "bus-raisepower") == 0 ||
270 strcmp(devctl_cmdname
, "bus-changepowerlow") == 0 ||
271 strcmp(devctl_cmdname
, "bus-changepowerhigh") == 0 ||
272 strcmp(devctl_cmdname
, "bus-idlecomp") == 0 ||
273 strcmp(devctl_cmdname
, "bus-busycomp") == 0 ||
274 strcmp(devctl_cmdname
, "bus-testbusy") == 0 ||
275 strcmp(devctl_cmdname
, "bus-failsuspend") == 0 ||
276 strcmp(devctl_cmdname
, "bus-teststrict") == 0 ||
277 strcmp(devctl_cmdname
, "bus-noinvol") == 0) {
278 dcp
= devctl_pm_bus_acquire(devctl_device
, 0);
280 (void) fprintf(stderr
,
281 "devctl: device_pm_bus_acquire %s - %s\n",
282 devctl_device
, strerror(errno
));
286 dcp
= devctl_bus_acquire(devctl_device
, 0);
288 (void) fprintf(stderr
, "devctl: bus_acquire "
290 devctl_device
, strerror(errno
));
294 } else if (strcmp(devctl_cmdname
, "dev-raisepower") == 0 ||
295 strcmp(devctl_cmdname
, "dev-changepowerlow") == 0 ||
296 strcmp(devctl_cmdname
, "dev-changepowerhigh") == 0 ||
297 strcmp(devctl_cmdname
, "dev-idlecomp") == 0 ||
298 strcmp(devctl_cmdname
, "dev-busycomp") == 0 ||
299 strcmp(devctl_cmdname
, "dev-testbusy") == 0 ||
300 strcmp(devctl_cmdname
, "dev-failsuspend") == 0 ||
301 strcmp(devctl_cmdname
, "dev-changeonresume") == 0 ||
302 strcmp(devctl_cmdname
, "dev-promprintf") == 0 ||
303 strcmp(devctl_cmdname
, "dev-nolowerpower") == 0) {
304 dcp
= devctl_pm_dev_acquire(devctl_device
, 0);
306 (void) fprintf(stderr
,
307 "devctl: device_pm_dev_acquire %s - %s\n",
308 devctl_device
, strerror(errno
));
312 dcp
= devctl_device_acquire(devctl_device
, 0);
314 (void) fprintf(stderr
,
315 "devctl: device_acquire %s - %s\n",
316 devctl_device
, strerror(errno
));
322 (void) printf("devctl: cmd (%s) device (%s)\n",
323 devctl_cmdname
, orig_path
);
325 (void) fflush(NULL
); /* get output out of the way */
327 rv
= (dcmd
->cmdf
)(dcp
);
337 dev_pm_testbusy(devctl_hdl_t dcp
)
342 busyp
= s_malloc(sizeof (uint_t
));
343 rv
= devctl_pm_testbusy(dcp
, busyp
);
345 (void) printf("%s: busy state %d\n", orig_path
, *busyp
);
351 bus_pm_teststrict(devctl_hdl_t dcp
)
356 strict
= s_malloc(sizeof (uint_t
));
358 rv
= devctl_pm_bus_teststrict(dcp
, strict
);
360 (void) printf("%s: strict %d\n", orig_path
, *strict
);
366 dev_getstate(devctl_hdl_t dcp
)
371 rv
= devctl_device_getstate(dcp
, &state
);
373 print_dev_state(orig_path
, state
);
379 bus_getstate(devctl_hdl_t dcp
)
384 rv
= devctl_bus_getstate(dcp
, &state
);
386 print_bus_state(orig_path
, state
);
392 * Only string property is supported now.
393 * Will add more later.
396 add_prop(devctl_ddef_t ddef_hdl
, char *prop_str
)
398 char *pname
, *pval
, *tmp
;
402 tmp
= strchr(prop_str
, '=');
404 (void) fprintf(stderr
, "invalid property %s", prop_str
);
408 (void) printf("prop string: %s\n", prop_str
);
412 (void) devctl_ddef_string(ddef_hdl
, pname
, tmp
);
417 while (*tmp
!= '\0') {
419 tmp
= strchr(pval
, '"');
421 (void) fprintf(stderr
, "missing quote in %s", tmp
);
425 strs
= (char **)s_realloc(strs
, nstr
* sizeof (char *));
426 strs
[nstr
- 1] = pval
;
428 (void) printf("string[%d] = %s\n", nstr
- 1, pval
);
430 tmp
= strchr(tmp
, '"');
432 (void) fprintf(stderr
, "string not ending with quote");
437 (void) devctl_ddef_string_array(ddef_hdl
, pname
, nstr
, strs
);
442 bus_devcreate(devctl_hdl_t bus_dcp
)
445 char **propp
= dev_props
;
446 devctl_ddef_t ddef_hdl
= NULL
;
447 devctl_hdl_t dev_hdl
= NULL
;
449 ddef_hdl
= devctl_ddef_alloc(dev_name
, 0);
450 if (dev_props
== NULL
) {
451 (void) fprintf(stderr
, "dev-create: missing device props\n");
456 add_prop(ddef_hdl
, *propp
);
460 if (devctl_bus_dev_create(bus_dcp
, ddef_hdl
, 0, &dev_hdl
)) {
461 (void) fprintf(stderr
,
462 "bus-devcreate: failed to create device node\n");
464 } else if (devctl_get_pathname(dev_hdl
, devctl_device
, MAXPATHLEN
)
466 (void) fprintf(stderr
,
467 "bus-devcreate: failed to get device path\n");
470 (void) printf("created device %s\n", devctl_device
);
474 devctl_ddef_free(ddef_hdl
);
475 devctl_release(dev_hdl
);
481 print_bus_state(char *devname
, uint_t state
)
483 (void) printf("\t%s: ", devname
);
484 if (state
== BUS_QUIESCED
)
485 (void) printf("Quiesced");
486 else if (state
== BUS_ACTIVE
)
487 (void) printf("Active");
488 else if (state
== BUS_SHUTDOWN
)
489 (void) printf("Shutdown");
494 print_dev_state(char *devname
, uint_t state
)
496 (void) printf("\t%s: ", devname
);
497 if (state
& DEVICE_ONLINE
) {
498 (void) printf("Online");
499 if (state
& DEVICE_BUSY
)
500 (void) printf(" Busy");
501 if (state
& DEVICE_DOWN
)
502 (void) printf(" Down");
504 if (state
& DEVICE_OFFLINE
) {
505 (void) printf("Offline");
506 if (state
& DEVICE_DOWN
)
507 (void) printf(" Down");
518 if (p
= strrchr(name
, '/'))
525 dc_cmd(struct cmds
*cmd_tbl
, char *devctl_cmdname
)
529 for (i
= 0; cmd_tbl
[i
].cmdname
!= NULL
; i
++) {
530 if (strcasecmp(cmd_tbl
[i
].cmdname
, devctl_cmdname
) == 0)
531 return (&cmd_tbl
[i
]);
538 * list all nexus drivers exporting the :devctl minor device
545 if ((dinode
= di_init("/", DINFOSUBTREE
|DINFOMINOR
)) == NULL
) {
546 (void) fprintf(stderr
, "%s: di_init() failed\n",
550 (void) di_walk_minor(dinode
, DDI_NT_NEXUS
, 0, 0, &nexif
);
557 nexif(di_node_t din
, di_minor_t dim
, void *arg
)
561 if ((devname
= di_devfs_path(din
)) != NULL
) {
562 (void) printf("%s%d: /devices%s\n", di_driver_name(din
),
563 di_instance(din
), devname
);
564 di_devfs_path_free(devname
);
567 return (DI_WALK_CONTINUE
);
573 void *buf
= malloc(len
);
576 perror("s_malloc failed");
583 s_realloc(void *ptr
, size_t len
)
585 void *buf
= realloc(ptr
, len
);
588 perror("s_realloc failed");
597 char *buf
= strdup(str
);
600 perror("s_malloc failed");