dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libdevice / devctl.c
blob22c1223080f6f90a5f6401d60065b5ca91718558
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <sys/nvpair.h>
39 #include "libdevice.h"
41 static int _libdevice_debug = 0;
42 static const char *devctl_minorname = ":devctl";
43 static const char *nullptr = "<null>";
44 static const char *devctl_target_raw = "a,raw";
46 typedef enum { DEVCTL_BUS, DEVCTL_DEVICE, DEVCTL_AP, DEVCTL_CLONE,
47 DEVCTL_PM_DEV, DEVCTL_PM_BUS } dc_type_t;
50 * devctl_hdl structures are allocated by the devctl_XX_acquire()
51 * interfaces and passed to the remaining interfaces in this library.
53 struct devctl_hdl {
54 char *opath; /* copy of the original path */
55 dc_type_t hdltype; /* handle type */
56 int fd; /* nexus device node */
57 char *nodename; /* DEVCTL_DEVICE handles only */
58 char *unitaddr; /* DEVCTL_DEVICE handles only */
60 #define DCP(x) ((struct devctl_hdl *)(x))
62 static int dc_cmd(uint_t, uint_t, struct devctl_hdl *, nvlist_t *, void *);
63 static devctl_hdl_t dc_mkhndl(dc_type_t, char *, uint_t, devctl_hdl_t);
66 #pragma init(_libdevice_init)
67 void
68 _libdevice_init()
70 _libdevice_debug = getenv("LIBDEVICE_DEBUG") != NULL;
74 * release a devctl_hdl structure
76 void
77 devctl_release(devctl_hdl_t hdl)
79 if (_libdevice_debug)
80 (void) printf("devctl_release: %p\n", (void *)hdl);
82 if (hdl == NULL)
83 return;
85 if (DCP(hdl)->fd != -1)
86 (void) close(DCP(hdl)->fd);
88 free(DCP(hdl)->opath);
90 free(DCP(hdl)->nodename);
92 free(DCP(hdl)->unitaddr);
94 free(hdl);
98 * construct a handle suitable for devctl_bus_*() operations
100 devctl_hdl_t
101 devctl_bus_acquire(char *devfs_path, uint_t flags)
103 uint_t oflags;
105 if (_libdevice_debug)
106 (void) printf("devctl_bus_acquire: %s (%d)\n",
107 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
109 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
110 errno = EINVAL;
111 return (NULL);
114 oflags = ((flags & DC_EXCL) != 0) ? O_EXCL|O_RDWR : O_RDWR;
115 return (dc_mkhndl(DEVCTL_BUS, devfs_path, oflags, NULL));
120 * construct a handle suitable for devctl_bus_*() and
121 * devctl_device_*() operations.
123 devctl_hdl_t
124 devctl_device_acquire(char *devfs_path, uint_t flags)
126 uint_t oflags;
128 if (_libdevice_debug)
129 (void) printf("devctl_device_acquire: %s (%d)\n",
130 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
132 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
133 errno = EINVAL;
134 return (NULL);
137 oflags = ((flags & DC_EXCL) != 0) ? O_EXCL|O_RDWR : O_RDWR;
138 return (dc_mkhndl(DEVCTL_DEVICE, devfs_path, oflags, NULL));
143 * given a devfs (/devices) pathname to an attachment point device,
144 * access the device and return a handle to be passed to the
145 * devctl_ap_XXX() functions.
147 devctl_hdl_t
148 devctl_ap_acquire(char *devfs_path, uint_t flags)
150 uint_t oflags;
152 if (_libdevice_debug)
153 (void) printf("devctl_ap_acquire: %s (%d)\n",
154 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
156 if ((devfs_path == NULL) ||
157 ((flags != 0) && ((flags & DC_EXCL) != 0) &&
158 ((flags & DC_RDONLY) != 0))) {
159 errno = EINVAL;
160 return (NULL);
163 oflags = ((flags & DC_EXCL) != 0) ? O_EXCL : 0;
164 oflags |= ((flags & DC_RDONLY) != 0) ? O_RDONLY : O_RDWR;
166 return (dc_mkhndl(DEVCTL_AP, devfs_path, oflags, NULL));
171 * given a devfs (/devices) pathname access the device and return
172 * a handle to be passed to the devctl_pm_XXX() functions.
173 * The minor name ":devctl" is appended.
175 devctl_hdl_t
176 devctl_pm_bus_acquire(char *devfs_path, uint_t flags)
178 uint_t oflags;
180 if (_libdevice_debug)
181 (void) printf("devctl_pm_bus_acquire: %s (%d)\n",
182 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
184 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
185 errno = EINVAL;
186 return (NULL);
189 oflags = ((flags & DC_EXCL) != 0) ? (O_EXCL | O_RDWR) : O_RDWR;
190 return (dc_mkhndl(DEVCTL_PM_BUS, devfs_path, oflags, NULL));
195 * given a devfs (/devices) pathname access the device and return
196 * a handle to be passed to the devctl_pm_XXX() functions.
197 * The minor name is derived from the device name.
199 devctl_hdl_t
200 devctl_pm_dev_acquire(char *devfs_path, uint_t flags)
202 uint_t oflags;
204 if (_libdevice_debug)
205 (void) printf("devctl_pm_dev_acquire: %s (%d)\n",
206 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
208 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
209 errno = EINVAL;
210 return (NULL);
213 oflags = ((flags & DC_EXCL) != 0) ? (O_EXCL | O_RDWR) : O_RDWR;
214 return (dc_mkhndl(DEVCTL_PM_DEV, devfs_path, oflags, NULL));
219 * allocate and initalize the devctl_hdl structure for the
220 * particular handle type.
222 static devctl_hdl_t
223 dc_mkhndl(dc_type_t type, char *path, uint_t oflags, devctl_hdl_t pc)
225 struct devctl_hdl *dcp;
226 struct stat sb;
227 char iocpath[MAXPATHLEN];
228 char *nodename, *unitsep, *minorsep, *chop;
229 char *minorname;
230 size_t strlcpy_size;
231 char *iocpath_dup;
232 char *tok;
234 if ((path == NULL) || (strlen(path) > MAXPATHLEN - 1)) {
235 errno = EINVAL;
236 return (NULL);
240 * allocate handle and make a copy of the original path
242 if ((dcp = calloc(1, sizeof (*dcp))) == NULL) {
243 errno = ENOMEM;
244 return (NULL);
246 if ((dcp->opath = strdup(path)) == NULL) {
247 devctl_release((devctl_hdl_t)dcp);
248 errno = ENOMEM;
249 return (NULL);
252 (void) strcpy(iocpath, path);
253 dcp->hdltype = type;
254 dcp->fd = -1;
257 * break apart the pathname according to the type handle
259 switch (type) {
260 case DEVCTL_PM_BUS:
262 * chop off any minor name and concatenate the
263 * ":devctl" minor node name string.
265 if ((chop = strrchr(iocpath, ':')) != NULL)
266 *chop = '\0';
268 if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >=
269 MAXPATHLEN) {
270 devctl_release((devctl_hdl_t)dcp);
271 errno = EINVAL;
272 return (NULL);
273 } else if (_libdevice_debug) {
274 (void) printf("DEVCTL_PM_BUS: iocpath %s\n", iocpath);
276 break;
278 case DEVCTL_PM_DEV:
280 * Chop up the last device component in the pathname.
281 * Concatenate either the device name itself, or the
282 * "a,raw" string, as the minor node name, to the iocpath.
284 if ((iocpath_dup = strdup(iocpath)) == NULL) {
285 devctl_release((devctl_hdl_t)dcp);
286 errno = ENOMEM;
287 return (NULL);
289 if ((chop = strrchr(iocpath_dup, '/')) == NULL) {
290 devctl_release((devctl_hdl_t)dcp);
291 errno = EINVAL;
292 return (NULL);
294 *chop = '\0';
295 nodename = chop + 1;
298 * remove the "@0,0" string
300 tok = strtok(nodename, "@");
301 if ((minorname = malloc(strlen(tok) +1)) == NULL) {
302 if (_libdevice_debug)
303 (void) printf("DEVCTL_PM_DEV: failed malloc for"
304 " minorname\n");
305 devctl_release((devctl_hdl_t)dcp);
306 errno = ENOMEM;
307 return (NULL);
309 (void) strcpy(minorname, tok);
310 if (_libdevice_debug) {
311 (void) printf("DEVCTL_PM_DEV: minorname %s\n",
312 minorname);
316 * construct the name of the ioctl device
317 * by concatenating either ":a,raw" or ":"minorname
319 (void) strlcat(iocpath, ":", MAXPATHLEN);
320 if (strcmp(minorname, "disk_chan") == 0 ||
321 strcmp(minorname, "disk_wwn") == 0 ||
322 strcmp(minorname, "disk_cdrom") == 0) {
323 strlcpy_size = strlcat(iocpath, devctl_target_raw,
324 MAXPATHLEN);
325 } else {
326 strlcpy_size = strlcat(iocpath, minorname, MAXPATHLEN);
328 if (strlcpy_size >= MAXPATHLEN) {
329 devctl_release((devctl_hdl_t)dcp);
330 errno = EINVAL;
331 return (NULL);
332 } else if (_libdevice_debug) {
333 (void) printf("DEVCTL_PM_DEV: iocpath %s\n",
334 iocpath);
336 break;
338 case DEVCTL_AP:
340 * take the pathname as provided.
342 break;
344 case DEVCTL_BUS:
346 * chop off any minor name and concatenate the
347 * ":devctl" minor node name string.
349 if ((chop = strrchr(iocpath, ':')) != NULL)
350 *chop = '\0';
352 if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >=
353 MAXPATHLEN) {
354 devctl_release((devctl_hdl_t)dcp);
355 errno = EINVAL;
356 return (NULL);
358 break;
360 case DEVCTL_CLONE:
362 * create a device handle for a new device created
363 * from a call to devctl_bus_dev_create()
365 dcp->hdltype = DEVCTL_DEVICE;
367 /* FALLTHRU */
369 case DEVCTL_DEVICE:
372 * Chop up the last device component in the pathname.
373 * The componets are passed as nodename and unitaddr
374 * in the IOCTL data for DEVCTL ops on devices.
376 if ((chop = strrchr(iocpath, '/')) == NULL) {
377 devctl_release((devctl_hdl_t)dcp);
378 errno = EINVAL;
379 return (NULL);
381 *chop = '\0';
383 nodename = chop + 1;
384 unitsep = strchr(nodename, '@');
385 minorsep = strchr(nodename, ':');
387 if (unitsep == NULL) {
388 devctl_release((devctl_hdl_t)dcp);
389 errno = EINVAL;
390 return (NULL);
394 * copy the nodename and unit address
396 if (((dcp->nodename = malloc(MAXNAMELEN)) == NULL) ||
397 ((dcp->unitaddr = malloc(MAXNAMELEN)) == NULL)) {
398 devctl_release((devctl_hdl_t)dcp);
399 errno = ENOMEM;
400 return (NULL);
402 *unitsep = '\0';
403 if (minorsep != NULL)
404 *minorsep = '\0';
405 (void) snprintf(dcp->nodename, MAXNAMELEN, "%s", nodename);
406 (void) snprintf(dcp->unitaddr, MAXNAMELEN, "%s", unitsep+1);
409 * construct the name of the ioctl device
411 if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >=
412 MAXPATHLEN) {
413 devctl_release((devctl_hdl_t)dcp);
414 errno = EINVAL;
415 return (NULL);
417 break;
419 default:
420 devctl_release((devctl_hdl_t)dcp);
421 errno = EINVAL;
422 return (NULL);
425 if (_libdevice_debug)
426 (void) printf("dc_mkhndl: iocpath %s ", iocpath);
429 * verify the devctl or ap device exists and is a
430 * character device interface.
432 if (stat(iocpath, &sb) == 0) {
433 if ((sb.st_mode & S_IFMT) != S_IFCHR) {
434 if (_libdevice_debug)
435 (void) printf(" - not character device\n");
436 errno = ENODEV;
437 devctl_release((devctl_hdl_t)dcp);
438 return (NULL);
440 } else {
442 * return failure with errno value set by stat
444 if (_libdevice_debug)
445 (void) printf(" - stat failed\n");
446 devctl_release((devctl_hdl_t)dcp);
447 return (NULL);
451 * if this was a new device, dup the parents handle, otherwise
452 * just open the device.
454 if (type == DEVCTL_CLONE)
455 dcp->fd = dup(DCP(pc)->fd);
456 else
457 dcp->fd = open(iocpath, oflags);
459 if (dcp->fd == -1) {
460 if (_libdevice_debug)
461 (void) printf(" - open/dup failed %d\n", errno);
463 * leave errno as set by open/dup
465 devctl_release((devctl_hdl_t)dcp);
466 return (NULL);
469 if (_libdevice_debug)
470 (void) printf(" - open success\n");
472 return ((devctl_hdl_t)dcp);
476 * Power up component 0, to level MAXPWR, via a pm_raise_power() call
479 devctl_pm_raisepower(devctl_hdl_t dcp)
481 int rv;
483 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
484 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
485 errno = EINVAL;
486 return (-1);
489 rv = dc_cmd(DEVCTL_PM_RAISE_PWR, 0, DCP(dcp), NULL, NULL);
491 if (_libdevice_debug)
492 (void) printf("devctl_pm_raisepower: %d\n", rv);
494 return (rv);
498 * Power up component 0, to level MAXPWR, via a power_has_changed() call
501 devctl_pm_changepowerhigh(devctl_hdl_t dcp)
503 int rv;
505 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
506 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
507 errno = EINVAL;
508 return (-1);
511 rv = dc_cmd(DEVCTL_PM_CHANGE_PWR_HIGH, 0, DCP(dcp), NULL, NULL);
513 if (_libdevice_debug)
514 (void) printf("devctl_pm_changepowerhigh: %d\n", rv);
516 return (rv);
520 * Power down component 0, to level 0, via a pm_change_power() call
523 devctl_pm_changepowerlow(devctl_hdl_t dcp)
525 int rv;
527 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
528 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
529 errno = EINVAL;
530 return (-1);
533 rv = dc_cmd(DEVCTL_PM_CHANGE_PWR_LOW, 0, DCP(dcp), NULL, NULL);
535 if (_libdevice_debug)
536 (void) printf("devctl_pm_changepowerlow: %d\n", rv);
538 return (rv);
542 * mark component 0 idle
545 devctl_pm_idlecomponent(devctl_hdl_t dcp)
547 int rv;
549 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
550 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
551 errno = EINVAL;
552 return (-1);
555 rv = dc_cmd(DEVCTL_PM_IDLE_COMP, 0, DCP(dcp), NULL, NULL);
557 if (_libdevice_debug)
558 (void) printf("devctl_pm_idlecomponent: %d\n", rv);
560 return (rv);
564 * mark component 0 busy
567 devctl_pm_busycomponent(devctl_hdl_t dcp)
569 int rv;
571 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
572 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
573 errno = EINVAL;
574 return (-1);
577 rv = dc_cmd(DEVCTL_PM_BUSY_COMP, 0, DCP(dcp), NULL, NULL);
579 if (_libdevice_debug)
580 (void) printf("devctl_pm_busycomponent: %d\n", rv);
582 return (rv);
586 * test pm busy state
589 devctl_pm_testbusy(devctl_hdl_t dcp, uint_t *busystate)
591 int rv;
592 uint_t busy_state = 0;
594 if (busystate == NULL) {
595 errno = EINVAL;
596 return (-1);
599 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
600 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
601 errno = EINVAL;
602 return (-1);
605 rv = dc_cmd(DEVCTL_PM_BUSY_COMP_TEST, 0, DCP(dcp), NULL,
606 (void *)&busy_state);
608 if (rv == -1)
609 *busystate = 0;
610 else
611 *busystate = busy_state;
613 if (_libdevice_debug)
614 (void) printf("devctl_pm_bus_testbusy: rv %d busystate %x\n",
615 rv, *busystate);
617 return (rv);
621 * set flag to fail DDI_SUSPEND
624 devctl_pm_failsuspend(devctl_hdl_t dcp)
626 int rv;
628 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
629 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
630 errno = EINVAL;
631 return (-1);
634 rv = dc_cmd(DEVCTL_PM_FAIL_SUSPEND, 0, DCP(dcp), NULL, NULL);
636 if (_libdevice_debug)
637 (void) printf("devctl_pm_failsuspend: %d\n", rv);
638 return (rv);
642 devctl_pm_bus_teststrict(devctl_hdl_t dcp, uint_t *strict)
644 int rv;
645 uint_t strict_state;
647 if (strict == NULL) {
648 errno = EINVAL;
649 return (-1);
652 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
653 errno = EINVAL;
654 return (-1);
657 rv = dc_cmd(DEVCTL_PM_BUS_STRICT_TEST, 0, DCP(dcp), NULL,
658 (void *)&strict_state);
660 if (rv == -1)
661 *strict = 0;
662 else
663 *strict = strict_state;
665 if (_libdevice_debug)
666 (void) printf("devctl_pm_bus_teststrict: rv %d strict %x\n",
667 rv, *strict);
669 return (rv);
673 * issue prom_printf() call
676 devctl_pm_device_promprintf(devctl_hdl_t dcp)
678 int rv;
680 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
681 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
682 errno = EINVAL;
683 return (-1);
686 rv = dc_cmd(DEVCTL_PM_PROM_PRINTF, 0, DCP(dcp), NULL, NULL);
688 if (_libdevice_debug)
689 (void) printf("devctl_pm_device_promprintf: %d\n", rv);
690 return (rv);
694 * set flag to power up the device via
695 * pm_power_has_changed() calls vs.
696 * pm_raise_power(), during DDI_RESUME
699 devctl_pm_device_changeonresume(devctl_hdl_t dcp)
701 int rv;
703 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
704 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
705 errno = EINVAL;
706 return (-1);
709 rv = dc_cmd(DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME, 0,
710 DCP(dcp), NULL, NULL);
712 if (_libdevice_debug)
713 (void) printf("devctl_pm_device_changeonresume: %d\n", rv);
714 return (rv);
718 * issue DEVCTL_PM_NO_LOWER_POWER to clear the LOWER_POWER_FLAG
719 * flag: pm_lower_power() will not be called on device detach
722 devctl_pm_device_no_lower_power(devctl_hdl_t dcp)
724 int rv;
726 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_PM_DEV) {
727 errno = EINVAL;
728 return (-1);
731 rv = dc_cmd(DEVCTL_PM_NO_LOWER_POWER, 0, DCP(dcp), NULL, NULL);
733 if (_libdevice_debug)
734 (void) printf("devctl_pm_device_no_lower_power: %d\n", rv);
735 return (rv);
739 * issue DEVCTL_PM_BUS_NO_INVOL ioctl to set the NO_INVOL_FLAG
740 * flag: parent driver will mark itself idle twice in
741 * DDI_CTLOPS_DETACH(POST)
744 devctl_pm_bus_no_invol(devctl_hdl_t dcp)
746 int rv;
748 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_PM_BUS) {
749 errno = EINVAL;
750 return (-1);
753 rv = dc_cmd(DEVCTL_PM_BUS_NO_INVOL, 0, DCP(dcp), NULL, NULL);
755 if (_libdevice_debug)
756 (void) printf("devctl_pm_bus_no_invol: %d\n", rv);
757 return (rv);
761 * Place the device ONLINE
764 devctl_device_online(devctl_hdl_t dcp)
766 int rv;
768 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) {
769 errno = EINVAL;
770 return (-1);
773 rv = dc_cmd(DEVCTL_DEVICE_ONLINE, 0, DCP(dcp), NULL, NULL);
775 if (_libdevice_debug)
776 (void) printf("devctl_device_online: %d\n", rv);
778 return (rv);
782 * take device OFFLINE
785 devctl_device_offline(devctl_hdl_t dcp)
787 int rv;
789 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) {
790 errno = EINVAL;
791 return (-1);
794 rv = dc_cmd(DEVCTL_DEVICE_OFFLINE, 0, DCP(dcp), NULL, NULL);
796 if (_libdevice_debug)
797 (void) printf("devctl_device_offline: %d\n", rv);
799 return (rv);
803 * take the device OFFLINE and remove its dev_info node
806 devctl_device_remove(devctl_hdl_t dcp)
808 int rv;
810 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) {
811 errno = EINVAL;
812 return (-1);
815 rv = dc_cmd(DEVCTL_DEVICE_REMOVE, 0, DCP(dcp), NULL, NULL);
817 if (_libdevice_debug)
818 (void) printf("devctl_device_remove: %d\n", rv);
820 return (rv);
825 * QUIESCE the bus
828 devctl_bus_quiesce(devctl_hdl_t dcp)
830 int rv;
832 rv = dc_cmd(DEVCTL_BUS_QUIESCE, 0, DCP(dcp), NULL, NULL);
834 if (_libdevice_debug)
835 (void) printf("devctl_bus_quiesce: %d\n", rv);
837 return (rv);
841 devctl_bus_unquiesce(devctl_hdl_t dcp)
843 int rv;
845 rv = dc_cmd(DEVCTL_BUS_UNQUIESCE, 0, DCP(dcp), NULL, NULL);
847 if (_libdevice_debug)
848 (void) printf("devctl_bus_unquiesce: %d\n", rv);
850 return (rv);
854 devctl_bus_reset(devctl_hdl_t dcp)
856 int rv;
858 rv = dc_cmd(DEVCTL_BUS_RESET, 0, DCP(dcp), NULL, NULL);
860 if (_libdevice_debug)
861 (void) printf("devctl_bus_reset: %d\n", rv);
863 return (rv);
867 devctl_bus_resetall(devctl_hdl_t dcp)
869 int rv;
871 rv = dc_cmd(DEVCTL_BUS_RESETALL, 0, DCP(dcp), NULL, NULL);
873 if (_libdevice_debug)
874 (void) printf("devctl_bus_resetall: %d\n", rv);
876 return (rv);
880 devctl_device_reset(devctl_hdl_t dcp)
882 int rv;
884 rv = dc_cmd(DEVCTL_DEVICE_RESET, 0, DCP(dcp), NULL, NULL);
886 if (_libdevice_debug)
887 (void) printf("devctl_device_reset: %d\n", rv);
889 return (rv);
893 devctl_device_getstate(devctl_hdl_t dcp, uint_t *devstate)
895 int rv;
896 uint_t device_state;
898 if (devstate == NULL) {
899 errno = EINVAL;
900 return (-1);
903 rv = dc_cmd(DEVCTL_DEVICE_GETSTATE, 0, DCP(dcp), NULL,
904 (void *)&device_state);
906 if (rv == -1)
907 *devstate = 0;
908 else
909 *devstate = device_state;
911 if (_libdevice_debug)
912 (void) printf("devctl_device_getstate: rv %d state %x\n",
913 rv, *devstate);
915 return (rv);
919 devctl_bus_getstate(devctl_hdl_t dcp, uint_t *devstate)
921 int rv;
922 uint_t device_state;
924 if (devstate == NULL) {
925 errno = EINVAL;
926 return (-1);
929 rv = dc_cmd(DEVCTL_BUS_GETSTATE, 0, DCP(dcp), NULL,
930 (void *)&device_state);
932 if (rv == -1)
933 *devstate = 0;
934 else
935 *devstate = device_state;
937 if (_libdevice_debug)
938 (void) printf("devctl_bus_getstate: rv %d, state %x\n",
939 rv, *devstate);
941 return (rv);
945 devctl_bus_configure(devctl_hdl_t dcp)
947 int rv;
949 rv = dc_cmd(DEVCTL_BUS_CONFIGURE, 0, DCP(dcp), NULL, NULL);
951 if (_libdevice_debug)
952 (void) printf("devctl_bus_configure: %d\n", rv);
954 return (rv);
958 devctl_bus_unconfigure(devctl_hdl_t dcp)
960 int rv;
962 rv = dc_cmd(DEVCTL_BUS_UNCONFIGURE, 0, DCP(dcp), NULL, NULL);
964 if (_libdevice_debug)
965 (void) printf("devctl_bus_unconfigure: %d\n", rv);
967 return (rv);
971 * devctl_bus_dev_create() - create a new child device
972 * Attempt to construct and attach a new child device below a
973 * bus nexus (dcp). The device is defined using the devctl_ddef_*()
974 * routines to specify the set of bus-specific properties required
975 * to initalize and attach the device.
978 devctl_bus_dev_create(devctl_hdl_t dcp, devctl_ddef_t ddef_hdl,
979 uint_t flags, devctl_hdl_t *new_dcp)
981 char devname[MAXNAMELEN];
982 char devpath[MAXPATHLEN];
983 int rv = 0;
985 if (dcp == NULL || ddef_hdl == NULL) {
986 errno = EINVAL;
987 return (-1);
990 (void) memset(devname, 0, sizeof (devname));
991 rv = dc_cmd(DEVCTL_BUS_DEV_CREATE, flags, DCP(dcp),
992 (nvlist_t *)ddef_hdl, devname);
995 * construct a device handle for the new device
997 if ((rv == 0) && (new_dcp != NULL)) {
998 char *minorname, *lastslash;
1000 (void) memset(devpath, 0, sizeof (devpath));
1001 (void) strcat(devpath, DCP(dcp)->opath);
1004 * Take the pathname of the parent device, chop off
1005 * any minor name info, and append the name@addr of
1006 * the new child device.
1007 * Call dc_mkhndl() with this constructed path and
1008 * the CLONE handle type to create a new handle which
1009 * references the new child device.
1011 lastslash = strrchr(devpath, '/');
1012 if (*(lastslash + 1) == '\0') {
1013 *lastslash = '\0';
1014 } else {
1015 if ((minorname = strchr(lastslash, ':')) != NULL)
1016 *minorname = '\0';
1018 (void) strcat(devpath, "/");
1019 (void) strlcat(devpath, devname, MAXPATHLEN);
1020 *new_dcp = dc_mkhndl(DEVCTL_CLONE, devpath, 0, dcp);
1021 if (*new_dcp == NULL)
1022 rv = -1;
1025 return (rv);
1029 devctl_ap_connect(devctl_hdl_t dcp, nvlist_t *ap_data)
1031 int rv;
1033 rv = dc_cmd(DEVCTL_AP_CONNECT, 0, DCP(dcp), ap_data, NULL);
1035 if (_libdevice_debug)
1036 (void) printf("devctl_ap_connect: %d\n", rv);
1038 return (rv);
1042 devctl_ap_disconnect(devctl_hdl_t dcp, nvlist_t *ap_data)
1044 int rv;
1046 rv = dc_cmd(DEVCTL_AP_DISCONNECT, 0, DCP(dcp), ap_data, NULL);
1048 if (_libdevice_debug)
1049 (void) printf("devctl_ap_disconnect: %d\n", rv);
1051 return (rv);
1055 devctl_ap_insert(devctl_hdl_t dcp, nvlist_t *ap_data)
1057 int rv;
1059 rv = dc_cmd(DEVCTL_AP_INSERT, 0, DCP(dcp), ap_data, NULL);
1061 if (_libdevice_debug)
1062 (void) printf("devctl_ap_insert: %d\n", rv);
1064 return (rv);
1068 devctl_ap_remove(devctl_hdl_t dcp, nvlist_t *ap_data)
1070 int rv;
1072 rv = dc_cmd(DEVCTL_AP_REMOVE, 0, DCP(dcp), ap_data, NULL);
1074 if (_libdevice_debug)
1075 (void) printf("devctl_ap_remove: %d\n", rv);
1077 return (rv);
1081 devctl_ap_configure(devctl_hdl_t dcp, nvlist_t *ap_data)
1083 int rv;
1085 rv = dc_cmd(DEVCTL_AP_CONFIGURE, 0, DCP(dcp), ap_data, NULL);
1087 if (_libdevice_debug)
1088 (void) printf("devctl_ap_configure: %d\n", rv);
1090 return (rv);
1094 devctl_ap_unconfigure(devctl_hdl_t dcp, nvlist_t *ap_data)
1096 int rv;
1098 rv = dc_cmd(DEVCTL_AP_UNCONFIGURE, 0, DCP(dcp), ap_data, NULL);
1100 if (_libdevice_debug)
1101 (void) printf("devctl_ap_unconfigure: %d\n", rv);
1103 return (rv);
1107 devctl_ap_getstate(devctl_hdl_t dcp, nvlist_t *ap_data,
1108 devctl_ap_state_t *apstate)
1110 int rv;
1111 devctl_ap_state_t ap_state;
1113 rv = dc_cmd(DEVCTL_AP_GETSTATE, 0, DCP(dcp), ap_data,
1114 (void *)&ap_state);
1116 if (rv == -1)
1117 (void) memset(apstate, 0, sizeof (struct devctl_ap_state));
1118 else
1119 *apstate = ap_state;
1121 if (_libdevice_debug)
1122 (void) printf("devctl_ap_getstate: %d\n", rv);
1124 return (rv);
1128 * Allocate a device 'definition' handle, in reality a list of
1129 * nvpair data.
1131 /* ARGSUSED */
1132 devctl_ddef_t
1133 devctl_ddef_alloc(char *nodename, int flags)
1136 nvlist_t *nvlp;
1138 if ((nodename == NULL) || *nodename == '\0') {
1139 errno = EINVAL;
1140 return (NULL);
1144 * allocate nvlist structure which is returned as an
1145 * opaque handle to the caller. If this fails, return
1146 * NULL with errno left set to the value
1148 if (nvlist_alloc(&nvlp, NV_UNIQUE_NAME_TYPE, 0) != 0) {
1149 errno = ENOMEM;
1150 return (NULL);
1154 * add the nodename of the new device to the list
1156 if (nvlist_add_string(nvlp, DC_DEVI_NODENAME, nodename) != 0) {
1157 nvlist_free(nvlp);
1158 errno = ENOMEM;
1159 return (NULL);
1162 if (_libdevice_debug)
1163 (void) printf("devctl_ddef_alloc: node %s nvp %p\n", nodename,
1164 (void *)nvlp);
1166 return ((devctl_ddef_t)nvlp);
1170 * free the definition handle
1172 void
1173 devctl_ddef_free(devctl_ddef_t ddef_hdl)
1175 if (_libdevice_debug)
1176 (void) printf("devctl_ddef_free: nvp %p\n", (void *)ddef_hdl);
1178 nvlist_free((nvlist_t *)ddef_hdl);
1182 * define an integer property
1185 devctl_ddef_int(devctl_ddef_t ddef_hdl, char *name, int32_t value)
1188 int rv;
1190 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1191 errno = EINVAL;
1192 return (-1);
1195 rv = nvlist_add_int32((nvlist_t *)ddef_hdl, name, value);
1197 if (_libdevice_debug)
1198 (void) printf("devctl_ddef_int: rv %d nvp %p name %s val %d\n",
1199 rv, (void *)ddef_hdl, name, value);
1201 return (rv);
1205 * define an integer array property
1208 devctl_ddef_int_array(devctl_ddef_t ddef_hdl, char *name, int nelements,
1209 int32_t *value)
1211 int rv, i;
1213 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1214 errno = EINVAL;
1215 return (-1);
1218 rv = nvlist_add_int32_array((nvlist_t *)ddef_hdl, name, value,
1219 nelements);
1221 if (_libdevice_debug) {
1222 (void) printf("devctl_ddef_int_array: rv %d nvp %p name %s: ",
1223 rv, (void *)ddef_hdl, name);
1224 for (i = 0; i < nelements; i++)
1225 (void) printf("0x%x ", value[i]);
1226 (void) printf("\n");
1229 return (rv);
1233 * define a string property
1236 devctl_ddef_string(devctl_ddef_t ddef_hdl, char *name, char *value)
1238 int rv;
1240 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1241 errno = EINVAL;
1242 return (-1);
1245 rv = nvlist_add_string((nvlist_t *)ddef_hdl, name, value);
1247 if (_libdevice_debug)
1248 (void) printf("devctl_ddef_string: rv %d nvp %p %s=\"%s\"\n",
1249 rv, (void *)ddef_hdl, name, value);
1251 return (rv);
1255 * define a string array property
1258 devctl_ddef_string_array(devctl_ddef_t ddef_hdl, char *name, int nelements,
1259 char **value)
1261 int rv, i;
1263 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1264 errno = EINVAL;
1265 return (-1);
1268 rv = nvlist_add_string_array((nvlist_t *)ddef_hdl, name,
1269 value, nelements);
1271 if (_libdevice_debug) {
1272 (void) printf("devctl_ddef_string_array: rv %d nvp %p "
1273 "name %s:\n", rv, (void *)ddef_hdl, name);
1274 for (i = 0; i < nelements; i++)
1275 (void) printf("\t%d: \"%s\"\n", i, value[i]);
1277 return (rv);
1281 * define a byte array property
1284 devctl_ddef_byte_array(devctl_ddef_t ddef_hdl, char *name, int nelements,
1285 uchar_t *value)
1287 int rv;
1289 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1290 errno = EINVAL;
1291 return (-1);
1294 rv = nvlist_add_byte_array((nvlist_t *)ddef_hdl, name, value,
1295 nelements);
1297 return (rv);
1301 * return the pathname which was used to acquire the handle
1303 char *
1304 devctl_get_pathname(devctl_hdl_t dcp, char *pathbuf, size_t bufsz)
1306 if (dcp == NULL || pathbuf == NULL || bufsz == 0) {
1307 errno = EINVAL;
1308 return (NULL);
1311 (void) snprintf(pathbuf, bufsz, "%s", DCP(dcp)->opath);
1312 return (pathbuf);
1317 * execute the IOCTL request
1319 static int
1320 dc_cmd(uint_t cmd, uint_t flags, struct devctl_hdl *dcp, nvlist_t *ulp,
1321 void *retinfo)
1323 struct devctl_iocdata iocdata;
1324 int rv = 0;
1326 if (_libdevice_debug)
1327 (void) printf("dc_cmd: %x dcp %p ulp %p flags %x rv %p\n", cmd,
1328 (void *)dcp, (void *)ulp, flags, retinfo);
1330 if ((dcp == NULL) || (DCP(dcp)->fd == -1)) {
1331 errno = EINVAL;
1332 return (-1);
1335 (void) memset(&iocdata, 0, sizeof (struct devctl_iocdata));
1338 * if there was any user supplied data in the form of a nvlist,
1339 * pack the list prior to copyin.
1341 if (ulp != NULL) {
1342 if (rv = nvlist_pack(ulp, (char **)&iocdata.nvl_user,
1343 &iocdata.nvl_usersz, NV_ENCODE_NATIVE, 0)) {
1345 * exit with errno set by nvlist_pack()
1347 goto exit;
1349 } else {
1350 iocdata.nvl_user = NULL;
1351 iocdata.nvl_usersz = 0;
1355 * finish initalizing the request and execute the IOCTL
1357 iocdata.cmd = cmd;
1358 iocdata.flags = flags;
1359 iocdata.c_nodename = dcp->nodename;
1360 iocdata.c_unitaddr = dcp->unitaddr;
1361 iocdata.cpyout_buf = retinfo;
1362 rv = ioctl(dcp->fd, cmd, &iocdata);
1363 if (rv < 0 && _libdevice_debug) {
1364 (void) printf("dc_cmd: exited with rv %d, errno(%d):%s\n",
1365 rv, errno, strerror(errno));
1368 exit:
1369 free(iocdata.nvl_user);
1371 return (rv);