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