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