Home | History | Annotate | Download | only in os
      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 (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Xen virtual device driver interfaces
     29  */
     30 
     31 /*
     32  * todo:
     33  * + name space clean up:
     34  *	xvdi_* - public xen interfaces, for use by all leaf drivers
     35  *	xd_* - public xen data structures
     36  *	i_xvdi_* - implementation private functions
     37  *	xendev_* - xendev driver interfaces, both internal and in cb_ops/bus_ops
     38  * + add mdb dcmds to dump ring status
     39  * + implement xvdi_xxx to wrap xenbus_xxx read/write function
     40  * + convert (xendev_ring_t *) into xvdi_ring_handle_t
     41  */
     42 #include <sys/conf.h>
     43 #include <sys/param.h>
     44 #include <sys/kmem.h>
     45 #include <vm/seg_kmem.h>
     46 #include <sys/debug.h>
     47 #include <sys/modctl.h>
     48 #include <sys/autoconf.h>
     49 #include <sys/ddi_impldefs.h>
     50 #include <sys/ddi_subrdefs.h>
     51 #include <sys/ddi.h>
     52 #include <sys/sunddi.h>
     53 #include <sys/sunndi.h>
     54 #include <sys/sunldi.h>
     55 #include <sys/fs/dv_node.h>
     56 #include <sys/avintr.h>
     57 #include <sys/psm.h>
     58 #include <sys/spl.h>
     59 #include <sys/promif.h>
     60 #include <sys/list.h>
     61 #include <sys/bootconf.h>
     62 #include <sys/bootsvcs.h>
     63 #include <sys/bootinfo.h>
     64 #include <sys/note.h>
     65 #include <sys/sysmacros.h>
     66 #ifdef XPV_HVM_DRIVER
     67 #include <sys/xpv_support.h>
     68 #include <sys/hypervisor.h>
     69 #include <public/grant_table.h>
     70 #include <public/xen.h>
     71 #include <public/io/xenbus.h>
     72 #include <public/io/xs_wire.h>
     73 #include <public/event_channel.h>
     74 #include <public/io/xenbus.h>
     75 #else /* XPV_HVM_DRIVER */
     76 #include <sys/hypervisor.h>
     77 #include <sys/xen_mmu.h>
     78 #include <xen/sys/xenbus_impl.h>
     79 #include <sys/evtchn_impl.h>
     80 #endif /* XPV_HVM_DRIVER */
     81 #include <sys/gnttab.h>
     82 #include <xen/sys/xendev.h>
     83 #include <vm/hat_i86.h>
     84 #include <sys/scsi/generic/inquiry.h>
     85 #include <util/sscanf.h>
     86 #include <xen/public/io/xs_wire.h>
     87 
     88 
     89 #define	isdigit(ch)	((ch) >= '0' && (ch) <= '9')
     90 #define	isxdigit(ch)	(isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
     91 			((ch) >= 'A' && (ch) <= 'F'))
     92 
     93 static void xvdi_ring_init_sring(xendev_ring_t *);
     94 static void xvdi_ring_init_front_ring(xendev_ring_t *, size_t, size_t);
     95 #ifndef XPV_HVM_DRIVER
     96 static void xvdi_ring_init_back_ring(xendev_ring_t *, size_t, size_t);
     97 #endif
     98 static void xvdi_reinit_ring(dev_info_t *, grant_ref_t *, xendev_ring_t *);
     99 
    100 static int i_xvdi_add_watches(dev_info_t *);
    101 static void i_xvdi_rem_watches(dev_info_t *);
    102 
    103 static int i_xvdi_add_watch_oestate(dev_info_t *);
    104 static void i_xvdi_rem_watch_oestate(dev_info_t *);
    105 static void i_xvdi_oestate_cb(struct xenbus_device *, XenbusState);
    106 static void i_xvdi_oestate_handler(void *);
    107 
    108 static int i_xvdi_add_watch_hpstate(dev_info_t *);
    109 static void i_xvdi_rem_watch_hpstate(dev_info_t *);
    110 static void i_xvdi_hpstate_cb(struct xenbus_watch *, const char **,
    111     unsigned int);
    112 static void i_xvdi_hpstate_handler(void *);
    113 
    114 static int i_xvdi_add_watch_bepath(dev_info_t *);
    115 static void i_xvdi_rem_watch_bepath(dev_info_t *);
    116 static void i_xvdi_bepath_cb(struct xenbus_watch *, const char **,
    117     unsigned in);
    118 
    119 static void xendev_offline_device(void *);
    120 
    121 static void i_xvdi_probe_path_cb(struct xenbus_watch *, const char **,
    122     unsigned int);
    123 static void i_xvdi_probe_path_handler(void *);
    124 
    125 typedef struct oestate_evt {
    126 	dev_info_t *dip;
    127 	XenbusState state;
    128 } i_oestate_evt_t;
    129 
    130 typedef struct xd_cfg {
    131 	xendev_devclass_t devclass;
    132 	char *xsdev;
    133 	char *xs_path_fe;
    134 	char *xs_path_be;
    135 	char *node_fe;
    136 	char *node_be;
    137 	char *device_type;
    138 	int xd_ipl;
    139 	int flags;
    140 } i_xd_cfg_t;
    141 
    142 #define	XD_DOM_ZERO	0x01	/* dom0 only. */
    143 #define	XD_DOM_GUEST	0x02	/* Guest domains (i.e. non-dom0). */
    144 #define	XD_DOM_IO	0x04	/* IO domains. */
    145 
    146 #define	XD_DOM_ALL	(XD_DOM_ZERO | XD_DOM_GUEST)
    147 
    148 static i_xd_cfg_t xdci[] = {
    149 	{ XEN_CONSOLE, NULL, NULL, NULL, "xencons", NULL,
    150 	    "console", IPL_CONS, XD_DOM_ALL, },
    151 
    152 	{ XEN_VNET, "vif", "device/vif", "backend/vif", "xnf", "xnb",
    153 	    "network", IPL_VIF, XD_DOM_ALL, },
    154 
    155 	{ XEN_VBLK, "vbd", "device/vbd", "backend/vbd", "xdf", "xdb",
    156 	    "block", IPL_VBD, XD_DOM_ALL, },
    157 
    158 	{ XEN_BLKTAP, "tap", NULL, "backend/tap", NULL, "xpvtap",
    159 	    "block", IPL_VBD, XD_DOM_ALL, },
    160 
    161 	{ XEN_XENBUS, NULL, NULL, NULL, "xenbus", NULL,
    162 	    NULL, 0, XD_DOM_ALL, },
    163 
    164 	{ XEN_DOMCAPS, NULL, NULL, NULL, "domcaps", NULL,
    165 	    NULL, 0, XD_DOM_ALL, },
    166 
    167 	{ XEN_BALLOON, NULL, NULL, NULL, "balloon", NULL,
    168 	    NULL, 0, XD_DOM_ALL, },
    169 
    170 	{ XEN_EVTCHN, NULL, NULL, NULL, "evtchn", NULL,
    171 	    NULL, 0, XD_DOM_ZERO, },
    172 
    173 	{ XEN_PRIVCMD, NULL, NULL, NULL, "privcmd", NULL,
    174 	    NULL, 0, XD_DOM_ZERO, },
    175 };
    176 #define	NXDC	(sizeof (xdci) / sizeof (xdci[0]))
    177 
    178 static void i_xvdi_enum_fe(dev_info_t *, i_xd_cfg_t *);
    179 static void i_xvdi_enum_be(dev_info_t *, i_xd_cfg_t *);
    180 static void i_xvdi_enum_worker(dev_info_t *, i_xd_cfg_t *, char *);
    181 
    182 /*
    183  * Xen device channel device access and DMA attributes
    184  */
    185 static ddi_device_acc_attr_t xendev_dc_accattr = {
    186 	DDI_DEVICE_ATTR_V0, DDI_NEVERSWAP_ACC, DDI_STRICTORDER_ACC
    187 };
    188 
    189 static ddi_dma_attr_t xendev_dc_dmaattr = {
    190 	DMA_ATTR_V0,		/* version of this structure */
    191 	0,			/* lowest usable address */
    192 	0xffffffffffffffffULL,	/* highest usable address */
    193 	0x7fffffff,		/* maximum DMAable byte count */
    194 	MMU_PAGESIZE,		/* alignment in bytes */
    195 	0x7ff,			/* bitmap of burst sizes */
    196 	1,			/* minimum transfer */
    197 	0xffffffffU,		/* maximum transfer */
    198 	0xffffffffffffffffULL,	/* maximum segment length */
    199 	1,			/* maximum number of segments */
    200 	1,			/* granularity */
    201 	0,			/* flags (reserved) */
    202 };
    203 
    204 static dev_info_t *xendev_dip = NULL;
    205 
    206 #define	XVDI_DBG_STATE	0x01
    207 #define	XVDI_DBG_PROBE	0x02
    208 
    209 #ifdef DEBUG
    210 int i_xvdi_debug = 0;
    211 
    212 #define	XVDI_DPRINTF(flag, format, ...)			\
    213 {							\
    214 	if (i_xvdi_debug & (flag))			\
    215 		prom_printf((format), __VA_ARGS__);	\
    216 }
    217 #else
    218 #define	XVDI_DPRINTF(flag, format, ...)
    219 #endif /* DEBUG */
    220 
    221 static i_xd_cfg_t *
    222 i_xvdi_devclass2cfg(xendev_devclass_t devclass)
    223 {
    224 	i_xd_cfg_t *xdcp;
    225 	int i;
    226 
    227 	for (i = 0, xdcp = xdci; i < NXDC; i++, xdcp++)
    228 		if (xdcp->devclass == devclass)
    229 			return (xdcp);
    230 
    231 	return (NULL);
    232 }
    233 
    234 int
    235 xvdi_init_dev(dev_info_t *dip)
    236 {
    237 	xendev_devclass_t devcls;
    238 	int vdevnum;
    239 	domid_t domid;
    240 	struct xendev_ppd *pdp;
    241 	i_xd_cfg_t *xdcp;
    242 	boolean_t backend;
    243 	char xsnamebuf[TYPICALMAXPATHLEN];
    244 	char *xsname;
    245 	void *prop_str;
    246 	unsigned int prop_len;
    247 	char unitaddr[8];
    248 
    249 	devcls = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
    250 	    DDI_PROP_DONTPASS, "devclass", XEN_INVAL);
    251 	vdevnum = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
    252 	    DDI_PROP_DONTPASS, "vdev", VDEV_NOXS);
    253 	domid = (domid_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
    254 	    DDI_PROP_DONTPASS, "domain", DOMID_SELF);
    255 
    256 	backend = (domid != DOMID_SELF);
    257 	xdcp = i_xvdi_devclass2cfg(devcls);
    258 	if (xdcp->device_type != NULL)
    259 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
    260 		    "device_type", xdcp->device_type);
    261 
    262 	pdp = kmem_zalloc(sizeof (*pdp), KM_SLEEP);
    263 	pdp->xd_domain = domid;
    264 	pdp->xd_vdevnum = vdevnum;
    265 	pdp->xd_devclass = devcls;
    266 	pdp->xd_evtchn = INVALID_EVTCHN;
    267 	list_create(&pdp->xd_xb_watches, sizeof (xd_xb_watches_t),
    268 	    offsetof(xd_xb_watches_t, xxw_list));
    269 	mutex_init(&pdp->xd_evt_lk, NULL, MUTEX_DRIVER, NULL);
    270 	mutex_init(&pdp->xd_ndi_lk, NULL, MUTEX_DRIVER, NULL);
    271 	ddi_set_parent_data(dip, pdp);
    272 
    273 	/*
    274 	 * devices that do not need to interact with xenstore
    275 	 */
    276 	if (vdevnum == VDEV_NOXS) {
    277 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
    278 		    "unit-address", "0");
    279 		if (devcls == XEN_CONSOLE)
    280 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
    281 			    "pm-hardware-state", "needs-suspend-resume");
    282 		return (DDI_SUCCESS);
    283 	}
    284 
    285 	/*
    286 	 * PV devices that need to probe xenstore
    287 	 */
    288 
    289 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
    290 	    "pm-hardware-state", "needs-suspend-resume");
    291 
    292 	xsname = xsnamebuf;
    293 	if (!backend)
    294 		(void) snprintf(xsnamebuf, sizeof (xsnamebuf),
    295 		    "%s/%d", xdcp->xs_path_fe, vdevnum);
    296 	else
    297 		(void) snprintf(xsnamebuf, sizeof (xsnamebuf),
    298 		    "%s/%d/%d", xdcp->xs_path_be, domid, vdevnum);
    299 	if ((xenbus_read_driver_state(xsname) >= XenbusStateClosing)) {
    300 		/* Don't try to init a dev that may be closing */
    301 		mutex_destroy(&pdp->xd_ndi_lk);
    302 		mutex_destroy(&pdp->xd_evt_lk);
    303 		kmem_free(pdp, sizeof (*pdp));
    304 		ddi_set_parent_data(dip, NULL);
    305 		return (DDI_FAILURE);
    306 	}
    307 
    308 	pdp->xd_xsdev.nodename = i_ddi_strdup(xsname, KM_SLEEP);
    309 	pdp->xd_xsdev.devicetype = xdcp->xsdev;
    310 	pdp->xd_xsdev.frontend = (backend ? 0 : 1);
    311 	pdp->xd_xsdev.data = dip;
    312 	pdp->xd_xsdev.otherend_id = (backend ? domid : -1);
    313 	if (i_xvdi_add_watches(dip) != DDI_SUCCESS) {
    314 		cmn_err(CE_WARN, "xvdi_init_dev: "
    315 		    "cannot add watches for %s", xsname);
    316 		xvdi_uninit_dev(dip);
    317 		return (DDI_FAILURE);
    318 	}
    319 
    320 	if (backend)
    321 		return (DDI_SUCCESS);
    322 
    323 	/*
    324 	 * The unit-address for frontend devices is the name of the
    325 	 * of the xenstore node containing the device configuration
    326 	 * and is contained in the 'vdev' property.
    327 	 * VIF devices are named using an incrementing integer.
    328 	 * VBD devices are either named using the 16-bit dev_t value
    329 	 * for linux 'hd' and 'xvd' devices, or a simple integer value
    330 	 * in the range 0..767.  768 is the base value of the linux
    331 	 * dev_t namespace, the dev_t value for 'hda'.
    332 	 */
    333 	(void) snprintf(unitaddr, sizeof (unitaddr), "%d", vdevnum);
    334 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "unit-address",
    335 	    unitaddr);
    336 
    337 	switch (devcls) {
    338 	case XEN_VNET:
    339 		if (xenbus_read(XBT_NULL, xsname, "mac", (void *)&prop_str,
    340 		    &prop_len) != 0)
    341 			break;
    342 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "mac",
    343 		    prop_str);
    344 		kmem_free(prop_str, prop_len);
    345 		break;
    346 	case XEN_VBLK:
    347 		/*
    348 		 * cache a copy of the otherend name
    349 		 * for ease of observeability
    350 		 */
    351 		if (xenbus_read(XBT_NULL, pdp->xd_xsdev.otherend, "dev",
    352 		    &prop_str, &prop_len) != 0)
    353 			break;
    354 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
    355 		    "dev-address", prop_str);
    356 		kmem_free(prop_str, prop_len);
    357 		break;
    358 	default:
    359 		break;
    360 	}
    361 
    362 	return (DDI_SUCCESS);
    363 }
    364 
    365 void
    366 xvdi_uninit_dev(dev_info_t *dip)
    367 {
    368 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
    369 
    370 	if (pdp != NULL) {
    371 		/* Remove any registered callbacks. */
    372 		xvdi_remove_event_handler(dip, NULL);
    373 
    374 		/* Remove any registered watches. */
    375 		i_xvdi_rem_watches(dip);
    376 
    377 		/* tell other end to close */
    378 		if (pdp->xd_xsdev.otherend_id != (domid_t)-1)
    379 			(void) xvdi_switch_state(dip, XBT_NULL,
    380 			    XenbusStateClosed);
    381 
    382 		if (pdp->xd_xsdev.nodename != NULL)
    383 			kmem_free((char *)(pdp->xd_xsdev.nodename),
    384 			    strlen(pdp->xd_xsdev.nodename) + 1);
    385 
    386 		ddi_set_parent_data(dip, NULL);
    387 
    388 		mutex_destroy(&pdp->xd_ndi_lk);
    389 		mutex_destroy(&pdp->xd_evt_lk);
    390 		kmem_free(pdp, sizeof (*pdp));
    391 	}
    392 }
    393 
    394 /*
    395  * Bind the event channel for this device instance.
    396  * Currently we only support one evtchn per device instance.
    397  */
    398 int
    399 xvdi_bind_evtchn(dev_info_t *dip, evtchn_port_t evtchn)
    400 {
    401 	struct xendev_ppd *pdp;
    402 	domid_t oeid;
    403 	int r;
    404 
    405 	pdp = ddi_get_parent_data(dip);
    406 	ASSERT(pdp != NULL);
    407 	ASSERT(pdp->xd_evtchn == INVALID_EVTCHN);
    408 
    409 	mutex_enter(&pdp->xd_evt_lk);
    410 	if (pdp->xd_devclass == XEN_CONSOLE) {
    411 		if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
    412 			pdp->xd_evtchn = xen_info->console.domU.evtchn;
    413 		} else {
    414 			pdp->xd_evtchn = INVALID_EVTCHN;
    415 			mutex_exit(&pdp->xd_evt_lk);
    416 			return (DDI_SUCCESS);
    417 		}
    418 	} else {
    419 		oeid = pdp->xd_xsdev.otherend_id;
    420 		if (oeid == (domid_t)-1) {
    421 			mutex_exit(&pdp->xd_evt_lk);
    422 			return (DDI_FAILURE);
    423 		}
    424 
    425 		if ((r = xen_bind_interdomain(oeid, evtchn, &pdp->xd_evtchn))) {
    426 			xvdi_dev_error(dip, r, "bind event channel");
    427 			mutex_exit(&pdp->xd_evt_lk);
    428 			return (DDI_FAILURE);
    429 		}
    430 	}
    431 #ifndef XPV_HVM_DRIVER
    432 	pdp->xd_ispec.intrspec_vec = ec_bind_evtchn_to_irq(pdp->xd_evtchn);
    433 #endif
    434 	mutex_exit(&pdp->xd_evt_lk);
    435 
    436 	return (DDI_SUCCESS);
    437 }
    438 
    439 /*
    440  * Allocate an event channel for this device instance.
    441  * Currently we only support one evtchn per device instance.
    442  */
    443 int
    444 xvdi_alloc_evtchn(dev_info_t *dip)
    445 {
    446 	struct xendev_ppd *pdp;
    447 	domid_t oeid;
    448 	int rv;
    449 
    450 	pdp = ddi_get_parent_data(dip);
    451 	ASSERT(pdp != NULL);
    452 	ASSERT(pdp->xd_evtchn == INVALID_EVTCHN);
    453 
    454 	mutex_enter(&pdp->xd_evt_lk);
    455 	if (pdp->xd_devclass == XEN_CONSOLE) {
    456 		if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
    457 			pdp->xd_evtchn = xen_info->console.domU.evtchn;
    458 		} else {
    459 			pdp->xd_evtchn = INVALID_EVTCHN;
    460 			mutex_exit(&pdp->xd_evt_lk);
    461 			return (DDI_SUCCESS);
    462 		}
    463 	} else {
    464 		oeid = pdp->xd_xsdev.otherend_id;
    465 		if (oeid == (domid_t)-1) {
    466 			mutex_exit(&pdp->xd_evt_lk);
    467 			return (DDI_FAILURE);
    468 		}
    469 
    470 		if ((rv = xen_alloc_unbound_evtchn(oeid, &pdp->xd_evtchn))) {
    471 			xvdi_dev_error(dip, rv, "bind event channel");
    472 			mutex_exit(&pdp->xd_evt_lk);
    473 			return (DDI_FAILURE);
    474 		}
    475 	}
    476 #ifndef XPV_HVM_DRIVER
    477 	pdp->xd_ispec.intrspec_vec = ec_bind_evtchn_to_irq(pdp->xd_evtchn);
    478 #endif
    479 	mutex_exit(&pdp->xd_evt_lk);
    480 
    481 	return (DDI_SUCCESS);
    482 }
    483 
    484 /*
    485  * Unbind the event channel for this device instance.
    486  * Currently we only support one evtchn per device instance.
    487  */
    488 void
    489 xvdi_free_evtchn(dev_info_t *dip)
    490 {
    491 	struct xendev_ppd *pdp;
    492 
    493 	pdp = ddi_get_parent_data(dip);
    494 	ASSERT(pdp != NULL);
    495 
    496 	mutex_enter(&pdp->xd_evt_lk);
    497 	if (pdp->xd_evtchn != INVALID_EVTCHN) {
    498 #ifndef XPV_HVM_DRIVER
    499 		ec_unbind_irq(pdp->xd_ispec.intrspec_vec);
    500 		pdp->xd_ispec.intrspec_vec = 0;
    501 #endif
    502 		pdp->xd_evtchn = INVALID_EVTCHN;
    503 	}
    504 	mutex_exit(&pdp->xd_evt_lk);
    505 }
    506 
    507 #ifndef XPV_HVM_DRIVER
    508 /*
    509  * Map an inter-domain communication ring for a virtual device.
    510  * This is used by backend drivers.
    511  */
    512 int
    513 xvdi_map_ring(dev_info_t *dip, size_t nentry, size_t entrysize,
    514     grant_ref_t gref, xendev_ring_t **ringpp)
    515 {
    516 	domid_t oeid;
    517 	gnttab_map_grant_ref_t mapop;
    518 	gnttab_unmap_grant_ref_t unmapop;
    519 	caddr_t ringva;
    520 	ddi_acc_hdl_t *ap;
    521 	ddi_acc_impl_t *iap;
    522 	xendev_ring_t *ring;
    523 	int err;
    524 	char errstr[] = "mapping in ring buffer";
    525 
    526 	ring = kmem_zalloc(sizeof (xendev_ring_t), KM_SLEEP);
    527 	oeid = xvdi_get_oeid(dip);
    528 
    529 	/* alloc va in backend dom for ring buffer */
    530 	ringva = vmem_xalloc(heap_arena, PAGESIZE, PAGESIZE,
    531 	    0, 0, 0, 0, VM_SLEEP);
    532 
    533 	/* map in ring page */
    534 	hat_prepare_mapping(kas.a_hat, ringva, NULL);
    535 	mapop.host_addr = (uint64_t)(uintptr_t)ringva;
    536 	mapop.flags = GNTMAP_host_map;
    537 	mapop.ref = gref;
    538 	mapop.dom = oeid;
    539 	err = xen_map_gref(GNTTABOP_map_grant_ref, &mapop, 1, B_FALSE);
    540 	if (err) {
    541 		xvdi_fatal_error(dip, err, errstr);
    542 		goto errout1;
    543 	}
    544 
    545 	if (mapop.status != 0) {
    546 		xvdi_fatal_error(dip, err, errstr);
    547 		goto errout2;
    548 	}
    549 	ring->xr_vaddr = ringva;
    550 	ring->xr_grant_hdl = mapop.handle;
    551 	ring->xr_gref = gref;
    552 
    553 	/*
    554 	 * init an acc handle and associate it w/ this ring
    555 	 * this is only for backend drivers. we get the memory by calling
    556 	 * vmem_xalloc(), instead of calling any ddi function, so we have
    557 	 * to init an acc handle by ourselves
    558 	 */
    559 	ring->xr_acc_hdl = impl_acc_hdl_alloc(KM_SLEEP, NULL);
    560 	ap = impl_acc_hdl_get(ring->xr_acc_hdl);
    561 	ap->ah_vers = VERS_ACCHDL;
    562 	ap->ah_dip = dip;
    563 	ap->ah_xfermodes = DDI_DMA_CONSISTENT;
    564 	ap->ah_acc = xendev_dc_accattr;
    565 	iap = (ddi_acc_impl_t *)ap->ah_platform_private;
    566 	iap->ahi_acc_attr |= DDI_ACCATTR_CPU_VADDR;
    567 	impl_acc_hdl_init(ap);
    568 	ap->ah_offset = 0;
    569 	ap->ah_len = (off_t)PAGESIZE;
    570 	ap->ah_addr = ring->xr_vaddr;
    571 
    572 	/* init backend ring */
    573 	xvdi_ring_init_back_ring(ring, nentry, entrysize);
    574 
    575 	*ringpp = ring;
    576 
    577 	return (DDI_SUCCESS);
    578 
    579 errout2:
    580 	/* unmap ring page */
    581 	unmapop.host_addr = (uint64_t)(uintptr_t)ringva;
    582 	unmapop.handle = ring->xr_grant_hdl;
    583 	unmapop.dev_bus_addr = NULL;
    584 	(void) HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unmapop, 1);
    585 	hat_release_mapping(kas.a_hat, ringva);
    586 errout1:
    587 	vmem_xfree(heap_arena, ringva, PAGESIZE);
    588 	kmem_free(ring, sizeof (xendev_ring_t));
    589 	return (DDI_FAILURE);
    590 }
    591 
    592 /*
    593  * Unmap a ring for a virtual device.
    594  * This is used by backend drivers.
    595  */
    596 void
    597 xvdi_unmap_ring(xendev_ring_t *ring)
    598 {
    599 	gnttab_unmap_grant_ref_t unmapop;
    600 
    601 	ASSERT((ring != NULL) && (ring->xr_vaddr != NULL));
    602 
    603 	impl_acc_hdl_free(ring->xr_acc_hdl);
    604 	unmapop.host_addr = (uint64_t)(uintptr_t)ring->xr_vaddr;
    605 	unmapop.handle = ring->xr_grant_hdl;
    606 	unmapop.dev_bus_addr = NULL;
    607 	(void) HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unmapop, 1);
    608 	hat_release_mapping(kas.a_hat, ring->xr_vaddr);
    609 	vmem_xfree(heap_arena, ring->xr_vaddr, PAGESIZE);
    610 	kmem_free(ring, sizeof (xendev_ring_t));
    611 }
    612 #endif /* XPV_HVM_DRIVER */
    613 
    614 /*
    615  * Re-initialise an inter-domain communications ring for the backend domain.
    616  * ring will be re-initialized after re-grant succeed
    617  * ring will be freed if fails to re-grant access to backend domain
    618  * so, don't keep useful data in the ring
    619  * used only in frontend driver
    620  */
    621 static void
    622 xvdi_reinit_ring(dev_info_t *dip, grant_ref_t *gref, xendev_ring_t *ringp)
    623 {
    624 	paddr_t rpaddr;
    625 	maddr_t rmaddr;
    626 
    627 	ASSERT((ringp != NULL) && (ringp->xr_paddr != 0));
    628 	rpaddr = ringp->xr_paddr;
    629 
    630 	rmaddr = DOMAIN_IS_INITDOMAIN(xen_info) ? rpaddr : pa_to_ma(rpaddr);
    631 	gnttab_grant_foreign_access_ref(ringp->xr_gref, xvdi_get_oeid(dip),
    632 	    rmaddr >> PAGESHIFT, 0);
    633 	*gref = ringp->xr_gref;
    634 
    635 	/* init frontend ring */
    636 	xvdi_ring_init_sring(ringp);
    637 	xvdi_ring_init_front_ring(ringp, ringp->xr_sring.fr.nr_ents,
    638 	    ringp->xr_entry_size);
    639 }
    640 
    641 /*
    642  * allocate Xen inter-domain communications ring for Xen virtual devices
    643  * used only in frontend driver
    644  * if *ringpp is not NULL, we'll simply re-init it
    645  */
    646 int
    647 xvdi_alloc_ring(dev_info_t *dip, size_t nentry, size_t entrysize,
    648     grant_ref_t *gref, xendev_ring_t **ringpp)
    649 {
    650 	size_t len;
    651 	xendev_ring_t *ring;
    652 	ddi_dma_cookie_t dma_cookie;
    653 	uint_t ncookies;
    654 	grant_ref_t ring_gref;
    655 	domid_t oeid;
    656 	maddr_t rmaddr;
    657 
    658 	if (*ringpp) {
    659 		xvdi_reinit_ring(dip, gref, *ringpp);
    660 		return (DDI_SUCCESS);
    661 	}
    662 
    663 	*ringpp = ring = kmem_zalloc(sizeof (xendev_ring_t), KM_SLEEP);
    664 	oeid = xvdi_get_oeid(dip);
    665 
    666 	/*
    667 	 * Allocate page for this ring buffer
    668 	 */
    669 	if (ddi_dma_alloc_handle(dip, &xendev_dc_dmaattr, DDI_DMA_SLEEP,
    670 	    0, &ring->xr_dma_hdl) != DDI_SUCCESS)
    671 		goto err;
    672 
    673 	if (ddi_dma_mem_alloc(ring->xr_dma_hdl, PAGESIZE,
    674 	    &xendev_dc_accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
    675 	    &ring->xr_vaddr, &len, &ring->xr_acc_hdl) != DDI_SUCCESS) {
    676 		ddi_dma_free_handle(&ring->xr_dma_hdl);
    677 		goto err;
    678 	}
    679 
    680 	if (ddi_dma_addr_bind_handle(ring->xr_dma_hdl, NULL,
    681 	    ring->xr_vaddr, len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
    682 	    DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_DMA_MAPPED) {
    683 		ddi_dma_mem_free(&ring->xr_acc_hdl);
    684 		ring->xr_vaddr = NULL;
    685 		ddi_dma_free_handle(&ring->xr_dma_hdl);
    686 		goto err;
    687 	}
    688 	ASSERT(ncookies == 1);
    689 	ring->xr_paddr = dma_cookie.dmac_laddress;
    690 	rmaddr = DOMAIN_IS_INITDOMAIN(xen_info) ? ring->xr_paddr :
    691 	    pa_to_ma(ring->xr_paddr);
    692 
    693 	if ((ring_gref = gnttab_grant_foreign_access(oeid,
    694 	    rmaddr >> PAGESHIFT, 0)) == (grant_ref_t)-1) {
    695 		(void) ddi_dma_unbind_handle(ring->xr_dma_hdl);
    696 		ddi_dma_mem_free(&ring->xr_acc_hdl);
    697 		ring->xr_vaddr = NULL;
    698 		ddi_dma_free_handle(&ring->xr_dma_hdl);
    699 		goto err;
    700 	}
    701 	*gref = ring->xr_gref = ring_gref;
    702 
    703 	/* init frontend ring */
    704 	xvdi_ring_init_sring(ring);
    705 	xvdi_ring_init_front_ring(ring, nentry, entrysize);
    706 
    707 	return (DDI_SUCCESS);
    708 
    709 err:
    710 	kmem_free(ring, sizeof (xendev_ring_t));
    711 	return (DDI_FAILURE);
    712 }
    713 
    714 /*
    715  * Release ring buffers allocated for Xen devices
    716  * used for frontend driver
    717  */
    718 void
    719 xvdi_free_ring(xendev_ring_t *ring)
    720 {
    721 	ASSERT((ring != NULL) && (ring->xr_vaddr != NULL));
    722 
    723 	(void) gnttab_end_foreign_access_ref(ring->xr_gref, 0);
    724 	(void) ddi_dma_unbind_handle(ring->xr_dma_hdl);
    725 	ddi_dma_mem_free(&ring->xr_acc_hdl);
    726 	ddi_dma_free_handle(&ring->xr_dma_hdl);
    727 	kmem_free(ring, sizeof (xendev_ring_t));
    728 }
    729 
    730 dev_info_t *
    731 xvdi_create_dev(dev_info_t *parent, xendev_devclass_t devclass,
    732     domid_t dom, int vdev)
    733 {
    734 	dev_info_t *dip;
    735 	boolean_t backend;
    736 	i_xd_cfg_t *xdcp;
    737 	char xsnamebuf[TYPICALMAXPATHLEN];
    738 	char *type, *node = NULL, *xsname = NULL;
    739 	unsigned int tlen;
    740 	int ret;
    741 
    742 	ASSERT(DEVI_BUSY_OWNED(parent));
    743 
    744 	backend = (dom != DOMID_SELF);
    745 	xdcp = i_xvdi_devclass2cfg(devclass);
    746 	ASSERT(xdcp != NULL);
    747 
    748 	if (vdev != VDEV_NOXS) {
    749 		if (!backend) {
    750 			(void) snprintf(xsnamebuf, sizeof (xsnamebuf),
    751 			    "%s/%d", xdcp->xs_path_fe, vdev);
    752 			xsname = xsnamebuf;
    753 			node = xdcp->node_fe;
    754 		} else {
    755 			(void) snprintf(xsnamebuf, sizeof (xsnamebuf),
    756 			    "%s/%d/%d", xdcp->xs_path_be, dom, vdev);
    757 			xsname = xsnamebuf;
    758 			node = xdcp->node_be;
    759 		}
    760 	} else {
    761 		node = xdcp->node_fe;
    762 	}
    763 
    764 	/* Must have a driver to use. */
    765 	if (node == NULL)
    766 		return (NULL);
    767 
    768 	/*
    769 	 * We need to check the state of this device before we go
    770 	 * further, otherwise we'll end up with a dead loop if
    771 	 * anything goes wrong.
    772 	 */
    773 	if ((xsname != NULL) &&
    774 	    (xenbus_read_driver_state(xsname) >= XenbusStateClosing))
    775 		return (NULL);
    776 
    777 	ndi_devi_alloc_sleep(parent, node, DEVI_SID_NODEID, &dip);
    778 
    779 	/*
    780 	 * Driver binding uses the compatible property _before_ the
    781 	 * node name, so we set the node name to the 'model' of the
    782 	 * device (i.e. 'xnb' or 'xdb') and, if 'type' is present,
    783 	 * encode both the model and the type in a compatible property
    784 	 * (i.e. 'xnb,netfront' or 'xnb,SUNW_mac').  This allows a
    785 	 * driver binding based on the <model,type> pair _before_ a
    786 	 * binding based on the node name.
    787 	 */
    788 	if ((xsname != NULL) &&
    789 	    (xenbus_read(XBT_NULL, xsname, "type", (void *)&type, &tlen)
    790 	    == 0)) {
    791 		size_t clen;
    792 		char *c[1];
    793 
    794 		clen = strlen(node) + strlen(type) + 2;
    795 		c[0] = kmem_alloc(clen, KM_SLEEP);
    796 		(void) snprintf(c[0], clen, "%s,%s", node, type);
    797 
    798 		(void) ndi_prop_update_string_array(DDI_DEV_T_NONE,
    799 		    dip, "compatible", (char **)c, 1);
    800 
    801 		kmem_free(c[0], clen);
    802 		kmem_free(type, tlen);
    803 	}
    804 
    805 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "devclass", devclass);
    806 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "domain", dom);
    807 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vdev", vdev);
    808 
    809 	if (i_ddi_devi_attached(parent))
    810 		ret = ndi_devi_online(dip, 0);
    811 	else
    812 		ret = ndi_devi_bind_driver(dip, 0);
    813 	if (ret != NDI_SUCCESS)
    814 		(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
    815 
    816 	return (dip);
    817 }
    818 
    819 /*
    820  * xendev_enum_class()
    821  */
    822 void
    823 xendev_enum_class(dev_info_t *parent, xendev_devclass_t devclass)
    824 {
    825 	boolean_t dom0 = DOMAIN_IS_INITDOMAIN(xen_info);
    826 	boolean_t domU = !dom0;
    827 	i_xd_cfg_t *xdcp;
    828 
    829 	xdcp = i_xvdi_devclass2cfg(devclass);
    830 	ASSERT(xdcp != NULL);
    831 
    832 	if (dom0 && !(xdcp->flags & XD_DOM_ZERO))
    833 		return;
    834 
    835 	if (domU && !(xdcp->flags & XD_DOM_GUEST))
    836 		return;
    837 
    838 	if (xdcp->xsdev == NULL) {
    839 		int circ;
    840 
    841 		/*
    842 		 * Don't need to probe this kind of device from the
    843 		 * store, just create one if it doesn't exist.
    844 		 */
    845 
    846 		ndi_devi_enter(parent, &circ);
    847 		if (xvdi_find_dev(parent, devclass, DOMID_SELF, VDEV_NOXS)
    848 		    == NULL)
    849 			(void) xvdi_create_dev(parent, devclass,
    850 			    DOMID_SELF, VDEV_NOXS);
    851 		ndi_devi_exit(parent, circ);
    852 	} else {
    853 		/*
    854 		 * Probe this kind of device from the store, both
    855 		 * frontend and backend.
    856 		 */
    857 		if (xdcp->node_fe != NULL) {
    858 			i_xvdi_enum_fe(parent, xdcp);
    859 		}
    860 		if (xdcp->node_be != NULL) {
    861 			i_xvdi_enum_be(parent, xdcp);
    862 		}
    863 	}
    864 }
    865 
    866 /*
    867  * xendev_enum_all()
    868  */
    869 void
    870 xendev_enum_all(dev_info_t *parent, boolean_t store_unavailable)
    871 {
    872 	int i;
    873 	i_xd_cfg_t *xdcp;
    874 	boolean_t dom0 = DOMAIN_IS_INITDOMAIN(xen_info);
    875 
    876 	for (i = 0, xdcp = xdci; i < NXDC; i++, xdcp++) {
    877 		/*
    878 		 * Dom0 relies on watchpoints to create non-soft
    879 		 * devices - don't attempt to iterate over the store.
    880 		 */
    881 		if (dom0 && (xdcp->xsdev != NULL))
    882 			continue;
    883 
    884 		/*
    885 		 * If the store is not yet available, don't attempt to
    886 		 * iterate.
    887 		 */
    888 		if (store_unavailable && (xdcp->xsdev != NULL))
    889 			continue;
    890 
    891 		xendev_enum_class(parent, xdcp->devclass);
    892 	}
    893 }
    894 
    895 xendev_devclass_t
    896 xendev_nodename_to_devclass(char *nodename)
    897 {
    898 	int i;
    899 	i_xd_cfg_t *xdcp;
    900 
    901 	/*
    902 	 * This relies on the convention that variants of a base
    903 	 * driver share the same prefix and that there are no drivers
    904 	 * which share a common prefix with the name of any other base
    905 	 * drivers.
    906 	 *
    907 	 * So for a base driver 'xnb' (which is the name listed in
    908 	 * xdci) the variants all begin with the string 'xnb' (in fact
    909 	 * they are 'xnbe', 'xnbo' and 'xnbu') and there are no other
    910 	 * base drivers which have the prefix 'xnb'.
    911 	 */
    912 	ASSERT(nodename != NULL);
    913 	for (i = 0, xdcp = xdci; i < NXDC; i++, xdcp++) {
    914 		if (((xdcp->node_fe != NULL) &&
    915 		    (strncmp(nodename, xdcp->node_fe,
    916 		    strlen(xdcp->node_fe)) == 0)) ||
    917 		    ((xdcp->node_be != NULL) &&
    918 		    (strncmp(nodename, xdcp->node_be,
    919 		    strlen(xdcp->node_be)) == 0)))
    920 
    921 			return (xdcp->devclass);
    922 	}
    923 	return (XEN_INVAL);
    924 }
    925 
    926 int
    927 xendev_devclass_ipl(xendev_devclass_t devclass)
    928 {
    929 	i_xd_cfg_t *xdcp;
    930 
    931 	xdcp = i_xvdi_devclass2cfg(devclass);
    932 	ASSERT(xdcp != NULL);
    933 
    934 	return (xdcp->xd_ipl);
    935 }
    936 
    937 /*
    938  * Determine if a devinfo instance exists of a particular device
    939  * class, domain and xenstore virtual device number.
    940  */
    941 dev_info_t *
    942 xvdi_find_dev(dev_info_t *parent, xendev_devclass_t devclass,
    943     domid_t dom, int vdev)
    944 {
    945 	dev_info_t *dip;
    946 
    947 	ASSERT(DEVI_BUSY_OWNED(parent));
    948 
    949 	switch (devclass) {
    950 	case XEN_CONSOLE:
    951 	case XEN_XENBUS:
    952 	case XEN_DOMCAPS:
    953 	case XEN_BALLOON:
    954 	case XEN_EVTCHN:
    955 	case XEN_PRIVCMD:
    956 		/* Console and soft devices have no vdev. */
    957 		vdev = VDEV_NOXS;
    958 		break;
    959 	default:
    960 		break;
    961 	}
    962 
    963 	for (dip = ddi_get_child(parent); dip != NULL;
    964 	    dip = ddi_get_next_sibling(dip)) {
    965 		int *vdevnump, *domidp, *devclsp, vdevnum;
    966 		uint_t ndomid, nvdevnum, ndevcls;
    967 		xendev_devclass_t devcls;
    968 		domid_t domid;
    969 		struct xendev_ppd *pdp = ddi_get_parent_data(dip);
    970 
    971 		if (pdp == NULL) {
    972 			if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
    973 			    DDI_PROP_DONTPASS, "domain", &domidp, &ndomid) !=
    974 			    DDI_PROP_SUCCESS)
    975 				continue;
    976 			ASSERT(ndomid == 1);
    977 			domid = (domid_t)*domidp;
    978 			ddi_prop_free(domidp);
    979 
    980 			if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
    981 			    DDI_PROP_DONTPASS, "vdev", &vdevnump, &nvdevnum) !=
    982 			    DDI_PROP_SUCCESS)
    983 				continue;
    984 			ASSERT(nvdevnum == 1);
    985 			vdevnum = *vdevnump;
    986 			ddi_prop_free(vdevnump);
    987 
    988 			if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
    989 			    DDI_PROP_DONTPASS, "devclass", &devclsp,
    990 			    &ndevcls) != DDI_PROP_SUCCESS)
    991 				continue;
    992 			ASSERT(ndevcls == 1);
    993 			devcls = (xendev_devclass_t)*devclsp;
    994 			ddi_prop_free(devclsp);
    995 		} else {
    996 			domid = pdp->xd_domain;
    997 			vdevnum = pdp->xd_vdevnum;
    998 			devcls = pdp->xd_devclass;
    999 		}
   1000 
   1001 		if ((domid == dom) && (vdevnum == vdev) && (devcls == devclass))
   1002 			return (dip);
   1003 	}
   1004 	return (NULL);
   1005 }
   1006 
   1007 int
   1008 xvdi_get_evtchn(dev_info_t *xdip)
   1009 {
   1010 	struct xendev_ppd *pdp = ddi_get_parent_data(xdip);
   1011 
   1012 	ASSERT(pdp != NULL);
   1013 	return (pdp->xd_evtchn);
   1014 }
   1015 
   1016 int
   1017 xvdi_get_vdevnum(dev_info_t *xdip)
   1018 {
   1019 	struct xendev_ppd *pdp = ddi_get_parent_data(xdip);
   1020 
   1021 	ASSERT(pdp != NULL);
   1022 	return (pdp->xd_vdevnum);
   1023 }
   1024 
   1025 char *
   1026 xvdi_get_xsname(dev_info_t *xdip)
   1027 {
   1028 	struct xendev_ppd *pdp = ddi_get_parent_data(xdip);
   1029 
   1030 	ASSERT(pdp != NULL);
   1031 	return ((char *)(pdp->xd_xsdev.nodename));
   1032 }
   1033 
   1034 char *
   1035 xvdi_get_oename(dev_info_t *xdip)
   1036 {
   1037 	struct xendev_ppd *pdp = ddi_get_parent_data(xdip);
   1038 
   1039 	ASSERT(pdp != NULL);
   1040 	if (pdp->xd_devclass == XEN_CONSOLE)
   1041 		return (NULL);
   1042 	return ((char *)(pdp->xd_xsdev.otherend));
   1043 }
   1044 
   1045 struct xenbus_device *
   1046 xvdi_get_xsd(dev_info_t *xdip)
   1047 {
   1048 	struct xendev_ppd *pdp = ddi_get_parent_data(xdip);
   1049 
   1050 	ASSERT(pdp != NULL);
   1051 	return (&pdp->xd_xsdev);
   1052 }
   1053 
   1054 domid_t
   1055 xvdi_get_oeid(dev_info_t *xdip)
   1056 {
   1057 	struct xendev_ppd *pdp = ddi_get_parent_data(xdip);
   1058 
   1059 	ASSERT(pdp != NULL);
   1060 	if (pdp->xd_devclass == XEN_CONSOLE)
   1061 		return ((domid_t)-1);
   1062 	return ((domid_t)(pdp->xd_xsdev.otherend_id));
   1063 }
   1064 
   1065 void
   1066 xvdi_dev_error(dev_info_t *dip, int errno, char *errstr)
   1067 {
   1068 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1069 
   1070 	ASSERT(pdp != NULL);
   1071 	xenbus_dev_error(&pdp->xd_xsdev, errno, errstr);
   1072 }
   1073 
   1074 void
   1075 xvdi_fatal_error(dev_info_t *dip, int errno, char *errstr)
   1076 {
   1077 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1078 
   1079 	ASSERT(pdp != NULL);
   1080 	xenbus_dev_fatal(&pdp->xd_xsdev, errno, errstr);
   1081 }
   1082 
   1083 static void
   1084 i_xvdi_oestate_handler(void *arg)
   1085 {
   1086 	i_oestate_evt_t *evt = (i_oestate_evt_t *)arg;
   1087 	dev_info_t *dip = evt->dip;
   1088 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1089 	XenbusState oestate = pdp->xd_xsdev.otherend_state;
   1090 	XenbusState curr_oestate = evt->state;
   1091 	ddi_eventcookie_t evc;
   1092 
   1093 	/* evt is alloc'ed in i_xvdi_oestate_cb */
   1094 	kmem_free(evt, sizeof (i_oestate_evt_t));
   1095 
   1096 	/*
   1097 	 * If the oestate we're handling is not the latest one,
   1098 	 * it does not make any sense to continue handling it.
   1099 	 */
   1100 	if (curr_oestate != oestate)
   1101 		return;
   1102 
   1103 	mutex_enter(&pdp->xd_ndi_lk);
   1104 
   1105 	if (pdp->xd_oe_ehid != NULL) {
   1106 		/* send notification to driver */
   1107 		if (ddi_get_eventcookie(dip, XS_OE_STATE,
   1108 		    &evc) == DDI_SUCCESS) {
   1109 			mutex_exit(&pdp->xd_ndi_lk);
   1110 			(void) ndi_post_event(dip, dip, evc, &oestate);
   1111 			mutex_enter(&pdp->xd_ndi_lk);
   1112 		}
   1113 	} else {
   1114 		/*
   1115 		 * take default action, if driver hasn't registered its
   1116 		 * event handler yet
   1117 		 */
   1118 		if (oestate == XenbusStateClosing) {
   1119 			(void) xvdi_switch_state(dip, XBT_NULL,
   1120 			    XenbusStateClosed);
   1121 		} else if (oestate == XenbusStateClosed) {
   1122 			(void) xvdi_switch_state(dip, XBT_NULL,
   1123 			    XenbusStateClosed);
   1124 			(void) xvdi_post_event(dip, XEN_HP_REMOVE);
   1125 		}
   1126 	}
   1127 
   1128 	mutex_exit(&pdp->xd_ndi_lk);
   1129 
   1130 	/*
   1131 	 * We'll try to remove the devinfo node of this device if the
   1132 	 * other end has closed.
   1133 	 */
   1134 	if (oestate == XenbusStateClosed)
   1135 		(void) ddi_taskq_dispatch(DEVI(ddi_get_parent(dip))->devi_taskq,
   1136 		    xendev_offline_device, dip, DDI_SLEEP);
   1137 }
   1138 
   1139 static void
   1140 i_xvdi_hpstate_handler(void *arg)
   1141 {
   1142 	dev_info_t *dip = (dev_info_t *)arg;
   1143 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1144 	ddi_eventcookie_t evc;
   1145 	char *hp_status;
   1146 	unsigned int hpl;
   1147 
   1148 	mutex_enter(&pdp->xd_ndi_lk);
   1149 	if ((ddi_get_eventcookie(dip, XS_HP_STATE, &evc) == DDI_SUCCESS) &&
   1150 	    (xenbus_read(XBT_NULL, pdp->xd_hp_watch.node, "",
   1151 	    (void *)&hp_status, &hpl) == 0)) {
   1152 
   1153 		xendev_hotplug_state_t new_state = Unrecognized;
   1154 
   1155 		if (strcmp(hp_status, "connected") == 0)
   1156 			new_state = Connected;
   1157 
   1158 		mutex_exit(&pdp->xd_ndi_lk);
   1159 
   1160 		(void) ndi_post_event(dip, dip, evc, &new_state);
   1161 		kmem_free(hp_status, hpl);
   1162 		return;
   1163 	}
   1164 	mutex_exit(&pdp->xd_ndi_lk);
   1165 }
   1166 
   1167 void
   1168 xvdi_notify_oe(dev_info_t *dip)
   1169 {
   1170 	struct xendev_ppd *pdp;
   1171 
   1172 	pdp = ddi_get_parent_data(dip);
   1173 	ASSERT(pdp->xd_evtchn != INVALID_EVTCHN);
   1174 	ec_notify_via_evtchn(pdp->xd_evtchn);
   1175 }
   1176 
   1177 static void
   1178 i_xvdi_bepath_cb(struct xenbus_watch *w, const char **vec, unsigned int len)
   1179 {
   1180 	dev_info_t *dip = (dev_info_t *)w->dev;
   1181 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1182 	char *be = NULL;
   1183 	unsigned int bel;
   1184 
   1185 	ASSERT(len > XS_WATCH_PATH);
   1186 	ASSERT(vec[XS_WATCH_PATH] != NULL);
   1187 
   1188 	/*
   1189 	 * If the backend is not the same as that we already stored,
   1190 	 * re-set our watch for its' state.
   1191 	 */
   1192 	if ((xenbus_read(XBT_NULL, "", vec[XS_WATCH_PATH], (void *)be, &bel)
   1193 	    == 0) && (strcmp(be, pdp->xd_xsdev.otherend) != 0))
   1194 		(void) i_xvdi_add_watch_oestate(dip);
   1195 
   1196 	if (be != NULL) {
   1197 		ASSERT(bel > 0);
   1198 		kmem_free(be, bel);
   1199 	}
   1200 }
   1201 
   1202 static void
   1203 i_xvdi_xb_watch_free(xd_xb_watches_t *xxwp)
   1204 {
   1205 	ASSERT(xxwp->xxw_ref == 0);
   1206 	strfree((char *)xxwp->xxw_watch.node);
   1207 	kmem_free(xxwp, sizeof (*xxwp));
   1208 }
   1209 
   1210 static void
   1211 i_xvdi_xb_watch_release(xd_xb_watches_t *xxwp)
   1212 {
   1213 	ASSERT(MUTEX_HELD(&xxwp->xxw_xppd->xd_ndi_lk));
   1214 	ASSERT(xxwp->xxw_ref > 0);
   1215 	if (--xxwp->xxw_ref == 0)
   1216 		i_xvdi_xb_watch_free(xxwp);
   1217 }
   1218 
   1219 static void
   1220 i_xvdi_xb_watch_hold(xd_xb_watches_t *xxwp)
   1221 {
   1222 	ASSERT(MUTEX_HELD(&xxwp->xxw_xppd->xd_ndi_lk));
   1223 	ASSERT(xxwp->xxw_ref > 0);
   1224 	xxwp->xxw_ref++;
   1225 }
   1226 
   1227 static void
   1228 i_xvdi_xb_watch_cb_tq(void *arg)
   1229 {
   1230 	xd_xb_watches_t		*xxwp = (xd_xb_watches_t *)arg;
   1231 	dev_info_t		*dip = (dev_info_t *)xxwp->xxw_watch.dev;
   1232 	struct xendev_ppd	*pdp = xxwp->xxw_xppd;
   1233 
   1234 	xxwp->xxw_cb(dip, xxwp->xxw_watch.node, xxwp->xxw_arg);
   1235 
   1236 	mutex_enter(&pdp->xd_ndi_lk);
   1237 	i_xvdi_xb_watch_release(xxwp);
   1238 	mutex_exit(&pdp->xd_ndi_lk);
   1239 }
   1240 
   1241 static void
   1242 i_xvdi_xb_watch_cb(struct xenbus_watch *w, const char **vec, unsigned int len)
   1243 {
   1244 	dev_info_t		*dip = (dev_info_t *)w->dev;
   1245 	struct xendev_ppd	*pdp = ddi_get_parent_data(dip);
   1246 	xd_xb_watches_t		*xxwp;
   1247 
   1248 	ASSERT(len > XS_WATCH_PATH);
   1249 	ASSERT(vec[XS_WATCH_PATH] != NULL);
   1250 
   1251 	mutex_enter(&pdp->xd_ndi_lk);
   1252 	for (xxwp = list_head(&pdp->xd_xb_watches); xxwp != NULL;
   1253 	    xxwp = list_next(&pdp->xd_xb_watches, xxwp)) {
   1254 		if (w == &xxwp->xxw_watch)
   1255 			break;
   1256 	}
   1257 
   1258 	if (xxwp == NULL) {
   1259 		mutex_exit(&pdp->xd_ndi_lk);
   1260 		return;
   1261 	}
   1262 
   1263 	i_xvdi_xb_watch_hold(xxwp);
   1264 	(void) ddi_taskq_dispatch(pdp->xd_xb_watch_taskq,
   1265 	    i_xvdi_xb_watch_cb_tq, xxwp, DDI_SLEEP);
   1266 	mutex_exit(&pdp->xd_ndi_lk);
   1267 }
   1268 
   1269 /*
   1270  * Any watches registered with xvdi_add_xb_watch_handler() get torn down during
   1271  * a suspend operation.  So if a frontend driver want's to use these interfaces,
   1272  * that driver is responsible for re-registering any watches it had before
   1273  * the suspend operation.
   1274  */
   1275 int
   1276 xvdi_add_xb_watch_handler(dev_info_t *dip, const char *dir, const char *node,
   1277     xvdi_xb_watch_cb_t cb, void *arg)
   1278 {
   1279 	struct xendev_ppd	*pdp = ddi_get_parent_data(dip);
   1280 	xd_xb_watches_t		*xxw_new, *xxwp;
   1281 	char			*path;
   1282 	int			n;
   1283 
   1284 	ASSERT((dip != NULL) && (dir != NULL) && (node != NULL));
   1285 	ASSERT(cb != NULL);
   1286 
   1287 	n = strlen(dir) + 1 + strlen(node) + 1;
   1288 	path = kmem_zalloc(n, KM_SLEEP);
   1289 	(void) strlcat(path, dir, n);
   1290 	(void) strlcat(path, "/", n);
   1291 	(void) strlcat(path, node, n);
   1292 	ASSERT((strlen(path) + 1) == n);
   1293 
   1294 	xxw_new = kmem_zalloc(sizeof (*xxw_new), KM_SLEEP);
   1295 	xxw_new->xxw_ref = 1;
   1296 	xxw_new->xxw_watch.node = path;
   1297 	xxw_new->xxw_watch.callback = i_xvdi_xb_watch_cb;
   1298 	xxw_new->xxw_watch.dev = (struct xenbus_device *)dip;
   1299 	xxw_new->xxw_xppd = pdp;
   1300 	xxw_new->xxw_cb = cb;
   1301 	xxw_new->xxw_arg = arg;
   1302 
   1303 	mutex_enter(&pdp->xd_ndi_lk);
   1304 
   1305 	/*
   1306 	 * If this is the first watch we're setting up, create a taskq
   1307 	 * to dispatch watch events and initialize the watch list.
   1308 	 */
   1309 	if (pdp->xd_xb_watch_taskq == NULL) {
   1310 		char tq_name[TASKQ_NAMELEN];
   1311 
   1312 		ASSERT(list_is_empty(&pdp->xd_xb_watches));
   1313 
   1314 		(void) snprintf(tq_name, sizeof (tq_name),
   1315 		    "%s_xb_watch_tq", ddi_get_name(dip));
   1316 
   1317 		if ((pdp->xd_xb_watch_taskq = ddi_taskq_create(dip, tq_name,
   1318 		    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
   1319 			i_xvdi_xb_watch_release(xxw_new);
   1320 			mutex_exit(&pdp->xd_ndi_lk);
   1321 			return (DDI_FAILURE);
   1322 		}
   1323 	}
   1324 
   1325 	/* Don't allow duplicate watches to be registered */
   1326 	for (xxwp = list_head(&pdp->xd_xb_watches); xxwp != NULL;
   1327 	    xxwp = list_next(&pdp->xd_xb_watches, xxwp)) {
   1328 
   1329 		ASSERT(strcmp(xxwp->xxw_watch.node, path) != 0);
   1330 		if (strcmp(xxwp->xxw_watch.node, path) != 0)
   1331 			continue;
   1332 		i_xvdi_xb_watch_release(xxw_new);
   1333 		mutex_exit(&pdp->xd_ndi_lk);
   1334 		return (DDI_FAILURE);
   1335 	}
   1336 
   1337 	if (register_xenbus_watch(&xxw_new->xxw_watch) != 0) {
   1338 		if (list_is_empty(&pdp->xd_xb_watches)) {
   1339 			ddi_taskq_destroy(pdp->xd_xb_watch_taskq);
   1340 			pdp->xd_xb_watch_taskq = NULL;
   1341 		}
   1342 		i_xvdi_xb_watch_release(xxw_new);
   1343 		mutex_exit(&pdp->xd_ndi_lk);
   1344 		return (DDI_FAILURE);
   1345 	}
   1346 
   1347 	list_insert_head(&pdp->xd_xb_watches, xxw_new);
   1348 	mutex_exit(&pdp->xd_ndi_lk);
   1349 	return (DDI_SUCCESS);
   1350 }
   1351 
   1352 /*
   1353  * Tear down all xenbus watches registered by the specified dip.
   1354  */
   1355 void
   1356 xvdi_remove_xb_watch_handlers(dev_info_t *dip)
   1357 {
   1358 	struct xendev_ppd	*pdp = ddi_get_parent_data(dip);
   1359 	xd_xb_watches_t		*xxwp;
   1360 	ddi_taskq_t		*tq;
   1361 
   1362 	mutex_enter(&pdp->xd_ndi_lk);
   1363 
   1364 	while ((xxwp = list_remove_head(&pdp->xd_xb_watches)) != NULL) {
   1365 		mutex_exit(&pdp->xd_ndi_lk);
   1366 		unregister_xenbus_watch(&xxwp->xxw_watch);
   1367 		mutex_enter(&pdp->xd_ndi_lk);
   1368 		i_xvdi_xb_watch_release(xxwp);
   1369 	}
   1370 	ASSERT(list_is_empty(&pdp->xd_xb_watches));
   1371 
   1372 	/*
   1373 	 * We can't hold xd_ndi_lk while we destroy the xd_xb_watch_taskq.
   1374 	 * This is because if there are currently any executing taskq threads,
   1375 	 * we will block until they are finished, and to finish they need
   1376 	 * to aquire xd_ndi_lk in i_xvdi_xb_watch_cb_tq() so they can release
   1377 	 * their reference on their corresponding xxwp structure.
   1378 	 */
   1379 	tq = pdp->xd_xb_watch_taskq;
   1380 	pdp->xd_xb_watch_taskq = NULL;
   1381 	mutex_exit(&pdp->xd_ndi_lk);
   1382 	if (tq != NULL)
   1383 		ddi_taskq_destroy(tq);
   1384 }
   1385 
   1386 static int
   1387 i_xvdi_add_watch_oestate(dev_info_t *dip)
   1388 {
   1389 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1390 
   1391 	ASSERT(pdp != NULL);
   1392 	ASSERT(pdp->xd_xsdev.nodename != NULL);
   1393 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
   1394 
   1395 	/*
   1396 	 * Create taskq for delivering other end state change event to
   1397 	 * this device later.
   1398 	 *
   1399 	 * Set nthreads to 1 to make sure that events can be delivered
   1400 	 * in order.
   1401 	 *
   1402 	 * Note: It is _not_ guaranteed that driver can see every
   1403 	 * xenstore change under the path that it is watching. If two
   1404 	 * changes happen consecutively in a very short amount of
   1405 	 * time, it is likely that the driver will see only the last
   1406 	 * one.
   1407 	 */
   1408 	if (pdp->xd_oe_taskq == NULL)
   1409 		if ((pdp->xd_oe_taskq = ddi_taskq_create(dip,
   1410 		    "xendev_oe_taskq", 1, TASKQ_DEFAULTPRI, 0)) == NULL)
   1411 			return (DDI_FAILURE);
   1412 
   1413 	/*
   1414 	 * Watch for changes to the XenbusState of otherend.
   1415 	 */
   1416 	pdp->xd_xsdev.otherend_state = XenbusStateUnknown;
   1417 	pdp->xd_xsdev.otherend_changed = i_xvdi_oestate_cb;
   1418 
   1419 	if (talk_to_otherend(&pdp->xd_xsdev) != 0) {
   1420 		i_xvdi_rem_watch_oestate(dip);
   1421 		return (DDI_FAILURE);
   1422 	}
   1423 
   1424 	return (DDI_SUCCESS);
   1425 }
   1426 
   1427 static void
   1428 i_xvdi_rem_watch_oestate(dev_info_t *dip)
   1429 {
   1430 	struct xendev_ppd *pdp;
   1431 	struct xenbus_device *dev;
   1432 
   1433 	pdp = ddi_get_parent_data(dip);
   1434 	ASSERT(pdp != NULL);
   1435 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
   1436 
   1437 	dev = &pdp->xd_xsdev;
   1438 
   1439 	/* Unwatch for changes to XenbusState of otherend */
   1440 	if (dev->otherend_watch.node != NULL) {
   1441 		mutex_exit(&pdp->xd_ndi_lk);
   1442 		unregister_xenbus_watch(&dev->otherend_watch);
   1443 		mutex_enter(&pdp->xd_ndi_lk);
   1444 	}
   1445 
   1446 	/* make sure no event handler is running */
   1447 	if (pdp->xd_oe_taskq != NULL) {
   1448 		mutex_exit(&pdp->xd_ndi_lk);
   1449 		ddi_taskq_destroy(pdp->xd_oe_taskq);
   1450 		mutex_enter(&pdp->xd_ndi_lk);
   1451 		pdp->xd_oe_taskq = NULL;
   1452 	}
   1453 
   1454 	/* clean up */
   1455 	dev->otherend_state = XenbusStateUnknown;
   1456 	dev->otherend_id = (domid_t)-1;
   1457 	if (dev->otherend_watch.node != NULL)
   1458 		kmem_free((void *)dev->otherend_watch.node,
   1459 		    strlen(dev->otherend_watch.node) + 1);
   1460 	dev->otherend_watch.node = NULL;
   1461 	if (dev->otherend != NULL)
   1462 		kmem_free((void *)dev->otherend, strlen(dev->otherend) + 1);
   1463 	dev->otherend = NULL;
   1464 }
   1465 
   1466 static int
   1467 i_xvdi_add_watch_hpstate(dev_info_t *dip)
   1468 {
   1469 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1470 
   1471 	ASSERT(pdp != NULL);
   1472 	ASSERT(pdp->xd_xsdev.frontend == 0);
   1473 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
   1474 
   1475 	/*
   1476 	 * Create taskq for delivering hotplug status change event to
   1477 	 * this device later.
   1478 	 *
   1479 	 * Set nthreads to 1 to make sure that events can be delivered
   1480 	 * in order.
   1481 	 *
   1482 	 * Note: It is _not_ guaranteed that driver can see every
   1483 	 * hotplug status change under the path that it is
   1484 	 * watching. If two changes happen consecutively in a very
   1485 	 * short amount of time, it is likely that the driver only
   1486 	 * sees the last one.
   1487 	 */
   1488 	if (pdp->xd_hp_taskq == NULL)
   1489 		if ((pdp->xd_hp_taskq = ddi_taskq_create(dip,
   1490 		    "xendev_hp_taskq", 1, TASKQ_DEFAULTPRI, 0)) == NULL)
   1491 			return (DDI_FAILURE);
   1492 
   1493 	if (pdp->xd_hp_watch.node == NULL) {
   1494 		size_t len;
   1495 		char *path;
   1496 
   1497 		ASSERT(pdp->xd_xsdev.nodename != NULL);
   1498 
   1499 		len = strlen(pdp->xd_xsdev.nodename) +
   1500 		    strlen("/hotplug-status") + 1;
   1501 		path = kmem_alloc(len, KM_SLEEP);
   1502 		(void) snprintf(path, len, "%s/hotplug-status",
   1503 		    pdp->xd_xsdev.nodename);
   1504 
   1505 		pdp->xd_hp_watch.node = path;
   1506 		pdp->xd_hp_watch.callback = i_xvdi_hpstate_cb;
   1507 		pdp->xd_hp_watch.dev = (struct xenbus_device *)dip; /* yuck! */
   1508 		if (register_xenbus_watch(&pdp->xd_hp_watch) != 0) {
   1509 			i_xvdi_rem_watch_hpstate(dip);
   1510 			return (DDI_FAILURE);
   1511 		}
   1512 	}
   1513 
   1514 	return (DDI_SUCCESS);
   1515 }
   1516 
   1517 static void
   1518 i_xvdi_rem_watch_hpstate(dev_info_t *dip)
   1519 {
   1520 	struct xendev_ppd *pdp;
   1521 	pdp = ddi_get_parent_data(dip);
   1522 
   1523 	ASSERT(pdp != NULL);
   1524 	ASSERT(pdp->xd_xsdev.frontend == 0);
   1525 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
   1526 
   1527 	/* Unwatch for changes to "hotplug-status" node for backend device. */
   1528 	if (pdp->xd_hp_watch.node != NULL) {
   1529 		mutex_exit(&pdp->xd_ndi_lk);
   1530 		unregister_xenbus_watch(&pdp->xd_hp_watch);
   1531 		mutex_enter(&pdp->xd_ndi_lk);
   1532 	}
   1533 
   1534 	/* Make sure no event handler is running. */
   1535 	if (pdp->xd_hp_taskq != NULL) {
   1536 		mutex_exit(&pdp->xd_ndi_lk);
   1537 		ddi_taskq_destroy(pdp->xd_hp_taskq);
   1538 		mutex_enter(&pdp->xd_ndi_lk);
   1539 		pdp->xd_hp_taskq = NULL;
   1540 	}
   1541 
   1542 	/* Clean up. */
   1543 	if (pdp->xd_hp_watch.node != NULL) {
   1544 		kmem_free((void *)pdp->xd_hp_watch.node,
   1545 		    strlen(pdp->xd_hp_watch.node) + 1);
   1546 		pdp->xd_hp_watch.node = NULL;
   1547 	}
   1548 }
   1549 
   1550 static int
   1551 i_xvdi_add_watches(dev_info_t *dip)
   1552 {
   1553 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1554 
   1555 	ASSERT(pdp != NULL);
   1556 
   1557 	mutex_enter(&pdp->xd_ndi_lk);
   1558 
   1559 	if (i_xvdi_add_watch_oestate(dip) != DDI_SUCCESS) {
   1560 		mutex_exit(&pdp->xd_ndi_lk);
   1561 		return (DDI_FAILURE);
   1562 	}
   1563 
   1564 	if (pdp->xd_xsdev.frontend == 1) {
   1565 		/*
   1566 		 * Frontend devices must watch for the backend path
   1567 		 * changing.
   1568 		 */
   1569 		if (i_xvdi_add_watch_bepath(dip) != DDI_SUCCESS)
   1570 			goto unwatch_and_fail;
   1571 	} else {
   1572 		/*
   1573 		 * Backend devices must watch for hotplug events.
   1574 		 */
   1575 		if (i_xvdi_add_watch_hpstate(dip) != DDI_SUCCESS)
   1576 			goto unwatch_and_fail;
   1577 	}
   1578 
   1579 	mutex_exit(&pdp->xd_ndi_lk);
   1580 
   1581 	return (DDI_SUCCESS);
   1582 
   1583 unwatch_and_fail:
   1584 	i_xvdi_rem_watch_oestate(dip);
   1585 	mutex_exit(&pdp->xd_ndi_lk);
   1586 
   1587 	return (DDI_FAILURE);
   1588 }
   1589 
   1590 static void
   1591 i_xvdi_rem_watches(dev_info_t *dip)
   1592 {
   1593 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1594 
   1595 	ASSERT(pdp != NULL);
   1596 
   1597 	mutex_enter(&pdp->xd_ndi_lk);
   1598 
   1599 	i_xvdi_rem_watch_oestate(dip);
   1600 
   1601 	if (pdp->xd_xsdev.frontend == 1)
   1602 		i_xvdi_rem_watch_bepath(dip);
   1603 	else
   1604 		i_xvdi_rem_watch_hpstate(dip);
   1605 
   1606 	mutex_exit(&pdp->xd_ndi_lk);
   1607 
   1608 	xvdi_remove_xb_watch_handlers(dip);
   1609 }
   1610 
   1611 static int
   1612 i_xvdi_add_watch_bepath(dev_info_t *dip)
   1613 {
   1614 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1615 
   1616 	ASSERT(pdp != NULL);
   1617 	ASSERT(pdp->xd_xsdev.frontend == 1);
   1618 
   1619 	/*
   1620 	 * Frontend devices need to watch for the backend path changing.
   1621 	 */
   1622 	if (pdp->xd_bepath_watch.node == NULL) {
   1623 		size_t len;
   1624 		char *path;
   1625 
   1626 		ASSERT(pdp->xd_xsdev.nodename != NULL);
   1627 
   1628 		len = strlen(pdp->xd_xsdev.nodename) + strlen("/backend") + 1;
   1629 		path = kmem_alloc(len, KM_SLEEP);
   1630 		(void) snprintf(path, len, "%s/backend",
   1631 		    pdp->xd_xsdev.nodename);
   1632 
   1633 		pdp->xd_bepath_watch.node = path;
   1634 		pdp->xd_bepath_watch.callback = i_xvdi_bepath_cb;
   1635 		pdp->xd_bepath_watch.dev = (struct xenbus_device *)dip;
   1636 		if (register_xenbus_watch(&pdp->xd_bepath_watch) != 0) {
   1637 			kmem_free(path, len);
   1638 			pdp->xd_bepath_watch.node = NULL;
   1639 			return (DDI_FAILURE);
   1640 		}
   1641 	}
   1642 
   1643 	return (DDI_SUCCESS);
   1644 }
   1645 
   1646 static void
   1647 i_xvdi_rem_watch_bepath(dev_info_t *dip)
   1648 {
   1649 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1650 
   1651 	ASSERT(pdp != NULL);
   1652 	ASSERT(pdp->xd_xsdev.frontend == 1);
   1653 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
   1654 
   1655 	if (pdp->xd_bepath_watch.node != NULL) {
   1656 		mutex_exit(&pdp->xd_ndi_lk);
   1657 		unregister_xenbus_watch(&pdp->xd_bepath_watch);
   1658 		mutex_enter(&pdp->xd_ndi_lk);
   1659 
   1660 		kmem_free((void *)(pdp->xd_bepath_watch.node),
   1661 		    strlen(pdp->xd_bepath_watch.node) + 1);
   1662 		pdp->xd_bepath_watch.node = NULL;
   1663 	}
   1664 }
   1665 
   1666 int
   1667 xvdi_switch_state(dev_info_t *dip, xenbus_transaction_t xbt,
   1668     XenbusState newState)
   1669 {
   1670 	int rv;
   1671 	struct xendev_ppd *pdp;
   1672 
   1673 	pdp = ddi_get_parent_data(dip);
   1674 	ASSERT(pdp != NULL);
   1675 
   1676 	XVDI_DPRINTF(XVDI_DBG_STATE,
   1677 	    "xvdi_switch_state: %s@%s's xenbus state moves to %d\n",
   1678 	    ddi_binding_name(dip) == NULL ? "null" : ddi_binding_name(dip),
   1679 	    ddi_get_name_addr(dip) == NULL ? "null" : ddi_get_name_addr(dip),
   1680 	    newState);
   1681 
   1682 	rv = xenbus_switch_state(&pdp->xd_xsdev, xbt, newState);
   1683 	if (rv > 0)
   1684 		cmn_err(CE_WARN, "xvdi_switch_state: change state failed");
   1685 
   1686 	return (rv);
   1687 }
   1688 
   1689 /*
   1690  * Notify hotplug script running in userland
   1691  */
   1692 int
   1693 xvdi_post_event(dev_info_t *dip, xendev_hotplug_cmd_t hpc)
   1694 {
   1695 	struct xendev_ppd *pdp;
   1696 	nvlist_t *attr_list = NULL;
   1697 	i_xd_cfg_t *xdcp;
   1698 	sysevent_id_t eid;
   1699 	int err;
   1700 	char devname[256]; /* XXPV dme: ? */
   1701 
   1702 	pdp = ddi_get_parent_data(dip);
   1703 	ASSERT(pdp != NULL);
   1704 
   1705 	xdcp = i_xvdi_devclass2cfg(pdp->xd_devclass);
   1706 	ASSERT(xdcp != NULL);
   1707 
   1708 	(void) snprintf(devname, sizeof (devname) - 1, "%s%d",
   1709 	    ddi_driver_name(dip),  ddi_get_instance(dip));
   1710 
   1711 	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME, KM_NOSLEEP);
   1712 	if (err != DDI_SUCCESS)
   1713 		goto failure;
   1714 
   1715 	err = nvlist_add_int32(attr_list, "domain", pdp->xd_domain);
   1716 	if (err != DDI_SUCCESS)
   1717 		goto failure;
   1718 	err = nvlist_add_int32(attr_list, "vdev", pdp->xd_vdevnum);
   1719 	if (err != DDI_SUCCESS)
   1720 		goto failure;
   1721 	err = nvlist_add_string(attr_list, "devclass", xdcp->xsdev);
   1722 	if (err != DDI_SUCCESS)
   1723 		goto failure;
   1724 	err = nvlist_add_string(attr_list, "device", devname);
   1725 	if (err != DDI_SUCCESS)
   1726 		goto failure;
   1727 	err = nvlist_add_string(attr_list, "fob",
   1728 	    ((pdp->xd_xsdev.frontend == 1) ? "frontend" : "backend"));
   1729 	if (err != DDI_SUCCESS)
   1730 		goto failure;
   1731 
   1732 	switch (hpc) {
   1733 	case XEN_HP_ADD:
   1734 		err = ddi_log_sysevent(dip, DDI_VENDOR_SUNW, "EC_xendev",
   1735 		    "add", attr_list, &eid, DDI_NOSLEEP);
   1736 		break;
   1737 	case XEN_HP_REMOVE:
   1738 		err = ddi_log_sysevent(dip, DDI_VENDOR_SUNW, "EC_xendev",
   1739 		    "remove", attr_list, &eid, DDI_NOSLEEP);
   1740 		break;
   1741 	default:
   1742 		err = DDI_FAILURE;
   1743 		goto failure;
   1744 	}
   1745 
   1746 failure:
   1747 	if (attr_list != NULL)
   1748 		nvlist_free(attr_list);
   1749 
   1750 	return (err);
   1751 }
   1752 
   1753 /* ARGSUSED */
   1754 static void
   1755 i_xvdi_probe_path_cb(struct xenbus_watch *w, const char **vec,
   1756     unsigned int len)
   1757 {
   1758 	char *path;
   1759 
   1760 	if (xendev_dip == NULL)
   1761 		xendev_dip = ddi_find_devinfo("xpvd", -1, 0);
   1762 
   1763 	path = i_ddi_strdup((char *)vec[XS_WATCH_PATH], KM_SLEEP);
   1764 
   1765 	(void) ddi_taskq_dispatch(DEVI(xendev_dip)->devi_taskq,
   1766 	    i_xvdi_probe_path_handler, (void *)path, DDI_SLEEP);
   1767 }
   1768 
   1769 static void
   1770 i_xvdi_watch_device(char *path)
   1771 {
   1772 	struct xenbus_watch *w;
   1773 
   1774 	ASSERT(path != NULL);
   1775 
   1776 	w = kmem_zalloc(sizeof (*w), KM_SLEEP);
   1777 	w->node = path;
   1778 	w->callback = &i_xvdi_probe_path_cb;
   1779 	w->dev = NULL;
   1780 
   1781 	if (register_xenbus_watch(w) != 0) {
   1782 		cmn_err(CE_WARN, "i_xvdi_watch_device: "
   1783 		    "cannot set watch on %s", path);
   1784 		kmem_free(w, sizeof (*w));
   1785 		return;
   1786 	}
   1787 }
   1788 
   1789 void
   1790 xvdi_watch_devices(int newstate)
   1791 {
   1792 	int devclass;
   1793 
   1794 	/*
   1795 	 * Watch for devices being created in the store.
   1796 	 */
   1797 	if (newstate == XENSTORE_DOWN)
   1798 		return;
   1799 	for (devclass = 0; devclass < NXDC; devclass++) {
   1800 		if (xdci[devclass].xs_path_fe != NULL)
   1801 			i_xvdi_watch_device(xdci[devclass].xs_path_fe);
   1802 		if (xdci[devclass].xs_path_be != NULL)
   1803 			i_xvdi_watch_device(xdci[devclass].xs_path_be);
   1804 	}
   1805 }
   1806 
   1807 /*
   1808  * Iterate over the store looking for backend devices to create.
   1809  */
   1810 static void
   1811 i_xvdi_enum_be(dev_info_t *parent, i_xd_cfg_t *xdcp)
   1812 {
   1813 	char **domains;
   1814 	unsigned int ndomains;
   1815 	int ldomains, i;
   1816 
   1817 	if ((domains = xenbus_directory(XBT_NULL, xdcp->xs_path_be, "",
   1818 	    &ndomains)) == NULL)
   1819 		return;
   1820 
   1821 	for (i = 0, ldomains = 0; i < ndomains; i++) {
   1822 		ldomains += strlen(domains[i]) + 1 + sizeof (char *);
   1823 
   1824 		i_xvdi_enum_worker(parent, xdcp, domains[i]);
   1825 	}
   1826 	kmem_free(domains, ldomains);
   1827 }
   1828 
   1829 /*
   1830  * Iterate over the store looking for frontend devices to create.
   1831  */
   1832 static void
   1833 i_xvdi_enum_fe(dev_info_t *parent, i_xd_cfg_t *xdcp)
   1834 {
   1835 	i_xvdi_enum_worker(parent, xdcp, NULL);
   1836 }
   1837 
   1838 static void
   1839 i_xvdi_enum_worker(dev_info_t *parent, i_xd_cfg_t *xdcp,
   1840     char *domain)
   1841 {
   1842 	char *path, *domain_path, *ep;
   1843 	char **devices;
   1844 	unsigned int ndevices;
   1845 	int ldevices, j, circ;
   1846 	domid_t dom;
   1847 	long tmplong;
   1848 
   1849 	if (domain == NULL) {
   1850 		dom = DOMID_SELF;
   1851 		path = xdcp->xs_path_fe;
   1852 		domain_path = "";
   1853 	} else {
   1854 		(void) ddi_strtol(domain, &ep, 0, &tmplong);
   1855 		dom = tmplong;
   1856 		path = xdcp->xs_path_be;
   1857 		domain_path = domain;
   1858 	}
   1859 
   1860 	if ((devices = xenbus_directory(XBT_NULL, path, domain_path,
   1861 	    &ndevices)) == NULL)
   1862 		return;
   1863 
   1864 	for (j = 0, ldevices = 0; j < ndevices; j++) {
   1865 		int vdev;
   1866 
   1867 		ldevices += strlen(devices[j]) + 1 + sizeof (char *);
   1868 		(void) ddi_strtol(devices[j], &ep, 0, &tmplong);
   1869 		vdev = tmplong;
   1870 
   1871 		ndi_devi_enter(parent, &circ);
   1872 
   1873 		if (xvdi_find_dev(parent, xdcp->devclass, dom, vdev) == NULL)
   1874 			(void) xvdi_create_dev(parent, xdcp->devclass,
   1875 			    dom, vdev);
   1876 
   1877 		ndi_devi_exit(parent, circ);
   1878 	}
   1879 	kmem_free(devices, ldevices);
   1880 }
   1881 
   1882 /*
   1883  * Leaf drivers should call this in their detach() routine during suspend.
   1884  */
   1885 void
   1886 xvdi_suspend(dev_info_t *dip)
   1887 {
   1888 	i_xvdi_rem_watches(dip);
   1889 }
   1890 
   1891 /*
   1892  * Leaf drivers should call this in their attach() routine during resume.
   1893  */
   1894 int
   1895 xvdi_resume(dev_info_t *dip)
   1896 {
   1897 	return (i_xvdi_add_watches(dip));
   1898 }
   1899 
   1900 /*
   1901  * Add event handler for the leaf driver
   1902  * to handle event triggered by the change in xenstore
   1903  */
   1904 int
   1905 xvdi_add_event_handler(dev_info_t *dip, char *name,
   1906     void (*evthandler)(dev_info_t *, ddi_eventcookie_t, void *, void *),
   1907     void *arg)
   1908 {
   1909 	ddi_eventcookie_t ecv;
   1910 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   1911 	ddi_callback_id_t *cbid;
   1912 	boolean_t call_handler;
   1913 	i_oestate_evt_t *evt = NULL;
   1914 	XenbusState oestate;
   1915 
   1916 	ASSERT(pdp != NULL);
   1917 
   1918 	mutex_enter(&pdp->xd_ndi_lk);
   1919 
   1920 	if (strcmp(name, XS_OE_STATE) == 0) {
   1921 		ASSERT(pdp->xd_xsdev.otherend != NULL);
   1922 
   1923 		cbid = &pdp->xd_oe_ehid;
   1924 	} else if (strcmp(name, XS_HP_STATE) == 0) {
   1925 		if (pdp->xd_xsdev.frontend == 1) {
   1926 			mutex_exit(&pdp->xd_ndi_lk);
   1927 			return (DDI_FAILURE);
   1928 		}
   1929 
   1930 		ASSERT(pdp->xd_hp_watch.node != NULL);
   1931 
   1932 		cbid = &pdp->xd_hp_ehid;
   1933 	} else {
   1934 		/* Unsupported watch. */
   1935 		mutex_exit(&pdp->xd_ndi_lk);
   1936 		return (DDI_FAILURE);
   1937 	}
   1938 
   1939 	/*
   1940 	 * No event handler provided, take default action to handle
   1941 	 * event.
   1942 	 */
   1943 	if (evthandler == NULL) {
   1944 		mutex_exit(&pdp->xd_ndi_lk);
   1945 		return (DDI_SUCCESS);
   1946 	}
   1947 
   1948 	ASSERT(*cbid == NULL);
   1949 
   1950 	if (ddi_get_eventcookie(dip, name, &ecv) != DDI_SUCCESS) {
   1951 		cmn_err(CE_WARN, "failed to find %s cookie for %s@%s",
   1952 		    name, ddi_get_name(dip), ddi_get_name_addr(dip));
   1953 		mutex_exit(&pdp->xd_ndi_lk);
   1954 		return (DDI_FAILURE);
   1955 	}
   1956 	if (ddi_add_event_handler(dip, ecv, evthandler, arg, cbid)
   1957 	    != DDI_SUCCESS) {
   1958 		cmn_err(CE_WARN, "failed to add %s event handler for %s@%s",
   1959 		    name, ddi_get_name(dip), ddi_get_name_addr(dip));
   1960 		*cbid = NULL;
   1961 		mutex_exit(&pdp->xd_ndi_lk);
   1962 		return (DDI_FAILURE);
   1963 	}
   1964 
   1965 	/*
   1966 	 * if we're adding an oe state callback, and the ring has already
   1967 	 * transitioned out of Unknown, call the handler after we release
   1968 	 * the mutex.
   1969 	 */
   1970 	call_handler = B_FALSE;
   1971 	if ((strcmp(name, XS_OE_STATE) == 0) &&
   1972 	    (pdp->xd_xsdev.otherend_state != XenbusStateUnknown)) {
   1973 		oestate = pdp->xd_xsdev.otherend_state;
   1974 		call_handler = B_TRUE;
   1975 	}
   1976 
   1977 	mutex_exit(&pdp->xd_ndi_lk);
   1978 
   1979 	if (call_handler) {
   1980 		evt = kmem_alloc(sizeof (i_oestate_evt_t), KM_SLEEP);
   1981 		evt->dip = dip;
   1982 		evt->state = oestate;
   1983 		(void) ddi_taskq_dispatch(pdp->xd_oe_taskq,
   1984 		    i_xvdi_oestate_handler, (void *)evt, DDI_SLEEP);
   1985 	}
   1986 
   1987 	return (DDI_SUCCESS);
   1988 }
   1989 
   1990 /*
   1991  * Remove event handler for the leaf driver and unwatch xenstore
   1992  * so, driver will not be notified when xenstore entry changed later
   1993  */
   1994 void
   1995 xvdi_remove_event_handler(dev_info_t *dip, char *name)
   1996 {
   1997 	struct xendev_ppd *pdp;
   1998 	boolean_t rem_oe = B_FALSE, rem_hp = B_FALSE;
   1999 	ddi_callback_id_t oeid = NULL, hpid = NULL;
   2000 
   2001 	pdp = ddi_get_parent_data(dip);
   2002 	ASSERT(pdp != NULL);
   2003 
   2004 	if (name == NULL) {
   2005 		rem_oe = B_TRUE;
   2006 		rem_hp = B_TRUE;
   2007 	} else if (strcmp(name, XS_OE_STATE) == 0) {
   2008 		rem_oe = B_TRUE;
   2009 	} else if (strcmp(name, XS_HP_STATE) == 0) {
   2010 		rem_hp = B_TRUE;
   2011 	} else {
   2012 		cmn_err(CE_WARN, "event %s not supported, cannot remove", name);
   2013 		return;
   2014 	}
   2015 
   2016 	mutex_enter(&pdp->xd_ndi_lk);
   2017 
   2018 	if (rem_oe && (pdp->xd_oe_ehid != NULL)) {
   2019 		oeid = pdp->xd_oe_ehid;
   2020 		pdp->xd_oe_ehid = NULL;
   2021 	}
   2022 
   2023 	if (rem_hp && (pdp->xd_hp_ehid != NULL)) {
   2024 		hpid = pdp->xd_hp_ehid;
   2025 		pdp->xd_hp_ehid = NULL;
   2026 	}
   2027 
   2028 	mutex_exit(&pdp->xd_ndi_lk);
   2029 
   2030 	if (oeid != NULL)
   2031 		(void) ddi_remove_event_handler(oeid);
   2032 	if (hpid != NULL)
   2033 		(void) ddi_remove_event_handler(hpid);
   2034 }
   2035 
   2036 
   2037 /*
   2038  * common ring interfaces
   2039  */
   2040 
   2041 #define	FRONT_RING(_ringp)	(&(_ringp)->xr_sring.fr)
   2042 #define	BACK_RING(_ringp)	(&(_ringp)->xr_sring.br)
   2043 #define	GET_RING_SIZE(_ringp)	RING_SIZE(FRONT_RING(ringp))
   2044 #define	GET_RING_ENTRY_FE(_ringp, _idx)		\
   2045 	(FRONT_RING(_ringp)->sring->ring +	\
   2046 	(_ringp)->xr_entry_size * ((_idx) & (GET_RING_SIZE(_ringp) - 1)))
   2047 #define	GET_RING_ENTRY_BE(_ringp, _idx)		\
   2048 	(BACK_RING(_ringp)->sring->ring +	\
   2049 	(_ringp)->xr_entry_size * ((_idx) & (GET_RING_SIZE(_ringp) - 1)))
   2050 
   2051 unsigned int
   2052 xvdi_ring_avail_slots(xendev_ring_t *ringp)
   2053 {
   2054 	comif_ring_fe_t *frp;
   2055 	comif_ring_be_t *brp;
   2056 
   2057 	if (ringp->xr_frontend) {
   2058 		frp = FRONT_RING(ringp);
   2059 		return (GET_RING_SIZE(ringp) -
   2060 		    (frp->req_prod_pvt - frp->rsp_cons));
   2061 	} else {
   2062 		brp = BACK_RING(ringp);
   2063 		return (GET_RING_SIZE(ringp) -
   2064 		    (brp->rsp_prod_pvt - brp->req_cons));
   2065 	}
   2066 }
   2067 
   2068 int
   2069 xvdi_ring_has_unconsumed_requests(xendev_ring_t *ringp)
   2070 {
   2071 	comif_ring_be_t *brp;
   2072 
   2073 	ASSERT(!ringp->xr_frontend);
   2074 	brp = BACK_RING(ringp);
   2075 	return ((brp->req_cons !=
   2076 	    ddi_get32(ringp->xr_acc_hdl, &brp->sring->req_prod)) &&
   2077 	    ((brp->req_cons - brp->rsp_prod_pvt) != RING_SIZE(brp)));
   2078 }
   2079 
   2080 int
   2081 xvdi_ring_has_incomp_request(xendev_ring_t *ringp)
   2082 {
   2083 	comif_ring_fe_t *frp;
   2084 
   2085 	ASSERT(ringp->xr_frontend);
   2086 	frp = FRONT_RING(ringp);
   2087 	return (frp->req_prod_pvt !=
   2088 	    ddi_get32(ringp->xr_acc_hdl, &frp->sring->rsp_prod));
   2089 }
   2090 
   2091 int
   2092 xvdi_ring_has_unconsumed_responses(xendev_ring_t *ringp)
   2093 {
   2094 	comif_ring_fe_t *frp;
   2095 
   2096 	ASSERT(ringp->xr_frontend);
   2097 	frp = FRONT_RING(ringp);
   2098 	return (frp->rsp_cons !=
   2099 	    ddi_get32(ringp->xr_acc_hdl, &frp->sring->rsp_prod));
   2100 }
   2101 
   2102 /* NOTE: req_event will be increased as needed */
   2103 void *
   2104 xvdi_ring_get_request(xendev_ring_t *ringp)
   2105 {
   2106 	comif_ring_fe_t *frp;
   2107 	comif_ring_be_t *brp;
   2108 
   2109 	if (ringp->xr_frontend) {
   2110 		/* for frontend ring */
   2111 		frp = FRONT_RING(ringp);
   2112 		if (!RING_FULL(frp))
   2113 			return (GET_RING_ENTRY_FE(ringp, frp->req_prod_pvt++));
   2114 		else
   2115 			return (NULL);
   2116 	} else {
   2117 		/* for backend ring */
   2118 		brp = BACK_RING(ringp);
   2119 		/* RING_FINAL_CHECK_FOR_REQUESTS() */
   2120 		if (xvdi_ring_has_unconsumed_requests(ringp))
   2121 			return (GET_RING_ENTRY_BE(ringp, brp->req_cons++));
   2122 		else {
   2123 			ddi_put32(ringp->xr_acc_hdl, &brp->sring->req_event,
   2124 			    brp->req_cons + 1);
   2125 			membar_enter();
   2126 			if (xvdi_ring_has_unconsumed_requests(ringp))
   2127 				return (GET_RING_ENTRY_BE(ringp,
   2128 				    brp->req_cons++));
   2129 			else
   2130 				return (NULL);
   2131 		}
   2132 	}
   2133 }
   2134 
   2135 int
   2136 xvdi_ring_push_request(xendev_ring_t *ringp)
   2137 {
   2138 	RING_IDX old, new, reqevt;
   2139 	comif_ring_fe_t *frp;
   2140 
   2141 	/* only frontend should be able to push request */
   2142 	ASSERT(ringp->xr_frontend);
   2143 
   2144 	/* RING_PUSH_REQUEST_AND_CHECK_NOTIFY() */
   2145 	frp = FRONT_RING(ringp);
   2146 	old = ddi_get32(ringp->xr_acc_hdl, &frp->sring->req_prod);
   2147 	new = frp->req_prod_pvt;
   2148 	ddi_put32(ringp->xr_acc_hdl, &frp->sring->req_prod, new);
   2149 	membar_enter();
   2150 	reqevt = ddi_get32(ringp->xr_acc_hdl, &frp->sring->req_event);
   2151 	return ((RING_IDX)(new - reqevt) < (RING_IDX)(new - old));
   2152 }
   2153 
   2154 /* NOTE: rsp_event will be increased as needed */
   2155 void *
   2156 xvdi_ring_get_response(xendev_ring_t *ringp)
   2157 {
   2158 	comif_ring_fe_t *frp;
   2159 	comif_ring_be_t *brp;
   2160 
   2161 	if (!ringp->xr_frontend) {
   2162 		/* for backend ring */
   2163 		brp = BACK_RING(ringp);
   2164 		return (GET_RING_ENTRY_BE(ringp, brp->rsp_prod_pvt++));
   2165 	} else {
   2166 		/* for frontend ring */
   2167 		frp = FRONT_RING(ringp);
   2168 		/* RING_FINAL_CHECK_FOR_RESPONSES() */
   2169 		if (xvdi_ring_has_unconsumed_responses(ringp))
   2170 			return (GET_RING_ENTRY_FE(ringp, frp->rsp_cons++));
   2171 		else {
   2172 			ddi_put32(ringp->xr_acc_hdl, &frp->sring->rsp_event,
   2173 			    frp->rsp_cons + 1);
   2174 			membar_enter();
   2175 			if (xvdi_ring_has_unconsumed_responses(ringp))
   2176 				return (GET_RING_ENTRY_FE(ringp,
   2177 				    frp->rsp_cons++));
   2178 			else
   2179 				return (NULL);
   2180 		}
   2181 	}
   2182 }
   2183 
   2184 int
   2185 xvdi_ring_push_response(xendev_ring_t *ringp)
   2186 {
   2187 	RING_IDX old, new, rspevt;
   2188 	comif_ring_be_t *brp;
   2189 
   2190 	/* only backend should be able to push response */
   2191 	ASSERT(!ringp->xr_frontend);
   2192 
   2193 	/* RING_PUSH_RESPONSE_AND_CHECK_NOTIFY() */
   2194 	brp = BACK_RING(ringp);
   2195 	old = ddi_get32(ringp->xr_acc_hdl, &brp->sring->rsp_prod);
   2196 	new = brp->rsp_prod_pvt;
   2197 	ddi_put32(ringp->xr_acc_hdl, &brp->sring->rsp_prod, new);
   2198 	membar_enter();
   2199 	rspevt = ddi_get32(ringp->xr_acc_hdl, &brp->sring->rsp_event);
   2200 	return ((RING_IDX)(new - rspevt) < (RING_IDX)(new - old));
   2201 }
   2202 
   2203 static void
   2204 xvdi_ring_init_sring(xendev_ring_t *ringp)
   2205 {
   2206 	ddi_acc_handle_t acchdl;
   2207 	comif_sring_t *xsrp;
   2208 	int i;
   2209 
   2210 	xsrp = (comif_sring_t *)ringp->xr_vaddr;
   2211 	acchdl = ringp->xr_acc_hdl;
   2212 
   2213 	/* shared ring initialization */
   2214 	ddi_put32(acchdl, &xsrp->req_prod, 0);
   2215 	ddi_put32(acchdl, &xsrp->rsp_prod, 0);
   2216 	ddi_put32(acchdl, &xsrp->req_event, 1);
   2217 	ddi_put32(acchdl, &xsrp->rsp_event, 1);
   2218 	for (i = 0; i < sizeof (xsrp->pad); i++)
   2219 		ddi_put8(acchdl, xsrp->pad + i, 0);
   2220 }
   2221 
   2222 static void
   2223 xvdi_ring_init_front_ring(xendev_ring_t *ringp, size_t nentry, size_t entrysize)
   2224 {
   2225 	comif_ring_fe_t *xfrp;
   2226 
   2227 	xfrp = &ringp->xr_sring.fr;
   2228 	xfrp->req_prod_pvt = 0;
   2229 	xfrp->rsp_cons = 0;
   2230 	xfrp->nr_ents = nentry;
   2231 	xfrp->sring = (comif_sring_t *)ringp->xr_vaddr;
   2232 
   2233 	ringp->xr_frontend = 1;
   2234 	ringp->xr_entry_size = entrysize;
   2235 }
   2236 
   2237 #ifndef XPV_HVM_DRIVER
   2238 static void
   2239 xvdi_ring_init_back_ring(xendev_ring_t *ringp, size_t nentry, size_t entrysize)
   2240 {
   2241 	comif_ring_be_t *xbrp;
   2242 
   2243 	xbrp = &ringp->xr_sring.br;
   2244 	xbrp->rsp_prod_pvt = 0;
   2245 	xbrp->req_cons = 0;
   2246 	xbrp->nr_ents = nentry;
   2247 	xbrp->sring = (comif_sring_t *)ringp->xr_vaddr;
   2248 
   2249 	ringp->xr_frontend = 0;
   2250 	ringp->xr_entry_size = entrysize;
   2251 }
   2252 #endif /* XPV_HVM_DRIVER */
   2253 
   2254 static void
   2255 xendev_offline_device(void *arg)
   2256 {
   2257 	dev_info_t *dip = (dev_info_t *)arg;
   2258 	char devname[MAXNAMELEN] = {0};
   2259 
   2260 	/*
   2261 	 * This is currently the only chance to delete a devinfo node, which
   2262 	 * is _not_ always successful.
   2263 	 */
   2264 	(void) ddi_deviname(dip, devname);
   2265 	(void) devfs_clean(ddi_get_parent(dip), devname + 1, DV_CLEAN_FORCE);
   2266 	(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
   2267 }
   2268 
   2269 static void
   2270 i_xvdi_oestate_cb(struct xenbus_device *dev, XenbusState oestate)
   2271 {
   2272 	dev_info_t *dip = (dev_info_t *)dev->data;
   2273 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   2274 	i_oestate_evt_t *evt = NULL;
   2275 	boolean_t call_handler;
   2276 
   2277 	XVDI_DPRINTF(XVDI_DBG_STATE,
   2278 	    "i_xvdi_oestate_cb: %s@%s sees oestate change to %d\n",
   2279 	    ddi_binding_name(dip) == NULL ? "null" : ddi_binding_name(dip),
   2280 	    ddi_get_name_addr(dip) == NULL ? "null" : ddi_get_name_addr(dip),
   2281 	    oestate);
   2282 
   2283 	/* only call the handler if our state has changed */
   2284 	call_handler = B_FALSE;
   2285 	mutex_enter(&pdp->xd_ndi_lk);
   2286 	if (dev->otherend_state != oestate) {
   2287 		dev->otherend_state = oestate;
   2288 		call_handler = B_TRUE;
   2289 	}
   2290 	mutex_exit(&pdp->xd_ndi_lk);
   2291 
   2292 	if (call_handler) {
   2293 		/*
   2294 		 * Try to deliver the oestate change event to the dip
   2295 		 */
   2296 		evt = kmem_alloc(sizeof (i_oestate_evt_t), KM_SLEEP);
   2297 		evt->dip = dip;
   2298 		evt->state = oestate;
   2299 		(void) ddi_taskq_dispatch(pdp->xd_oe_taskq,
   2300 		    i_xvdi_oestate_handler, (void *)evt, DDI_SLEEP);
   2301 	}
   2302 }
   2303 
   2304 /*ARGSUSED*/
   2305 static void
   2306 i_xvdi_hpstate_cb(struct xenbus_watch *w, const char **vec,
   2307     unsigned int len)
   2308 {
   2309 	dev_info_t *dip = (dev_info_t *)w->dev;
   2310 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
   2311 
   2312 #ifdef DEBUG
   2313 	char *hp_status = NULL;
   2314 	unsigned int hpl = 0;
   2315 
   2316 	(void) xenbus_read(XBT_NULL, pdp->xd_hp_watch.node, "",
   2317 	    (void *)&hp_status, &hpl);
   2318 	XVDI_DPRINTF(XVDI_DBG_STATE,
   2319 	    "i_xvdi_hpstate_cb: %s@%s sees hpstate change to %s\n",
   2320 	    ddi_binding_name(dip) == NULL ?  "null" : ddi_binding_name(dip),
   2321 	    ddi_get_name_addr(dip) == NULL ?  "null" : ddi_get_name_addr(dip),
   2322 	    hp_status == NULL ? "null" : hp_status);
   2323 	if (hp_status != NULL)
   2324 		kmem_free(hp_status, hpl);
   2325 #endif /* DEBUG */
   2326 
   2327 	(void) ddi_taskq_dispatch(pdp->xd_hp_taskq,
   2328 	    i_xvdi_hpstate_handler, (void *)dip, DDI_SLEEP);
   2329 }
   2330 
   2331 static void
   2332 i_xvdi_probe_path_handler(void *arg)
   2333 {
   2334 	dev_info_t *parent;
   2335 	char *path = arg, *p = NULL;
   2336 	int i, vdev, circ;
   2337 	i_xd_cfg_t *xdcp;
   2338 	boolean_t frontend;
   2339 	domid_t dom;
   2340 
   2341 	for (i = 0, xdcp = &xdci[0]; i < NXDC; i++, xdcp++) {
   2342 
   2343 		if ((xdcp->xs_path_fe != NULL) &&
   2344 		    (strncmp(path, xdcp->xs_path_fe, strlen(xdcp->xs_path_fe))
   2345 		    == 0)) {
   2346 
   2347 			frontend = B_TRUE;
   2348 			p = path + strlen(xdcp->xs_path_fe);
   2349 			break;
   2350 		}
   2351 
   2352 		if ((xdcp->xs_path_be != NULL) &&
   2353 		    (strncmp(path, xdcp->xs_path_be, strlen(xdcp->xs_path_be))
   2354 		    == 0)) {
   2355 
   2356 			frontend = B_FALSE;
   2357 			p = path + strlen(xdcp->xs_path_be);
   2358 			break;
   2359 		}
   2360 
   2361 	}
   2362 
   2363 	if (p == NULL) {
   2364 		cmn_err(CE_WARN, "i_xvdi_probe_path_handler: "
   2365 		    "unexpected path prefix in %s", path);
   2366 		goto done;
   2367 	}
   2368 
   2369 	if (frontend) {
   2370 		dom = DOMID_SELF;
   2371 		if (sscanf(p, "/%d/", &vdev) != 1) {
   2372 			XVDI_DPRINTF(XVDI_DBG_PROBE,
   2373 			    "i_xvdi_probe_path_handler: "
   2374 			    "cannot parse frontend path %s",
   2375 			    path);
   2376 			goto done;
   2377 		}
   2378 	} else {
   2379 		if (sscanf(p, "/%hu/%d/", &dom, &vdev) != 2) {
   2380 			XVDI_DPRINTF(XVDI_DBG_PROBE,
   2381 			    "i_xvdi_probe_path_handler: "
   2382 			    "cannot parse backend path %s",
   2383 			    path);
   2384 			goto done;
   2385 		}
   2386 	}
   2387 
   2388 	/*
   2389 	 * This is an oxymoron, so indicates a bogus configuration we
   2390 	 * must check for.
   2391 	 */
   2392 	if (vdev == VDEV_NOXS) {
   2393 		cmn_err(CE_WARN, "i_xvdi_probe_path_handler: "
   2394 		    "invalid path %s", path);
   2395 		goto done;
   2396 	}
   2397 
   2398 	parent = xendev_dip;
   2399 	ASSERT(parent != NULL);
   2400 
   2401 	ndi_devi_enter(parent, &circ);
   2402 
   2403 	if (xvdi_find_dev(parent, xdcp->devclass, dom, vdev) == NULL) {
   2404 		XVDI_DPRINTF(XVDI_DBG_PROBE,
   2405 		    "i_xvdi_probe_path_handler: create for %s", path);
   2406 		(void) xvdi_create_dev(parent, xdcp->devclass, dom, vdev);
   2407 	} else {
   2408 		XVDI_DPRINTF(XVDI_DBG_PROBE,
   2409 		    "i_xvdi_probe_path_handler: %s already exists", path);
   2410 	}
   2411 
   2412 	ndi_devi_exit(parent, circ);
   2413 
   2414 done:
   2415 	kmem_free(path, strlen(path) + 1);
   2416 }
   2417