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