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