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