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