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