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