xref: /titanic_51/usr/src/uts/common/xen/os/xvdi.c (revision 7f0b8309074a5d8e9f9d8ffe7aad7bb0b1ee6b1f)
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 		unregister_xenbus_watch(&xxwp->xxw_watch);
1366 		i_xvdi_xb_watch_release(xxwp);
1367 	}
1368 	ASSERT(list_is_empty(&pdp->xd_xb_watches));
1369 
1370 	/*
1371 	 * We can't hold xd_ndi_lk while we destroy the xd_xb_watch_taskq.
1372 	 * This is because if there are currently any executing taskq threads,
1373 	 * we will block until they are finished, and to finish they need
1374 	 * to aquire xd_ndi_lk in i_xvdi_xb_watch_cb_tq() so they can release
1375 	 * their reference on their corresponding xxwp structure.
1376 	 */
1377 	tq = pdp->xd_xb_watch_taskq;
1378 	pdp->xd_xb_watch_taskq = NULL;
1379 	mutex_exit(&pdp->xd_ndi_lk);
1380 	if (tq != NULL)
1381 		ddi_taskq_destroy(tq);
1382 }
1383 
1384 static int
1385 i_xvdi_add_watch_oestate(dev_info_t *dip)
1386 {
1387 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
1388 
1389 	ASSERT(pdp != NULL);
1390 	ASSERT(pdp->xd_xsdev.nodename != NULL);
1391 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
1392 
1393 	/*
1394 	 * Create taskq for delivering other end state change event to
1395 	 * this device later.
1396 	 *
1397 	 * Set nthreads to 1 to make sure that events can be delivered
1398 	 * in order.
1399 	 *
1400 	 * Note: It is _not_ guaranteed that driver can see every
1401 	 * xenstore change under the path that it is watching. If two
1402 	 * changes happen consecutively in a very short amount of
1403 	 * time, it is likely that the driver will see only the last
1404 	 * one.
1405 	 */
1406 	if (pdp->xd_oe_taskq == NULL)
1407 		if ((pdp->xd_oe_taskq = ddi_taskq_create(dip,
1408 		    "xendev_oe_taskq", 1, TASKQ_DEFAULTPRI, 0)) == NULL)
1409 			return (DDI_FAILURE);
1410 
1411 	/*
1412 	 * Watch for changes to the XenbusState of otherend.
1413 	 */
1414 	pdp->xd_xsdev.otherend_state = XenbusStateUnknown;
1415 	pdp->xd_xsdev.otherend_changed = i_xvdi_oestate_cb;
1416 
1417 	if (talk_to_otherend(&pdp->xd_xsdev) != 0) {
1418 		i_xvdi_rem_watch_oestate(dip);
1419 		return (DDI_FAILURE);
1420 	}
1421 
1422 	return (DDI_SUCCESS);
1423 }
1424 
1425 static void
1426 i_xvdi_rem_watch_oestate(dev_info_t *dip)
1427 {
1428 	struct xendev_ppd *pdp;
1429 	struct xenbus_device *dev;
1430 
1431 	pdp = ddi_get_parent_data(dip);
1432 	ASSERT(pdp != NULL);
1433 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
1434 
1435 	dev = &pdp->xd_xsdev;
1436 
1437 	/* Unwatch for changes to XenbusState of otherend */
1438 	if (dev->otherend_watch.node != NULL) {
1439 		mutex_exit(&pdp->xd_ndi_lk);
1440 		unregister_xenbus_watch(&dev->otherend_watch);
1441 		mutex_enter(&pdp->xd_ndi_lk);
1442 	}
1443 
1444 	/* make sure no event handler is running */
1445 	if (pdp->xd_oe_taskq != NULL) {
1446 		mutex_exit(&pdp->xd_ndi_lk);
1447 		ddi_taskq_destroy(pdp->xd_oe_taskq);
1448 		mutex_enter(&pdp->xd_ndi_lk);
1449 		pdp->xd_oe_taskq = NULL;
1450 	}
1451 
1452 	/* clean up */
1453 	dev->otherend_state = XenbusStateUnknown;
1454 	dev->otherend_id = (domid_t)-1;
1455 	if (dev->otherend_watch.node != NULL)
1456 		kmem_free((void *)dev->otherend_watch.node,
1457 		    strlen(dev->otherend_watch.node) + 1);
1458 	dev->otherend_watch.node = NULL;
1459 	if (dev->otherend != NULL)
1460 		kmem_free((void *)dev->otherend, strlen(dev->otherend) + 1);
1461 	dev->otherend = NULL;
1462 }
1463 
1464 static int
1465 i_xvdi_add_watch_hpstate(dev_info_t *dip)
1466 {
1467 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
1468 
1469 	ASSERT(pdp != NULL);
1470 	ASSERT(pdp->xd_xsdev.frontend == 0);
1471 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
1472 
1473 	/*
1474 	 * Create taskq for delivering hotplug status change event to
1475 	 * this device later.
1476 	 *
1477 	 * Set nthreads to 1 to make sure that events can be delivered
1478 	 * in order.
1479 	 *
1480 	 * Note: It is _not_ guaranteed that driver can see every
1481 	 * hotplug status change under the path that it is
1482 	 * watching. If two changes happen consecutively in a very
1483 	 * short amount of time, it is likely that the driver only
1484 	 * sees the last one.
1485 	 */
1486 	if (pdp->xd_hp_taskq == NULL)
1487 		if ((pdp->xd_hp_taskq = ddi_taskq_create(dip,
1488 		    "xendev_hp_taskq", 1, TASKQ_DEFAULTPRI, 0)) == NULL)
1489 			return (DDI_FAILURE);
1490 
1491 	if (pdp->xd_hp_watch.node == NULL) {
1492 		size_t len;
1493 		char *path;
1494 
1495 		ASSERT(pdp->xd_xsdev.nodename != NULL);
1496 
1497 		len = strlen(pdp->xd_xsdev.nodename) +
1498 		    strlen("/hotplug-status") + 1;
1499 		path = kmem_alloc(len, KM_SLEEP);
1500 		(void) snprintf(path, len, "%s/hotplug-status",
1501 		    pdp->xd_xsdev.nodename);
1502 
1503 		pdp->xd_hp_watch.node = path;
1504 		pdp->xd_hp_watch.callback = i_xvdi_hpstate_cb;
1505 		pdp->xd_hp_watch.dev = (struct xenbus_device *)dip; /* yuck! */
1506 		if (register_xenbus_watch(&pdp->xd_hp_watch) != 0) {
1507 			i_xvdi_rem_watch_hpstate(dip);
1508 			return (DDI_FAILURE);
1509 		}
1510 	}
1511 
1512 	return (DDI_SUCCESS);
1513 }
1514 
1515 static void
1516 i_xvdi_rem_watch_hpstate(dev_info_t *dip)
1517 {
1518 	struct xendev_ppd *pdp;
1519 	pdp = ddi_get_parent_data(dip);
1520 
1521 	ASSERT(pdp != NULL);
1522 	ASSERT(pdp->xd_xsdev.frontend == 0);
1523 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
1524 
1525 	/* Unwatch for changes to "hotplug-status" node for backend device. */
1526 	if (pdp->xd_hp_watch.node != NULL) {
1527 		mutex_exit(&pdp->xd_ndi_lk);
1528 		unregister_xenbus_watch(&pdp->xd_hp_watch);
1529 		mutex_enter(&pdp->xd_ndi_lk);
1530 	}
1531 
1532 	/* Make sure no event handler is running. */
1533 	if (pdp->xd_hp_taskq != NULL) {
1534 		mutex_exit(&pdp->xd_ndi_lk);
1535 		ddi_taskq_destroy(pdp->xd_hp_taskq);
1536 		mutex_enter(&pdp->xd_ndi_lk);
1537 		pdp->xd_hp_taskq = NULL;
1538 	}
1539 
1540 	/* Clean up. */
1541 	if (pdp->xd_hp_watch.node != NULL) {
1542 		kmem_free((void *)pdp->xd_hp_watch.node,
1543 		    strlen(pdp->xd_hp_watch.node) + 1);
1544 		pdp->xd_hp_watch.node = NULL;
1545 	}
1546 }
1547 
1548 static int
1549 i_xvdi_add_watches(dev_info_t *dip)
1550 {
1551 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
1552 
1553 	ASSERT(pdp != NULL);
1554 
1555 	mutex_enter(&pdp->xd_ndi_lk);
1556 
1557 	if (i_xvdi_add_watch_oestate(dip) != DDI_SUCCESS) {
1558 		mutex_exit(&pdp->xd_ndi_lk);
1559 		return (DDI_FAILURE);
1560 	}
1561 
1562 	if (pdp->xd_xsdev.frontend == 1) {
1563 		/*
1564 		 * Frontend devices must watch for the backend path
1565 		 * changing.
1566 		 */
1567 		if (i_xvdi_add_watch_bepath(dip) != DDI_SUCCESS)
1568 			goto unwatch_and_fail;
1569 	} else {
1570 		/*
1571 		 * Backend devices must watch for hotplug events.
1572 		 */
1573 		if (i_xvdi_add_watch_hpstate(dip) != DDI_SUCCESS)
1574 			goto unwatch_and_fail;
1575 	}
1576 
1577 	mutex_exit(&pdp->xd_ndi_lk);
1578 
1579 	return (DDI_SUCCESS);
1580 
1581 unwatch_and_fail:
1582 	i_xvdi_rem_watch_oestate(dip);
1583 	mutex_exit(&pdp->xd_ndi_lk);
1584 
1585 	return (DDI_FAILURE);
1586 }
1587 
1588 static void
1589 i_xvdi_rem_watches(dev_info_t *dip)
1590 {
1591 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
1592 
1593 	ASSERT(pdp != NULL);
1594 
1595 	mutex_enter(&pdp->xd_ndi_lk);
1596 
1597 	i_xvdi_rem_watch_oestate(dip);
1598 
1599 	if (pdp->xd_xsdev.frontend == 1)
1600 		i_xvdi_rem_watch_bepath(dip);
1601 	else
1602 		i_xvdi_rem_watch_hpstate(dip);
1603 
1604 	mutex_exit(&pdp->xd_ndi_lk);
1605 
1606 	xvdi_remove_xb_watch_handlers(dip);
1607 }
1608 
1609 static int
1610 i_xvdi_add_watch_bepath(dev_info_t *dip)
1611 {
1612 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
1613 
1614 	ASSERT(pdp != NULL);
1615 	ASSERT(pdp->xd_xsdev.frontend == 1);
1616 
1617 	/*
1618 	 * Frontend devices need to watch for the backend path changing.
1619 	 */
1620 	if (pdp->xd_bepath_watch.node == NULL) {
1621 		size_t len;
1622 		char *path;
1623 
1624 		ASSERT(pdp->xd_xsdev.nodename != NULL);
1625 
1626 		len = strlen(pdp->xd_xsdev.nodename) + strlen("/backend") + 1;
1627 		path = kmem_alloc(len, KM_SLEEP);
1628 		(void) snprintf(path, len, "%s/backend",
1629 		    pdp->xd_xsdev.nodename);
1630 
1631 		pdp->xd_bepath_watch.node = path;
1632 		pdp->xd_bepath_watch.callback = i_xvdi_bepath_cb;
1633 		pdp->xd_bepath_watch.dev = (struct xenbus_device *)dip;
1634 		if (register_xenbus_watch(&pdp->xd_bepath_watch) != 0) {
1635 			kmem_free(path, len);
1636 			pdp->xd_bepath_watch.node = NULL;
1637 			return (DDI_FAILURE);
1638 		}
1639 	}
1640 
1641 	return (DDI_SUCCESS);
1642 }
1643 
1644 static void
1645 i_xvdi_rem_watch_bepath(dev_info_t *dip)
1646 {
1647 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
1648 
1649 	ASSERT(pdp != NULL);
1650 	ASSERT(pdp->xd_xsdev.frontend == 1);
1651 	ASSERT(mutex_owned(&pdp->xd_ndi_lk));
1652 
1653 	if (pdp->xd_bepath_watch.node != NULL) {
1654 		mutex_exit(&pdp->xd_ndi_lk);
1655 		unregister_xenbus_watch(&pdp->xd_bepath_watch);
1656 		mutex_enter(&pdp->xd_ndi_lk);
1657 
1658 		kmem_free((void *)(pdp->xd_bepath_watch.node),
1659 		    strlen(pdp->xd_bepath_watch.node) + 1);
1660 		pdp->xd_bepath_watch.node = NULL;
1661 	}
1662 }
1663 
1664 int
1665 xvdi_switch_state(dev_info_t *dip, xenbus_transaction_t xbt,
1666     XenbusState newState)
1667 {
1668 	int rv;
1669 	struct xendev_ppd *pdp;
1670 
1671 	pdp = ddi_get_parent_data(dip);
1672 	ASSERT(pdp != NULL);
1673 
1674 	XVDI_DPRINTF(XVDI_DBG_STATE,
1675 	    "xvdi_switch_state: %s@%s's xenbus state moves to %d\n",
1676 	    ddi_binding_name(dip) == NULL ? "null" : ddi_binding_name(dip),
1677 	    ddi_get_name_addr(dip) == NULL ? "null" : ddi_get_name_addr(dip),
1678 	    newState);
1679 
1680 	rv = xenbus_switch_state(&pdp->xd_xsdev, xbt, newState);
1681 	if (rv > 0)
1682 		cmn_err(CE_WARN, "xvdi_switch_state: change state failed");
1683 
1684 	return (rv);
1685 }
1686 
1687 /*
1688  * Notify hotplug script running in userland
1689  */
1690 int
1691 xvdi_post_event(dev_info_t *dip, xendev_hotplug_cmd_t hpc)
1692 {
1693 	struct xendev_ppd *pdp;
1694 	nvlist_t *attr_list = NULL;
1695 	i_xd_cfg_t *xdcp;
1696 	sysevent_id_t eid;
1697 	int err;
1698 	char devname[256]; /* XXPV dme: ? */
1699 
1700 	pdp = ddi_get_parent_data(dip);
1701 	ASSERT(pdp != NULL);
1702 
1703 	xdcp = i_xvdi_devclass2cfg(pdp->xd_devclass);
1704 	ASSERT(xdcp != NULL);
1705 
1706 	(void) snprintf(devname, sizeof (devname) - 1, "%s%d",
1707 	    ddi_driver_name(dip),  ddi_get_instance(dip));
1708 
1709 	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME, KM_NOSLEEP);
1710 	if (err != DDI_SUCCESS)
1711 		goto failure;
1712 
1713 	err = nvlist_add_int32(attr_list, "domain", pdp->xd_domain);
1714 	if (err != DDI_SUCCESS)
1715 		goto failure;
1716 	err = nvlist_add_int32(attr_list, "vdev", pdp->xd_vdevnum);
1717 	if (err != DDI_SUCCESS)
1718 		goto failure;
1719 	err = nvlist_add_string(attr_list, "devclass", xdcp->xsdev);
1720 	if (err != DDI_SUCCESS)
1721 		goto failure;
1722 	err = nvlist_add_string(attr_list, "device", devname);
1723 	if (err != DDI_SUCCESS)
1724 		goto failure;
1725 	err = nvlist_add_string(attr_list, "fob",
1726 	    ((pdp->xd_xsdev.frontend == 1) ? "frontend" : "backend"));
1727 	if (err != DDI_SUCCESS)
1728 		goto failure;
1729 
1730 	switch (hpc) {
1731 	case XEN_HP_ADD:
1732 		err = ddi_log_sysevent(dip, DDI_VENDOR_SUNW, "EC_xendev",
1733 		    "add", attr_list, &eid, DDI_NOSLEEP);
1734 		break;
1735 	case XEN_HP_REMOVE:
1736 		err = ddi_log_sysevent(dip, DDI_VENDOR_SUNW, "EC_xendev",
1737 		    "remove", attr_list, &eid, DDI_NOSLEEP);
1738 		break;
1739 	default:
1740 		err = DDI_FAILURE;
1741 		goto failure;
1742 	}
1743 
1744 failure:
1745 	if (attr_list != NULL)
1746 		nvlist_free(attr_list);
1747 
1748 	return (err);
1749 }
1750 
1751 /* ARGSUSED */
1752 static void
1753 i_xvdi_probe_path_cb(struct xenbus_watch *w, const char **vec,
1754     unsigned int len)
1755 {
1756 	char *path;
1757 
1758 	if (xendev_dip == NULL)
1759 		xendev_dip = ddi_find_devinfo("xpvd", -1, 0);
1760 
1761 	path = i_ddi_strdup((char *)vec[XS_WATCH_PATH], KM_SLEEP);
1762 
1763 	(void) ddi_taskq_dispatch(DEVI(xendev_dip)->devi_taskq,
1764 	    i_xvdi_probe_path_handler, (void *)path, DDI_SLEEP);
1765 }
1766 
1767 static void
1768 i_xvdi_watch_device(char *path)
1769 {
1770 	struct xenbus_watch *w;
1771 
1772 	ASSERT(path != NULL);
1773 
1774 	w = kmem_zalloc(sizeof (*w), KM_SLEEP);
1775 	w->node = path;
1776 	w->callback = &i_xvdi_probe_path_cb;
1777 	w->dev = NULL;
1778 
1779 	if (register_xenbus_watch(w) != 0) {
1780 		cmn_err(CE_WARN, "i_xvdi_watch_device: "
1781 		    "cannot set watch on %s", path);
1782 		kmem_free(w, sizeof (*w));
1783 		return;
1784 	}
1785 }
1786 
1787 void
1788 xvdi_watch_devices(int newstate)
1789 {
1790 	int devclass;
1791 
1792 	/*
1793 	 * Watch for devices being created in the store.
1794 	 */
1795 	if (newstate == XENSTORE_DOWN)
1796 		return;
1797 	for (devclass = 0; devclass < NXDC; devclass++) {
1798 		if (xdci[devclass].xs_path_fe != NULL)
1799 			i_xvdi_watch_device(xdci[devclass].xs_path_fe);
1800 		if (xdci[devclass].xs_path_be != NULL)
1801 			i_xvdi_watch_device(xdci[devclass].xs_path_be);
1802 	}
1803 }
1804 
1805 /*
1806  * Iterate over the store looking for backend devices to create.
1807  */
1808 static void
1809 i_xvdi_enum_be(dev_info_t *parent, i_xd_cfg_t *xdcp)
1810 {
1811 	char **domains;
1812 	unsigned int ndomains;
1813 	int ldomains, i;
1814 
1815 	if ((domains = xenbus_directory(XBT_NULL, xdcp->xs_path_be, "",
1816 	    &ndomains)) == NULL)
1817 		return;
1818 
1819 	for (i = 0, ldomains = 0; i < ndomains; i++) {
1820 		ldomains += strlen(domains[i]) + 1 + sizeof (char *);
1821 
1822 		i_xvdi_enum_worker(parent, xdcp, domains[i]);
1823 	}
1824 	kmem_free(domains, ldomains);
1825 }
1826 
1827 /*
1828  * Iterate over the store looking for frontend devices to create.
1829  */
1830 static void
1831 i_xvdi_enum_fe(dev_info_t *parent, i_xd_cfg_t *xdcp)
1832 {
1833 	i_xvdi_enum_worker(parent, xdcp, NULL);
1834 }
1835 
1836 static void
1837 i_xvdi_enum_worker(dev_info_t *parent, i_xd_cfg_t *xdcp,
1838     char *domain)
1839 {
1840 	char *path, *domain_path, *ep;
1841 	char **devices;
1842 	unsigned int ndevices;
1843 	int ldevices, j, circ;
1844 	domid_t dom;
1845 	long tmplong;
1846 
1847 	if (domain == NULL) {
1848 		dom = DOMID_SELF;
1849 		path = xdcp->xs_path_fe;
1850 		domain_path = "";
1851 	} else {
1852 		(void) ddi_strtol(domain, &ep, 0, &tmplong);
1853 		dom = tmplong;
1854 		path = xdcp->xs_path_be;
1855 		domain_path = domain;
1856 	}
1857 
1858 	if ((devices = xenbus_directory(XBT_NULL, path, domain_path,
1859 	    &ndevices)) == NULL)
1860 		return;
1861 
1862 	for (j = 0, ldevices = 0; j < ndevices; j++) {
1863 		int vdev;
1864 
1865 		ldevices += strlen(devices[j]) + 1 + sizeof (char *);
1866 		(void) ddi_strtol(devices[j], &ep, 0, &tmplong);
1867 		vdev = tmplong;
1868 
1869 		ndi_devi_enter(parent, &circ);
1870 
1871 		if (xvdi_find_dev(parent, xdcp->devclass, dom, vdev) == NULL)
1872 			(void) xvdi_create_dev(parent, xdcp->devclass,
1873 			    dom, vdev);
1874 
1875 		ndi_devi_exit(parent, circ);
1876 	}
1877 	kmem_free(devices, ldevices);
1878 }
1879 
1880 /*
1881  * Leaf drivers should call this in their detach() routine during suspend.
1882  */
1883 void
1884 xvdi_suspend(dev_info_t *dip)
1885 {
1886 	i_xvdi_rem_watches(dip);
1887 }
1888 
1889 /*
1890  * Leaf drivers should call this in their attach() routine during resume.
1891  */
1892 int
1893 xvdi_resume(dev_info_t *dip)
1894 {
1895 	return (i_xvdi_add_watches(dip));
1896 }
1897 
1898 /*
1899  * Add event handler for the leaf driver
1900  * to handle event triggered by the change in xenstore
1901  */
1902 int
1903 xvdi_add_event_handler(dev_info_t *dip, char *name,
1904     void (*evthandler)(dev_info_t *, ddi_eventcookie_t, void *, void *),
1905     void *arg)
1906 {
1907 	ddi_eventcookie_t ecv;
1908 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
1909 	ddi_callback_id_t *cbid;
1910 	boolean_t call_handler;
1911 	i_oestate_evt_t *evt = NULL;
1912 	XenbusState oestate;
1913 
1914 	ASSERT(pdp != NULL);
1915 
1916 	mutex_enter(&pdp->xd_ndi_lk);
1917 
1918 	if (strcmp(name, XS_OE_STATE) == 0) {
1919 		ASSERT(pdp->xd_xsdev.otherend != NULL);
1920 
1921 		cbid = &pdp->xd_oe_ehid;
1922 	} else if (strcmp(name, XS_HP_STATE) == 0) {
1923 		if (pdp->xd_xsdev.frontend == 1) {
1924 			mutex_exit(&pdp->xd_ndi_lk);
1925 			return (DDI_FAILURE);
1926 		}
1927 
1928 		ASSERT(pdp->xd_hp_watch.node != NULL);
1929 
1930 		cbid = &pdp->xd_hp_ehid;
1931 	} else {
1932 		/* Unsupported watch. */
1933 		mutex_exit(&pdp->xd_ndi_lk);
1934 		return (DDI_FAILURE);
1935 	}
1936 
1937 	/*
1938 	 * No event handler provided, take default action to handle
1939 	 * event.
1940 	 */
1941 	if (evthandler == NULL) {
1942 		mutex_exit(&pdp->xd_ndi_lk);
1943 		return (DDI_SUCCESS);
1944 	}
1945 
1946 	ASSERT(*cbid == NULL);
1947 
1948 	if (ddi_get_eventcookie(dip, name, &ecv) != DDI_SUCCESS) {
1949 		cmn_err(CE_WARN, "failed to find %s cookie for %s@%s",
1950 		    name, ddi_get_name(dip), ddi_get_name_addr(dip));
1951 		mutex_exit(&pdp->xd_ndi_lk);
1952 		return (DDI_FAILURE);
1953 	}
1954 	if (ddi_add_event_handler(dip, ecv, evthandler, arg, cbid)
1955 	    != DDI_SUCCESS) {
1956 		cmn_err(CE_WARN, "failed to add %s event handler for %s@%s",
1957 		    name, ddi_get_name(dip), ddi_get_name_addr(dip));
1958 		*cbid = NULL;
1959 		mutex_exit(&pdp->xd_ndi_lk);
1960 		return (DDI_FAILURE);
1961 	}
1962 
1963 	/*
1964 	 * if we're adding an oe state callback, and the ring has already
1965 	 * transitioned out of Unknown, call the handler after we release
1966 	 * the mutex.
1967 	 */
1968 	call_handler = B_FALSE;
1969 	if ((strcmp(name, XS_OE_STATE) == 0) &&
1970 	    (pdp->xd_xsdev.otherend_state != XenbusStateUnknown)) {
1971 		oestate = pdp->xd_xsdev.otherend_state;
1972 		call_handler = B_TRUE;
1973 	}
1974 
1975 	mutex_exit(&pdp->xd_ndi_lk);
1976 
1977 	if (call_handler) {
1978 		evt = kmem_alloc(sizeof (i_oestate_evt_t), KM_SLEEP);
1979 		evt->dip = dip;
1980 		evt->state = oestate;
1981 		(void) ddi_taskq_dispatch(pdp->xd_oe_taskq,
1982 		    i_xvdi_oestate_handler, (void *)evt, DDI_SLEEP);
1983 	}
1984 
1985 	return (DDI_SUCCESS);
1986 }
1987 
1988 /*
1989  * Remove event handler for the leaf driver and unwatch xenstore
1990  * so, driver will not be notified when xenstore entry changed later
1991  */
1992 void
1993 xvdi_remove_event_handler(dev_info_t *dip, char *name)
1994 {
1995 	struct xendev_ppd *pdp;
1996 	boolean_t rem_oe = B_FALSE, rem_hp = B_FALSE;
1997 	ddi_callback_id_t oeid = NULL, hpid = NULL;
1998 
1999 	pdp = ddi_get_parent_data(dip);
2000 	ASSERT(pdp != NULL);
2001 
2002 	if (name == NULL) {
2003 		rem_oe = B_TRUE;
2004 		rem_hp = B_TRUE;
2005 	} else if (strcmp(name, XS_OE_STATE) == 0) {
2006 		rem_oe = B_TRUE;
2007 	} else if (strcmp(name, XS_HP_STATE) == 0) {
2008 		rem_hp = B_TRUE;
2009 	} else {
2010 		cmn_err(CE_WARN, "event %s not supported, cannot remove", name);
2011 		return;
2012 	}
2013 
2014 	mutex_enter(&pdp->xd_ndi_lk);
2015 
2016 	if (rem_oe && (pdp->xd_oe_ehid != NULL)) {
2017 		oeid = pdp->xd_oe_ehid;
2018 		pdp->xd_oe_ehid = NULL;
2019 	}
2020 
2021 	if (rem_hp && (pdp->xd_hp_ehid != NULL)) {
2022 		hpid = pdp->xd_hp_ehid;
2023 		pdp->xd_hp_ehid = NULL;
2024 	}
2025 
2026 	mutex_exit(&pdp->xd_ndi_lk);
2027 
2028 	if (oeid != NULL)
2029 		(void) ddi_remove_event_handler(oeid);
2030 	if (hpid != NULL)
2031 		(void) ddi_remove_event_handler(hpid);
2032 }
2033 
2034 
2035 /*
2036  * common ring interfaces
2037  */
2038 
2039 #define	FRONT_RING(_ringp)	(&(_ringp)->xr_sring.fr)
2040 #define	BACK_RING(_ringp)	(&(_ringp)->xr_sring.br)
2041 #define	GET_RING_SIZE(_ringp)	RING_SIZE(FRONT_RING(ringp))
2042 #define	GET_RING_ENTRY_FE(_ringp, _idx)		\
2043 	(FRONT_RING(_ringp)->sring->ring +	\
2044 	(_ringp)->xr_entry_size * ((_idx) & (GET_RING_SIZE(_ringp) - 1)))
2045 #define	GET_RING_ENTRY_BE(_ringp, _idx)		\
2046 	(BACK_RING(_ringp)->sring->ring +	\
2047 	(_ringp)->xr_entry_size * ((_idx) & (GET_RING_SIZE(_ringp) - 1)))
2048 
2049 unsigned int
2050 xvdi_ring_avail_slots(xendev_ring_t *ringp)
2051 {
2052 	comif_ring_fe_t *frp;
2053 	comif_ring_be_t *brp;
2054 
2055 	if (ringp->xr_frontend) {
2056 		frp = FRONT_RING(ringp);
2057 		return (GET_RING_SIZE(ringp) -
2058 		    (frp->req_prod_pvt - frp->rsp_cons));
2059 	} else {
2060 		brp = BACK_RING(ringp);
2061 		return (GET_RING_SIZE(ringp) -
2062 		    (brp->rsp_prod_pvt - brp->req_cons));
2063 	}
2064 }
2065 
2066 int
2067 xvdi_ring_has_unconsumed_requests(xendev_ring_t *ringp)
2068 {
2069 	comif_ring_be_t *brp;
2070 
2071 	ASSERT(!ringp->xr_frontend);
2072 	brp = BACK_RING(ringp);
2073 	return ((brp->req_cons !=
2074 	    ddi_get32(ringp->xr_acc_hdl, &brp->sring->req_prod)) &&
2075 	    ((brp->req_cons - brp->rsp_prod_pvt) != RING_SIZE(brp)));
2076 }
2077 
2078 int
2079 xvdi_ring_has_incomp_request(xendev_ring_t *ringp)
2080 {
2081 	comif_ring_fe_t *frp;
2082 
2083 	ASSERT(ringp->xr_frontend);
2084 	frp = FRONT_RING(ringp);
2085 	return (frp->req_prod_pvt !=
2086 	    ddi_get32(ringp->xr_acc_hdl, &frp->sring->rsp_prod));
2087 }
2088 
2089 int
2090 xvdi_ring_has_unconsumed_responses(xendev_ring_t *ringp)
2091 {
2092 	comif_ring_fe_t *frp;
2093 
2094 	ASSERT(ringp->xr_frontend);
2095 	frp = FRONT_RING(ringp);
2096 	return (frp->rsp_cons !=
2097 	    ddi_get32(ringp->xr_acc_hdl, &frp->sring->rsp_prod));
2098 }
2099 
2100 /* NOTE: req_event will be increased as needed */
2101 void *
2102 xvdi_ring_get_request(xendev_ring_t *ringp)
2103 {
2104 	comif_ring_fe_t *frp;
2105 	comif_ring_be_t *brp;
2106 
2107 	if (ringp->xr_frontend) {
2108 		/* for frontend ring */
2109 		frp = FRONT_RING(ringp);
2110 		if (!RING_FULL(frp))
2111 			return (GET_RING_ENTRY_FE(ringp, frp->req_prod_pvt++));
2112 		else
2113 			return (NULL);
2114 	} else {
2115 		/* for backend ring */
2116 		brp = BACK_RING(ringp);
2117 		/* RING_FINAL_CHECK_FOR_REQUESTS() */
2118 		if (xvdi_ring_has_unconsumed_requests(ringp))
2119 			return (GET_RING_ENTRY_BE(ringp, brp->req_cons++));
2120 		else {
2121 			ddi_put32(ringp->xr_acc_hdl, &brp->sring->req_event,
2122 			    brp->req_cons + 1);
2123 			membar_enter();
2124 			if (xvdi_ring_has_unconsumed_requests(ringp))
2125 				return (GET_RING_ENTRY_BE(ringp,
2126 				    brp->req_cons++));
2127 			else
2128 				return (NULL);
2129 		}
2130 	}
2131 }
2132 
2133 int
2134 xvdi_ring_push_request(xendev_ring_t *ringp)
2135 {
2136 	RING_IDX old, new, reqevt;
2137 	comif_ring_fe_t *frp;
2138 
2139 	/* only frontend should be able to push request */
2140 	ASSERT(ringp->xr_frontend);
2141 
2142 	/* RING_PUSH_REQUEST_AND_CHECK_NOTIFY() */
2143 	frp = FRONT_RING(ringp);
2144 	old = ddi_get32(ringp->xr_acc_hdl, &frp->sring->req_prod);
2145 	new = frp->req_prod_pvt;
2146 	ddi_put32(ringp->xr_acc_hdl, &frp->sring->req_prod, new);
2147 	membar_enter();
2148 	reqevt = ddi_get32(ringp->xr_acc_hdl, &frp->sring->req_event);
2149 	return ((RING_IDX)(new - reqevt) < (RING_IDX)(new - old));
2150 }
2151 
2152 /* NOTE: rsp_event will be increased as needed */
2153 void *
2154 xvdi_ring_get_response(xendev_ring_t *ringp)
2155 {
2156 	comif_ring_fe_t *frp;
2157 	comif_ring_be_t *brp;
2158 
2159 	if (!ringp->xr_frontend) {
2160 		/* for backend ring */
2161 		brp = BACK_RING(ringp);
2162 		return (GET_RING_ENTRY_BE(ringp, brp->rsp_prod_pvt++));
2163 	} else {
2164 		/* for frontend ring */
2165 		frp = FRONT_RING(ringp);
2166 		/* RING_FINAL_CHECK_FOR_RESPONSES() */
2167 		if (xvdi_ring_has_unconsumed_responses(ringp))
2168 			return (GET_RING_ENTRY_FE(ringp, frp->rsp_cons++));
2169 		else {
2170 			ddi_put32(ringp->xr_acc_hdl, &frp->sring->rsp_event,
2171 			    frp->rsp_cons + 1);
2172 			membar_enter();
2173 			if (xvdi_ring_has_unconsumed_responses(ringp))
2174 				return (GET_RING_ENTRY_FE(ringp,
2175 				    frp->rsp_cons++));
2176 			else
2177 				return (NULL);
2178 		}
2179 	}
2180 }
2181 
2182 int
2183 xvdi_ring_push_response(xendev_ring_t *ringp)
2184 {
2185 	RING_IDX old, new, rspevt;
2186 	comif_ring_be_t *brp;
2187 
2188 	/* only backend should be able to push response */
2189 	ASSERT(!ringp->xr_frontend);
2190 
2191 	/* RING_PUSH_RESPONSE_AND_CHECK_NOTIFY() */
2192 	brp = BACK_RING(ringp);
2193 	old = ddi_get32(ringp->xr_acc_hdl, &brp->sring->rsp_prod);
2194 	new = brp->rsp_prod_pvt;
2195 	ddi_put32(ringp->xr_acc_hdl, &brp->sring->rsp_prod, new);
2196 	membar_enter();
2197 	rspevt = ddi_get32(ringp->xr_acc_hdl, &brp->sring->rsp_event);
2198 	return ((RING_IDX)(new - rspevt) < (RING_IDX)(new - old));
2199 }
2200 
2201 static void
2202 xvdi_ring_init_sring(xendev_ring_t *ringp)
2203 {
2204 	ddi_acc_handle_t acchdl;
2205 	comif_sring_t *xsrp;
2206 	int i;
2207 
2208 	xsrp = (comif_sring_t *)ringp->xr_vaddr;
2209 	acchdl = ringp->xr_acc_hdl;
2210 
2211 	/* shared ring initialization */
2212 	ddi_put32(acchdl, &xsrp->req_prod, 0);
2213 	ddi_put32(acchdl, &xsrp->rsp_prod, 0);
2214 	ddi_put32(acchdl, &xsrp->req_event, 1);
2215 	ddi_put32(acchdl, &xsrp->rsp_event, 1);
2216 	for (i = 0; i < sizeof (xsrp->pad); i++)
2217 		ddi_put8(acchdl, xsrp->pad + i, 0);
2218 }
2219 
2220 static void
2221 xvdi_ring_init_front_ring(xendev_ring_t *ringp, size_t nentry, size_t entrysize)
2222 {
2223 	comif_ring_fe_t *xfrp;
2224 
2225 	xfrp = &ringp->xr_sring.fr;
2226 	xfrp->req_prod_pvt = 0;
2227 	xfrp->rsp_cons = 0;
2228 	xfrp->nr_ents = nentry;
2229 	xfrp->sring = (comif_sring_t *)ringp->xr_vaddr;
2230 
2231 	ringp->xr_frontend = 1;
2232 	ringp->xr_entry_size = entrysize;
2233 }
2234 
2235 #ifndef XPV_HVM_DRIVER
2236 static void
2237 xvdi_ring_init_back_ring(xendev_ring_t *ringp, size_t nentry, size_t entrysize)
2238 {
2239 	comif_ring_be_t *xbrp;
2240 
2241 	xbrp = &ringp->xr_sring.br;
2242 	xbrp->rsp_prod_pvt = 0;
2243 	xbrp->req_cons = 0;
2244 	xbrp->nr_ents = nentry;
2245 	xbrp->sring = (comif_sring_t *)ringp->xr_vaddr;
2246 
2247 	ringp->xr_frontend = 0;
2248 	ringp->xr_entry_size = entrysize;
2249 }
2250 #endif /* XPV_HVM_DRIVER */
2251 
2252 static void
2253 xendev_offline_device(void *arg)
2254 {
2255 	dev_info_t *dip = (dev_info_t *)arg;
2256 	char devname[MAXNAMELEN] = {0};
2257 
2258 	/*
2259 	 * This is currently the only chance to delete a devinfo node, which
2260 	 * is _not_ always successful.
2261 	 */
2262 	(void) ddi_deviname(dip, devname);
2263 	(void) devfs_clean(ddi_get_parent(dip), devname + 1, DV_CLEAN_FORCE);
2264 	(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
2265 }
2266 
2267 static void
2268 i_xvdi_oestate_cb(struct xenbus_device *dev, XenbusState oestate)
2269 {
2270 	dev_info_t *dip = (dev_info_t *)dev->data;
2271 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
2272 	i_oestate_evt_t *evt = NULL;
2273 	boolean_t call_handler;
2274 
2275 	XVDI_DPRINTF(XVDI_DBG_STATE,
2276 	    "i_xvdi_oestate_cb: %s@%s sees oestate change to %d\n",
2277 	    ddi_binding_name(dip) == NULL ? "null" : ddi_binding_name(dip),
2278 	    ddi_get_name_addr(dip) == NULL ? "null" : ddi_get_name_addr(dip),
2279 	    oestate);
2280 
2281 	/* only call the handler if our state has changed */
2282 	call_handler = B_FALSE;
2283 	mutex_enter(&pdp->xd_ndi_lk);
2284 	if (dev->otherend_state != oestate) {
2285 		dev->otherend_state = oestate;
2286 		call_handler = B_TRUE;
2287 	}
2288 	mutex_exit(&pdp->xd_ndi_lk);
2289 
2290 	if (call_handler) {
2291 		/*
2292 		 * Try to deliver the oestate change event to the dip
2293 		 */
2294 		evt = kmem_alloc(sizeof (i_oestate_evt_t), KM_SLEEP);
2295 		evt->dip = dip;
2296 		evt->state = oestate;
2297 		(void) ddi_taskq_dispatch(pdp->xd_oe_taskq,
2298 		    i_xvdi_oestate_handler, (void *)evt, DDI_SLEEP);
2299 	}
2300 }
2301 
2302 /*ARGSUSED*/
2303 static void
2304 i_xvdi_hpstate_cb(struct xenbus_watch *w, const char **vec,
2305     unsigned int len)
2306 {
2307 	dev_info_t *dip = (dev_info_t *)w->dev;
2308 	struct xendev_ppd *pdp = ddi_get_parent_data(dip);
2309 
2310 #ifdef DEBUG
2311 	char *hp_status = NULL;
2312 	unsigned int hpl = 0;
2313 
2314 	(void) xenbus_read(XBT_NULL, pdp->xd_hp_watch.node, "",
2315 	    (void *)&hp_status, &hpl);
2316 	XVDI_DPRINTF(XVDI_DBG_STATE,
2317 	    "i_xvdi_hpstate_cb: %s@%s sees hpstate change to %s\n",
2318 	    ddi_binding_name(dip) == NULL ?  "null" : ddi_binding_name(dip),
2319 	    ddi_get_name_addr(dip) == NULL ?  "null" : ddi_get_name_addr(dip),
2320 	    hp_status == NULL ? "null" : hp_status);
2321 	if (hp_status != NULL)
2322 		kmem_free(hp_status, hpl);
2323 #endif /* DEBUG */
2324 
2325 	(void) ddi_taskq_dispatch(pdp->xd_hp_taskq,
2326 	    i_xvdi_hpstate_handler, (void *)dip, DDI_SLEEP);
2327 }
2328 
2329 static void
2330 i_xvdi_probe_path_handler(void *arg)
2331 {
2332 	dev_info_t *parent;
2333 	char *path = arg, *p = NULL;
2334 	int i, vdev, circ;
2335 	i_xd_cfg_t *xdcp;
2336 	boolean_t frontend;
2337 	domid_t dom;
2338 
2339 	for (i = 0, xdcp = &xdci[0]; i < NXDC; i++, xdcp++) {
2340 
2341 		if ((xdcp->xs_path_fe != NULL) &&
2342 		    (strncmp(path, xdcp->xs_path_fe, strlen(xdcp->xs_path_fe))
2343 		    == 0)) {
2344 
2345 			frontend = B_TRUE;
2346 			p = path + strlen(xdcp->xs_path_fe);
2347 			break;
2348 		}
2349 
2350 		if ((xdcp->xs_path_be != NULL) &&
2351 		    (strncmp(path, xdcp->xs_path_be, strlen(xdcp->xs_path_be))
2352 		    == 0)) {
2353 
2354 			frontend = B_FALSE;
2355 			p = path + strlen(xdcp->xs_path_be);
2356 			break;
2357 		}
2358 
2359 	}
2360 
2361 	if (p == NULL) {
2362 		cmn_err(CE_WARN, "i_xvdi_probe_path_handler: "
2363 		    "unexpected path prefix in %s", path);
2364 		goto done;
2365 	}
2366 
2367 	if (frontend) {
2368 		dom = DOMID_SELF;
2369 		if (sscanf(p, "/%d/", &vdev) != 1) {
2370 			XVDI_DPRINTF(XVDI_DBG_PROBE,
2371 			    "i_xvdi_probe_path_handler: "
2372 			    "cannot parse frontend path %s",
2373 			    path);
2374 			goto done;
2375 		}
2376 	} else {
2377 		if (sscanf(p, "/%hu/%d/", &dom, &vdev) != 2) {
2378 			XVDI_DPRINTF(XVDI_DBG_PROBE,
2379 			    "i_xvdi_probe_path_handler: "
2380 			    "cannot parse backend path %s",
2381 			    path);
2382 			goto done;
2383 		}
2384 	}
2385 
2386 	/*
2387 	 * This is an oxymoron, so indicates a bogus configuration we
2388 	 * must check for.
2389 	 */
2390 	if (vdev == VDEV_NOXS) {
2391 		cmn_err(CE_WARN, "i_xvdi_probe_path_handler: "
2392 		    "invalid path %s", path);
2393 		goto done;
2394 	}
2395 
2396 	parent = xendev_dip;
2397 	ASSERT(parent != NULL);
2398 
2399 	ndi_devi_enter(parent, &circ);
2400 
2401 	if (xvdi_find_dev(parent, xdcp->devclass, dom, vdev) == NULL) {
2402 		XVDI_DPRINTF(XVDI_DBG_PROBE,
2403 		    "i_xvdi_probe_path_handler: create for %s", path);
2404 		(void) xvdi_create_dev(parent, xdcp->devclass, dom, vdev);
2405 	} else {
2406 		XVDI_DPRINTF(XVDI_DBG_PROBE,
2407 		    "i_xvdi_probe_path_handler: %s already exists", path);
2408 	}
2409 
2410 	ndi_devi_exit(parent, circ);
2411 
2412 done:
2413 	kmem_free(path, strlen(path) + 1);
2414 }
2415