6198 Let's EOL cachefs
[illumos-gate.git] / usr / src / lib / libdevice / devctl.c
blobda48342db3a92850b83f2a66306776404f5b9bad
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 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <unistd.h>
40 #include <sys/nvpair.h>
41 #include "libdevice.h"
43 static int _libdevice_debug = 0;
44 static const char *devctl_minorname = ":devctl";
45 static const char *nullptr = "<null>";
46 static const char *devctl_target_raw = "a,raw";
48 typedef enum { DEVCTL_BUS, DEVCTL_DEVICE, DEVCTL_AP, DEVCTL_CLONE,
49 DEVCTL_PM_DEV, DEVCTL_PM_BUS } dc_type_t;
52 * devctl_hdl structures are allocated by the devctl_XX_acquire()
53 * interfaces and passed to the remaining interfaces in this library.
55 struct devctl_hdl {
56 char *opath; /* copy of the original path */
57 dc_type_t hdltype; /* handle type */
58 int fd; /* nexus device node */
59 char *nodename; /* DEVCTL_DEVICE handles only */
60 char *unitaddr; /* DEVCTL_DEVICE handles only */
62 #define DCP(x) ((struct devctl_hdl *)(x))
64 static int dc_cmd(uint_t, uint_t, struct devctl_hdl *, nvlist_t *, void *);
65 static devctl_hdl_t dc_mkhndl(dc_type_t, char *, uint_t, devctl_hdl_t);
68 #pragma init(_libdevice_init)
69 void
70 _libdevice_init()
72 _libdevice_debug = getenv("LIBDEVICE_DEBUG") != NULL;
76 * release a devctl_hdl structure
78 void
79 devctl_release(devctl_hdl_t hdl)
81 if (_libdevice_debug)
82 (void) printf("devctl_release: %p\n", (void *)hdl);
84 if (hdl == NULL)
85 return;
87 if (DCP(hdl)->fd != -1)
88 (void) close(DCP(hdl)->fd);
90 if (DCP(hdl)->opath != NULL)
91 free(DCP(hdl)->opath);
93 if (DCP(hdl)->nodename != NULL)
94 free(DCP(hdl)->nodename);
96 if (DCP(hdl)->unitaddr != NULL)
97 free(DCP(hdl)->unitaddr);
99 free(hdl);
103 * construct a handle suitable for devctl_bus_*() operations
105 devctl_hdl_t
106 devctl_bus_acquire(char *devfs_path, uint_t flags)
108 uint_t oflags;
110 if (_libdevice_debug)
111 (void) printf("devctl_bus_acquire: %s (%d)\n",
112 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
114 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
115 errno = EINVAL;
116 return (NULL);
119 oflags = ((flags & DC_EXCL) != 0) ? O_EXCL|O_RDWR : O_RDWR;
120 return (dc_mkhndl(DEVCTL_BUS, devfs_path, oflags, NULL));
125 * construct a handle suitable for devctl_bus_*() and
126 * devctl_device_*() operations.
128 devctl_hdl_t
129 devctl_device_acquire(char *devfs_path, uint_t flags)
131 uint_t oflags;
133 if (_libdevice_debug)
134 (void) printf("devctl_device_acquire: %s (%d)\n",
135 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
137 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
138 errno = EINVAL;
139 return (NULL);
142 oflags = ((flags & DC_EXCL) != 0) ? O_EXCL|O_RDWR : O_RDWR;
143 return (dc_mkhndl(DEVCTL_DEVICE, devfs_path, oflags, NULL));
148 * given a devfs (/devices) pathname to an attachment point device,
149 * access the device and return a handle to be passed to the
150 * devctl_ap_XXX() functions.
152 devctl_hdl_t
153 devctl_ap_acquire(char *devfs_path, uint_t flags)
155 uint_t oflags;
157 if (_libdevice_debug)
158 (void) printf("devctl_ap_acquire: %s (%d)\n",
159 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
161 if ((devfs_path == NULL) ||
162 ((flags != 0) && ((flags & DC_EXCL) != 0) &&
163 ((flags & DC_RDONLY) != 0))) {
164 errno = EINVAL;
165 return (NULL);
168 oflags = ((flags & DC_EXCL) != 0) ? O_EXCL : 0;
169 oflags |= ((flags & DC_RDONLY) != 0) ? O_RDONLY : O_RDWR;
171 return (dc_mkhndl(DEVCTL_AP, devfs_path, oflags, NULL));
176 * given a devfs (/devices) pathname access the device and return
177 * a handle to be passed to the devctl_pm_XXX() functions.
178 * The minor name ":devctl" is appended.
180 devctl_hdl_t
181 devctl_pm_bus_acquire(char *devfs_path, uint_t flags)
183 uint_t oflags;
185 if (_libdevice_debug)
186 (void) printf("devctl_pm_bus_acquire: %s (%d)\n",
187 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
189 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
190 errno = EINVAL;
191 return (NULL);
194 oflags = ((flags & DC_EXCL) != 0) ? (O_EXCL | O_RDWR) : O_RDWR;
195 return (dc_mkhndl(DEVCTL_PM_BUS, devfs_path, oflags, NULL));
200 * given a devfs (/devices) pathname access the device and return
201 * a handle to be passed to the devctl_pm_XXX() functions.
202 * The minor name is derived from the device name.
204 devctl_hdl_t
205 devctl_pm_dev_acquire(char *devfs_path, uint_t flags)
207 uint_t oflags;
209 if (_libdevice_debug)
210 (void) printf("devctl_pm_dev_acquire: %s (%d)\n",
211 ((devfs_path != NULL) ? devfs_path : nullptr), flags);
213 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
214 errno = EINVAL;
215 return (NULL);
218 oflags = ((flags & DC_EXCL) != 0) ? (O_EXCL | O_RDWR) : O_RDWR;
219 return (dc_mkhndl(DEVCTL_PM_DEV, devfs_path, oflags, NULL));
224 * allocate and initalize the devctl_hdl structure for the
225 * particular handle type.
227 static devctl_hdl_t
228 dc_mkhndl(dc_type_t type, char *path, uint_t oflags, devctl_hdl_t pc)
230 struct devctl_hdl *dcp;
231 struct stat sb;
232 char iocpath[MAXPATHLEN];
233 char *nodename, *unitsep, *minorsep, *chop;
234 char *minorname;
235 size_t strlcpy_size;
236 char *iocpath_dup;
237 char *tok;
239 if ((path == NULL) || (strlen(path) > MAXPATHLEN - 1)) {
240 errno = EINVAL;
241 return (NULL);
245 * allocate handle and make a copy of the original path
247 if ((dcp = calloc(1, sizeof (*dcp))) == NULL) {
248 errno = ENOMEM;
249 return (NULL);
251 if ((dcp->opath = strdup(path)) == NULL) {
252 devctl_release((devctl_hdl_t)dcp);
253 errno = ENOMEM;
254 return (NULL);
257 (void) strcpy(iocpath, path);
258 dcp->hdltype = type;
259 dcp->fd = -1;
262 * break apart the pathname according to the type handle
264 switch (type) {
265 case DEVCTL_PM_BUS:
267 * chop off any minor name and concatenate the
268 * ":devctl" minor node name string.
270 if ((chop = strrchr(iocpath, ':')) != NULL)
271 *chop = '\0';
273 if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >=
274 MAXPATHLEN) {
275 devctl_release((devctl_hdl_t)dcp);
276 errno = EINVAL;
277 return (NULL);
278 } else if (_libdevice_debug) {
279 (void) printf("DEVCTL_PM_BUS: iocpath %s\n", iocpath);
281 break;
283 case DEVCTL_PM_DEV:
285 * Chop up the last device component in the pathname.
286 * Concatenate either the device name itself, or the
287 * "a,raw" string, as the minor node name, to the iocpath.
289 if ((iocpath_dup = strdup(iocpath)) == NULL) {
290 devctl_release((devctl_hdl_t)dcp);
291 errno = ENOMEM;
292 return (NULL);
294 if ((chop = strrchr(iocpath_dup, '/')) == NULL) {
295 devctl_release((devctl_hdl_t)dcp);
296 errno = EINVAL;
297 return (NULL);
299 *chop = '\0';
300 nodename = chop + 1;
303 * remove the "@0,0" string
305 tok = strtok(nodename, "@");
306 if ((minorname = malloc(strlen(tok) +1)) == NULL) {
307 if (_libdevice_debug)
308 (void) printf("DEVCTL_PM_DEV: failed malloc for"
309 " minorname\n");
310 devctl_release((devctl_hdl_t)dcp);
311 errno = ENOMEM;
312 return (NULL);
314 (void) strcpy(minorname, tok);
315 if (_libdevice_debug) {
316 (void) printf("DEVCTL_PM_DEV: minorname %s\n",
317 minorname);
321 * construct the name of the ioctl device
322 * by concatenating either ":a,raw" or ":"minorname
324 (void) strlcat(iocpath, ":", MAXPATHLEN);
325 if (strcmp(minorname, "disk_chan") == 0 ||
326 strcmp(minorname, "disk_wwn") == 0 ||
327 strcmp(minorname, "disk_cdrom") == 0) {
328 strlcpy_size = strlcat(iocpath, devctl_target_raw,
329 MAXPATHLEN);
330 } else {
331 strlcpy_size = strlcat(iocpath, minorname, MAXPATHLEN);
333 if (strlcpy_size >= MAXPATHLEN) {
334 devctl_release((devctl_hdl_t)dcp);
335 errno = EINVAL;
336 return (NULL);
337 } else if (_libdevice_debug) {
338 (void) printf("DEVCTL_PM_DEV: iocpath %s\n",
339 iocpath);
341 break;
343 case DEVCTL_AP:
345 * take the pathname as provided.
347 break;
349 case DEVCTL_BUS:
351 * chop off any minor name and concatenate the
352 * ":devctl" minor node name string.
354 if ((chop = strrchr(iocpath, ':')) != NULL)
355 *chop = '\0';
357 if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >=
358 MAXPATHLEN) {
359 devctl_release((devctl_hdl_t)dcp);
360 errno = EINVAL;
361 return (NULL);
363 break;
365 case DEVCTL_CLONE:
367 * create a device handle for a new device created
368 * from a call to devctl_bus_dev_create()
370 dcp->hdltype = DEVCTL_DEVICE;
372 /* FALLTHRU */
374 case DEVCTL_DEVICE:
377 * Chop up the last device component in the pathname.
378 * The componets are passed as nodename and unitaddr
379 * in the IOCTL data for DEVCTL ops on devices.
381 if ((chop = strrchr(iocpath, '/')) == NULL) {
382 devctl_release((devctl_hdl_t)dcp);
383 errno = EINVAL;
384 return (NULL);
386 *chop = '\0';
388 nodename = chop + 1;
389 unitsep = strchr(nodename, '@');
390 minorsep = strchr(nodename, ':');
392 if (unitsep == NULL) {
393 devctl_release((devctl_hdl_t)dcp);
394 errno = EINVAL;
395 return (NULL);
399 * copy the nodename and unit address
401 if (((dcp->nodename = malloc(MAXNAMELEN)) == NULL) ||
402 ((dcp->unitaddr = malloc(MAXNAMELEN)) == NULL)) {
403 devctl_release((devctl_hdl_t)dcp);
404 errno = ENOMEM;
405 return (NULL);
407 *unitsep = '\0';
408 if (minorsep != NULL)
409 *minorsep = '\0';
410 (void) snprintf(dcp->nodename, MAXNAMELEN, "%s", nodename);
411 (void) snprintf(dcp->unitaddr, MAXNAMELEN, "%s", unitsep+1);
414 * construct the name of the ioctl device
416 if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >=
417 MAXPATHLEN) {
418 devctl_release((devctl_hdl_t)dcp);
419 errno = EINVAL;
420 return (NULL);
422 break;
424 default:
425 devctl_release((devctl_hdl_t)dcp);
426 errno = EINVAL;
427 return (NULL);
430 if (_libdevice_debug)
431 (void) printf("dc_mkhndl: iocpath %s ", iocpath);
434 * verify the devctl or ap device exists and is a
435 * character device interface.
437 if (stat(iocpath, &sb) == 0) {
438 if ((sb.st_mode & S_IFMT) != S_IFCHR) {
439 if (_libdevice_debug)
440 (void) printf(" - not character device\n");
441 errno = ENODEV;
442 devctl_release((devctl_hdl_t)dcp);
443 return (NULL);
445 } else {
447 * return failure with errno value set by stat
449 if (_libdevice_debug)
450 (void) printf(" - stat failed\n");
451 devctl_release((devctl_hdl_t)dcp);
452 return (NULL);
456 * if this was a new device, dup the parents handle, otherwise
457 * just open the device.
459 if (type == DEVCTL_CLONE)
460 dcp->fd = dup(DCP(pc)->fd);
461 else
462 dcp->fd = open(iocpath, oflags);
464 if (dcp->fd == -1) {
465 if (_libdevice_debug)
466 (void) printf(" - open/dup failed %d\n", errno);
468 * leave errno as set by open/dup
470 devctl_release((devctl_hdl_t)dcp);
471 return (NULL);
474 if (_libdevice_debug)
475 (void) printf(" - open success\n");
477 return ((devctl_hdl_t)dcp);
481 * Power up component 0, to level MAXPWR, via a pm_raise_power() call
484 devctl_pm_raisepower(devctl_hdl_t dcp)
486 int rv;
488 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
489 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
490 errno = EINVAL;
491 return (-1);
494 rv = dc_cmd(DEVCTL_PM_RAISE_PWR, 0, DCP(dcp), NULL, NULL);
496 if (_libdevice_debug)
497 (void) printf("devctl_pm_raisepower: %d\n", rv);
499 return (rv);
503 * Power up component 0, to level MAXPWR, via a power_has_changed() call
506 devctl_pm_changepowerhigh(devctl_hdl_t dcp)
508 int rv;
510 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
511 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
512 errno = EINVAL;
513 return (-1);
516 rv = dc_cmd(DEVCTL_PM_CHANGE_PWR_HIGH, 0, DCP(dcp), NULL, NULL);
518 if (_libdevice_debug)
519 (void) printf("devctl_pm_changepowerhigh: %d\n", rv);
521 return (rv);
525 * Power down component 0, to level 0, via a pm_change_power() call
528 devctl_pm_changepowerlow(devctl_hdl_t dcp)
530 int rv;
532 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
533 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
534 errno = EINVAL;
535 return (-1);
538 rv = dc_cmd(DEVCTL_PM_CHANGE_PWR_LOW, 0, DCP(dcp), NULL, NULL);
540 if (_libdevice_debug)
541 (void) printf("devctl_pm_changepowerlow: %d\n", rv);
543 return (rv);
547 * mark component 0 idle
550 devctl_pm_idlecomponent(devctl_hdl_t dcp)
552 int rv;
554 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
555 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
556 errno = EINVAL;
557 return (-1);
560 rv = dc_cmd(DEVCTL_PM_IDLE_COMP, 0, DCP(dcp), NULL, NULL);
562 if (_libdevice_debug)
563 (void) printf("devctl_pm_idlecomponent: %d\n", rv);
565 return (rv);
569 * mark component 0 busy
572 devctl_pm_busycomponent(devctl_hdl_t dcp)
574 int rv;
576 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
577 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
578 errno = EINVAL;
579 return (-1);
582 rv = dc_cmd(DEVCTL_PM_BUSY_COMP, 0, DCP(dcp), NULL, NULL);
584 if (_libdevice_debug)
585 (void) printf("devctl_pm_busycomponent: %d\n", rv);
587 return (rv);
591 * test pm busy state
594 devctl_pm_testbusy(devctl_hdl_t dcp, uint_t *busystate)
596 int rv;
597 uint_t busy_state = 0;
599 if (busystate == NULL) {
600 errno = EINVAL;
601 return (-1);
604 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
605 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
606 errno = EINVAL;
607 return (-1);
610 rv = dc_cmd(DEVCTL_PM_BUSY_COMP_TEST, 0, DCP(dcp), NULL,
611 (void *)&busy_state);
613 if (rv == -1)
614 *busystate = 0;
615 else
616 *busystate = busy_state;
618 if (_libdevice_debug)
619 (void) printf("devctl_pm_bus_testbusy: rv %d busystate %x\n",
620 rv, *busystate);
622 return (rv);
626 * set flag to fail DDI_SUSPEND
629 devctl_pm_failsuspend(devctl_hdl_t dcp)
631 int rv;
633 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
634 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
635 errno = EINVAL;
636 return (-1);
639 rv = dc_cmd(DEVCTL_PM_FAIL_SUSPEND, 0, DCP(dcp), NULL, NULL);
641 if (_libdevice_debug)
642 (void) printf("devctl_pm_failsuspend: %d\n", rv);
643 return (rv);
647 devctl_pm_bus_teststrict(devctl_hdl_t dcp, uint_t *strict)
649 int rv;
650 uint_t strict_state;
652 if (strict == NULL) {
653 errno = EINVAL;
654 return (-1);
657 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
658 errno = EINVAL;
659 return (-1);
662 rv = dc_cmd(DEVCTL_PM_BUS_STRICT_TEST, 0, DCP(dcp), NULL,
663 (void *)&strict_state);
665 if (rv == -1)
666 *strict = 0;
667 else
668 *strict = strict_state;
670 if (_libdevice_debug)
671 (void) printf("devctl_pm_bus_teststrict: rv %d strict %x\n",
672 rv, *strict);
674 return (rv);
678 * issue prom_printf() call
681 devctl_pm_device_promprintf(devctl_hdl_t dcp)
683 int rv;
685 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
686 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
687 errno = EINVAL;
688 return (-1);
691 rv = dc_cmd(DEVCTL_PM_PROM_PRINTF, 0, DCP(dcp), NULL, NULL);
693 if (_libdevice_debug)
694 (void) printf("devctl_pm_device_promprintf: %d\n", rv);
695 return (rv);
699 * set flag to power up the device via
700 * pm_power_has_changed() calls vs.
701 * pm_raise_power(), during DDI_RESUME
704 devctl_pm_device_changeonresume(devctl_hdl_t dcp)
706 int rv;
708 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
709 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
710 errno = EINVAL;
711 return (-1);
714 rv = dc_cmd(DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME, 0,
715 DCP(dcp), NULL, NULL);
717 if (_libdevice_debug)
718 (void) printf("devctl_pm_device_changeonresume: %d\n", rv);
719 return (rv);
723 * issue DEVCTL_PM_NO_LOWER_POWER to clear the LOWER_POWER_FLAG
724 * flag: pm_lower_power() will not be called on device detach
727 devctl_pm_device_no_lower_power(devctl_hdl_t dcp)
729 int rv;
731 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_PM_DEV) {
732 errno = EINVAL;
733 return (-1);
736 rv = dc_cmd(DEVCTL_PM_NO_LOWER_POWER, 0, DCP(dcp), NULL, NULL);
738 if (_libdevice_debug)
739 (void) printf("devctl_pm_device_no_lower_power: %d\n", rv);
740 return (rv);
744 * issue DEVCTL_PM_BUS_NO_INVOL ioctl to set the NO_INVOL_FLAG
745 * flag: parent driver will mark itself idle twice in
746 * DDI_CTLOPS_DETACH(POST)
749 devctl_pm_bus_no_invol(devctl_hdl_t dcp)
751 int rv;
753 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_PM_BUS) {
754 errno = EINVAL;
755 return (-1);
758 rv = dc_cmd(DEVCTL_PM_BUS_NO_INVOL, 0, DCP(dcp), NULL, NULL);
760 if (_libdevice_debug)
761 (void) printf("devctl_pm_bus_no_invol: %d\n", rv);
762 return (rv);
766 * Place the device ONLINE
769 devctl_device_online(devctl_hdl_t dcp)
771 int rv;
773 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) {
774 errno = EINVAL;
775 return (-1);
778 rv = dc_cmd(DEVCTL_DEVICE_ONLINE, 0, DCP(dcp), NULL, NULL);
780 if (_libdevice_debug)
781 (void) printf("devctl_device_online: %d\n", rv);
783 return (rv);
787 * take device OFFLINE
790 devctl_device_offline(devctl_hdl_t dcp)
792 int rv;
794 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) {
795 errno = EINVAL;
796 return (-1);
799 rv = dc_cmd(DEVCTL_DEVICE_OFFLINE, 0, DCP(dcp), NULL, NULL);
801 if (_libdevice_debug)
802 (void) printf("devctl_device_offline: %d\n", rv);
804 return (rv);
808 * take the device OFFLINE and remove its dev_info node
811 devctl_device_remove(devctl_hdl_t dcp)
813 int rv;
815 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) {
816 errno = EINVAL;
817 return (-1);
820 rv = dc_cmd(DEVCTL_DEVICE_REMOVE, 0, DCP(dcp), NULL, NULL);
822 if (_libdevice_debug)
823 (void) printf("devctl_device_remove: %d\n", rv);
825 return (rv);
830 * QUIESCE the bus
833 devctl_bus_quiesce(devctl_hdl_t dcp)
835 int rv;
837 rv = dc_cmd(DEVCTL_BUS_QUIESCE, 0, DCP(dcp), NULL, NULL);
839 if (_libdevice_debug)
840 (void) printf("devctl_bus_quiesce: %d\n", rv);
842 return (rv);
846 devctl_bus_unquiesce(devctl_hdl_t dcp)
848 int rv;
850 rv = dc_cmd(DEVCTL_BUS_UNQUIESCE, 0, DCP(dcp), NULL, NULL);
852 if (_libdevice_debug)
853 (void) printf("devctl_bus_unquiesce: %d\n", rv);
855 return (rv);
859 devctl_bus_reset(devctl_hdl_t dcp)
861 int rv;
863 rv = dc_cmd(DEVCTL_BUS_RESET, 0, DCP(dcp), NULL, NULL);
865 if (_libdevice_debug)
866 (void) printf("devctl_bus_reset: %d\n", rv);
868 return (rv);
872 devctl_bus_resetall(devctl_hdl_t dcp)
874 int rv;
876 rv = dc_cmd(DEVCTL_BUS_RESETALL, 0, DCP(dcp), NULL, NULL);
878 if (_libdevice_debug)
879 (void) printf("devctl_bus_resetall: %d\n", rv);
881 return (rv);
885 devctl_device_reset(devctl_hdl_t dcp)
887 int rv;
889 rv = dc_cmd(DEVCTL_DEVICE_RESET, 0, DCP(dcp), NULL, NULL);
891 if (_libdevice_debug)
892 (void) printf("devctl_device_reset: %d\n", rv);
894 return (rv);
898 devctl_device_getstate(devctl_hdl_t dcp, uint_t *devstate)
900 int rv;
901 uint_t device_state;
903 if (devstate == NULL) {
904 errno = EINVAL;
905 return (-1);
908 rv = dc_cmd(DEVCTL_DEVICE_GETSTATE, 0, DCP(dcp), NULL,
909 (void *)&device_state);
911 if (rv == -1)
912 *devstate = 0;
913 else
914 *devstate = device_state;
916 if (_libdevice_debug)
917 (void) printf("devctl_device_getstate: rv %d state %x\n",
918 rv, *devstate);
920 return (rv);
924 devctl_bus_getstate(devctl_hdl_t dcp, uint_t *devstate)
926 int rv;
927 uint_t device_state;
929 if (devstate == NULL) {
930 errno = EINVAL;
931 return (-1);
934 rv = dc_cmd(DEVCTL_BUS_GETSTATE, 0, DCP(dcp), NULL,
935 (void *)&device_state);
937 if (rv == -1)
938 *devstate = 0;
939 else
940 *devstate = device_state;
942 if (_libdevice_debug)
943 (void) printf("devctl_bus_getstate: rv %d, state %x\n",
944 rv, *devstate);
946 return (rv);
950 devctl_bus_configure(devctl_hdl_t dcp)
952 int rv;
954 rv = dc_cmd(DEVCTL_BUS_CONFIGURE, 0, DCP(dcp), NULL, NULL);
956 if (_libdevice_debug)
957 (void) printf("devctl_bus_configure: %d\n", rv);
959 return (rv);
963 devctl_bus_unconfigure(devctl_hdl_t dcp)
965 int rv;
967 rv = dc_cmd(DEVCTL_BUS_UNCONFIGURE, 0, DCP(dcp), NULL, NULL);
969 if (_libdevice_debug)
970 (void) printf("devctl_bus_unconfigure: %d\n", rv);
972 return (rv);
976 * devctl_bus_dev_create() - create a new child device
977 * Attempt to construct and attach a new child device below a
978 * bus nexus (dcp). The device is defined using the devctl_ddef_*()
979 * routines to specify the set of bus-specific properties required
980 * to initalize and attach the device.
983 devctl_bus_dev_create(devctl_hdl_t dcp, devctl_ddef_t ddef_hdl,
984 uint_t flags, devctl_hdl_t *new_dcp)
986 char devname[MAXNAMELEN];
987 char devpath[MAXPATHLEN];
988 int rv = 0;
990 if (dcp == NULL || ddef_hdl == NULL) {
991 errno = EINVAL;
992 return (-1);
995 (void) memset(devname, 0, sizeof (devname));
996 rv = dc_cmd(DEVCTL_BUS_DEV_CREATE, flags, DCP(dcp),
997 (nvlist_t *)ddef_hdl, devname);
1000 * construct a device handle for the new device
1002 if ((rv == 0) && (new_dcp != NULL)) {
1003 char *minorname, *lastslash;
1005 (void) memset(devpath, 0, sizeof (devpath));
1006 (void) strcat(devpath, DCP(dcp)->opath);
1009 * Take the pathname of the parent device, chop off
1010 * any minor name info, and append the name@addr of
1011 * the new child device.
1012 * Call dc_mkhndl() with this constructed path and
1013 * the CLONE handle type to create a new handle which
1014 * references the new child device.
1016 lastslash = strrchr(devpath, '/');
1017 if (*(lastslash + 1) == '\0') {
1018 *lastslash = '\0';
1019 } else {
1020 if ((minorname = strchr(lastslash, ':')) != NULL)
1021 *minorname = '\0';
1023 (void) strcat(devpath, "/");
1024 (void) strlcat(devpath, devname, MAXPATHLEN);
1025 *new_dcp = dc_mkhndl(DEVCTL_CLONE, devpath, 0, dcp);
1026 if (*new_dcp == NULL)
1027 rv = -1;
1030 return (rv);
1034 devctl_ap_connect(devctl_hdl_t dcp, nvlist_t *ap_data)
1036 int rv;
1038 rv = dc_cmd(DEVCTL_AP_CONNECT, 0, DCP(dcp), ap_data, NULL);
1040 if (_libdevice_debug)
1041 (void) printf("devctl_ap_connect: %d\n", rv);
1043 return (rv);
1047 devctl_ap_disconnect(devctl_hdl_t dcp, nvlist_t *ap_data)
1049 int rv;
1051 rv = dc_cmd(DEVCTL_AP_DISCONNECT, 0, DCP(dcp), ap_data, NULL);
1053 if (_libdevice_debug)
1054 (void) printf("devctl_ap_disconnect: %d\n", rv);
1056 return (rv);
1060 devctl_ap_insert(devctl_hdl_t dcp, nvlist_t *ap_data)
1062 int rv;
1064 rv = dc_cmd(DEVCTL_AP_INSERT, 0, DCP(dcp), ap_data, NULL);
1066 if (_libdevice_debug)
1067 (void) printf("devctl_ap_insert: %d\n", rv);
1069 return (rv);
1073 devctl_ap_remove(devctl_hdl_t dcp, nvlist_t *ap_data)
1075 int rv;
1077 rv = dc_cmd(DEVCTL_AP_REMOVE, 0, DCP(dcp), ap_data, NULL);
1079 if (_libdevice_debug)
1080 (void) printf("devctl_ap_remove: %d\n", rv);
1082 return (rv);
1086 devctl_ap_configure(devctl_hdl_t dcp, nvlist_t *ap_data)
1088 int rv;
1090 rv = dc_cmd(DEVCTL_AP_CONFIGURE, 0, DCP(dcp), ap_data, NULL);
1092 if (_libdevice_debug)
1093 (void) printf("devctl_ap_configure: %d\n", rv);
1095 return (rv);
1099 devctl_ap_unconfigure(devctl_hdl_t dcp, nvlist_t *ap_data)
1101 int rv;
1103 rv = dc_cmd(DEVCTL_AP_UNCONFIGURE, 0, DCP(dcp), ap_data, NULL);
1105 if (_libdevice_debug)
1106 (void) printf("devctl_ap_unconfigure: %d\n", rv);
1108 return (rv);
1112 devctl_ap_getstate(devctl_hdl_t dcp, nvlist_t *ap_data,
1113 devctl_ap_state_t *apstate)
1115 int rv;
1116 devctl_ap_state_t ap_state;
1118 rv = dc_cmd(DEVCTL_AP_GETSTATE, 0, DCP(dcp), ap_data,
1119 (void *)&ap_state);
1121 if (rv == -1)
1122 (void) memset(apstate, 0, sizeof (struct devctl_ap_state));
1123 else
1124 *apstate = ap_state;
1126 if (_libdevice_debug)
1127 (void) printf("devctl_ap_getstate: %d\n", rv);
1129 return (rv);
1133 * Allocate a device 'definition' handle, in reality a list of
1134 * nvpair data.
1136 /* ARGSUSED */
1137 devctl_ddef_t
1138 devctl_ddef_alloc(char *nodename, int flags)
1141 nvlist_t *nvlp;
1143 if ((nodename == NULL) || *nodename == '\0') {
1144 errno = EINVAL;
1145 return (NULL);
1149 * allocate nvlist structure which is returned as an
1150 * opaque handle to the caller. If this fails, return
1151 * NULL with errno left set to the value
1153 if (nvlist_alloc(&nvlp, NV_UNIQUE_NAME_TYPE, 0) != 0) {
1154 errno = ENOMEM;
1155 return (NULL);
1159 * add the nodename of the new device to the list
1161 if (nvlist_add_string(nvlp, DC_DEVI_NODENAME, nodename) != 0) {
1162 nvlist_free(nvlp);
1163 errno = ENOMEM;
1164 return (NULL);
1167 if (_libdevice_debug)
1168 (void) printf("devctl_ddef_alloc: node %s nvp %p\n", nodename,
1169 (void *)nvlp);
1171 return ((devctl_ddef_t)nvlp);
1175 * free the definition handle
1177 void
1178 devctl_ddef_free(devctl_ddef_t ddef_hdl)
1180 if (_libdevice_debug)
1181 (void) printf("devctl_ddef_free: nvp %p\n", (void *)ddef_hdl);
1183 if (ddef_hdl != NULL) {
1184 nvlist_free((nvlist_t *)ddef_hdl);
1189 * define an integer property
1192 devctl_ddef_int(devctl_ddef_t ddef_hdl, char *name, int32_t value)
1195 int rv;
1197 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1198 errno = EINVAL;
1199 return (-1);
1202 rv = nvlist_add_int32((nvlist_t *)ddef_hdl, name, value);
1204 if (_libdevice_debug)
1205 (void) printf("devctl_ddef_int: rv %d nvp %p name %s val %d\n",
1206 rv, (void *)ddef_hdl, name, value);
1208 return (rv);
1212 * define an integer array property
1215 devctl_ddef_int_array(devctl_ddef_t ddef_hdl, char *name, int nelements,
1216 int32_t *value)
1218 int rv, i;
1220 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1221 errno = EINVAL;
1222 return (-1);
1225 rv = nvlist_add_int32_array((nvlist_t *)ddef_hdl, name, value,
1226 nelements);
1228 if (_libdevice_debug) {
1229 (void) printf("devctl_ddef_int_array: rv %d nvp %p name %s: ",
1230 rv, (void *)ddef_hdl, name);
1231 for (i = 0; i < nelements; i++)
1232 (void) printf("0x%x ", value[i]);
1233 (void) printf("\n");
1236 return (rv);
1240 * define a string property
1243 devctl_ddef_string(devctl_ddef_t ddef_hdl, char *name, char *value)
1245 int rv;
1247 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1248 errno = EINVAL;
1249 return (-1);
1252 rv = nvlist_add_string((nvlist_t *)ddef_hdl, name, value);
1254 if (_libdevice_debug)
1255 (void) printf("devctl_ddef_string: rv %d nvp %p %s=\"%s\"\n",
1256 rv, (void *)ddef_hdl, name, value);
1258 return (rv);
1262 * define a string array property
1265 devctl_ddef_string_array(devctl_ddef_t ddef_hdl, char *name, int nelements,
1266 char **value)
1268 int rv, i;
1270 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1271 errno = EINVAL;
1272 return (-1);
1275 rv = nvlist_add_string_array((nvlist_t *)ddef_hdl, name,
1276 value, nelements);
1278 if (_libdevice_debug) {
1279 (void) printf("devctl_ddef_string_array: rv %d nvp %p "
1280 "name %s:\n", rv, (void *)ddef_hdl, name);
1281 for (i = 0; i < nelements; i++)
1282 (void) printf("\t%d: \"%s\"\n", i, value[i]);
1284 return (rv);
1288 * define a byte array property
1291 devctl_ddef_byte_array(devctl_ddef_t ddef_hdl, char *name, int nelements,
1292 uchar_t *value)
1294 int rv;
1296 if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1297 errno = EINVAL;
1298 return (-1);
1301 rv = nvlist_add_byte_array((nvlist_t *)ddef_hdl, name, value,
1302 nelements);
1304 return (rv);
1308 * return the pathname which was used to acquire the handle
1310 char *
1311 devctl_get_pathname(devctl_hdl_t dcp, char *pathbuf, size_t bufsz)
1313 if (dcp == NULL || pathbuf == NULL || bufsz == 0) {
1314 errno = EINVAL;
1315 return (NULL);
1318 (void) snprintf(pathbuf, bufsz, "%s", DCP(dcp)->opath);
1319 return (pathbuf);
1324 * execute the IOCTL request
1326 static int
1327 dc_cmd(uint_t cmd, uint_t flags, struct devctl_hdl *dcp, nvlist_t *ulp,
1328 void *retinfo)
1330 struct devctl_iocdata iocdata;
1331 int rv = 0;
1333 if (_libdevice_debug)
1334 (void) printf("dc_cmd: %x dcp %p ulp %p flags %x rv %p\n", cmd,
1335 (void *)dcp, (void *)ulp, flags, retinfo);
1337 if ((dcp == NULL) || (DCP(dcp)->fd == -1)) {
1338 errno = EINVAL;
1339 return (-1);
1342 (void) memset(&iocdata, 0, sizeof (struct devctl_iocdata));
1345 * if there was any user supplied data in the form of a nvlist,
1346 * pack the list prior to copyin.
1348 if (ulp != NULL) {
1349 if (rv = nvlist_pack(ulp, (char **)&iocdata.nvl_user,
1350 &iocdata.nvl_usersz, NV_ENCODE_NATIVE, 0)) {
1352 * exit with errno set by nvlist_pack()
1354 goto exit;
1356 } else {
1357 iocdata.nvl_user = NULL;
1358 iocdata.nvl_usersz = 0;
1362 * finish initalizing the request and execute the IOCTL
1364 iocdata.cmd = cmd;
1365 iocdata.flags = flags;
1366 iocdata.c_nodename = dcp->nodename;
1367 iocdata.c_unitaddr = dcp->unitaddr;
1368 iocdata.cpyout_buf = retinfo;
1369 rv = ioctl(dcp->fd, cmd, &iocdata);
1370 if (rv < 0 && _libdevice_debug) {
1371 (void) printf("dc_cmd: exited with rv %d, errno(%d):%s\n",
1372 rv, errno, strerror(errno));
1375 exit:
1376 if (iocdata.nvl_user != NULL)
1377 free(iocdata.nvl_user);
1379 return (rv);