xref: /illumos-gate/usr/src/uts/sun4v/io/dr_io.c (revision 99c7e855)
18fea755aSjm /*
28fea755aSjm  * CDDL HEADER START
38fea755aSjm  *
48fea755aSjm  * The contents of this file are subject to the terms of the
58fea755aSjm  * Common Development and Distribution License (the "License").
68fea755aSjm  * You may not use this file except in compliance with the License.
78fea755aSjm  *
88fea755aSjm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98fea755aSjm  * or http://www.opensolaris.org/os/licensing.
108fea755aSjm  * See the License for the specific language governing permissions
118fea755aSjm  * and limitations under the License.
128fea755aSjm  *
138fea755aSjm  * When distributing Covered Code, include this CDDL HEADER in each
148fea755aSjm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158fea755aSjm  * If applicable, add the following below this CDDL HEADER, with the
168fea755aSjm  * fields enclosed by brackets "[]" replaced with your own identifying
178fea755aSjm  * information: Portions Copyright [yyyy] [name of copyright owner]
188fea755aSjm  *
198fea755aSjm  * CDDL HEADER END
208fea755aSjm  */
218fea755aSjm 
228fea755aSjm /*
238fea755aSjm  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
248fea755aSjm  * Use is subject to license terms.
258fea755aSjm  */
268fea755aSjm 
278fea755aSjm /*
288fea755aSjm  * sun4v VIO DR Module
298fea755aSjm  */
308fea755aSjm 
318fea755aSjm #include <sys/modctl.h>
328fea755aSjm #include <sys/sunddi.h>
338fea755aSjm #include <sys/sunndi.h>
348fea755aSjm #include <sys/note.h>
358fea755aSjm #include <sys/sysevent/dr.h>
368fea755aSjm #include <sys/hypervisor_api.h>
378fea755aSjm #include <sys/mach_descrip.h>
388fea755aSjm #include <sys/mdesc.h>
398fea755aSjm #include <sys/mdesc_impl.h>
408fea755aSjm #include <sys/ds.h>
418fea755aSjm #include <sys/drctl.h>
428fea755aSjm #include <sys/dr_util.h>
438fea755aSjm #include <sys/dr_io.h>
448fea755aSjm #include <sys/promif.h>
458fea755aSjm #include <sys/machsystm.h>
468fea755aSjm #include <sys/ethernet.h>
478fea755aSjm #include <sys/hotplug/pci/pcicfg.h>
488fea755aSjm 
498fea755aSjm 
508fea755aSjm static struct modlmisc modlmisc = {
518fea755aSjm 	&mod_miscops,
52f500b196SRichard Bean 	"sun4v VIO DR"
538fea755aSjm };
548fea755aSjm 
558fea755aSjm static struct modlinkage modlinkage = {
568fea755aSjm 	MODREV_1,
578fea755aSjm 	(void *)&modlmisc,
588fea755aSjm 	NULL
598fea755aSjm };
608fea755aSjm 
618fea755aSjm 
628fea755aSjm /*
638fea755aSjm  * VIO DS Interface
648fea755aSjm  */
658fea755aSjm 
668fea755aSjm /*
678fea755aSjm  * Global DS Handle
688fea755aSjm  */
698fea755aSjm static ds_svc_hdl_t ds_vio_handle;
708fea755aSjm 
718fea755aSjm /*
728fea755aSjm  * Supported DS Capability Versions
738fea755aSjm  */
748fea755aSjm static ds_ver_t		dr_vio_vers[] = { { 1, 0 } };
758fea755aSjm #define	DR_VIO_NVERS	(sizeof (dr_vio_vers) / sizeof (dr_vio_vers[0]))
768fea755aSjm 
778fea755aSjm /*
788fea755aSjm  * DS Capability Description
798fea755aSjm  */
808fea755aSjm static ds_capability_t dr_vio_cap = {
818fea755aSjm 	DR_VIO_DS_ID,		/* svc_id */
828fea755aSjm 	dr_vio_vers,		/* vers */
838fea755aSjm 	DR_VIO_NVERS		/* nvers */
848fea755aSjm };
858fea755aSjm 
868fea755aSjm /*
878fea755aSjm  * DS Callbacks
888fea755aSjm  */
898fea755aSjm static void dr_vio_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
908fea755aSjm static void dr_vio_unreg_handler(ds_cb_arg_t arg);
918fea755aSjm static void dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
928fea755aSjm 
938fea755aSjm /*
948fea755aSjm  * DS Client Ops Vector
958fea755aSjm  */
968fea755aSjm static ds_clnt_ops_t dr_vio_ops = {
978fea755aSjm 	dr_vio_reg_handler,	/* ds_reg_cb */
988fea755aSjm 	dr_vio_unreg_handler,	/* ds_unreg_cb */
998fea755aSjm 	dr_vio_data_handler,	/* ds_data_cb */
1008fea755aSjm 	NULL			/* cb_arg */
1018fea755aSjm };
1028fea755aSjm 
1038fea755aSjm 
1048fea755aSjm typedef struct {
1058fea755aSjm 	char		*name;
1068fea755aSjm 	uint64_t	devid;
1078fea755aSjm 	dev_info_t	*dip;
1088fea755aSjm } dr_search_arg_t;
1098fea755aSjm 
1108fea755aSjm static int
dr_io_check_node(dev_info_t * dip,void * arg)1118fea755aSjm dr_io_check_node(dev_info_t *dip, void *arg)
1128fea755aSjm {
1138fea755aSjm 	char 		*name;
1148fea755aSjm 	uint64_t	devid;
1158fea755aSjm 	dr_search_arg_t	*sarg = (dr_search_arg_t *)arg;
1168fea755aSjm 
1178fea755aSjm 	name = ddi_node_name(dip);
1188fea755aSjm 
1198fea755aSjm 	if (strcmp(name, sarg->name) != 0)
1208fea755aSjm 		return (DDI_WALK_CONTINUE);
1218fea755aSjm 
1228fea755aSjm 	devid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1238fea755aSjm 	    "reg", -1);
1248fea755aSjm 
1258fea755aSjm 	DR_DBG_IO("%s: found devid=%ld, looking for %ld\n",
1268fea755aSjm 	    __func__, devid, sarg->devid);
1278fea755aSjm 
1288fea755aSjm 	if (devid == sarg->devid) {
1298fea755aSjm 		DR_DBG_IO("%s: matched", __func__);
1308fea755aSjm 
1318fea755aSjm 		/* matching node must be returned held */
1328fea755aSjm 		if (!e_ddi_branch_held(dip))
1338fea755aSjm 			e_ddi_branch_hold(dip);
1348fea755aSjm 
1358fea755aSjm 		sarg->dip = dip;
1368fea755aSjm 		return (DDI_WALK_TERMINATE);
1378fea755aSjm 	}
1388fea755aSjm 
1398fea755aSjm 	return (DDI_WALK_CONTINUE);
1408fea755aSjm }
1418fea755aSjm 
1428fea755aSjm /*
1438fea755aSjm  * Walk the device tree to find the dip corresponding to the devid
1448fea755aSjm  * passed in. If present, the dip is returned held. The caller must
1458fea755aSjm  * release the hold on the dip once it is no longer required. If no
1468fea755aSjm  * matching node if found, NULL is returned.
1478fea755aSjm  */
1488fea755aSjm static dev_info_t *
dr_io_find_node(char * name,uint64_t devid)1498fea755aSjm dr_io_find_node(char *name, uint64_t devid)
1508fea755aSjm {
1518fea755aSjm 	dr_search_arg_t	arg;
1528fea755aSjm 
1538fea755aSjm 	DR_DBG_IO("dr_io_find_node...\n");
1548fea755aSjm 
1558fea755aSjm 	arg.name = name;
1568fea755aSjm 	arg.devid = devid;
1578fea755aSjm 	arg.dip = NULL;
1588fea755aSjm 
1598fea755aSjm 	ddi_walk_devs(ddi_root_node(), dr_io_check_node, &arg);
1608fea755aSjm 
1618fea755aSjm 	ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip)));
1628fea755aSjm 
1638fea755aSjm 	return ((arg.dip) ? arg.dip : NULL);
1648fea755aSjm }
1658fea755aSjm 
1668fea755aSjm /*
1678fea755aSjm  * Look up a particular IO node in the MD. Returns the mde_cookie_t
1688fea755aSjm  * representing that IO node if present, and MDE_INVAL_ELEM_COOKIE otherwise.
1698fea755aSjm  * It is assumed the scratch array has already been allocated so that
1708fea755aSjm  * it can accommodate the worst case scenario, every node in the MD.
1718fea755aSjm  */
1728fea755aSjm static mde_cookie_t
dr_io_find_node_md(md_t * mdp,char * name,uint64_t id,mde_cookie_t * listp)1738fea755aSjm dr_io_find_node_md(md_t *mdp, char *name, uint64_t id, mde_cookie_t *listp)
1748fea755aSjm {
1758fea755aSjm 	int		i;
1768fea755aSjm 	int		nnodes;
1778fea755aSjm 	char		*devnm;
1788fea755aSjm 	uint64_t	devid;
1798fea755aSjm 	mde_cookie_t	rootnode;
1808fea755aSjm 	mde_cookie_t	result = MDE_INVAL_ELEM_COOKIE;
1818fea755aSjm 
1828fea755aSjm 	DR_DBG_IO("%s: %s@%ld\n", __func__, name, id);
1838fea755aSjm 
1848fea755aSjm 	rootnode = md_root_node(mdp);
1858fea755aSjm 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
1868fea755aSjm 
1878fea755aSjm 	/*
1888fea755aSjm 	 * Scan the DAG for all candidate nodes.
1898fea755aSjm 	 */
1908fea755aSjm 	nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"),
1918fea755aSjm 	    md_find_name(mdp, "fwd"), listp);
1928fea755aSjm 
1938fea755aSjm 	if (nnodes < 0) {
1948fea755aSjm 		DR_DBG_IO("%s: scan for "
1958fea755aSjm 		    "'virtual-device' nodes failed\n", __func__);
1968fea755aSjm 		return (result);
1978fea755aSjm 	}
1988fea755aSjm 
1998fea755aSjm 	DR_DBG_IO("%s: found %d nodes in the MD\n", __func__, nnodes);
2008fea755aSjm 
2018fea755aSjm 	/*
2028fea755aSjm 	 * Find the node of interest
2038fea755aSjm 	 */
2048fea755aSjm 	for (i = 0; i < nnodes; i++) {
2058fea755aSjm 
2068fea755aSjm 		if (md_get_prop_str(mdp, listp[i], "name", &devnm)) {
2078fea755aSjm 			DR_DBG_IO("%s: missing 'name' property for"
2088fea755aSjm 			    " IO node %d\n", __func__, i);
2098fea755aSjm 			return (DDI_WALK_ERROR);
2108fea755aSjm 		}
2118fea755aSjm 
2128fea755aSjm 		if (strcmp(devnm, name) != 0)
2138fea755aSjm 			continue;
2148fea755aSjm 
2158fea755aSjm 		if (md_get_prop_val(mdp, listp[i], "cfg-handle", &devid)) {
2168fea755aSjm 			DR_DBG_IO("%s: missing 'cfg-handle' property for"
2178fea755aSjm 			    " IO node %d\n", __func__, i);
2188fea755aSjm 			break;
2198fea755aSjm 		}
2208fea755aSjm 
2218fea755aSjm 		if (devid == id) {
2228fea755aSjm 			/* found a match */
2238fea755aSjm 			DR_DBG_IO("%s: found IO node %s@%ld "
2248fea755aSjm 			    "in MD\n", __func__, name, id);
2258fea755aSjm 			result = listp[i];
2268fea755aSjm 			break;
2278fea755aSjm 		}
2288fea755aSjm 	}
2298fea755aSjm 
2308fea755aSjm 	if (result == MDE_INVAL_ELEM_COOKIE)
2318fea755aSjm 		DR_DBG_IO("%s: IO node %ld not in MD\n", __func__, id);
2328fea755aSjm 
2338fea755aSjm 	return (result);
2348fea755aSjm }
2358fea755aSjm 
2368fea755aSjm typedef struct {
2378fea755aSjm 	md_t		*mdp;
2388fea755aSjm 	mde_cookie_t	node;
2398fea755aSjm 	dev_info_t	*dip;
2408fea755aSjm } cb_arg_t;
2418fea755aSjm 
2428fea755aSjm #define	STR_ARR_LEN	5
2438fea755aSjm 
2448fea755aSjm static int
new_dev_node(dev_info_t * new_node,void * arg,uint_t flags)2458fea755aSjm new_dev_node(dev_info_t *new_node, void *arg, uint_t flags)
2468fea755aSjm {
2478fea755aSjm 	_NOTE(ARGUNUSED(flags))
2488fea755aSjm 
2498fea755aSjm 	cb_arg_t	*cba;
2508fea755aSjm 	char		*devnm, *devtype;
2518fea755aSjm 	char		*compat;
2528fea755aSjm 	uint64_t	devid;
2538fea755aSjm 	int		len = 0;
2548fea755aSjm 	char		*curr;
2558fea755aSjm 	int		i = 0;
2568fea755aSjm 	char		*str_arr[STR_ARR_LEN];
2578fea755aSjm 
2588fea755aSjm 	cba = (cb_arg_t *)arg;
2598fea755aSjm 
2608fea755aSjm 	/*
2618fea755aSjm 	 * Add 'name' property
2628fea755aSjm 	 */
2638fea755aSjm 	if (md_get_prop_str(cba->mdp, cba->node, "name", &devnm)) {
2648fea755aSjm 		DR_DBG_IO("%s: failed to read 'name' prop from MD\n", __func__);
2658fea755aSjm 		return (DDI_WALK_ERROR);
2668fea755aSjm 	}
2678fea755aSjm 	DR_DBG_IO("%s: device name is %s\n", __func__, devnm);
2688fea755aSjm 
2698fea755aSjm 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
2708fea755aSjm 	    "name", devnm) != DDI_SUCCESS) {
2718fea755aSjm 		DR_DBG_IO("%s: failed to create 'name' prop\n", __func__);
2728fea755aSjm 		return (DDI_WALK_ERROR);
2738fea755aSjm 	}
2748fea755aSjm 
2758fea755aSjm 	/*
2768fea755aSjm 	 * Add 'compatible' property
2778fea755aSjm 	 */
2788fea755aSjm 	if (md_get_prop_data(cba->mdp, cba->node, "compatible",
2798fea755aSjm 	    (uint8_t **)&compat, &len)) {
2808fea755aSjm 		DR_DBG_IO("%s: failed to read "
2818fea755aSjm 		    "'compatible' prop from MD\n", __func__);
2828fea755aSjm 		return (DDI_WALK_ERROR);
2838fea755aSjm 	}
2848fea755aSjm 
2858fea755aSjm 	/* parse the MD string array */
2868fea755aSjm 	curr = compat;
2878fea755aSjm 	while (curr < (compat + len)) {
2888fea755aSjm 
2898fea755aSjm 		DR_DBG_IO("%s: adding '%s' to "
2908fea755aSjm 		    "'compatible' prop\n", __func__, curr);
2918fea755aSjm 
2928fea755aSjm 		str_arr[i++] = curr;
2938fea755aSjm 		curr += strlen(curr) + 1;
2948fea755aSjm 
2958fea755aSjm 		if (i == STR_ARR_LEN) {
2968fea755aSjm 			DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN);
2978fea755aSjm 			break;
2988fea755aSjm 		}
2998fea755aSjm 	}
3008fea755aSjm 
3018fea755aSjm 
3028fea755aSjm 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node,
3038fea755aSjm 	    "compatible", str_arr, i) != DDI_SUCCESS) {
3048fea755aSjm 		DR_DBG_IO("%s: cannot create 'compatible' prop\n", __func__);
3058fea755aSjm 		return (DDI_WALK_ERROR);
3068fea755aSjm 	}
3078fea755aSjm 
3088fea755aSjm 	/*
3098fea755aSjm 	 * Add 'device_type' property
3108fea755aSjm 	 */
3118fea755aSjm 	if (md_get_prop_str(cba->mdp, cba->node, "device-type", &devtype)) {
3128fea755aSjm 		DR_DBG_IO("%s: failed to read "
3138fea755aSjm 		    "'device-type' prop from MD\n", __func__);
3148fea755aSjm 		return (DDI_WALK_ERROR);
3158fea755aSjm 	}
3168fea755aSjm 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
3178fea755aSjm 	    "device_type", devtype) != DDI_SUCCESS) {
3188fea755aSjm 		DR_DBG_IO("%s: failed to create "
3198fea755aSjm 		    "'device-type' prop\n", __func__);
3208fea755aSjm 		return (DDI_WALK_ERROR);
3218fea755aSjm 	}
3228fea755aSjm 
3238fea755aSjm 	DR_DBG_IO("%s: device type is %s\n", __func__, devtype);
3248fea755aSjm 
3258fea755aSjm 	/*
3268fea755aSjm 	 * Add 'reg' (cfg-handle) property
3278fea755aSjm 	 */
3288fea755aSjm 	if (md_get_prop_val(cba->mdp, cba->node, "cfg-handle", &devid)) {
3298fea755aSjm 		DR_DBG_IO("%s: failed to read "
3308fea755aSjm 		    "'cfg-handle' prop from MD\n", __func__);
3318fea755aSjm 		return (DDI_WALK_ERROR);
3328fea755aSjm 	}
3338fea755aSjm 
3348fea755aSjm 	DR_DBG_IO("%s: new device is %s@%ld\n", __func__, devnm, devid);
3358fea755aSjm 
3368fea755aSjm 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node, "reg", devid)
3378fea755aSjm 	    != DDI_SUCCESS) {
3388fea755aSjm 		DR_DBG_IO("%s: failed to create 'reg' prop\n", __func__);
3398fea755aSjm 		return (DDI_WALK_ERROR);
3408fea755aSjm 	}
3418fea755aSjm 
3428fea755aSjm 	/* if vnet/vswitch, probe and add mac-address and mtu properties */
3438fea755aSjm 	if (strcmp(devnm, "vsw") == 0 || strcmp(devnm, "network") == 0) {
3448fea755aSjm 
3458fea755aSjm 		int i, j;
3468fea755aSjm 		uint64_t mtu, macaddr;
3478fea755aSjm 		uchar_t maddr_arr[ETHERADDRL];
3488fea755aSjm 
3498fea755aSjm 		if (md_get_prop_val(cba->mdp, cba->node, "local-mac-address",
3508fea755aSjm 		    &macaddr)) {
3518fea755aSjm 			DR_DBG_IO("%s: failed to read "
3528fea755aSjm 			    "'local-mac-address' prop from MD\n", __func__);
3538fea755aSjm 			return (DDI_WALK_ERROR);
3548fea755aSjm 		}
3558fea755aSjm 
3568fea755aSjm 		for (i = 0, j = (ETHERADDRL - 1); i < ETHERADDRL; i++, j--)
3578fea755aSjm 			maddr_arr[j] = (macaddr >> (i * 8)) & 0xff;
3588fea755aSjm 
3598fea755aSjm 		if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, new_node,
3608fea755aSjm 		    "local-mac-address", maddr_arr, ETHERADDRL)
3618fea755aSjm 		    != DDI_SUCCESS) {
3628fea755aSjm 			DR_DBG_IO("%s: failed to create "
3638fea755aSjm 			    "'local-mac-address' prop\n", __func__);
3648fea755aSjm 			return (DDI_WALK_ERROR);
3658fea755aSjm 		}
3668fea755aSjm 
3678fea755aSjm 		if (md_get_prop_val(cba->mdp, cba->node, "mtu", &mtu)) {
3688fea755aSjm 			DR_DBG_IO("%s: failed to read "
3698fea755aSjm 			    "'mtu' prop from MD\n", __func__);
3708fea755aSjm 			return (DDI_WALK_ERROR);
3718fea755aSjm 		}
3728fea755aSjm 
3738fea755aSjm 		if (ndi_prop_update_int64(DDI_DEV_T_NONE, new_node, "mtu",
3748fea755aSjm 		    mtu) != DDI_SUCCESS) {
3758fea755aSjm 			DR_DBG_IO("%s: failed to "
3768fea755aSjm 			    "create 'mtu' prop\n", __func__);
3778fea755aSjm 			return (DDI_WALK_ERROR);
3788fea755aSjm 		}
3798fea755aSjm 
3808fea755aSjm 		DR_DBG_IO("%s: Added properties for %s@%ld, "
3818fea755aSjm 		    "mac=%ld, mtu=%ld\n", __func__, devnm, devid, macaddr, mtu);
3828fea755aSjm 	}
3838fea755aSjm 
3848fea755aSjm 	cba->dip = new_node;
3858fea755aSjm 
3868fea755aSjm 	return (DDI_WALK_TERMINATE);
3878fea755aSjm }
3888fea755aSjm 
3898fea755aSjm /*
3908fea755aSjm  * Find the parent node of the argument virtual device node in
3918fea755aSjm  * the MD.  For virtual devices, the parent is always
3928fea755aSjm  * "channel-devices", so scan the MD using the "back" arcs
3938fea755aSjm  * looking for a node with that name.
3948fea755aSjm  */
3958fea755aSjm static mde_cookie_t
dr_vio_find_parent_md(md_t * mdp,mde_cookie_t node)3968fea755aSjm dr_vio_find_parent_md(md_t *mdp, mde_cookie_t node)
3978fea755aSjm {
3988fea755aSjm 	int		max_nodes;
3998fea755aSjm 	int		num_nodes;
4008fea755aSjm 	int		listsz;
4018fea755aSjm 	mde_cookie_t    *listp;
4028fea755aSjm 	mde_cookie_t	pnode = MDE_INVAL_ELEM_COOKIE;
4038fea755aSjm 
4048fea755aSjm 	max_nodes = md_node_count(mdp);
4058fea755aSjm 	listsz = max_nodes * sizeof (mde_cookie_t);
4068fea755aSjm 	listp = kmem_zalloc(listsz, KM_SLEEP);
407*99c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %d\n",
408*99c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)listp, listsz);
4098fea755aSjm 
4108fea755aSjm 	num_nodes = md_scan_dag(mdp, node,
4118fea755aSjm 	    md_find_name(mdp, "channel-devices"),
4128fea755aSjm 	    md_find_name(mdp, "back"), listp);
4138fea755aSjm 
4148fea755aSjm 	ASSERT(num_nodes == 1);
4158fea755aSjm 
4168fea755aSjm 	if (num_nodes == 1)
4178fea755aSjm 		pnode = listp[0];
4188fea755aSjm 
419*99c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: free addr %p size %d\n",
420*99c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)listp, listsz);
4218fea755aSjm 	kmem_free(listp, listsz);
4228fea755aSjm 
4238fea755aSjm 	return (pnode);
4248fea755aSjm }
4258fea755aSjm 
4268fea755aSjm static int
dr_io_configure(dr_vio_req_t * req,dr_vio_res_t * res)4278fea755aSjm dr_io_configure(dr_vio_req_t *req, dr_vio_res_t *res)
4288fea755aSjm {
4298fea755aSjm 	int		rv = ENXIO;
4308fea755aSjm 	int		listsz;
4318fea755aSjm 	int		nnodes;
4328fea755aSjm 	uint64_t	devid = req->dev_id;
4338fea755aSjm 	uint64_t	pdevid;
4348fea755aSjm 	char		*name = req->name;
4358fea755aSjm 	char		*pname;
4368fea755aSjm 	md_t		*mdp = NULL;
4378fea755aSjm 	mde_cookie_t	*listp = NULL;
4388fea755aSjm 	mde_cookie_t	node;
4398fea755aSjm 	mde_cookie_t	pnode;
4408fea755aSjm 	dev_info_t	*pdip = NULL;
4418fea755aSjm 	dev_info_t	*dip;
4428fea755aSjm 	devi_branch_t	br;
4438fea755aSjm 	cb_arg_t	cba;
4448fea755aSjm 	int		drctl_cmd;
4458fea755aSjm 	int		drctl_flags = 0;
4468fea755aSjm 	drctl_rsrc_t	*drctl_req;
4478fea755aSjm 	size_t		drctl_req_len;
448*99c7e855SJames Marks - Sun Microsystems 	drctl_rsrc_t	*drctl_rsrc = NULL;
4498fea755aSjm 	drctl_cookie_t	drctl_res_ck;
4508fea755aSjm 	char		*p;
451*99c7e855SJames Marks - Sun Microsystems 	drctl_resp_t	*drctl_resp;
452*99c7e855SJames Marks - Sun Microsystems 	size_t		drctl_resp_len = 0;
4538fea755aSjm 
4548fea755aSjm 	res->result = DR_VIO_RES_FAILURE;
4558fea755aSjm 
4568fea755aSjm 	if ((dip = dr_io_find_node(name, devid)) != NULL) {
4578fea755aSjm 		DR_DBG_IO("%s: %s@%ld already configured\n",
4588fea755aSjm 		    __func__, name, devid);
4598fea755aSjm 
4608fea755aSjm 		/* Return success if resources is already there. */
4618fea755aSjm 		res->result = DR_VIO_RES_OK;
4628fea755aSjm 		res->status = DR_VIO_STAT_CONFIGURED;
4638fea755aSjm 		e_ddi_branch_rele(dip);
4648fea755aSjm 		return (0);
4658fea755aSjm 	}
4668fea755aSjm 
4678fea755aSjm 	/* Assume we fail to find the node to be added. */
4688fea755aSjm 	res->status = DR_VIO_STAT_NOT_PRESENT;
4698fea755aSjm 
4708fea755aSjm 	if ((mdp = md_get_handle()) == NULL) {
4718fea755aSjm 		DR_DBG_IO("%s: unable to initialize MD\n", __func__);
4728fea755aSjm 		return (ENXIO);
4738fea755aSjm 	}
4748fea755aSjm 
4758fea755aSjm 	nnodes = md_node_count(mdp);
4768fea755aSjm 	ASSERT(nnodes > 0);
4778fea755aSjm 
4788fea755aSjm 	listsz = nnodes * sizeof (mde_cookie_t);
4798fea755aSjm 	listp = kmem_zalloc(listsz, KM_SLEEP);
480*99c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %d\n",
481*99c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)listp, listsz);
4828fea755aSjm 
4838fea755aSjm 	/*
4848fea755aSjm 	 * Get the MD device node.
4858fea755aSjm 	 */
4868fea755aSjm 	node = dr_io_find_node_md(mdp, name, devid, listp);
4878fea755aSjm 
4888fea755aSjm 	if (node == MDE_INVAL_ELEM_COOKIE) {
4898fea755aSjm 		DR_DBG_IO("%s: scan for %s name node failed\n", __func__, name);
4908fea755aSjm 		res->result = DR_VIO_RES_NOT_IN_MD;
4918fea755aSjm 		goto done;
4928fea755aSjm 	}
4938fea755aSjm 
4948fea755aSjm 	/*
4958fea755aSjm 	 * Get the MD parent node.
4968fea755aSjm 	 */
4978fea755aSjm 	pnode = dr_vio_find_parent_md(mdp, node);
4988fea755aSjm 	if (pnode == MDE_INVAL_ELEM_COOKIE) {
4998fea755aSjm 		DR_DBG_IO("%s: failed to find MD parent of %lx\n",
5008fea755aSjm 		    __func__, pnode);
5018fea755aSjm 		goto done;
5028fea755aSjm 	}
5038fea755aSjm 
5048fea755aSjm 	if (md_get_prop_str(mdp, pnode, "name", &pname)) {
5058fea755aSjm 		DR_DBG_IO("%s: failed to read "
5068fea755aSjm 		    "'name' for pnode %lx from MD\n", __func__, pnode);
5078fea755aSjm 		goto done;
5088fea755aSjm 	}
5098fea755aSjm 
5108fea755aSjm 	if (md_get_prop_val(mdp, pnode, "cfg-handle", &pdevid)) {
5118fea755aSjm 		DR_DBG_IO("%s: failed to read 'cfg-handle' "
5128fea755aSjm 		    "for pnode '%s' from MD\n", __func__, pname);
5138fea755aSjm 		goto done;
5148fea755aSjm 	}
5158fea755aSjm 
5168fea755aSjm 	DR_DBG_IO("%s: parent device %s@%lx\n", __func__, pname, pdevid);
5178fea755aSjm 
5188fea755aSjm 	/*
5198fea755aSjm 	 * Get the devinfo parent node.
5208fea755aSjm 	 */
5218fea755aSjm 	if ((pdip = dr_io_find_node(pname, pdevid)) == NULL) {
5228fea755aSjm 		DR_DBG_IO("%s: parent device %s@%ld not found\n",
5238fea755aSjm 		    __func__, pname, pdevid);
5248fea755aSjm 		goto done;
5258fea755aSjm 	}
5268fea755aSjm 
5278fea755aSjm 	drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN;
5288fea755aSjm 	drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
529*99c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
530*99c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)drctl_req, drctl_req_len);
5318fea755aSjm 	drctl_req->status = DRCTL_STATUS_INIT;
5328fea755aSjm 
5338fea755aSjm 	drctl_cmd = DRCTL_IO_CONFIG_REQUEST;
5348fea755aSjm 
5358fea755aSjm 	/*
5368fea755aSjm 	 * Construct the path of the device as it will be if it
5378fea755aSjm 	 * is successfully added.
5388fea755aSjm 	 */
5398fea755aSjm 	p = drctl_req->res_dev_path;
5408fea755aSjm 	(void) sprintf(p, "/devices");
5418fea755aSjm 	(void) ddi_pathname(pdip, p + strlen(p));
5428fea755aSjm 	(void) sprintf(p + strlen(p), "/%s@%ld", name, devid);
5438fea755aSjm 	DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path);
5448fea755aSjm 
545*99c7e855SJames Marks - Sun Microsystems 	rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
546*99c7e855SJames Marks - Sun Microsystems 	    1, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
5478fea755aSjm 
548*99c7e855SJames Marks - Sun Microsystems 	ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
549*99c7e855SJames Marks - Sun Microsystems 
550*99c7e855SJames Marks - Sun Microsystems 	drctl_rsrc = drctl_resp->resp_resources;
551*99c7e855SJames Marks - Sun Microsystems 
552*99c7e855SJames Marks - Sun Microsystems 	if (rv != 0) {
5538fea755aSjm 		DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv);
554*99c7e855SJames Marks - Sun Microsystems 
555*99c7e855SJames Marks - Sun Microsystems 		ASSERT(drctl_resp->resp_type == DRCTL_RESP_ERR);
556*99c7e855SJames Marks - Sun Microsystems 
557*99c7e855SJames Marks - Sun Microsystems 		(void) strlcpy(res->reason,
558*99c7e855SJames Marks - Sun Microsystems 		    drctl_resp->resp_err_msg, DR_VIO_MAXREASONLEN);
559*99c7e855SJames Marks - Sun Microsystems 
560*99c7e855SJames Marks - Sun Microsystems 		DR_DBG_IO("%s: %s\n", __func__, res->reason);
561*99c7e855SJames Marks - Sun Microsystems 
5628fea755aSjm 		goto done;
5638fea755aSjm 
564*99c7e855SJames Marks - Sun Microsystems 	}
565*99c7e855SJames Marks - Sun Microsystems 
566*99c7e855SJames Marks - Sun Microsystems 	ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
567*99c7e855SJames Marks - Sun Microsystems 
568*99c7e855SJames Marks - Sun Microsystems 	if (drctl_rsrc->status == DRCTL_STATUS_DENY) {
569*99c7e855SJames Marks - Sun Microsystems 
5708fea755aSjm 		res->result = DR_VIO_RES_BLOCKED;
5718fea755aSjm 
5728fea755aSjm 		DR_DBG_IO("%s: drctl_config_init denied\n", __func__);
573*99c7e855SJames Marks - Sun Microsystems 		p = (char *)drctl_rsrc + drctl_rsrc->offset;
5748fea755aSjm 
575*99c7e855SJames Marks - Sun Microsystems 		(void) strlcpy(res->reason, p, DR_VIO_MAXREASONLEN);
5768fea755aSjm 
5778fea755aSjm 		DR_DBG_IO("%s: %s\n", __func__, res->reason);
5788fea755aSjm 
5798fea755aSjm 		drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE;
5808fea755aSjm 
5818fea755aSjm 		rv = EPERM;
5828fea755aSjm 	} else {
5838fea755aSjm 		cba.mdp = mdp;
5848fea755aSjm 		cba.node = node;
5858fea755aSjm 
5868fea755aSjm 		br.arg = (void *)&cba;
5878fea755aSjm 		br.type = DEVI_BRANCH_SID;
5888fea755aSjm 		br.create.sid_branch_create = new_dev_node;
5898fea755aSjm 		br.devi_branch_callback = NULL;
5908fea755aSjm 
5918fea755aSjm 		rv = e_ddi_branch_create(pdip,
5928fea755aSjm 		    &br, NULL, DEVI_BRANCH_CONFIGURE);
5938fea755aSjm 
5948fea755aSjm 		drctl_req->status = (rv == 0) ?
5958fea755aSjm 		    DRCTL_STATUS_CONFIG_SUCCESS : DRCTL_STATUS_CONFIG_FAILURE;
5968fea755aSjm 
5978fea755aSjm 		DR_DBG_IO("%s: %s@%ld = %d\n", __func__, name, devid, rv);
5988fea755aSjm 	}
5998fea755aSjm 
6008fea755aSjm 	if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0)
6018fea755aSjm 		DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv);
6028fea755aSjm 
6038fea755aSjm done:
604*99c7e855SJames Marks - Sun Microsystems 	if (listp) {
605*99c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %d\n",
606*99c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)listp, listsz);
6078fea755aSjm 		kmem_free(listp, listsz);
608*99c7e855SJames Marks - Sun Microsystems 	}
6098fea755aSjm 
6108fea755aSjm 	if (mdp)
6118fea755aSjm 		(void) md_fini_handle(mdp);
6128fea755aSjm 
6138fea755aSjm 	if (pdip)
6148fea755aSjm 		e_ddi_branch_rele(pdip);
6158fea755aSjm 
616*99c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: free addr %p size %ld\n",
617*99c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)drctl_req, drctl_req_len);
6188fea755aSjm 	kmem_free(drctl_req, drctl_req_len);
619*99c7e855SJames Marks - Sun Microsystems 
620*99c7e855SJames Marks - Sun Microsystems 	if (drctl_resp) {
621*99c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %ld\n",
622*99c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)drctl_resp, drctl_resp_len);
623*99c7e855SJames Marks - Sun Microsystems 		kmem_free(drctl_resp, drctl_resp_len);
624*99c7e855SJames Marks - Sun Microsystems 	}
6258fea755aSjm 
6268fea755aSjm 	if (rv == 0) {
6278fea755aSjm 		res->result = DR_VIO_RES_OK;
6288fea755aSjm 		res->status = DR_VIO_STAT_CONFIGURED;
6298fea755aSjm 
6308fea755aSjm 		/* notify interested parties about the operation */
6318fea755aSjm 		dr_generate_event(DR_TYPE_VIO, SE_HINT_INSERT);
6328fea755aSjm 	} else {
6338fea755aSjm 		res->status = DR_VIO_STAT_UNCONFIGURED;
6348fea755aSjm 	}
6358fea755aSjm 
6368fea755aSjm 	return (rv);
6378fea755aSjm }
6388fea755aSjm 
6398fea755aSjm static int
dr_io_unconfigure(dr_vio_req_t * req,dr_vio_res_t * res)6408fea755aSjm dr_io_unconfigure(dr_vio_req_t *req, dr_vio_res_t *res)
6418fea755aSjm {
6428fea755aSjm 	int		rv;
6438fea755aSjm 	char		*name = req->name;
6448fea755aSjm 	char		*p;
6458fea755aSjm 	uint64_t	devid = req->dev_id;
6468fea755aSjm 	dev_info_t	*dip;
6478fea755aSjm 	dev_info_t	*fdip = NULL;
6488fea755aSjm 	int		drctl_cmd;
6498fea755aSjm 	int		drctl_flags = 0;
6508fea755aSjm 	drctl_rsrc_t	*drctl_req;
6518fea755aSjm 	size_t		drctl_req_len;
652*99c7e855SJames Marks - Sun Microsystems 	drctl_rsrc_t	*drctl_rsrc = NULL;
6538fea755aSjm 	drctl_cookie_t	drctl_res_ck;
654*99c7e855SJames Marks - Sun Microsystems 	drctl_resp_t	*drctl_resp;
655*99c7e855SJames Marks - Sun Microsystems 	size_t		drctl_resp_len;
6568fea755aSjm 
6578fea755aSjm 	if ((dip = dr_io_find_node(name, devid)) == NULL) {
6588fea755aSjm 		DR_DBG_IO("%s: %s@%ld already unconfigured\n",
6598fea755aSjm 		    __func__, name, devid);
6608fea755aSjm 		res->result = DR_VIO_RES_OK;
6618fea755aSjm 		res->status = DR_VIO_STAT_NOT_PRESENT;
6628fea755aSjm 		return (0);
6638fea755aSjm 	}
6648fea755aSjm 
6658fea755aSjm 	res->result = DR_VIO_RES_FAILURE;
6668fea755aSjm 
6678fea755aSjm 	ASSERT(e_ddi_branch_held(dip));
6688fea755aSjm 
6698fea755aSjm 	/* Assume we fail to unconfigure the resource. */
6708fea755aSjm 	res->status = DR_VIO_STAT_CONFIGURED;
6718fea755aSjm 
6728fea755aSjm 	drctl_req_len = sizeof (drctl_rsrc_t) + MAXPATHLEN;
6738fea755aSjm 	drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
674*99c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
675*99c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)drctl_req, drctl_req_len);
6768fea755aSjm 	drctl_req->status = DRCTL_STATUS_INIT;
6778fea755aSjm 
6788fea755aSjm 	drctl_cmd = DRCTL_IO_UNCONFIG_REQUEST;
6798fea755aSjm 
6808fea755aSjm 	if (req->msg_type == DR_VIO_FORCE_UNCONFIG)
6818fea755aSjm 		drctl_flags = DRCTL_FLAG_FORCE;
6828fea755aSjm 
6838fea755aSjm 	p = drctl_req->res_dev_path;
6848fea755aSjm 	(void) sprintf(p, "/devices");
6858fea755aSjm 	(void) ddi_pathname(dip, p + strlen(p));
6868fea755aSjm 	DR_DBG_IO("%s: devpath=%s\n", __func__, drctl_req->res_dev_path);
6878fea755aSjm 
688*99c7e855SJames Marks - Sun Microsystems 	rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
689*99c7e855SJames Marks - Sun Microsystems 	    1, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
690*99c7e855SJames Marks - Sun Microsystems 
691*99c7e855SJames Marks - Sun Microsystems 	ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
692*99c7e855SJames Marks - Sun Microsystems 
693*99c7e855SJames Marks - Sun Microsystems 	drctl_rsrc = drctl_resp->resp_resources;
694*99c7e855SJames Marks - Sun Microsystems 
695*99c7e855SJames Marks - Sun Microsystems 	if (rv != 0) {
6968fea755aSjm 
6978fea755aSjm 		DR_DBG_IO("%s: drctl_config_init failed: %d\n", __func__, rv);
698*99c7e855SJames Marks - Sun Microsystems 
699*99c7e855SJames Marks - Sun Microsystems 		ASSERT(drctl_resp->resp_type == DRCTL_RESP_ERR);
700*99c7e855SJames Marks - Sun Microsystems 
701*99c7e855SJames Marks - Sun Microsystems 		(void) strlcpy(res->reason,
702*99c7e855SJames Marks - Sun Microsystems 		    drctl_resp->resp_err_msg, DR_VIO_MAXREASONLEN);
703*99c7e855SJames Marks - Sun Microsystems 
704*99c7e855SJames Marks - Sun Microsystems 		DR_DBG_IO("%s: %s\n", __func__, res->reason);
705*99c7e855SJames Marks - Sun Microsystems 
7068fea755aSjm 		goto done;
707*99c7e855SJames Marks - Sun Microsystems 	}
7088fea755aSjm 
709*99c7e855SJames Marks - Sun Microsystems 	if (drctl_rsrc->status == DRCTL_STATUS_DENY) {
7108fea755aSjm 		res->result = DR_VIO_RES_BLOCKED;
7118fea755aSjm 
7128fea755aSjm 		DR_DBG_IO("%s: drctl_config_init denied\n", __func__);
713*99c7e855SJames Marks - Sun Microsystems 		p = (char *)drctl_rsrc + drctl_rsrc->offset;
7148fea755aSjm 
715*99c7e855SJames Marks - Sun Microsystems 		(void) strlcpy(res->reason, p, DR_VIO_MAXREASONLEN);
7168fea755aSjm 
7178fea755aSjm 		DR_DBG_IO("%s: %s\n", __func__, res->reason);
7188fea755aSjm 
7198fea755aSjm 		drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE;
7208fea755aSjm 
7218fea755aSjm 		rv = EPERM;
7228fea755aSjm 	} else if (rv = e_ddi_branch_destroy(dip, &fdip, 0)) {
7238fea755aSjm 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
7248fea755aSjm 
725*99c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: alloc addr %p size %d\n",
726*99c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)path, MAXPATHLEN);
7278fea755aSjm 		/*
7288fea755aSjm 		 * If non-NULL, fdip is held and must be released.
7298fea755aSjm 		 */
7308fea755aSjm 		if (fdip != NULL) {
7318fea755aSjm 			(void) ddi_pathname(fdip, path);
7328fea755aSjm 			ddi_release_devi(fdip);
7338fea755aSjm 		} else {
7348fea755aSjm 			(void) ddi_pathname(dip, path);
7358fea755aSjm 		}
7368fea755aSjm 
7378fea755aSjm 		DR_DBG_IO("%s: node removal failed: %s (%p)",
7388fea755aSjm 		    __func__, path, (fdip) ? (void *)fdip : (void *)dip);
7398fea755aSjm 
7408fea755aSjm 		drctl_req->status = DRCTL_STATUS_CONFIG_FAILURE;
7418fea755aSjm 
742*99c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %d\n",
743*99c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)path, MAXPATHLEN);
7448fea755aSjm 		kmem_free(path, MAXPATHLEN);
7458fea755aSjm 	} else {
7468fea755aSjm 		drctl_req->status = DRCTL_STATUS_CONFIG_SUCCESS;
7478fea755aSjm 	}
7488fea755aSjm 
7498fea755aSjm 	if (drctl_config_fini(&drctl_res_ck, drctl_req, 1) != 0)
7508fea755aSjm 		DR_DBG_IO("%s: drctl_config_fini returned: %d\n", __func__, rv);
7518fea755aSjm 
7528fea755aSjm 	DR_DBG_IO("%s: (%s@%ld) = %d\n", __func__, name, devid, rv);
7538fea755aSjm 
7548fea755aSjm 	if (rv == 0) {
7558fea755aSjm 		res->result = DR_VIO_RES_OK;
7568fea755aSjm 		res->status = DR_VIO_STAT_UNCONFIGURED;
7578fea755aSjm 
7588fea755aSjm 		/* Notify interested parties about the operation. */
7598fea755aSjm 		dr_generate_event(DR_TYPE_VIO, SE_HINT_REMOVE);
7608fea755aSjm 	}
7618fea755aSjm done:
762*99c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: free addr %p size %ld\n",
763*99c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)drctl_req, drctl_req_len);
7648fea755aSjm 	kmem_free(drctl_req, drctl_req_len);
7658fea755aSjm 
766*99c7e855SJames Marks - Sun Microsystems 	if (drctl_resp) {
767*99c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %ld\n",
768*99c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)drctl_resp, drctl_resp_len);
769*99c7e855SJames Marks - Sun Microsystems 		kmem_free(drctl_resp, drctl_resp_len);
770*99c7e855SJames Marks - Sun Microsystems 	}
7718fea755aSjm 
7728fea755aSjm 	return (rv);
7738fea755aSjm }
7748fea755aSjm 
7758fea755aSjm static void
dr_vio_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)7768fea755aSjm dr_vio_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
7778fea755aSjm {
7788fea755aSjm 	_NOTE(ARGUNUSED(arg))
7798fea755aSjm 
7808fea755aSjm 	size_t		res_len;
7818fea755aSjm 	dr_vio_res_t	*res;
7828fea755aSjm 	dr_vio_req_t	*req;
7838fea755aSjm 
7848fea755aSjm 	/*
7858fea755aSjm 	 * Allocate a response buffer, because we always want to
7868fea755aSjm 	 * send back a response message.
7878fea755aSjm 	 */
7888fea755aSjm 	res_len = sizeof (dr_vio_res_t) + DR_VIO_MAXREASONLEN;
7898fea755aSjm 	res = kmem_zalloc(res_len, KM_SLEEP);
790*99c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
791*99c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)res, res_len);
7928fea755aSjm 	res->result = DR_VIO_RES_FAILURE;
7938fea755aSjm 
7948fea755aSjm 	/*
7958fea755aSjm 	 * Sanity check the message
7968fea755aSjm 	 */
7978fea755aSjm 	if (buf == NULL) {
7988fea755aSjm 		DR_DBG_IO("empty message: expected at least %ld bytes\n",
7998fea755aSjm 		    sizeof (dr_vio_req_t));
8008fea755aSjm 		goto done;
8018fea755aSjm 	}
8028fea755aSjm 	if (buflen < sizeof (dr_vio_req_t)) {
8038fea755aSjm 		DR_DBG_IO("incoming message short: expected at least %ld "
8048fea755aSjm 		    "bytes, received %ld\n", sizeof (dr_vio_req_t), buflen);
8058fea755aSjm 		goto done;
8068fea755aSjm 	}
8078fea755aSjm 
8088fea755aSjm 	DR_DBG_TRANS("incoming request:\n");
8098fea755aSjm 	DR_DBG_DUMP_MSG(buf, buflen);
8108fea755aSjm 
8118fea755aSjm 	req = buf;
8128fea755aSjm 	switch (req->msg_type) {
8138fea755aSjm 	case DR_VIO_CONFIGURE:
8148fea755aSjm 		(void) dr_io_configure(req, res);
8158fea755aSjm 		break;
8168fea755aSjm 	case DR_VIO_FORCE_UNCONFIG:
8178fea755aSjm 	case DR_VIO_UNCONFIGURE:
8188fea755aSjm 		(void) dr_io_unconfigure(req, res);
8198fea755aSjm 		break;
8208fea755aSjm 	default:
8218fea755aSjm 		cmn_err(CE_NOTE, "bad msg_type %d\n", req->msg_type);
8228fea755aSjm 		break;
8238fea755aSjm 	}
8248fea755aSjm done:
8258fea755aSjm 	res->req_num = (req) ? req->req_num : 0;
8268fea755aSjm 
8278fea755aSjm 	DR_DBG_TRANS("outgoing response:\n");
8288fea755aSjm 	DR_DBG_DUMP_MSG(res, res_len);
8298fea755aSjm 
8308fea755aSjm 	/* send back the response */
8318fea755aSjm 	if (ds_cap_send(ds_vio_handle, res, res_len) != 0)
8328fea755aSjm 		DR_DBG_IO("ds_send failed\n");
8338fea755aSjm 
834*99c7e855SJames Marks - Sun Microsystems 	if (res) {
835*99c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %ld\n",
836*99c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)res, res_len);
8378fea755aSjm 		kmem_free(res, res_len);
838*99c7e855SJames Marks - Sun Microsystems 	}
8398fea755aSjm }
8408fea755aSjm 
8418fea755aSjm static void
dr_vio_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)8428fea755aSjm dr_vio_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
8438fea755aSjm {
8448fea755aSjm 	DR_DBG_IO("vio_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n",
8458fea755aSjm 	    arg, ver->major, ver->minor, hdl);
8468fea755aSjm 
8478fea755aSjm 	ds_vio_handle = hdl;
8488fea755aSjm }
8498fea755aSjm 
8508fea755aSjm static void
dr_vio_unreg_handler(ds_cb_arg_t arg)8518fea755aSjm dr_vio_unreg_handler(ds_cb_arg_t arg)
8528fea755aSjm {
8538fea755aSjm 	DR_DBG_IO("vio_unreg_handler: arg=0x%p\n", arg);
8548fea755aSjm 
8558fea755aSjm 	ds_vio_handle = DS_INVALID_HDL;
8568fea755aSjm }
8578fea755aSjm 
8588fea755aSjm static int
dr_io_init(void)8598fea755aSjm dr_io_init(void)
8608fea755aSjm {
8618fea755aSjm 	int	rv;
8628fea755aSjm 
8638fea755aSjm 	if ((rv = ds_cap_init(&dr_vio_cap, &dr_vio_ops)) != 0) {
8648fea755aSjm 		cmn_err(CE_NOTE, "ds_cap_init vio failed: %d", rv);
8658fea755aSjm 		return (-1);
8668fea755aSjm 	}
8678fea755aSjm 
8688fea755aSjm 	return (0);
8698fea755aSjm }
8708fea755aSjm 
8718fea755aSjm static int
dr_io_fini(void)8728fea755aSjm dr_io_fini(void)
8738fea755aSjm {
8748fea755aSjm 	int	rv;
8758fea755aSjm 
8768fea755aSjm 	if ((rv = ds_cap_fini(&dr_vio_cap)) != 0) {
8778fea755aSjm 		cmn_err(CE_NOTE, "ds_cap_fini vio failed: %d", rv);
8788fea755aSjm 		return (-1);
8798fea755aSjm 	}
8808fea755aSjm 
8818fea755aSjm 	return (0);
8828fea755aSjm }
8838fea755aSjm 
8848fea755aSjm int
_init(void)8858fea755aSjm _init(void)
8868fea755aSjm {
8878fea755aSjm 	int	status;
8888fea755aSjm 
8898fea755aSjm 	/* check that IO DR is enabled */
8908fea755aSjm 	if (dr_is_disabled(DR_TYPE_VIO)) {
8918fea755aSjm 		cmn_err(CE_CONT, "!VIO DR is disabled\n");
8928fea755aSjm 		return (-1);
8938fea755aSjm 	}
8948fea755aSjm 
8958fea755aSjm 	if ((status = dr_io_init()) != 0) {
8968fea755aSjm 		cmn_err(CE_NOTE, "VIO DR initialization failed");
8978fea755aSjm 		return (status);
8988fea755aSjm 	}
8998fea755aSjm 
9008fea755aSjm 	if ((status = mod_install(&modlinkage)) != 0) {
9018fea755aSjm 		(void) dr_io_fini();
9028fea755aSjm 	}
9038fea755aSjm 
9048fea755aSjm 	return (status);
9058fea755aSjm }
9068fea755aSjm 
9078fea755aSjm int
_info(struct modinfo * modinfop)9088fea755aSjm _info(struct modinfo *modinfop)
9098fea755aSjm {
9108fea755aSjm 	return (mod_info(&modlinkage, modinfop));
9118fea755aSjm }
9128fea755aSjm 
9138fea755aSjm int dr_io_allow_unload = 0;
9148fea755aSjm 
9158fea755aSjm int
_fini(void)9168fea755aSjm _fini(void)
9178fea755aSjm {
9188fea755aSjm 	int	status;
9198fea755aSjm 
9208fea755aSjm 	if (dr_io_allow_unload == 0)
9218fea755aSjm 		return (EBUSY);
9228fea755aSjm 
9238fea755aSjm 	if ((status = mod_remove(&modlinkage)) == 0) {
9248fea755aSjm 		(void) dr_io_fini();
9258fea755aSjm 	}
9268fea755aSjm 
9278fea755aSjm 	return (status);
9288fea755aSjm }
929