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  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  28  */
  29 
  30 /*
  31  *      Host to hypervisor virtual devices nexus driver
  32  *
  33  * TODO:
  34  * - Add watchpoints on vbd/vif and enumerate/offline on watch callback
  35  * - Add DR IOCTLs
  36  * - Filter/restrict property lookups into xenstore
  37  */
  38 
  39 #include <sys/conf.h>
  40 #include <sys/kmem.h>
  41 #include <sys/debug.h>
  42 #include <sys/modctl.h>
  43 #include <sys/autoconf.h>
  44 #include <sys/ddi_impldefs.h>
  45 #include <sys/ddi_subrdefs.h>
  46 #include <sys/ddi.h>
  47 #include <sys/sunddi.h>
  48 #include <sys/sunndi.h>
  49 #include <sys/avintr.h>
  50 #include <sys/psm.h>
  51 #include <sys/spl.h>
  52 #include <sys/promif.h>
  53 #include <sys/list.h>
  54 #include <sys/bootconf.h>
  55 #include <sys/bootsvcs.h>
  56 #include <util/sscanf.h>
  57 #include <sys/mach_intr.h>
  58 #include <sys/bootinfo.h>
  59 #ifdef XPV_HVM_DRIVER
  60 #include <sys/xpv_support.h>
  61 #include <sys/hypervisor.h>
  62 #include <sys/archsystm.h>
  63 #include <sys/cpu.h>
  64 #include <public/xen.h>
  65 #include <public/event_channel.h>
  66 #include <public/io/xenbus.h>
  67 #else
  68 #include <sys/hypervisor.h>
  69 #include <sys/evtchn_impl.h>
  70 #include <sys/xen_mmu.h>
  71 #endif
  72 #include <xen/sys/xenbus_impl.h>
  73 #include <xen/sys/xendev.h>
  74 
  75 /*
  76  * DDI dev_ops entrypoints
  77  */
  78 static int xpvd_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
  79 static int xpvd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
  80 static int xpvd_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
  81 
  82 
  83 /*
  84  * NDI bus_ops entrypoints
  85  */
  86 static int xpvd_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
  87         void *);
  88 static int xpvd_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
  89         ddi_intr_handle_impl_t *, void *);
  90 static int xpvd_prop_op(dev_t, dev_info_t *, dev_info_t *, ddi_prop_op_t,
  91         int, char *, caddr_t, int *);
  92 static int xpvd_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t,
  93         void *, dev_info_t **);
  94 static int xpvd_bus_unconfig(dev_info_t *, uint_t, ddi_bus_config_op_t,
  95     void *);
  96 static int xpvd_get_eventcookie(dev_info_t *, dev_info_t *,
  97     char *, ddi_eventcookie_t *);
  98 static int xpvd_add_eventcall(dev_info_t *, dev_info_t *,
  99     ddi_eventcookie_t, void (*)(dev_info_t *,
 100     ddi_eventcookie_t, void *, void *),
 101     void *, ddi_callback_id_t *);
 102 static int xpvd_remove_eventcall(dev_info_t *, ddi_callback_id_t);
 103 static int xpvd_post_event(dev_info_t *, dev_info_t *,
 104     ddi_eventcookie_t, void *);
 105 
 106 /*
 107  * misc functions
 108  */
 109 static int xpvd_enable_intr(dev_info_t *, ddi_intr_handle_impl_t *, int);
 110 static void xpvd_disable_intr(dev_info_t *, ddi_intr_handle_impl_t *, int);
 111 static int xpvd_removechild(dev_info_t *);
 112 static int xpvd_initchild(dev_info_t *);
 113 static int xpvd_name_child(dev_info_t *, char *, int);
 114 static boolean_t i_xpvd_parse_devname(char *, xendev_devclass_t *,
 115     domid_t *, int *);
 116 
 117 
 118 /* Extern declarations */
 119 extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
 120     psm_intr_op_t, int *);
 121 
 122 struct bus_ops xpvd_bus_ops = {
 123         BUSO_REV,
 124         i_ddi_bus_map,
 125         NULL,
 126         NULL,
 127         NULL,
 128         i_ddi_map_fault,
 129         NULL,
 130         ddi_dma_allochdl,
 131         ddi_dma_freehdl,
 132         ddi_dma_bindhdl,
 133         ddi_dma_unbindhdl,
 134         ddi_dma_flush,
 135         ddi_dma_win,
 136         ddi_dma_mctl,
 137         xpvd_ctlops,
 138         xpvd_prop_op,
 139         xpvd_get_eventcookie,
 140         xpvd_add_eventcall,
 141         xpvd_remove_eventcall,
 142         xpvd_post_event,
 143         0,              /* (*bus_intr_ctl)(); */
 144         xpvd_bus_config,
 145         xpvd_bus_unconfig,
 146         NULL,           /* (*bus_fm_init)(); */
 147         NULL,           /* (*bus_fm_fini)(); */
 148         NULL,           /* (*bus_fm_access_enter)(); */
 149         NULL,           /* (*bus_fm_access_exit)(); */
 150         NULL,           /* (*bus_power)(); */
 151         xpvd_intr_ops   /* (*bus_intr_op)(); */
 152 };
 153 
 154 struct dev_ops xpvd_ops = {
 155         DEVO_REV,               /* devo_rev */
 156         0,                      /* refcnt  */
 157         xpvd_info,              /* info */
 158         nulldev,                /* identify */
 159         nulldev,                /* probe */
 160         xpvd_attach,            /* attach */
 161         xpvd_detach,            /* detach */
 162         nulldev,                /* reset */
 163         (struct cb_ops *)0,     /* driver operations */
 164         &xpvd_bus_ops,              /* bus operations */
 165         NULL,                   /* power */
 166         ddi_quiesce_not_needed,         /* quiesce */
 167 };
 168 
 169 
 170 dev_info_t *xpvd_dip;
 171 
 172 #define CF_DBG          0x1
 173 #define ALL_DBG         0xff
 174 
 175 static ndi_event_definition_t xpvd_ndi_event_defs[] = {
 176         { 0, XS_OE_STATE, EPL_KERNEL, NDI_EVENT_POST_TO_TGT },
 177         { 1, XS_HP_STATE, EPL_KERNEL, NDI_EVENT_POST_TO_TGT },
 178 };
 179 
 180 #define XENDEV_N_NDI_EVENTS \
 181         (sizeof (xpvd_ndi_event_defs) / sizeof (xpvd_ndi_event_defs[0]))
 182 
 183 static ndi_event_set_t xpvd_ndi_events = {
 184         NDI_EVENTS_REV1, XENDEV_N_NDI_EVENTS, xpvd_ndi_event_defs
 185 };
 186 
 187 static ndi_event_hdl_t xpvd_ndi_event_handle;
 188 
 189 /*
 190  * Hypervisor interrupt capabilities
 191  */
 192 #define XENDEV_INTR_CAPABILITIES \
 193         (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_MASKABLE | DDI_INTR_FLAG_PENDING)
 194 
 195 /*
 196  * Module linkage information for the kernel.
 197  */
 198 
 199 static struct modldrv modldrv = {
 200         &mod_driverops, /* Type of module */
 201         "virtual device nexus driver",
 202         &xpvd_ops,  /* driver ops */
 203 };
 204 
 205 static struct modlinkage modlinkage = {
 206         MODREV_1,
 207         { (void *)&modldrv, NULL }
 208 };
 209 
 210 int
 211 _init(void)
 212 {
 213         return (mod_install(&modlinkage));
 214 }
 215 
 216 int
 217 _fini(void)
 218 {
 219         return (mod_remove(&modlinkage));
 220 }
 221 
 222 int
 223 _info(struct modinfo *modinfop)
 224 {
 225         return (mod_info(&modlinkage, modinfop));
 226 }
 227 
 228 /* ARGSUSED */
 229 static int
 230 xpvd_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 231 {
 232         switch (cmd) {
 233         default:
 234                 return (DDI_FAILURE);
 235 
 236         case DDI_INFO_DEVT2INSTANCE:
 237                 *result = (void *)0;
 238                 return (DDI_SUCCESS);
 239 
 240         case DDI_INFO_DEVT2DEVINFO:
 241                 *result = (void *)xpvd_dip;
 242                 return (DDI_SUCCESS);
 243         }
 244 }
 245 
 246 /*ARGSUSED*/
 247 static int
 248 xpvd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 249 {
 250         extern void xvdi_watch_devices(int);
 251 #ifdef XPV_HVM_DRIVER
 252         extern dev_info_t *xpv_dip;
 253 
 254         if (xpv_dip == NULL) {
 255                 if (ddi_hold_installed_driver(ddi_name_to_major("xpv")) ==
 256                     NULL) {
 257                         cmn_err(CE_WARN, "Couldn't initialize xpv framework");
 258                         return (DDI_FAILURE);
 259                 }
 260         }
 261 #endif /* XPV_HVM_DRIVER */
 262 
 263         if (ndi_event_alloc_hdl(devi, 0, &xpvd_ndi_event_handle,
 264             NDI_SLEEP) != NDI_SUCCESS) {
 265                 xpvd_dip = NULL;
 266                 return (DDI_FAILURE);
 267         }
 268         if (ndi_event_bind_set(xpvd_ndi_event_handle, &xpvd_ndi_events,
 269             NDI_SLEEP) != NDI_SUCCESS) {
 270                 (void) ndi_event_free_hdl(xpvd_ndi_event_handle);
 271                 xpvd_dip = NULL;
 272                 return (DDI_FAILURE);
 273         }
 274 
 275 #ifdef XPV_HVM_DRIVER
 276         (void) ddi_prop_update_int(DDI_DEV_T_NONE, devi, DDI_NO_AUTODETACH, 1);
 277 
 278         /*
 279          * Report our version to dom0.
 280          */
 281         if (xenbus_printf(XBT_NULL, "guest/xpvd", "version", "%d",
 282             HVMPV_XPVD_VERS))
 283                 cmn_err(CE_WARN, "xpvd: couldn't write version\n");
 284 #endif /* XPV_HVM_DRIVER */
 285 
 286         /* watch both frontend and backend for new devices */
 287         if (DOMAIN_IS_INITDOMAIN(xen_info))
 288                 (void) xs_register_xenbus_callback(xvdi_watch_devices);
 289         else
 290                 xvdi_watch_devices(XENSTORE_UP);
 291 
 292         xpvd_dip = devi;
 293         ddi_report_dev(devi);
 294 
 295         return (DDI_SUCCESS);
 296 }
 297 
 298 /*ARGSUSED*/
 299 static int
 300 xpvd_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 301 {
 302         return (DDI_FAILURE);
 303 }
 304 
 305 /*
 306  * xpvd_prop_op()
 307  *
 308  * Query xenstore for the value of properties if DDI_PROP_NOTPROM
 309  * is not set.  Xenstore property values are represented as ascii strings.
 310  */
 311 static int
 312 xpvd_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
 313     ddi_prop_op_t prop_op, int mod_flags, char *name, caddr_t valuep,
 314     int *lengthp)
 315 {
 316         caddr_t buff;
 317         struct xendev_ppd *pdp;
 318         void *prop_str;
 319         size_t prop_len;
 320         unsigned int len;
 321         int rv;
 322 
 323         pdp = (struct xendev_ppd *)ddi_get_parent_data(ch_dip);
 324 
 325         if ((pdp == NULL) || !(mod_flags & (DDI_PROP_CANSLEEP)) ||
 326             (mod_flags & DDI_PROP_NOTPROM) || (pdp->xd_xsdev.nodename == NULL))
 327                 goto toss_off;
 328         /*
 329          * First try reading the property off the the frontend. if that
 330          * fails, try and read it from the backend node.  If that
 331          * also fails, pass the request on the DDI framework
 332          */
 333         prop_str = NULL;
 334         if ((xenbus_read(XBT_NULL, pdp->xd_xsdev.nodename, name, &prop_str,
 335             &len) == 0) && (prop_str != NULL) && (strlen(prop_str) != 0))
 336                 goto got_xs_prop;
 337 
 338         prop_str = NULL;
 339         if ((pdp->xd_xsdev.otherend != NULL) &&
 340             (xenbus_read(XBT_NULL, pdp->xd_xsdev.otherend, name, &prop_str,
 341             &len) == 0) && (prop_str != NULL) && (strlen(prop_str) != 0))
 342                 goto got_xs_prop;
 343 
 344 toss_off:
 345         return (ddi_bus_prop_op(dev, dip, ch_dip, prop_op,
 346             mod_flags | DDI_PROP_NOTPROM, name, valuep, lengthp));
 347 
 348 got_xs_prop:
 349         prop_len = strlen(prop_str) + 1;
 350         rv = DDI_PROP_SUCCESS;
 351 
 352         switch (prop_op) {
 353         case PROP_LEN:
 354                 *lengthp = prop_len;
 355                 break;
 356 
 357         case PROP_LEN_AND_VAL_ALLOC:
 358                 buff = kmem_alloc((size_t)prop_len, KM_SLEEP);
 359                 *(caddr_t *)valuep = (caddr_t)buff;
 360                 break;
 361         case PROP_LEN_AND_VAL_BUF:
 362                 buff = (caddr_t)valuep;
 363                 if (*lengthp < prop_len)
 364                         rv = DDI_PROP_BUF_TOO_SMALL;
 365                 break;
 366         default:
 367                 rv = DDI_PROP_INVAL_ARG;
 368                 break;
 369         }
 370 
 371         if ((rv == DDI_PROP_SUCCESS) && (prop_len > 0)) {
 372                 bcopy(prop_str, buff, prop_len);
 373                 *lengthp = prop_len;
 374         }
 375         kmem_free(prop_str, len);
 376         return (rv);
 377 }
 378 
 379 
 380 /*
 381  * return address of the device's interrupt spec structure.
 382  */
 383 /*ARGSUSED*/
 384 struct intrspec *
 385 xpvd_get_ispec(dev_info_t *rdip, uint_t inumber)
 386 {
 387         struct xendev_ppd *pdp;
 388 
 389         ASSERT(inumber == 0);
 390 
 391         if ((pdp = ddi_get_parent_data(rdip)) == NULL)
 392                 return (NULL);
 393 
 394         return (&pdp->xd_ispec);
 395 }
 396 
 397 /*
 398  * return (and determine) the interrupt priority of the device.
 399  */
 400 /*ARGSUSED*/
 401 static int
 402 xpvd_get_priority(dev_info_t *dip, int inum, int *pri)
 403 {
 404         struct xendev_ppd *pdp;
 405         struct intrspec *ispec;
 406         int     *intpriorities;
 407         uint_t  num_intpriorities;
 408 
 409         DDI_INTR_NEXDBG((CE_CONT, "xpvd_get_priority: dip = 0x%p\n",
 410             (void *)dip));
 411 
 412         ASSERT(inum == 0);
 413 
 414         if ((pdp = ddi_get_parent_data(dip)) == NULL)
 415                 return (DDI_FAILURE);
 416 
 417         ispec = &pdp->xd_ispec;
 418 
 419         /*
 420          * Set the default priority based on the device class.  The
 421          * "interrupt-priorities" property can be used to override
 422          * the default.
 423          */
 424         if (ispec->intrspec_pri == 0) {
 425                 ispec->intrspec_pri = xendev_devclass_ipl(pdp->xd_devclass);
 426                 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
 427                     DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
 428                     "interrupt-priorities", &intpriorities,
 429                     &num_intpriorities) == DDI_PROP_SUCCESS) {
 430                         ispec->intrspec_pri = intpriorities[0];
 431                         ddi_prop_free(intpriorities);
 432                 }
 433         }
 434         *pri = ispec->intrspec_pri;
 435         return (DDI_SUCCESS);
 436 }
 437 
 438 
 439 /*
 440  * xpvd_intr_ops: bus_intr_op() function for interrupt support
 441  */
 442 /* ARGSUSED */
 443 static int
 444 xpvd_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
 445     ddi_intr_handle_impl_t *hdlp, void *result)
 446 {
 447         int priority = 0;
 448         struct intrspec *ispec;
 449         struct xendev_ppd *pdp;
 450 
 451         DDI_INTR_NEXDBG((CE_CONT,
 452             "xpvd_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
 453             (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
 454 
 455         /* Process the request */
 456         switch (intr_op) {
 457         case DDI_INTROP_SUPPORTED_TYPES:
 458                 /* Fixed supported by default */
 459                 *(int *)result = DDI_INTR_TYPE_FIXED;
 460                 break;
 461 
 462         case DDI_INTROP_NINTRS:
 463                 *(int *)result = 1;
 464                 break;
 465 
 466         case DDI_INTROP_ALLOC:
 467                 /*
 468                  * FIXED interrupts: just return available interrupts
 469                  */
 470                 if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
 471                         /*
 472                          * event channels are edge-triggered, maskable,
 473                          * and support int pending.
 474                          */
 475                         hdlp->ih_cap |= XENDEV_INTR_CAPABILITIES;
 476                         *(int *)result = 1;     /* DDI_INTR_TYPE_FIXED */
 477                 } else {
 478                         return (DDI_FAILURE);
 479                 }
 480                 break;
 481 
 482         case DDI_INTROP_FREE:
 483                 ispec = xpvd_get_ispec(rdip, (int)hdlp->ih_inum);
 484                 if (ispec == NULL)
 485                         return (DDI_FAILURE);
 486                 ispec->intrspec_pri = 0; /* mark as un-initialized */
 487                 break;
 488 
 489         case DDI_INTROP_GETPRI:
 490                 if (xpvd_get_priority(rdip, hdlp->ih_inum, &priority) !=
 491                     DDI_SUCCESS)
 492                         return (DDI_FAILURE);
 493                 DDI_INTR_NEXDBG((CE_CONT, "xpvd_intr_ops: priority = 0x%x\n",
 494                     priority));
 495                 *(int *)result = priority;
 496                 break;
 497 
 498         case DDI_INTROP_SETPRI:
 499                 /* Validate the interrupt priority passed */
 500                 if (*(int *)result > LOCK_LEVEL)
 501                         return (DDI_FAILURE);
 502 
 503                 /* Ensure that PSM is all initialized */
 504                 if (psm_intr_ops == NULL)
 505                         return (DDI_FAILURE);
 506 
 507                 /* Change the priority */
 508                 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
 509                     PSM_FAILURE)
 510                         return (DDI_FAILURE);
 511 
 512                 ispec = xpvd_get_ispec(rdip, (int)hdlp->ih_inum);
 513                 if (ispec == NULL)
 514                         return (DDI_FAILURE);
 515                 ispec->intrspec_pri = *(int *)result;
 516                 break;
 517 
 518         case DDI_INTROP_ADDISR:
 519                 /* update ispec */
 520                 ispec = xpvd_get_ispec(rdip, (int)hdlp->ih_inum);
 521                 if (ispec == NULL)
 522                         return (DDI_FAILURE);
 523                 ispec->intrspec_func = hdlp->ih_cb_func;
 524 
 525                 break;
 526 
 527         case DDI_INTROP_REMISR:
 528                 ispec = xpvd_get_ispec(rdip, (int)hdlp->ih_inum);
 529                 pdp = (struct xendev_ppd *)ddi_get_parent_data(rdip);
 530 
 531                 ASSERT(pdp != NULL);
 532                 ASSERT(pdp->xd_evtchn != INVALID_EVTCHN);
 533 
 534                 if (ispec) {
 535                         ispec->intrspec_vec = 0;
 536                         ispec->intrspec_func = (uint_t (*)()) 0;
 537                 }
 538                 pdp->xd_evtchn = INVALID_EVTCHN;
 539                 break;
 540 
 541         case DDI_INTROP_GETCAP:
 542                 if (hdlp->ih_type ==  DDI_INTR_TYPE_FIXED) {
 543                         /*
 544                          * event channels are edge-triggered, maskable,
 545                          * and support int pending.
 546                          */
 547                         *(int *)result = XENDEV_INTR_CAPABILITIES;
 548                 } else {
 549                         *(int *)result = 0;
 550                         return (DDI_FAILURE);
 551                 }
 552                 DDI_INTR_NEXDBG((CE_CONT, "xpvd: GETCAP returned = %x\n",
 553                     *(int *)result));
 554                 break;
 555         case DDI_INTROP_SETCAP:
 556                 DDI_INTR_NEXDBG((CE_CONT, "xpvd_intr_ops: SETCAP cap=0x%x\n",
 557                     *(int *)result));
 558                 if (psm_intr_ops == NULL)
 559                         return (DDI_FAILURE);
 560 
 561                 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
 562                         DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
 563                             " returned failure\n"));
 564                         return (DDI_FAILURE);
 565                 }
 566                 break;
 567 
 568         case DDI_INTROP_ENABLE:
 569                 if (psm_intr_ops == NULL)
 570                         return (DDI_FAILURE);
 571 
 572                 if (xpvd_enable_intr(rdip, hdlp, (int)hdlp->ih_inum) !=
 573                     DDI_SUCCESS)
 574                         return (DDI_FAILURE);
 575 
 576                 DDI_INTR_NEXDBG((CE_CONT, "xpvd_intr_ops: ENABLE vec=0x%x\n",
 577                     hdlp->ih_vector));
 578                 break;
 579 
 580         case DDI_INTROP_DISABLE:
 581                 if (psm_intr_ops == NULL)
 582                         return (DDI_FAILURE);
 583                 xpvd_disable_intr(rdip, hdlp, hdlp->ih_inum);
 584                 DDI_INTR_NEXDBG((CE_CONT, "xpvd_intr_ops: DISABLE vec = %x\n",
 585                     hdlp->ih_vector));
 586                 break;
 587 
 588         case DDI_INTROP_BLOCKENABLE:
 589         case DDI_INTROP_BLOCKDISABLE:
 590                 return (DDI_FAILURE);
 591 
 592         case DDI_INTROP_SETMASK:
 593         case DDI_INTROP_CLRMASK:
 594 #ifdef XPV_HVM_DRIVER
 595                 return (DDI_ENOTSUP);
 596 #else
 597                 /*
 598                  * Handle this here
 599                  */
 600                 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
 601                         return (DDI_FAILURE);
 602                 if (intr_op == DDI_INTROP_SETMASK) {
 603                         ec_disable_irq(hdlp->ih_vector);
 604                 } else {
 605                         ec_enable_irq(hdlp->ih_vector);
 606                 }
 607                 break;
 608 #endif
 609         case DDI_INTROP_GETPENDING:
 610 #ifdef XPV_HVM_DRIVER
 611                 return (DDI_ENOTSUP);
 612 #else
 613                 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
 614                         return (DDI_FAILURE);
 615                 *(int *)result = ec_pending_irq(hdlp->ih_vector);
 616                 DDI_INTR_NEXDBG((CE_CONT, "xpvd: GETPENDING returned = %x\n",
 617                     *(int *)result));
 618                 break;
 619 #endif
 620 
 621         case DDI_INTROP_NAVAIL:
 622                 *(int *)result = 1;
 623                 DDI_INTR_NEXDBG((CE_CONT, "xpvd: NAVAIL returned = %x\n",
 624                     *(int *)result));
 625                 break;
 626 
 627         default:
 628                 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
 629         }
 630 
 631         return (DDI_SUCCESS);
 632 }
 633 
 634 
 635 static int
 636 xpvd_enable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp, int inum)
 637 {
 638         int             vector;
 639         ihdl_plat_t     *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
 640 
 641         DDI_INTR_NEXDBG((CE_CONT, "xpvd_enable_intr: hdlp %p inum %x\n",
 642             (void *)hdlp, inum));
 643 
 644         ihdl_plat_datap->ip_ispecp = xpvd_get_ispec(rdip, inum);
 645         if (ihdl_plat_datap->ip_ispecp == NULL)
 646                 return (DDI_FAILURE);
 647 
 648         /* translate the interrupt if needed */
 649         (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &vector);
 650         DDI_INTR_NEXDBG((CE_CONT, "xpvd_enable_intr: priority=%x vector=%x\n",
 651             hdlp->ih_pri, vector));
 652 
 653         /* Add the interrupt handler */
 654         if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
 655             DEVI(rdip)->devi_name, vector, hdlp->ih_cb_arg1,
 656             hdlp->ih_cb_arg2, NULL, rdip))
 657                 return (DDI_FAILURE);
 658 
 659         /* Note this really is an irq. */
 660         hdlp->ih_vector = (ushort_t)vector;
 661 
 662         return (DDI_SUCCESS);
 663 }
 664 
 665 
 666 static void
 667 xpvd_disable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp, int inum)
 668 {
 669         int             vector;
 670         ihdl_plat_t     *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
 671 
 672         DDI_INTR_NEXDBG((CE_CONT, "xpvd_disable_intr: \n"));
 673         ihdl_plat_datap->ip_ispecp = xpvd_get_ispec(rdip, inum);
 674         if (ihdl_plat_datap->ip_ispecp == NULL)
 675                 return;
 676 
 677         /* translate the interrupt if needed */
 678         (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &vector);
 679 
 680         /* Disable the interrupt handler */
 681         rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, vector);
 682         ihdl_plat_datap->ip_ispecp = NULL;
 683 }
 684 
 685 /*ARGSUSED*/
 686 static int
 687 xpvd_ctlops(dev_info_t *dip, dev_info_t *rdip,
 688         ddi_ctl_enum_t ctlop, void *arg, void *result)
 689 {
 690         switch (ctlop) {
 691         case DDI_CTLOPS_REPORTDEV:
 692                 if (rdip == (dev_info_t *)0)
 693                         return (DDI_FAILURE);
 694                 cmn_err(CE_CONT, "?%s@%s, %s%d\n", ddi_node_name(rdip),
 695                     ddi_get_name_addr(rdip), ddi_driver_name(rdip),
 696                     ddi_get_instance(rdip));
 697                 return (DDI_SUCCESS);
 698 
 699         case DDI_CTLOPS_INITCHILD:
 700                 return (xpvd_initchild((dev_info_t *)arg));
 701 
 702         case DDI_CTLOPS_UNINITCHILD:
 703                 return (xpvd_removechild((dev_info_t *)arg));
 704 
 705         case DDI_CTLOPS_SIDDEV:
 706                 return (DDI_SUCCESS);
 707 
 708         case DDI_CTLOPS_REGSIZE:
 709         case DDI_CTLOPS_NREGS:
 710                 return (DDI_FAILURE);
 711 
 712         case DDI_CTLOPS_POWER: {
 713                 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
 714         }
 715 
 716         default:
 717                 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
 718         }
 719 
 720         /* NOTREACHED */
 721 
 722 }
 723 
 724 /*
 725  * Assign the address portion of the node name
 726  */
 727 static int
 728 xpvd_name_child(dev_info_t *child, char *addr, int addrlen)
 729 {
 730         int *domain, *vdev;
 731         uint_t ndomain, nvdev;
 732         char *prop_str;
 733 
 734         /*
 735          * i_xpvd_parse_devname() knows the formats used by this
 736          * routine.  If this code changes, so must that.
 737          */
 738 
 739         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
 740             "domain", &domain, &ndomain) != DDI_PROP_SUCCESS)
 741                 return (DDI_FAILURE);
 742         ASSERT(ndomain == 1);
 743 
 744         /*
 745          * Use "domain" and "vdev" properties (backend drivers).
 746          */
 747         if (*domain != DOMID_SELF) {
 748                 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
 749                     DDI_PROP_DONTPASS, "vdev", &vdev, &nvdev)
 750                     != DDI_PROP_SUCCESS) {
 751                         ddi_prop_free(domain);
 752                         return (DDI_FAILURE);
 753                 }
 754                 ASSERT(nvdev == 1);
 755 
 756                 (void) snprintf(addr, addrlen, "%d,%d", domain[0], vdev[0]);
 757                 ddi_prop_free(vdev);
 758                 ddi_prop_free(domain);
 759                 return (DDI_SUCCESS);
 760         }
 761         ddi_prop_free(domain);
 762 
 763         /*
 764          * Use "unit-address" property (frontend/softdev drivers).
 765          */
 766         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
 767             "unit-address", &prop_str) != DDI_PROP_SUCCESS)
 768                 return (DDI_FAILURE);
 769         (void) strlcpy(addr, prop_str, addrlen);
 770         ddi_prop_free(prop_str);
 771         return (DDI_SUCCESS);
 772 }
 773 
 774 static int
 775 xpvd_initchild(dev_info_t *child)
 776 {
 777         char addr[80];
 778 
 779         /*
 780          * Pseudo nodes indicate a prototype node with per-instance
 781          * properties to be merged into the real h/w device node.
 782          */
 783         if (ndi_dev_is_persistent_node(child) == 0) {
 784                 ddi_set_parent_data(child, NULL);
 785 
 786                 /*
 787                  * Try to merge the properties from this prototype
 788                  * node into real h/w nodes.
 789                  */
 790                 if (ndi_merge_node(child, xpvd_name_child) == DDI_SUCCESS) {
 791                         /*
 792                          * Merged ok - return failure to remove the node.
 793                          */
 794                         ddi_set_name_addr(child, NULL);
 795                         return (DDI_FAILURE);
 796                 }
 797 
 798                 /*
 799                  * The child was not merged into a h/w node,
 800                  * but there's not much we can do with it other
 801                  * than return failure to cause the node to be removed.
 802                  */
 803                 cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
 804                     ddi_get_name(child), ddi_get_name_addr(child),
 805                     ddi_get_name(child));
 806                 ddi_set_name_addr(child, NULL);
 807                 return (DDI_NOT_WELL_FORMED);
 808         }
 809 
 810         if (xvdi_init_dev(child) != DDI_SUCCESS)
 811                 return (DDI_FAILURE);
 812 
 813         if (xpvd_name_child(child, addr, sizeof (addr)) != DDI_SUCCESS) {
 814                 xvdi_uninit_dev(child);
 815                 return (DDI_FAILURE);
 816         }
 817         ddi_set_name_addr(child, addr);
 818 
 819         return (DDI_SUCCESS);
 820 }
 821 
 822 static int
 823 xpvd_removechild(dev_info_t *dip)
 824 {
 825         xvdi_uninit_dev(dip);
 826 
 827         ddi_set_name_addr(dip, NULL);
 828 
 829         /*
 830          * Strip the node to properly convert it back to prototype
 831          * form.
 832          */
 833         ddi_remove_minor_node(dip, NULL);
 834 
 835         return (DDI_SUCCESS);
 836 }
 837 
 838 static int
 839 xpvd_bus_unconfig(dev_info_t *parent, uint_t flag, ddi_bus_config_op_t op,
 840     void *device_name)
 841 {
 842         return (ndi_busop_bus_unconfig(parent, flag, op, device_name));
 843 }
 844 
 845 /*
 846  * Given the name of a child of xpvd, determine the device class,
 847  * domain and vdevnum to which it refers.
 848  */
 849 static boolean_t
 850 i_xpvd_parse_devname(char *name, xendev_devclass_t *devclassp,
 851     domid_t *domp, int *vdevp)
 852 {
 853         int len = strlen(name) + 1;
 854         char *device_name = i_ddi_strdup(name, KM_SLEEP);
 855         char *cname = NULL, *caddr = NULL;
 856         boolean_t ret;
 857 
 858         i_ddi_parse_name(device_name, &cname, &caddr, NULL);
 859 
 860         if ((cname == NULL) || (strlen(cname) == 0) ||
 861             (caddr == NULL) || (strlen(caddr) == 0)) {
 862                 ret = B_FALSE;
 863                 goto done;
 864         }
 865 
 866         *devclassp = xendev_nodename_to_devclass(cname);
 867         if (*devclassp < 0) {
 868                 ret = B_FALSE;
 869                 goto done;
 870         }
 871 
 872         /*
 873          * Parsing the address component requires knowledge of how
 874          * xpvd_name_child() works.  If that code changes, so must
 875          * this.
 876          */
 877 
 878         /* Backend format is "<domain>,<vdev>". */
 879         if (sscanf(caddr, "%hu,%d", domp, vdevp) == 2) {
 880                 ret = B_TRUE;
 881                 goto done;
 882         }
 883 
 884         /* Frontend format is "<vdev>". */
 885         *domp = DOMID_SELF;
 886         if (sscanf(caddr, "%d", vdevp) == 1)
 887                 ret = B_TRUE;
 888 done:
 889         kmem_free(device_name, len);
 890         return (ret);
 891 }
 892 
 893 /*
 894  * xpvd_bus_config()
 895  *
 896  * BUS_CONFIG_ONE:
 897  *      Enumerate the exact instance of a driver.
 898  *
 899  * BUS_CONFIG_ALL:
 900  *      Enumerate all the instances of all the possible children (seen before
 901  *      and never seen before).
 902  *
 903  * BUS_CONFIG_DRIVER:
 904  *      Enumerate all the instances of a particular driver.
 905  */
 906 static int
 907 xpvd_bus_config(dev_info_t *parent, uint_t flag, ddi_bus_config_op_t op,
 908         void *arg, dev_info_t **childp)
 909 {
 910         int circ;
 911         char *cname = NULL;
 912 
 913         ndi_devi_enter(parent, &circ);
 914 
 915         switch (op) {
 916         case BUS_CONFIG_ONE: {
 917                 xendev_devclass_t devclass;
 918                 domid_t dom;
 919                 int vdev;
 920 
 921                 if (!i_xpvd_parse_devname(arg, &devclass, &dom, &vdev)) {
 922                         ndi_devi_exit(parent, circ);
 923                         return (NDI_FAILURE);
 924                 }
 925 
 926                 *childp = xvdi_find_dev(parent, devclass, dom, vdev);
 927                 if (*childp == NULL)
 928                         *childp = xvdi_create_dev(parent, devclass, dom, vdev);
 929 
 930                 ndi_devi_exit(parent, circ);
 931 
 932                 if (*childp == NULL)
 933                         return (NDI_FAILURE);
 934                 else
 935                         return (ndi_busop_bus_config(parent, flag,
 936                             op, arg, childp, 0));
 937         }
 938 
 939         case BUS_CONFIG_DRIVER: {
 940                 xendev_devclass_t devclass = XEN_INVAL;
 941 
 942                 cname = ddi_major_to_name((major_t)(uintptr_t)arg);
 943                 if (cname != NULL)
 944                         devclass = xendev_nodename_to_devclass(cname);
 945 
 946                 if (devclass == XEN_INVAL) {
 947                         ndi_devi_exit(parent, circ);
 948                         return (NDI_FAILURE);
 949                 } else {
 950                         xendev_enum_class(parent, devclass);
 951                         ndi_devi_exit(parent, circ);
 952                         return (ndi_busop_bus_config(parent, flag, op,
 953                             arg, childp, 0));
 954                 }
 955                 /* NOTREACHED */
 956         }
 957 
 958         case BUS_CONFIG_ALL:
 959                 xendev_enum_all(parent, B_FALSE);
 960                 ndi_devi_exit(parent, circ);
 961 
 962                 return (ndi_busop_bus_config(parent, flag, op,
 963                     arg, childp, 0));
 964 
 965         default:
 966                 ndi_devi_exit(parent, circ);
 967                 return (NDI_FAILURE);
 968         }
 969 }
 970 
 971 /*ARGSUSED*/
 972 static int
 973 xpvd_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
 974     char *eventname, ddi_eventcookie_t *cookie)
 975 {
 976         return (ndi_event_retrieve_cookie(xpvd_ndi_event_handle,
 977             rdip, eventname, cookie, NDI_EVENT_NOPASS));
 978 }
 979 
 980 /*ARGSUSED*/
 981 static int
 982 xpvd_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
 983     ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
 984     ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
 985     void *arg, ddi_callback_id_t *cb_id)
 986 {
 987         return (ndi_event_add_callback(xpvd_ndi_event_handle,
 988             rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
 989 }
 990 
 991 /*ARGSUSED*/
 992 static int
 993 xpvd_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
 994 {
 995         return (ndi_event_remove_callback(xpvd_ndi_event_handle,
 996             cb_id));
 997 }
 998 
 999 /*ARGSUSED*/
1000 static int
1001 xpvd_post_event(dev_info_t *dip, dev_info_t *rdip,
1002     ddi_eventcookie_t cookie, void *bus_impldata)
1003 {
1004         return (ndi_event_run_callbacks(xpvd_ndi_event_handle, rdip,
1005             cookie, bus_impldata));
1006 }