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