xref: /titanic_50/usr/src/lib/libdevice/devctl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
32*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
33*7c478bd9Sstevel@tonic-gate #include <string.h>
34*7c478bd9Sstevel@tonic-gate #include <strings.h>
35*7c478bd9Sstevel@tonic-gate #include <errno.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
38*7c478bd9Sstevel@tonic-gate #include <stdio.h>
39*7c478bd9Sstevel@tonic-gate #include <unistd.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/nvpair.h>
41*7c478bd9Sstevel@tonic-gate #include "libdevice.h"
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate static int _libdevice_debug = 0;
44*7c478bd9Sstevel@tonic-gate static const char *devctl_minorname = ":devctl";
45*7c478bd9Sstevel@tonic-gate static const char *nullptr = "<null>";
46*7c478bd9Sstevel@tonic-gate static const char *devctl_target_raw = "a,raw";
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate typedef enum { DEVCTL_BUS, DEVCTL_DEVICE, DEVCTL_AP, DEVCTL_CLONE,
49*7c478bd9Sstevel@tonic-gate     DEVCTL_PM_DEV, DEVCTL_PM_BUS } dc_type_t;
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * devctl_hdl structures are allocated by the devctl_XX_acquire()
53*7c478bd9Sstevel@tonic-gate  * interfaces and passed to the remaining interfaces in this library.
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate struct devctl_hdl {
56*7c478bd9Sstevel@tonic-gate 	char		*opath;		/* copy of the original path */
57*7c478bd9Sstevel@tonic-gate 	dc_type_t	hdltype;	/* handle type */
58*7c478bd9Sstevel@tonic-gate 	int		fd;		/* nexus device node */
59*7c478bd9Sstevel@tonic-gate 	char		*nodename;	/* DEVCTL_DEVICE handles only */
60*7c478bd9Sstevel@tonic-gate 	char		*unitaddr;	/* DEVCTL_DEVICE handles only */
61*7c478bd9Sstevel@tonic-gate };
62*7c478bd9Sstevel@tonic-gate #define	DCP(x)	((struct devctl_hdl *)(x))
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate static int dc_cmd(uint_t, uint_t, struct devctl_hdl *, nvlist_t *, void *);
65*7c478bd9Sstevel@tonic-gate static devctl_hdl_t dc_mkhndl(dc_type_t, char *, uint_t, devctl_hdl_t);
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #pragma init(_libdevice_init)
69*7c478bd9Sstevel@tonic-gate void
_libdevice_init()70*7c478bd9Sstevel@tonic-gate _libdevice_init()
71*7c478bd9Sstevel@tonic-gate {
72*7c478bd9Sstevel@tonic-gate 	_libdevice_debug = getenv("LIBDEVICE_DEBUG") != NULL;
73*7c478bd9Sstevel@tonic-gate }
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate /*
76*7c478bd9Sstevel@tonic-gate  * release a devctl_hdl structure
77*7c478bd9Sstevel@tonic-gate  */
78*7c478bd9Sstevel@tonic-gate void
devctl_release(devctl_hdl_t hdl)79*7c478bd9Sstevel@tonic-gate devctl_release(devctl_hdl_t hdl)
80*7c478bd9Sstevel@tonic-gate {
81*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
82*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_release: %p\n", (void *)hdl);
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 	if (hdl == NULL)
85*7c478bd9Sstevel@tonic-gate 		return;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	if (DCP(hdl)->fd != -1)
88*7c478bd9Sstevel@tonic-gate 		(void) close(DCP(hdl)->fd);
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	if (DCP(hdl)->opath != NULL)
91*7c478bd9Sstevel@tonic-gate 		free(DCP(hdl)->opath);
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	if (DCP(hdl)->nodename != NULL)
94*7c478bd9Sstevel@tonic-gate 		free(DCP(hdl)->nodename);
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	if (DCP(hdl)->unitaddr != NULL)
97*7c478bd9Sstevel@tonic-gate 		free(DCP(hdl)->unitaddr);
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	free(hdl);
100*7c478bd9Sstevel@tonic-gate }
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate /*
103*7c478bd9Sstevel@tonic-gate  * construct a handle suitable for devctl_bus_*() operations
104*7c478bd9Sstevel@tonic-gate  */
105*7c478bd9Sstevel@tonic-gate devctl_hdl_t
devctl_bus_acquire(char * devfs_path,uint_t flags)106*7c478bd9Sstevel@tonic-gate devctl_bus_acquire(char *devfs_path, uint_t flags)
107*7c478bd9Sstevel@tonic-gate {
108*7c478bd9Sstevel@tonic-gate 	uint_t oflags;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
111*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_bus_acquire: %s (%d)\n",
112*7c478bd9Sstevel@tonic-gate 			((devfs_path != NULL) ? devfs_path : nullptr), flags);
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
115*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
116*7c478bd9Sstevel@tonic-gate 		return (NULL);
117*7c478bd9Sstevel@tonic-gate 	}
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	oflags = ((flags & DC_EXCL) != 0) ? O_EXCL|O_RDWR : O_RDWR;
120*7c478bd9Sstevel@tonic-gate 	return (dc_mkhndl(DEVCTL_BUS, devfs_path, oflags, NULL));
121*7c478bd9Sstevel@tonic-gate }
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate /*
125*7c478bd9Sstevel@tonic-gate  * construct a handle suitable for devctl_bus_*() and
126*7c478bd9Sstevel@tonic-gate  * devctl_device_*() operations.
127*7c478bd9Sstevel@tonic-gate  */
128*7c478bd9Sstevel@tonic-gate devctl_hdl_t
devctl_device_acquire(char * devfs_path,uint_t flags)129*7c478bd9Sstevel@tonic-gate devctl_device_acquire(char *devfs_path, uint_t flags)
130*7c478bd9Sstevel@tonic-gate {
131*7c478bd9Sstevel@tonic-gate 	uint_t oflags;
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
134*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_device_acquire: %s (%d)\n",
135*7c478bd9Sstevel@tonic-gate 		    ((devfs_path != NULL) ? devfs_path : nullptr), flags);
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
138*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
139*7c478bd9Sstevel@tonic-gate 		return (NULL);
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	oflags = ((flags & DC_EXCL) != 0) ? O_EXCL|O_RDWR : O_RDWR;
143*7c478bd9Sstevel@tonic-gate 	return (dc_mkhndl(DEVCTL_DEVICE, devfs_path, oflags, NULL));
144*7c478bd9Sstevel@tonic-gate }
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /*
148*7c478bd9Sstevel@tonic-gate  * given a devfs (/devices) pathname to an attachment point device,
149*7c478bd9Sstevel@tonic-gate  * access the device and return a handle to be passed to the
150*7c478bd9Sstevel@tonic-gate  * devctl_ap_XXX() functions.
151*7c478bd9Sstevel@tonic-gate  */
152*7c478bd9Sstevel@tonic-gate devctl_hdl_t
devctl_ap_acquire(char * devfs_path,uint_t flags)153*7c478bd9Sstevel@tonic-gate devctl_ap_acquire(char *devfs_path, uint_t flags)
154*7c478bd9Sstevel@tonic-gate {
155*7c478bd9Sstevel@tonic-gate 	uint_t oflags;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
158*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ap_acquire: %s (%d)\n",
159*7c478bd9Sstevel@tonic-gate 		    ((devfs_path != NULL) ? devfs_path : nullptr), flags);
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	if ((devfs_path == NULL) ||
162*7c478bd9Sstevel@tonic-gate 	    ((flags != 0) && ((flags & DC_EXCL) != 0) &&
163*7c478bd9Sstevel@tonic-gate 	    ((flags & DC_RDONLY) != 0))) {
164*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
165*7c478bd9Sstevel@tonic-gate 		return (NULL);
166*7c478bd9Sstevel@tonic-gate 	}
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	oflags = ((flags & DC_EXCL) != 0) ? O_EXCL : 0;
169*7c478bd9Sstevel@tonic-gate 	oflags |= ((flags & DC_RDONLY) != 0) ? O_RDONLY : O_RDWR;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	return (dc_mkhndl(DEVCTL_AP, devfs_path, oflags, NULL));
172*7c478bd9Sstevel@tonic-gate }
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate /*
176*7c478bd9Sstevel@tonic-gate  * given a devfs (/devices) pathname access the device and return
177*7c478bd9Sstevel@tonic-gate  * a handle to be passed to the devctl_pm_XXX() functions.
178*7c478bd9Sstevel@tonic-gate  * The minor name ":devctl" is appended.
179*7c478bd9Sstevel@tonic-gate  */
180*7c478bd9Sstevel@tonic-gate devctl_hdl_t
devctl_pm_bus_acquire(char * devfs_path,uint_t flags)181*7c478bd9Sstevel@tonic-gate devctl_pm_bus_acquire(char *devfs_path, uint_t flags)
182*7c478bd9Sstevel@tonic-gate {
183*7c478bd9Sstevel@tonic-gate 	uint_t oflags;
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
186*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_bus_acquire: %s (%d)\n",
187*7c478bd9Sstevel@tonic-gate 		    ((devfs_path != NULL) ? devfs_path : nullptr), flags);
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
190*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
191*7c478bd9Sstevel@tonic-gate 		return (NULL);
192*7c478bd9Sstevel@tonic-gate 	}
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	oflags = ((flags & DC_EXCL) != 0) ? (O_EXCL | O_RDWR) : O_RDWR;
195*7c478bd9Sstevel@tonic-gate 	return (dc_mkhndl(DEVCTL_PM_BUS, devfs_path, oflags, NULL));
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate /*
200*7c478bd9Sstevel@tonic-gate  * given a devfs (/devices) pathname access the device and return
201*7c478bd9Sstevel@tonic-gate  * a handle to be passed to the devctl_pm_XXX() functions.
202*7c478bd9Sstevel@tonic-gate  * The minor name is derived from the device name.
203*7c478bd9Sstevel@tonic-gate  */
204*7c478bd9Sstevel@tonic-gate devctl_hdl_t
devctl_pm_dev_acquire(char * devfs_path,uint_t flags)205*7c478bd9Sstevel@tonic-gate devctl_pm_dev_acquire(char *devfs_path, uint_t flags)
206*7c478bd9Sstevel@tonic-gate {
207*7c478bd9Sstevel@tonic-gate 	uint_t oflags;
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
210*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_dev_acquire: %s (%d)\n",
211*7c478bd9Sstevel@tonic-gate 		    ((devfs_path != NULL) ? devfs_path : nullptr), flags);
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) {
214*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
215*7c478bd9Sstevel@tonic-gate 		return (NULL);
216*7c478bd9Sstevel@tonic-gate 	}
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	oflags = ((flags & DC_EXCL) != 0) ? (O_EXCL | O_RDWR) : O_RDWR;
219*7c478bd9Sstevel@tonic-gate 	return (dc_mkhndl(DEVCTL_PM_DEV, devfs_path, oflags, NULL));
220*7c478bd9Sstevel@tonic-gate }
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate /*
224*7c478bd9Sstevel@tonic-gate  * allocate and initalize the devctl_hdl structure for the
225*7c478bd9Sstevel@tonic-gate  * particular handle type.
226*7c478bd9Sstevel@tonic-gate  */
227*7c478bd9Sstevel@tonic-gate static devctl_hdl_t
dc_mkhndl(dc_type_t type,char * path,uint_t oflags,devctl_hdl_t pc)228*7c478bd9Sstevel@tonic-gate dc_mkhndl(dc_type_t type, char *path, uint_t oflags, devctl_hdl_t pc)
229*7c478bd9Sstevel@tonic-gate {
230*7c478bd9Sstevel@tonic-gate 	struct devctl_hdl *dcp;
231*7c478bd9Sstevel@tonic-gate 	struct stat sb;
232*7c478bd9Sstevel@tonic-gate 	char iocpath[MAXPATHLEN];
233*7c478bd9Sstevel@tonic-gate 	char *nodename, *unitsep, *minorsep, *chop;
234*7c478bd9Sstevel@tonic-gate 	char *minorname;
235*7c478bd9Sstevel@tonic-gate 	size_t strlcpy_size;
236*7c478bd9Sstevel@tonic-gate 	char *iocpath_dup;
237*7c478bd9Sstevel@tonic-gate 	char *tok;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	if ((path == NULL) || (strlen(path) > MAXPATHLEN - 1)) {
240*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
241*7c478bd9Sstevel@tonic-gate 		return (NULL);
242*7c478bd9Sstevel@tonic-gate 	}
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	/*
245*7c478bd9Sstevel@tonic-gate 	 * allocate handle and make a copy of the original path
246*7c478bd9Sstevel@tonic-gate 	 */
247*7c478bd9Sstevel@tonic-gate 	if ((dcp = calloc(1, sizeof (*dcp))) == NULL) {
248*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
249*7c478bd9Sstevel@tonic-gate 		return (NULL);
250*7c478bd9Sstevel@tonic-gate 	}
251*7c478bd9Sstevel@tonic-gate 	if ((dcp->opath = strdup(path)) == NULL) {
252*7c478bd9Sstevel@tonic-gate 		devctl_release((devctl_hdl_t)dcp);
253*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
254*7c478bd9Sstevel@tonic-gate 		return (NULL);
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	(void) strcpy(iocpath, path);
258*7c478bd9Sstevel@tonic-gate 	dcp->hdltype = type;
259*7c478bd9Sstevel@tonic-gate 	dcp->fd = -1;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	/*
262*7c478bd9Sstevel@tonic-gate 	 * break apart the pathname according to the type handle
263*7c478bd9Sstevel@tonic-gate 	 */
264*7c478bd9Sstevel@tonic-gate 	switch (type) {
265*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_BUS:
266*7c478bd9Sstevel@tonic-gate 		/*
267*7c478bd9Sstevel@tonic-gate 		 * chop off any minor name and concatenate the
268*7c478bd9Sstevel@tonic-gate 		 * ":devctl" minor node name string.
269*7c478bd9Sstevel@tonic-gate 		 */
270*7c478bd9Sstevel@tonic-gate 		if ((chop = strrchr(iocpath, ':')) != NULL)
271*7c478bd9Sstevel@tonic-gate 			*chop = '\0';
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 		if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >=
274*7c478bd9Sstevel@tonic-gate 		    MAXPATHLEN) {
275*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
276*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
277*7c478bd9Sstevel@tonic-gate 			return (NULL);
278*7c478bd9Sstevel@tonic-gate 		} else if (_libdevice_debug) {
279*7c478bd9Sstevel@tonic-gate 			(void) printf("DEVCTL_PM_BUS: iocpath %s\n", iocpath);
280*7c478bd9Sstevel@tonic-gate 		}
281*7c478bd9Sstevel@tonic-gate 		break;
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_DEV:
284*7c478bd9Sstevel@tonic-gate 		/*
285*7c478bd9Sstevel@tonic-gate 		 * Chop up the last device component in the pathname.
286*7c478bd9Sstevel@tonic-gate 		 * Concatenate either the device name itself, or the
287*7c478bd9Sstevel@tonic-gate 		 * "a,raw" string, as the minor node name, to the iocpath.
288*7c478bd9Sstevel@tonic-gate 		 */
289*7c478bd9Sstevel@tonic-gate 		if ((iocpath_dup = strdup(iocpath)) == NULL) {
290*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
291*7c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
292*7c478bd9Sstevel@tonic-gate 			return (NULL);
293*7c478bd9Sstevel@tonic-gate 		}
294*7c478bd9Sstevel@tonic-gate 		if ((chop = strrchr(iocpath_dup, '/')) == NULL) {
295*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
296*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
297*7c478bd9Sstevel@tonic-gate 			return (NULL);
298*7c478bd9Sstevel@tonic-gate 		}
299*7c478bd9Sstevel@tonic-gate 		*chop = '\0';
300*7c478bd9Sstevel@tonic-gate 		nodename = chop + 1;
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 		/*
303*7c478bd9Sstevel@tonic-gate 		 * remove the "@0,0" string
304*7c478bd9Sstevel@tonic-gate 		 */
305*7c478bd9Sstevel@tonic-gate 		tok = strtok(nodename, "@");
306*7c478bd9Sstevel@tonic-gate 		if ((minorname = malloc(strlen(tok) +1)) == NULL) {
307*7c478bd9Sstevel@tonic-gate 			if (_libdevice_debug)
308*7c478bd9Sstevel@tonic-gate 				(void) printf("DEVCTL_PM_DEV: failed malloc for"
309*7c478bd9Sstevel@tonic-gate 				    " minorname\n");
310*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
311*7c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
312*7c478bd9Sstevel@tonic-gate 			return (NULL);
313*7c478bd9Sstevel@tonic-gate 		}
314*7c478bd9Sstevel@tonic-gate 		(void) strcpy(minorname, tok);
315*7c478bd9Sstevel@tonic-gate 		if (_libdevice_debug) {
316*7c478bd9Sstevel@tonic-gate 			(void) printf("DEVCTL_PM_DEV: minorname %s\n",
317*7c478bd9Sstevel@tonic-gate 			    minorname);
318*7c478bd9Sstevel@tonic-gate 		}
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 		/*
321*7c478bd9Sstevel@tonic-gate 		 * construct the name of the ioctl device
322*7c478bd9Sstevel@tonic-gate 		 * by concatenating either ":a,raw" or ":"minorname
323*7c478bd9Sstevel@tonic-gate 		 */
324*7c478bd9Sstevel@tonic-gate 		(void) strlcat(iocpath, ":", MAXPATHLEN);
325*7c478bd9Sstevel@tonic-gate 		if (strcmp(minorname, "disk_chan") == 0 ||
326*7c478bd9Sstevel@tonic-gate 		    strcmp(minorname, "disk_wwn") == 0 ||
327*7c478bd9Sstevel@tonic-gate 		    strcmp(minorname, "disk_cdrom") == 0) {
328*7c478bd9Sstevel@tonic-gate 			strlcpy_size = strlcat(iocpath, devctl_target_raw,
329*7c478bd9Sstevel@tonic-gate 			    MAXPATHLEN);
330*7c478bd9Sstevel@tonic-gate 		} else {
331*7c478bd9Sstevel@tonic-gate 			strlcpy_size = strlcat(iocpath, minorname, MAXPATHLEN);
332*7c478bd9Sstevel@tonic-gate 		}
333*7c478bd9Sstevel@tonic-gate 		if (strlcpy_size >= MAXPATHLEN) {
334*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
335*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
336*7c478bd9Sstevel@tonic-gate 			return (NULL);
337*7c478bd9Sstevel@tonic-gate 		} else if (_libdevice_debug) {
338*7c478bd9Sstevel@tonic-gate 			(void) printf("DEVCTL_PM_DEV: iocpath %s\n",
339*7c478bd9Sstevel@tonic-gate 			    iocpath);
340*7c478bd9Sstevel@tonic-gate 		}
341*7c478bd9Sstevel@tonic-gate 		break;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	case DEVCTL_AP:
344*7c478bd9Sstevel@tonic-gate 		/*
345*7c478bd9Sstevel@tonic-gate 		 * take the pathname as provided.
346*7c478bd9Sstevel@tonic-gate 		 */
347*7c478bd9Sstevel@tonic-gate 		break;
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS:
350*7c478bd9Sstevel@tonic-gate 		/*
351*7c478bd9Sstevel@tonic-gate 		 * chop off any minor name and concatenate the
352*7c478bd9Sstevel@tonic-gate 		 * ":devctl" minor node name string.
353*7c478bd9Sstevel@tonic-gate 		 */
354*7c478bd9Sstevel@tonic-gate 		if ((chop = strrchr(iocpath, ':')) != NULL)
355*7c478bd9Sstevel@tonic-gate 			*chop = '\0';
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 		if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >=
358*7c478bd9Sstevel@tonic-gate 		    MAXPATHLEN) {
359*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
360*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
361*7c478bd9Sstevel@tonic-gate 			return (NULL);
362*7c478bd9Sstevel@tonic-gate 		}
363*7c478bd9Sstevel@tonic-gate 		break;
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	case DEVCTL_CLONE:
366*7c478bd9Sstevel@tonic-gate 		/*
367*7c478bd9Sstevel@tonic-gate 		 * create a device handle for a new device created
368*7c478bd9Sstevel@tonic-gate 		 * from a call to devctl_bus_dev_create()
369*7c478bd9Sstevel@tonic-gate 		 */
370*7c478bd9Sstevel@tonic-gate 		dcp->hdltype = DEVCTL_DEVICE;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE:
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 		/*
377*7c478bd9Sstevel@tonic-gate 		 * Chop up the last device component in the pathname.
378*7c478bd9Sstevel@tonic-gate 		 * The componets are passed as nodename and unitaddr
379*7c478bd9Sstevel@tonic-gate 		 * in the IOCTL data for DEVCTL ops on devices.
380*7c478bd9Sstevel@tonic-gate 		 */
381*7c478bd9Sstevel@tonic-gate 		if ((chop = strrchr(iocpath, '/')) == NULL) {
382*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
383*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
384*7c478bd9Sstevel@tonic-gate 			return (NULL);
385*7c478bd9Sstevel@tonic-gate 		}
386*7c478bd9Sstevel@tonic-gate 		*chop = '\0';
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 		nodename = chop + 1;
389*7c478bd9Sstevel@tonic-gate 		unitsep = strchr(nodename, '@');
390*7c478bd9Sstevel@tonic-gate 		minorsep = strchr(nodename, ':');
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 		if (unitsep == NULL) {
393*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
394*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
395*7c478bd9Sstevel@tonic-gate 			return (NULL);
396*7c478bd9Sstevel@tonic-gate 		}
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 		/*
399*7c478bd9Sstevel@tonic-gate 		 * copy the nodename and unit address
400*7c478bd9Sstevel@tonic-gate 		 */
401*7c478bd9Sstevel@tonic-gate 		if (((dcp->nodename = malloc(MAXNAMELEN)) == NULL) ||
402*7c478bd9Sstevel@tonic-gate 		    ((dcp->unitaddr = malloc(MAXNAMELEN)) == NULL)) {
403*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
404*7c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
405*7c478bd9Sstevel@tonic-gate 			return (NULL);
406*7c478bd9Sstevel@tonic-gate 		}
407*7c478bd9Sstevel@tonic-gate 		*unitsep = '\0';
408*7c478bd9Sstevel@tonic-gate 		if (minorsep != NULL)
409*7c478bd9Sstevel@tonic-gate 			*minorsep = '\0';
410*7c478bd9Sstevel@tonic-gate 		(void) snprintf(dcp->nodename, MAXNAMELEN, "%s", nodename);
411*7c478bd9Sstevel@tonic-gate 		(void) snprintf(dcp->unitaddr, MAXNAMELEN, "%s", unitsep+1);
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 		/*
414*7c478bd9Sstevel@tonic-gate 		 * construct the name of the ioctl device
415*7c478bd9Sstevel@tonic-gate 		 */
416*7c478bd9Sstevel@tonic-gate 		if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >=
417*7c478bd9Sstevel@tonic-gate 		    MAXPATHLEN) {
418*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
419*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
420*7c478bd9Sstevel@tonic-gate 			return (NULL);
421*7c478bd9Sstevel@tonic-gate 		}
422*7c478bd9Sstevel@tonic-gate 		break;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	default:
425*7c478bd9Sstevel@tonic-gate 		devctl_release((devctl_hdl_t)dcp);
426*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
427*7c478bd9Sstevel@tonic-gate 		return (NULL);
428*7c478bd9Sstevel@tonic-gate 	}
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
431*7c478bd9Sstevel@tonic-gate 		(void) printf("dc_mkhndl: iocpath %s ", iocpath);
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	/*
434*7c478bd9Sstevel@tonic-gate 	 * verify the devctl or ap device exists and is a
435*7c478bd9Sstevel@tonic-gate 	 * character device interface.
436*7c478bd9Sstevel@tonic-gate 	 */
437*7c478bd9Sstevel@tonic-gate 	if (stat(iocpath, &sb) == 0) {
438*7c478bd9Sstevel@tonic-gate 		if ((sb.st_mode & S_IFMT) != S_IFCHR) {
439*7c478bd9Sstevel@tonic-gate 			if (_libdevice_debug)
440*7c478bd9Sstevel@tonic-gate 				(void) printf(" - not character device\n");
441*7c478bd9Sstevel@tonic-gate 			errno = ENODEV;
442*7c478bd9Sstevel@tonic-gate 			devctl_release((devctl_hdl_t)dcp);
443*7c478bd9Sstevel@tonic-gate 			return (NULL);
444*7c478bd9Sstevel@tonic-gate 		}
445*7c478bd9Sstevel@tonic-gate 	} else {
446*7c478bd9Sstevel@tonic-gate 		/*
447*7c478bd9Sstevel@tonic-gate 		 * return failure with errno value set by stat
448*7c478bd9Sstevel@tonic-gate 		 */
449*7c478bd9Sstevel@tonic-gate 		if (_libdevice_debug)
450*7c478bd9Sstevel@tonic-gate 			(void) printf(" - stat failed\n");
451*7c478bd9Sstevel@tonic-gate 		devctl_release((devctl_hdl_t)dcp);
452*7c478bd9Sstevel@tonic-gate 		return (NULL);
453*7c478bd9Sstevel@tonic-gate 	}
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	/*
456*7c478bd9Sstevel@tonic-gate 	 * if this was a new device, dup the parents handle, otherwise
457*7c478bd9Sstevel@tonic-gate 	 * just open the device.
458*7c478bd9Sstevel@tonic-gate 	 */
459*7c478bd9Sstevel@tonic-gate 	if (type == DEVCTL_CLONE)
460*7c478bd9Sstevel@tonic-gate 		dcp->fd = dup(DCP(pc)->fd);
461*7c478bd9Sstevel@tonic-gate 	else
462*7c478bd9Sstevel@tonic-gate 		dcp->fd = open(iocpath, oflags);
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	if (dcp->fd == -1) {
465*7c478bd9Sstevel@tonic-gate 		if (_libdevice_debug)
466*7c478bd9Sstevel@tonic-gate 			(void) printf(" - open/dup failed %d\n", errno);
467*7c478bd9Sstevel@tonic-gate 		/*
468*7c478bd9Sstevel@tonic-gate 		 * leave errno as set by open/dup
469*7c478bd9Sstevel@tonic-gate 		 */
470*7c478bd9Sstevel@tonic-gate 		devctl_release((devctl_hdl_t)dcp);
471*7c478bd9Sstevel@tonic-gate 		return (NULL);
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
475*7c478bd9Sstevel@tonic-gate 		(void) printf(" - open success\n");
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	return ((devctl_hdl_t)dcp);
478*7c478bd9Sstevel@tonic-gate }
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate /*
481*7c478bd9Sstevel@tonic-gate  * Power up component 0, to level MAXPWR, via a pm_raise_power() call
482*7c478bd9Sstevel@tonic-gate  */
483*7c478bd9Sstevel@tonic-gate int
devctl_pm_raisepower(devctl_hdl_t dcp)484*7c478bd9Sstevel@tonic-gate devctl_pm_raisepower(devctl_hdl_t dcp)
485*7c478bd9Sstevel@tonic-gate {
486*7c478bd9Sstevel@tonic-gate 	int  rv;
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
489*7c478bd9Sstevel@tonic-gate 	    DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
490*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
491*7c478bd9Sstevel@tonic-gate 		return (-1);
492*7c478bd9Sstevel@tonic-gate 	}
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_RAISE_PWR, 0, DCP(dcp), NULL, NULL);
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
497*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_raisepower: %d\n", rv);
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	return (rv);
500*7c478bd9Sstevel@tonic-gate }
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate /*
503*7c478bd9Sstevel@tonic-gate  * Power up component 0, to level MAXPWR, via a power_has_changed() call
504*7c478bd9Sstevel@tonic-gate  */
505*7c478bd9Sstevel@tonic-gate int
devctl_pm_changepowerhigh(devctl_hdl_t dcp)506*7c478bd9Sstevel@tonic-gate devctl_pm_changepowerhigh(devctl_hdl_t dcp)
507*7c478bd9Sstevel@tonic-gate {
508*7c478bd9Sstevel@tonic-gate 	int  rv;
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
511*7c478bd9Sstevel@tonic-gate 	    DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
512*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
513*7c478bd9Sstevel@tonic-gate 		return (-1);
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_CHANGE_PWR_HIGH, 0, DCP(dcp), NULL, NULL);
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
519*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_changepowerhigh: %d\n", rv);
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	return (rv);
522*7c478bd9Sstevel@tonic-gate }
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate /*
525*7c478bd9Sstevel@tonic-gate  * Power down component 0, to level 0, via a pm_change_power() call
526*7c478bd9Sstevel@tonic-gate  */
527*7c478bd9Sstevel@tonic-gate int
devctl_pm_changepowerlow(devctl_hdl_t dcp)528*7c478bd9Sstevel@tonic-gate devctl_pm_changepowerlow(devctl_hdl_t dcp)
529*7c478bd9Sstevel@tonic-gate {
530*7c478bd9Sstevel@tonic-gate 	int  rv;
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
533*7c478bd9Sstevel@tonic-gate 	    DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
534*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
535*7c478bd9Sstevel@tonic-gate 		return (-1);
536*7c478bd9Sstevel@tonic-gate 	}
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_CHANGE_PWR_LOW, 0, DCP(dcp), NULL, NULL);
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
541*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_changepowerlow: %d\n", rv);
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	return (rv);
544*7c478bd9Sstevel@tonic-gate }
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate /*
547*7c478bd9Sstevel@tonic-gate  * mark component 0 idle
548*7c478bd9Sstevel@tonic-gate  */
549*7c478bd9Sstevel@tonic-gate int
devctl_pm_idlecomponent(devctl_hdl_t dcp)550*7c478bd9Sstevel@tonic-gate devctl_pm_idlecomponent(devctl_hdl_t dcp)
551*7c478bd9Sstevel@tonic-gate {
552*7c478bd9Sstevel@tonic-gate 	int  rv;
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
555*7c478bd9Sstevel@tonic-gate 	    DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
556*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
557*7c478bd9Sstevel@tonic-gate 		return (-1);
558*7c478bd9Sstevel@tonic-gate 	}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_IDLE_COMP, 0, DCP(dcp), NULL, NULL);
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
563*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_idlecomponent: %d\n", rv);
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	return (rv);
566*7c478bd9Sstevel@tonic-gate }
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate /*
569*7c478bd9Sstevel@tonic-gate  * mark component 0 busy
570*7c478bd9Sstevel@tonic-gate  */
571*7c478bd9Sstevel@tonic-gate int
devctl_pm_busycomponent(devctl_hdl_t dcp)572*7c478bd9Sstevel@tonic-gate devctl_pm_busycomponent(devctl_hdl_t dcp)
573*7c478bd9Sstevel@tonic-gate {
574*7c478bd9Sstevel@tonic-gate 	int  rv;
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
577*7c478bd9Sstevel@tonic-gate 	    DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
578*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
579*7c478bd9Sstevel@tonic-gate 		return (-1);
580*7c478bd9Sstevel@tonic-gate 	}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_BUSY_COMP, 0, DCP(dcp), NULL, NULL);
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
585*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_busycomponent: %d\n", rv);
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	return (rv);
588*7c478bd9Sstevel@tonic-gate }
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate /*
591*7c478bd9Sstevel@tonic-gate  * test pm busy state
592*7c478bd9Sstevel@tonic-gate  */
593*7c478bd9Sstevel@tonic-gate int
devctl_pm_testbusy(devctl_hdl_t dcp,uint_t * busystate)594*7c478bd9Sstevel@tonic-gate devctl_pm_testbusy(devctl_hdl_t dcp, uint_t *busystate)
595*7c478bd9Sstevel@tonic-gate {
596*7c478bd9Sstevel@tonic-gate 	int  rv;
597*7c478bd9Sstevel@tonic-gate 	uint_t	busy_state = 0;
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	if (busystate == NULL) {
600*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
601*7c478bd9Sstevel@tonic-gate 		return (-1);
602*7c478bd9Sstevel@tonic-gate 	}
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
605*7c478bd9Sstevel@tonic-gate 	    DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
606*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
607*7c478bd9Sstevel@tonic-gate 		return (-1);
608*7c478bd9Sstevel@tonic-gate 	}
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_BUSY_COMP_TEST, 0, DCP(dcp), NULL,
611*7c478bd9Sstevel@tonic-gate 	    (void *)&busy_state);
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	if (rv == -1)
614*7c478bd9Sstevel@tonic-gate 		*busystate = 0;
615*7c478bd9Sstevel@tonic-gate 	else
616*7c478bd9Sstevel@tonic-gate 		*busystate = busy_state;
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
619*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_bus_testbusy: rv %d busystate %x\n",
620*7c478bd9Sstevel@tonic-gate 		    rv, *busystate);
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	return (rv);
623*7c478bd9Sstevel@tonic-gate }
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate /*
626*7c478bd9Sstevel@tonic-gate  * set flag to fail DDI_SUSPEND
627*7c478bd9Sstevel@tonic-gate  */
628*7c478bd9Sstevel@tonic-gate int
devctl_pm_failsuspend(devctl_hdl_t dcp)629*7c478bd9Sstevel@tonic-gate devctl_pm_failsuspend(devctl_hdl_t dcp)
630*7c478bd9Sstevel@tonic-gate {
631*7c478bd9Sstevel@tonic-gate 	int rv;
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
634*7c478bd9Sstevel@tonic-gate 	    DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
635*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
636*7c478bd9Sstevel@tonic-gate 		return (-1);
637*7c478bd9Sstevel@tonic-gate 	}
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_FAIL_SUSPEND, 0, DCP(dcp), NULL, NULL);
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
642*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_failsuspend: %d\n", rv);
643*7c478bd9Sstevel@tonic-gate 	return (rv);
644*7c478bd9Sstevel@tonic-gate }
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate int
devctl_pm_bus_teststrict(devctl_hdl_t dcp,uint_t * strict)647*7c478bd9Sstevel@tonic-gate devctl_pm_bus_teststrict(devctl_hdl_t dcp, uint_t *strict)
648*7c478bd9Sstevel@tonic-gate {
649*7c478bd9Sstevel@tonic-gate 	int  rv;
650*7c478bd9Sstevel@tonic-gate 	uint_t	strict_state;
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	if (strict == NULL) {
653*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
654*7c478bd9Sstevel@tonic-gate 		return (-1);
655*7c478bd9Sstevel@tonic-gate 	}
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
658*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
659*7c478bd9Sstevel@tonic-gate 		return (-1);
660*7c478bd9Sstevel@tonic-gate 	}
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_BUS_STRICT_TEST, 0, DCP(dcp), NULL,
663*7c478bd9Sstevel@tonic-gate 	    (void *)&strict_state);
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	if (rv == -1)
666*7c478bd9Sstevel@tonic-gate 		*strict = 0;
667*7c478bd9Sstevel@tonic-gate 	else
668*7c478bd9Sstevel@tonic-gate 		*strict = strict_state;
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
671*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_bus_teststrict: rv %d strict %x\n",
672*7c478bd9Sstevel@tonic-gate 		    rv, *strict);
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	return (rv);
675*7c478bd9Sstevel@tonic-gate }
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate /*
678*7c478bd9Sstevel@tonic-gate  * issue prom_printf() call
679*7c478bd9Sstevel@tonic-gate  */
680*7c478bd9Sstevel@tonic-gate int
devctl_pm_device_promprintf(devctl_hdl_t dcp)681*7c478bd9Sstevel@tonic-gate devctl_pm_device_promprintf(devctl_hdl_t dcp)
682*7c478bd9Sstevel@tonic-gate {
683*7c478bd9Sstevel@tonic-gate 	int rv;
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
686*7c478bd9Sstevel@tonic-gate 	    DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
687*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
688*7c478bd9Sstevel@tonic-gate 		return (-1);
689*7c478bd9Sstevel@tonic-gate 	}
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_PROM_PRINTF, 0, DCP(dcp), NULL, NULL);
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
694*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_device_promprintf: %d\n", rv);
695*7c478bd9Sstevel@tonic-gate 	return (rv);
696*7c478bd9Sstevel@tonic-gate }
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate /*
699*7c478bd9Sstevel@tonic-gate  * set flag to power up the device via
700*7c478bd9Sstevel@tonic-gate  * pm_power_has_changed() calls vs.
701*7c478bd9Sstevel@tonic-gate  * pm_raise_power(), during DDI_RESUME
702*7c478bd9Sstevel@tonic-gate  */
703*7c478bd9Sstevel@tonic-gate int
devctl_pm_device_changeonresume(devctl_hdl_t dcp)704*7c478bd9Sstevel@tonic-gate devctl_pm_device_changeonresume(devctl_hdl_t dcp)
705*7c478bd9Sstevel@tonic-gate {
706*7c478bd9Sstevel@tonic-gate 	int rv;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV &&
709*7c478bd9Sstevel@tonic-gate 	    DCP(dcp)->hdltype != DEVCTL_PM_BUS)) {
710*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
711*7c478bd9Sstevel@tonic-gate 		return (-1);
712*7c478bd9Sstevel@tonic-gate 	}
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME, 0,
715*7c478bd9Sstevel@tonic-gate 	    DCP(dcp), NULL, NULL);
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
718*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_device_changeonresume: %d\n", rv);
719*7c478bd9Sstevel@tonic-gate 	return (rv);
720*7c478bd9Sstevel@tonic-gate }
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate /*
723*7c478bd9Sstevel@tonic-gate  * issue DEVCTL_PM_NO_LOWER_POWER to clear the LOWER_POWER_FLAG
724*7c478bd9Sstevel@tonic-gate  * flag: pm_lower_power() will not be called on device detach
725*7c478bd9Sstevel@tonic-gate  */
726*7c478bd9Sstevel@tonic-gate int
devctl_pm_device_no_lower_power(devctl_hdl_t dcp)727*7c478bd9Sstevel@tonic-gate devctl_pm_device_no_lower_power(devctl_hdl_t dcp)
728*7c478bd9Sstevel@tonic-gate {
729*7c478bd9Sstevel@tonic-gate 	int rv;
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_PM_DEV) {
732*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
733*7c478bd9Sstevel@tonic-gate 		return (-1);
734*7c478bd9Sstevel@tonic-gate 	}
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_NO_LOWER_POWER, 0, DCP(dcp), NULL, NULL);
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
739*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_device_no_lower_power: %d\n", rv);
740*7c478bd9Sstevel@tonic-gate 	return (rv);
741*7c478bd9Sstevel@tonic-gate }
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate /*
744*7c478bd9Sstevel@tonic-gate  * issue DEVCTL_PM_BUS_NO_INVOL ioctl to set the NO_INVOL_FLAG
745*7c478bd9Sstevel@tonic-gate  * flag: parent driver will mark itself idle twice in
746*7c478bd9Sstevel@tonic-gate  * DDI_CTLOPS_DETACH(POST)
747*7c478bd9Sstevel@tonic-gate  */
748*7c478bd9Sstevel@tonic-gate int
devctl_pm_bus_no_invol(devctl_hdl_t dcp)749*7c478bd9Sstevel@tonic-gate devctl_pm_bus_no_invol(devctl_hdl_t dcp)
750*7c478bd9Sstevel@tonic-gate {
751*7c478bd9Sstevel@tonic-gate 	int rv;
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_PM_BUS) {
754*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
755*7c478bd9Sstevel@tonic-gate 		return (-1);
756*7c478bd9Sstevel@tonic-gate 	}
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_PM_BUS_NO_INVOL, 0, DCP(dcp), NULL, NULL);
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
761*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_pm_bus_no_invol: %d\n", rv);
762*7c478bd9Sstevel@tonic-gate 	return (rv);
763*7c478bd9Sstevel@tonic-gate }
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate /*
766*7c478bd9Sstevel@tonic-gate  * Place the device ONLINE
767*7c478bd9Sstevel@tonic-gate  */
768*7c478bd9Sstevel@tonic-gate int
devctl_device_online(devctl_hdl_t dcp)769*7c478bd9Sstevel@tonic-gate devctl_device_online(devctl_hdl_t dcp)
770*7c478bd9Sstevel@tonic-gate {
771*7c478bd9Sstevel@tonic-gate 	int  rv;
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) {
774*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
775*7c478bd9Sstevel@tonic-gate 		return (-1);
776*7c478bd9Sstevel@tonic-gate 	}
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_DEVICE_ONLINE, 0, DCP(dcp), NULL, NULL);
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
781*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_device_online: %d\n", rv);
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	return (rv);
784*7c478bd9Sstevel@tonic-gate }
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate /*
787*7c478bd9Sstevel@tonic-gate  * take device OFFLINE
788*7c478bd9Sstevel@tonic-gate  */
789*7c478bd9Sstevel@tonic-gate int
devctl_device_offline(devctl_hdl_t dcp)790*7c478bd9Sstevel@tonic-gate devctl_device_offline(devctl_hdl_t dcp)
791*7c478bd9Sstevel@tonic-gate {
792*7c478bd9Sstevel@tonic-gate 	int  rv;
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) {
795*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
796*7c478bd9Sstevel@tonic-gate 		return (-1);
797*7c478bd9Sstevel@tonic-gate 	}
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_DEVICE_OFFLINE, 0, DCP(dcp), NULL, NULL);
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
802*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_device_offline: %d\n", rv);
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	return (rv);
805*7c478bd9Sstevel@tonic-gate }
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate /*
808*7c478bd9Sstevel@tonic-gate  * take the device OFFLINE and remove its dev_info node
809*7c478bd9Sstevel@tonic-gate  */
810*7c478bd9Sstevel@tonic-gate int
devctl_device_remove(devctl_hdl_t dcp)811*7c478bd9Sstevel@tonic-gate devctl_device_remove(devctl_hdl_t dcp)
812*7c478bd9Sstevel@tonic-gate {
813*7c478bd9Sstevel@tonic-gate 	int  rv;
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) {
816*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
817*7c478bd9Sstevel@tonic-gate 		return (-1);
818*7c478bd9Sstevel@tonic-gate 	}
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_DEVICE_REMOVE, 0, DCP(dcp), NULL, NULL);
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
823*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_device_remove: %d\n", rv);
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	return (rv);
826*7c478bd9Sstevel@tonic-gate }
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate /*
830*7c478bd9Sstevel@tonic-gate  * QUIESCE the bus
831*7c478bd9Sstevel@tonic-gate  */
832*7c478bd9Sstevel@tonic-gate int
devctl_bus_quiesce(devctl_hdl_t dcp)833*7c478bd9Sstevel@tonic-gate devctl_bus_quiesce(devctl_hdl_t dcp)
834*7c478bd9Sstevel@tonic-gate {
835*7c478bd9Sstevel@tonic-gate 	int  rv;
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_BUS_QUIESCE, 0, DCP(dcp), NULL, NULL);
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
840*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_bus_quiesce: %d\n", rv);
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	return (rv);
843*7c478bd9Sstevel@tonic-gate }
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate int
devctl_bus_unquiesce(devctl_hdl_t dcp)846*7c478bd9Sstevel@tonic-gate devctl_bus_unquiesce(devctl_hdl_t dcp)
847*7c478bd9Sstevel@tonic-gate {
848*7c478bd9Sstevel@tonic-gate 	int  rv;
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_BUS_UNQUIESCE, 0, DCP(dcp), NULL, NULL);
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
853*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_bus_unquiesce: %d\n", rv);
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	return (rv);
856*7c478bd9Sstevel@tonic-gate }
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate int
devctl_bus_reset(devctl_hdl_t dcp)859*7c478bd9Sstevel@tonic-gate devctl_bus_reset(devctl_hdl_t dcp)
860*7c478bd9Sstevel@tonic-gate {
861*7c478bd9Sstevel@tonic-gate 	int  rv;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_BUS_RESET, 0, DCP(dcp), NULL, NULL);
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
866*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_bus_reset: %d\n", rv);
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	return (rv);
869*7c478bd9Sstevel@tonic-gate }
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate int
devctl_bus_resetall(devctl_hdl_t dcp)872*7c478bd9Sstevel@tonic-gate devctl_bus_resetall(devctl_hdl_t dcp)
873*7c478bd9Sstevel@tonic-gate {
874*7c478bd9Sstevel@tonic-gate 	int  rv;
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_BUS_RESETALL, 0, DCP(dcp), NULL, NULL);
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
879*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_bus_resetall: %d\n", rv);
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 	return (rv);
882*7c478bd9Sstevel@tonic-gate }
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate int
devctl_device_reset(devctl_hdl_t dcp)885*7c478bd9Sstevel@tonic-gate devctl_device_reset(devctl_hdl_t dcp)
886*7c478bd9Sstevel@tonic-gate {
887*7c478bd9Sstevel@tonic-gate 	int  rv;
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_DEVICE_RESET, 0, DCP(dcp), NULL, NULL);
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
892*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_device_reset: %d\n", rv);
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	return (rv);
895*7c478bd9Sstevel@tonic-gate }
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate int
devctl_device_getstate(devctl_hdl_t dcp,uint_t * devstate)898*7c478bd9Sstevel@tonic-gate devctl_device_getstate(devctl_hdl_t dcp, uint_t *devstate)
899*7c478bd9Sstevel@tonic-gate {
900*7c478bd9Sstevel@tonic-gate 	int  rv;
901*7c478bd9Sstevel@tonic-gate 	uint_t device_state;
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	if (devstate == NULL) {
904*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
905*7c478bd9Sstevel@tonic-gate 		return (-1);
906*7c478bd9Sstevel@tonic-gate 	}
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_DEVICE_GETSTATE, 0, DCP(dcp), NULL,
909*7c478bd9Sstevel@tonic-gate 	    (void *)&device_state);
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 	if (rv == -1)
912*7c478bd9Sstevel@tonic-gate 		*devstate = 0;
913*7c478bd9Sstevel@tonic-gate 	else
914*7c478bd9Sstevel@tonic-gate 		*devstate = device_state;
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
917*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_device_getstate: rv %d state %x\n",
918*7c478bd9Sstevel@tonic-gate 		    rv, *devstate);
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	return (rv);
921*7c478bd9Sstevel@tonic-gate }
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate int
devctl_bus_getstate(devctl_hdl_t dcp,uint_t * devstate)924*7c478bd9Sstevel@tonic-gate devctl_bus_getstate(devctl_hdl_t dcp, uint_t *devstate)
925*7c478bd9Sstevel@tonic-gate {
926*7c478bd9Sstevel@tonic-gate 	int  rv;
927*7c478bd9Sstevel@tonic-gate 	uint_t device_state;
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	if (devstate == NULL) {
930*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
931*7c478bd9Sstevel@tonic-gate 		return (-1);
932*7c478bd9Sstevel@tonic-gate 	}
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_BUS_GETSTATE, 0, DCP(dcp), NULL,
935*7c478bd9Sstevel@tonic-gate 	    (void *)&device_state);
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 	if (rv == -1)
938*7c478bd9Sstevel@tonic-gate 		*devstate = 0;
939*7c478bd9Sstevel@tonic-gate 	else
940*7c478bd9Sstevel@tonic-gate 		*devstate = device_state;
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
943*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_bus_getstate: rv %d, state %x\n",
944*7c478bd9Sstevel@tonic-gate 		    rv, *devstate);
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 	return (rv);
947*7c478bd9Sstevel@tonic-gate }
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate int
devctl_bus_configure(devctl_hdl_t dcp)950*7c478bd9Sstevel@tonic-gate devctl_bus_configure(devctl_hdl_t dcp)
951*7c478bd9Sstevel@tonic-gate {
952*7c478bd9Sstevel@tonic-gate 	int  rv;
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_BUS_CONFIGURE, 0, DCP(dcp), NULL, NULL);
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
957*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_bus_configure: %d\n", rv);
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate 	return (rv);
960*7c478bd9Sstevel@tonic-gate }
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate int
devctl_bus_unconfigure(devctl_hdl_t dcp)963*7c478bd9Sstevel@tonic-gate devctl_bus_unconfigure(devctl_hdl_t dcp)
964*7c478bd9Sstevel@tonic-gate {
965*7c478bd9Sstevel@tonic-gate 	int  rv;
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_BUS_UNCONFIGURE, 0, DCP(dcp), NULL, NULL);
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
970*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_bus_unconfigure: %d\n", rv);
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	return (rv);
973*7c478bd9Sstevel@tonic-gate }
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate /*
976*7c478bd9Sstevel@tonic-gate  * devctl_bus_dev_create() - create a new child device
977*7c478bd9Sstevel@tonic-gate  * Attempt to construct and attach a new child device below a
978*7c478bd9Sstevel@tonic-gate  * bus nexus (dcp).  The device is defined using the devctl_ddef_*()
979*7c478bd9Sstevel@tonic-gate  * routines to specify the set of bus-specific properties required
980*7c478bd9Sstevel@tonic-gate  * to initalize and attach the device.
981*7c478bd9Sstevel@tonic-gate  */
982*7c478bd9Sstevel@tonic-gate int
devctl_bus_dev_create(devctl_hdl_t dcp,devctl_ddef_t ddef_hdl,uint_t flags,devctl_hdl_t * new_dcp)983*7c478bd9Sstevel@tonic-gate devctl_bus_dev_create(devctl_hdl_t dcp, devctl_ddef_t ddef_hdl,
984*7c478bd9Sstevel@tonic-gate     uint_t flags, devctl_hdl_t *new_dcp)
985*7c478bd9Sstevel@tonic-gate {
986*7c478bd9Sstevel@tonic-gate 	char devname[MAXNAMELEN];
987*7c478bd9Sstevel@tonic-gate 	char devpath[MAXPATHLEN];
988*7c478bd9Sstevel@tonic-gate 	int  rv = 0;
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || ddef_hdl == NULL) {
991*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
992*7c478bd9Sstevel@tonic-gate 		return (-1);
993*7c478bd9Sstevel@tonic-gate 	}
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 	(void) memset(devname, 0, sizeof (devname));
996*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_BUS_DEV_CREATE, flags, DCP(dcp),
997*7c478bd9Sstevel@tonic-gate 	    (nvlist_t *)ddef_hdl, devname);
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	/*
1000*7c478bd9Sstevel@tonic-gate 	 * construct a device handle for the new device
1001*7c478bd9Sstevel@tonic-gate 	 */
1002*7c478bd9Sstevel@tonic-gate 	if ((rv == 0) && (new_dcp != NULL)) {
1003*7c478bd9Sstevel@tonic-gate 		char *minorname, *lastslash;
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate 		(void) memset(devpath, 0, sizeof (devpath));
1006*7c478bd9Sstevel@tonic-gate 		(void) strcat(devpath, DCP(dcp)->opath);
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 		/*
1009*7c478bd9Sstevel@tonic-gate 		 * Take the pathname of the parent device, chop off
1010*7c478bd9Sstevel@tonic-gate 		 * any minor name info, and append the name@addr of
1011*7c478bd9Sstevel@tonic-gate 		 * the new child device.
1012*7c478bd9Sstevel@tonic-gate 		 * Call dc_mkhndl() with this constructed path and
1013*7c478bd9Sstevel@tonic-gate 		 * the CLONE handle type to create a new handle which
1014*7c478bd9Sstevel@tonic-gate 		 * references the new child device.
1015*7c478bd9Sstevel@tonic-gate 		 */
1016*7c478bd9Sstevel@tonic-gate 		lastslash = strrchr(devpath, '/');
1017*7c478bd9Sstevel@tonic-gate 		if (*(lastslash + 1) == '\0') {
1018*7c478bd9Sstevel@tonic-gate 			*lastslash = '\0';
1019*7c478bd9Sstevel@tonic-gate 		} else {
1020*7c478bd9Sstevel@tonic-gate 			if ((minorname = strchr(lastslash, ':')) != NULL)
1021*7c478bd9Sstevel@tonic-gate 				*minorname = '\0';
1022*7c478bd9Sstevel@tonic-gate 		}
1023*7c478bd9Sstevel@tonic-gate 		(void) strcat(devpath, "/");
1024*7c478bd9Sstevel@tonic-gate 		(void) strlcat(devpath, devname, MAXPATHLEN);
1025*7c478bd9Sstevel@tonic-gate 		*new_dcp = dc_mkhndl(DEVCTL_CLONE, devpath, 0, dcp);
1026*7c478bd9Sstevel@tonic-gate 		if (*new_dcp == NULL)
1027*7c478bd9Sstevel@tonic-gate 			rv = -1;
1028*7c478bd9Sstevel@tonic-gate 	}
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 	return (rv);
1031*7c478bd9Sstevel@tonic-gate }
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate int
devctl_ap_connect(devctl_hdl_t dcp,nvlist_t * ap_data)1034*7c478bd9Sstevel@tonic-gate devctl_ap_connect(devctl_hdl_t dcp, nvlist_t *ap_data)
1035*7c478bd9Sstevel@tonic-gate {
1036*7c478bd9Sstevel@tonic-gate 	int  rv;
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_AP_CONNECT, 0, DCP(dcp), ap_data, NULL);
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1041*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ap_connect: %d\n", rv);
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	return (rv);
1044*7c478bd9Sstevel@tonic-gate }
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate int
devctl_ap_disconnect(devctl_hdl_t dcp,nvlist_t * ap_data)1047*7c478bd9Sstevel@tonic-gate devctl_ap_disconnect(devctl_hdl_t dcp, nvlist_t *ap_data)
1048*7c478bd9Sstevel@tonic-gate {
1049*7c478bd9Sstevel@tonic-gate 	int  rv;
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_AP_DISCONNECT, 0, DCP(dcp), ap_data, NULL);
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1054*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ap_disconnect: %d\n", rv);
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate 	return (rv);
1057*7c478bd9Sstevel@tonic-gate }
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate int
devctl_ap_insert(devctl_hdl_t dcp,nvlist_t * ap_data)1060*7c478bd9Sstevel@tonic-gate devctl_ap_insert(devctl_hdl_t dcp, nvlist_t *ap_data)
1061*7c478bd9Sstevel@tonic-gate {
1062*7c478bd9Sstevel@tonic-gate 	int  rv;
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_AP_INSERT, 0, DCP(dcp), ap_data, NULL);
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1067*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ap_insert: %d\n", rv);
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	return (rv);
1070*7c478bd9Sstevel@tonic-gate }
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate int
devctl_ap_remove(devctl_hdl_t dcp,nvlist_t * ap_data)1073*7c478bd9Sstevel@tonic-gate devctl_ap_remove(devctl_hdl_t dcp, nvlist_t *ap_data)
1074*7c478bd9Sstevel@tonic-gate {
1075*7c478bd9Sstevel@tonic-gate 	int  rv;
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_AP_REMOVE, 0, DCP(dcp), ap_data, NULL);
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1080*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ap_remove: %d\n", rv);
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 	return (rv);
1083*7c478bd9Sstevel@tonic-gate }
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate int
devctl_ap_configure(devctl_hdl_t dcp,nvlist_t * ap_data)1086*7c478bd9Sstevel@tonic-gate devctl_ap_configure(devctl_hdl_t dcp, nvlist_t *ap_data)
1087*7c478bd9Sstevel@tonic-gate {
1088*7c478bd9Sstevel@tonic-gate 	int  rv;
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_AP_CONFIGURE, 0, DCP(dcp), ap_data, NULL);
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1093*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ap_configure: %d\n", rv);
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	return (rv);
1096*7c478bd9Sstevel@tonic-gate }
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate int
devctl_ap_unconfigure(devctl_hdl_t dcp,nvlist_t * ap_data)1099*7c478bd9Sstevel@tonic-gate devctl_ap_unconfigure(devctl_hdl_t dcp, nvlist_t *ap_data)
1100*7c478bd9Sstevel@tonic-gate {
1101*7c478bd9Sstevel@tonic-gate 	int  rv;
1102*7c478bd9Sstevel@tonic-gate 
1103*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_AP_UNCONFIGURE, 0, DCP(dcp), ap_data, NULL);
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1106*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ap_unconfigure: %d\n", rv);
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate 	return (rv);
1109*7c478bd9Sstevel@tonic-gate }
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate int
devctl_ap_getstate(devctl_hdl_t dcp,nvlist_t * ap_data,devctl_ap_state_t * apstate)1112*7c478bd9Sstevel@tonic-gate devctl_ap_getstate(devctl_hdl_t dcp, nvlist_t *ap_data,
1113*7c478bd9Sstevel@tonic-gate     devctl_ap_state_t *apstate)
1114*7c478bd9Sstevel@tonic-gate {
1115*7c478bd9Sstevel@tonic-gate 	int  rv;
1116*7c478bd9Sstevel@tonic-gate 	devctl_ap_state_t ap_state;
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	rv = dc_cmd(DEVCTL_AP_GETSTATE, 0, DCP(dcp), ap_data,
1119*7c478bd9Sstevel@tonic-gate 	    (void *)&ap_state);
1120*7c478bd9Sstevel@tonic-gate 
1121*7c478bd9Sstevel@tonic-gate 	if (rv == -1)
1122*7c478bd9Sstevel@tonic-gate 		(void) memset(apstate, 0, sizeof (struct devctl_ap_state));
1123*7c478bd9Sstevel@tonic-gate 	else
1124*7c478bd9Sstevel@tonic-gate 		*apstate = ap_state;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1127*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ap_getstate: %d\n", rv);
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 	return (rv);
1130*7c478bd9Sstevel@tonic-gate }
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate /*
1133*7c478bd9Sstevel@tonic-gate  * Allocate a device 'definition' handle, in reality a list of
1134*7c478bd9Sstevel@tonic-gate  * nvpair data.
1135*7c478bd9Sstevel@tonic-gate  */
1136*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1137*7c478bd9Sstevel@tonic-gate devctl_ddef_t
devctl_ddef_alloc(char * nodename,int flags)1138*7c478bd9Sstevel@tonic-gate devctl_ddef_alloc(char *nodename, int flags)
1139*7c478bd9Sstevel@tonic-gate {
1140*7c478bd9Sstevel@tonic-gate 
1141*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvlp;
1142*7c478bd9Sstevel@tonic-gate 
1143*7c478bd9Sstevel@tonic-gate 	if ((nodename == NULL) || *nodename == '\0') {
1144*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1145*7c478bd9Sstevel@tonic-gate 		return (NULL);
1146*7c478bd9Sstevel@tonic-gate 	}
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 	/*
1149*7c478bd9Sstevel@tonic-gate 	 * allocate nvlist structure which is returned as an
1150*7c478bd9Sstevel@tonic-gate 	 * opaque handle to the caller.  If this fails, return
1151*7c478bd9Sstevel@tonic-gate 	 * NULL with errno left set to the value
1152*7c478bd9Sstevel@tonic-gate 	 */
1153*7c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&nvlp, NV_UNIQUE_NAME_TYPE, 0) != 0) {
1154*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
1155*7c478bd9Sstevel@tonic-gate 		return (NULL);
1156*7c478bd9Sstevel@tonic-gate 	}
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate 	/*
1159*7c478bd9Sstevel@tonic-gate 	 * add the nodename of the new device to the list
1160*7c478bd9Sstevel@tonic-gate 	 */
1161*7c478bd9Sstevel@tonic-gate 	if (nvlist_add_string(nvlp, DC_DEVI_NODENAME, nodename) != 0) {
1162*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1163*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
1164*7c478bd9Sstevel@tonic-gate 		return (NULL);
1165*7c478bd9Sstevel@tonic-gate 	}
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1168*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ddef_alloc: node %s nvp %p\n", nodename,
1169*7c478bd9Sstevel@tonic-gate 		    (void *)nvlp);
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 	return ((devctl_ddef_t)nvlp);
1172*7c478bd9Sstevel@tonic-gate }
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate /*
1175*7c478bd9Sstevel@tonic-gate  * free the definition handle
1176*7c478bd9Sstevel@tonic-gate  */
1177*7c478bd9Sstevel@tonic-gate void
devctl_ddef_free(devctl_ddef_t ddef_hdl)1178*7c478bd9Sstevel@tonic-gate devctl_ddef_free(devctl_ddef_t ddef_hdl)
1179*7c478bd9Sstevel@tonic-gate {
1180*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1181*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ddef_free: nvp %p\n", (void *)ddef_hdl);
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	if (ddef_hdl != NULL) {
1184*7c478bd9Sstevel@tonic-gate 		nvlist_free((nvlist_t *)ddef_hdl);
1185*7c478bd9Sstevel@tonic-gate 	}
1186*7c478bd9Sstevel@tonic-gate }
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate /*
1189*7c478bd9Sstevel@tonic-gate  * define an integer property
1190*7c478bd9Sstevel@tonic-gate  */
1191*7c478bd9Sstevel@tonic-gate int
devctl_ddef_int(devctl_ddef_t ddef_hdl,char * name,int32_t value)1192*7c478bd9Sstevel@tonic-gate devctl_ddef_int(devctl_ddef_t ddef_hdl, char *name, int32_t value)
1193*7c478bd9Sstevel@tonic-gate {
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate 	int rv;
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1198*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1199*7c478bd9Sstevel@tonic-gate 		return (-1);
1200*7c478bd9Sstevel@tonic-gate 	}
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_int32((nvlist_t *)ddef_hdl, name, value);
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1205*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ddef_int: rv %d nvp %p name %s val %d\n",
1206*7c478bd9Sstevel@tonic-gate 		    rv, (void *)ddef_hdl, name, value);
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	return (rv);
1209*7c478bd9Sstevel@tonic-gate }
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate /*
1212*7c478bd9Sstevel@tonic-gate  * define an integer array property
1213*7c478bd9Sstevel@tonic-gate  */
1214*7c478bd9Sstevel@tonic-gate int
devctl_ddef_int_array(devctl_ddef_t ddef_hdl,char * name,int nelements,int32_t * value)1215*7c478bd9Sstevel@tonic-gate devctl_ddef_int_array(devctl_ddef_t ddef_hdl, char *name, int nelements,
1216*7c478bd9Sstevel@tonic-gate     int32_t *value)
1217*7c478bd9Sstevel@tonic-gate {
1218*7c478bd9Sstevel@tonic-gate 	int rv, i;
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate 	if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1221*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1222*7c478bd9Sstevel@tonic-gate 		return (-1);
1223*7c478bd9Sstevel@tonic-gate 	}
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_int32_array((nvlist_t *)ddef_hdl, name, value,
1226*7c478bd9Sstevel@tonic-gate 	    nelements);
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug) {
1229*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ddef_int_array: rv %d nvp %p name %s: ",
1230*7c478bd9Sstevel@tonic-gate 		    rv, (void *)ddef_hdl, name);
1231*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelements; i++)
1232*7c478bd9Sstevel@tonic-gate 			(void) printf("0x%x ", value[i]);
1233*7c478bd9Sstevel@tonic-gate 		(void) printf("\n");
1234*7c478bd9Sstevel@tonic-gate 	}
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate 	return (rv);
1237*7c478bd9Sstevel@tonic-gate }
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate /*
1240*7c478bd9Sstevel@tonic-gate  * define a string property
1241*7c478bd9Sstevel@tonic-gate  */
1242*7c478bd9Sstevel@tonic-gate int
devctl_ddef_string(devctl_ddef_t ddef_hdl,char * name,char * value)1243*7c478bd9Sstevel@tonic-gate devctl_ddef_string(devctl_ddef_t ddef_hdl, char *name, char *value)
1244*7c478bd9Sstevel@tonic-gate {
1245*7c478bd9Sstevel@tonic-gate 	int rv;
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate 	if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1248*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1249*7c478bd9Sstevel@tonic-gate 		return (-1);
1250*7c478bd9Sstevel@tonic-gate 	}
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_string((nvlist_t *)ddef_hdl, name, value);
1253*7c478bd9Sstevel@tonic-gate 
1254*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1255*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ddef_string: rv %d nvp %p %s=\"%s\"\n",
1256*7c478bd9Sstevel@tonic-gate 		    rv, (void *)ddef_hdl, name, value);
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	return (rv);
1259*7c478bd9Sstevel@tonic-gate }
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate /*
1262*7c478bd9Sstevel@tonic-gate  * define a string array property
1263*7c478bd9Sstevel@tonic-gate  */
1264*7c478bd9Sstevel@tonic-gate int
devctl_ddef_string_array(devctl_ddef_t ddef_hdl,char * name,int nelements,char ** value)1265*7c478bd9Sstevel@tonic-gate devctl_ddef_string_array(devctl_ddef_t ddef_hdl, char *name, int nelements,
1266*7c478bd9Sstevel@tonic-gate     char **value)
1267*7c478bd9Sstevel@tonic-gate {
1268*7c478bd9Sstevel@tonic-gate 	int rv, i;
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate 	if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1271*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1272*7c478bd9Sstevel@tonic-gate 		return (-1);
1273*7c478bd9Sstevel@tonic-gate 	}
1274*7c478bd9Sstevel@tonic-gate 
1275*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_string_array((nvlist_t *)ddef_hdl, name,
1276*7c478bd9Sstevel@tonic-gate 	    value, nelements);
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug) {
1279*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl_ddef_string_array: rv %d nvp %p "
1280*7c478bd9Sstevel@tonic-gate 		    "name %s:\n", rv, (void *)ddef_hdl, name);
1281*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelements; i++)
1282*7c478bd9Sstevel@tonic-gate 			(void) printf("\t%d: \"%s\"\n", i, value[i]);
1283*7c478bd9Sstevel@tonic-gate 	}
1284*7c478bd9Sstevel@tonic-gate 	return (rv);
1285*7c478bd9Sstevel@tonic-gate }
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate /*
1288*7c478bd9Sstevel@tonic-gate  * define a byte array property
1289*7c478bd9Sstevel@tonic-gate  */
1290*7c478bd9Sstevel@tonic-gate int
devctl_ddef_byte_array(devctl_ddef_t ddef_hdl,char * name,int nelements,uchar_t * value)1291*7c478bd9Sstevel@tonic-gate devctl_ddef_byte_array(devctl_ddef_t ddef_hdl, char *name, int nelements,
1292*7c478bd9Sstevel@tonic-gate     uchar_t *value)
1293*7c478bd9Sstevel@tonic-gate {
1294*7c478bd9Sstevel@tonic-gate 	int rv;
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate 	if (ddef_hdl == NULL || name == NULL || *name == '\0') {
1297*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1298*7c478bd9Sstevel@tonic-gate 		return (-1);
1299*7c478bd9Sstevel@tonic-gate 	}
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate 	rv = nvlist_add_byte_array((nvlist_t *)ddef_hdl, name, value,
1302*7c478bd9Sstevel@tonic-gate 	    nelements);
1303*7c478bd9Sstevel@tonic-gate 
1304*7c478bd9Sstevel@tonic-gate 	return (rv);
1305*7c478bd9Sstevel@tonic-gate }
1306*7c478bd9Sstevel@tonic-gate 
1307*7c478bd9Sstevel@tonic-gate /*
1308*7c478bd9Sstevel@tonic-gate  * return the pathname which was used to acquire the handle
1309*7c478bd9Sstevel@tonic-gate  */
1310*7c478bd9Sstevel@tonic-gate char *
devctl_get_pathname(devctl_hdl_t dcp,char * pathbuf,size_t bufsz)1311*7c478bd9Sstevel@tonic-gate devctl_get_pathname(devctl_hdl_t dcp, char *pathbuf, size_t bufsz)
1312*7c478bd9Sstevel@tonic-gate {
1313*7c478bd9Sstevel@tonic-gate 	if (dcp == NULL || pathbuf == NULL || bufsz == 0) {
1314*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1315*7c478bd9Sstevel@tonic-gate 		return (NULL);
1316*7c478bd9Sstevel@tonic-gate 	}
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	(void) snprintf(pathbuf, bufsz, "%s", DCP(dcp)->opath);
1319*7c478bd9Sstevel@tonic-gate 	return (pathbuf);
1320*7c478bd9Sstevel@tonic-gate }
1321*7c478bd9Sstevel@tonic-gate 
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate /*
1324*7c478bd9Sstevel@tonic-gate  * execute the IOCTL request
1325*7c478bd9Sstevel@tonic-gate  */
1326*7c478bd9Sstevel@tonic-gate static int
dc_cmd(uint_t cmd,uint_t flags,struct devctl_hdl * dcp,nvlist_t * ulp,void * retinfo)1327*7c478bd9Sstevel@tonic-gate dc_cmd(uint_t cmd, uint_t flags, struct devctl_hdl *dcp, nvlist_t *ulp,
1328*7c478bd9Sstevel@tonic-gate     void *retinfo)
1329*7c478bd9Sstevel@tonic-gate {
1330*7c478bd9Sstevel@tonic-gate 	struct devctl_iocdata iocdata;
1331*7c478bd9Sstevel@tonic-gate 	int  rv = 0;
1332*7c478bd9Sstevel@tonic-gate 
1333*7c478bd9Sstevel@tonic-gate 	if (_libdevice_debug)
1334*7c478bd9Sstevel@tonic-gate 		(void) printf("dc_cmd: %x dcp %p ulp %p flags %x rv %p\n", cmd,
1335*7c478bd9Sstevel@tonic-gate 		    (void *)dcp, (void *)ulp, flags, retinfo);
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate 	if ((dcp == NULL) || (DCP(dcp)->fd == -1)) {
1338*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
1339*7c478bd9Sstevel@tonic-gate 		return (-1);
1340*7c478bd9Sstevel@tonic-gate 	}
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate 	(void) memset(&iocdata, 0, sizeof (struct devctl_iocdata));
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	/*
1345*7c478bd9Sstevel@tonic-gate 	 * if there was any user supplied data in the form of a nvlist,
1346*7c478bd9Sstevel@tonic-gate 	 * pack the list prior to copyin.
1347*7c478bd9Sstevel@tonic-gate 	 */
1348*7c478bd9Sstevel@tonic-gate 	if (ulp != NULL) {
1349*7c478bd9Sstevel@tonic-gate 		if (rv = nvlist_pack(ulp, (char **)&iocdata.nvl_user,
1350*7c478bd9Sstevel@tonic-gate 		    &iocdata.nvl_usersz, NV_ENCODE_NATIVE, 0)) {
1351*7c478bd9Sstevel@tonic-gate 			/*
1352*7c478bd9Sstevel@tonic-gate 			 * exit with errno set by nvlist_pack()
1353*7c478bd9Sstevel@tonic-gate 			 */
1354*7c478bd9Sstevel@tonic-gate 			goto exit;
1355*7c478bd9Sstevel@tonic-gate 		}
1356*7c478bd9Sstevel@tonic-gate 	} else {
1357*7c478bd9Sstevel@tonic-gate 		iocdata.nvl_user = NULL;
1358*7c478bd9Sstevel@tonic-gate 		iocdata.nvl_usersz = 0;
1359*7c478bd9Sstevel@tonic-gate 	}
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate 	/*
1362*7c478bd9Sstevel@tonic-gate 	 * finish initalizing the request and execute the IOCTL
1363*7c478bd9Sstevel@tonic-gate 	 */
1364*7c478bd9Sstevel@tonic-gate 	iocdata.cmd = cmd;
1365*7c478bd9Sstevel@tonic-gate 	iocdata.flags = flags;
1366*7c478bd9Sstevel@tonic-gate 	iocdata.c_nodename = dcp->nodename;
1367*7c478bd9Sstevel@tonic-gate 	iocdata.c_unitaddr = dcp->unitaddr;
1368*7c478bd9Sstevel@tonic-gate 	iocdata.cpyout_buf = retinfo;
1369*7c478bd9Sstevel@tonic-gate 	rv = ioctl(dcp->fd, cmd, &iocdata);
1370*7c478bd9Sstevel@tonic-gate 	if (rv < 0 && _libdevice_debug) {
1371*7c478bd9Sstevel@tonic-gate 		(void) printf("dc_cmd: exited with rv %d, errno(%d):%s\n",
1372*7c478bd9Sstevel@tonic-gate 		    rv, errno, strerror(errno));
1373*7c478bd9Sstevel@tonic-gate 	}
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate exit:
1376*7c478bd9Sstevel@tonic-gate 	if (iocdata.nvl_user != NULL)
1377*7c478bd9Sstevel@tonic-gate 		free(iocdata.nvl_user);
1378*7c478bd9Sstevel@tonic-gate 
1379*7c478bd9Sstevel@tonic-gate 	return (rv);
1380*7c478bd9Sstevel@tonic-gate }
1381