Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/pseudonex.c
          +++ new/usr/src/uts/common/io/pseudonex.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   * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
  26   26  
  27   27  /*
  28   28   * Pseudo devices are devices implemented entirely in software; pseudonex
  29   29   * (pseudo) is the traditional nexus for pseudodevices.  Instances are
  30   30   * typically specified via driver.conf files; e.g. a leaf device which
  31   31   * should be attached below pseudonex will have an entry like:
  32   32   *
  33   33   *      name="foo" parent="/pseudo" instance=0;
  34   34   *
  35   35   * pseudonex also supports the devctl (see <sys/devctl.h>) interface via
  36   36   * its :devctl minor node.  This allows priveleged userland applications to
  37   37   * online/offline children of pseudo as needed.
  38   38   *
  39   39   * In general, we discourage widespread use of this tactic, as it may lead to a
  40   40   * proliferation of nodes in /pseudo.  It is preferred that implementors update
  41   41   * pseudo.conf, adding another 'pseudo' nexus child of /pseudo, and then use
  42   42   * that for their collection of device nodes.  To do so, add a driver alias
  43   43   * for the name of the nexus child and a line in pseudo.conf such as:
  44   44   *
  45   45   *      name="foo" parent="/pseudo" instance=<n> valid-children="bar","baz";
  46   46   *
  47   47   * Setting 'valid-children' is important because we have an annoying problem;
  48   48   * we need to prevent pseudo devices with 'parent="pseudo"' set from binding
  49   49   * to our new pseudonex child node.  A better way might be to teach the
  50   50   * spec-node code to understand that parent="pseudo" really means
  51   51   * parent="/pseudo".
  52   52   *
  53   53   * At some point in the future, it would be desirable to extend the instance
  54   54   * database to include nexus children of pseudo.  Then we could use devctl
  55   55   * or devfs to online nexus children of pseudo, auto-selecting an instance #,
  56   56   * and the instance number selected would be preserved across reboot in
  57   57   * path_to_inst.
  58   58   */
  59   59  
  60   60  #include <sys/types.h>
  61   61  #include <sys/cmn_err.h>
  62   62  #include <sys/conf.h>
  63   63  #include <sys/ddi.h>
  64   64  #include <sys/ddi_impldefs.h>
  65   65  #include <sys/devops.h>
  66   66  #include <sys/instance.h>
  67   67  #include <sys/modctl.h>
  68   68  #include <sys/open.h>
  69   69  #include <sys/stat.h>
  70   70  #include <sys/sunddi.h>
  71   71  #include <sys/sunndi.h>
  72   72  #include <sys/systm.h>
  73   73  #include <sys/mkdev.h>
  74   74  
  75   75  /*
  76   76   * Config information
  77   77   */
  78   78  static int pseudonex_intr_op(dev_info_t *dip, dev_info_t *rdip,
  79   79              ddi_intr_op_t op, ddi_intr_handle_impl_t *hdlp, void *result);
  80   80  
  81   81  static int pseudonex_attach(dev_info_t *, ddi_attach_cmd_t);
  82   82  static int pseudonex_detach(dev_info_t *, ddi_detach_cmd_t);
  83   83  static int pseudonex_open(dev_t *, int, int, cred_t *);
  84   84  static int pseudonex_close(dev_t, int, int, cred_t *);
  85   85  static int pseudonex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  86   86  static int pseudonex_fm_init(dev_info_t *, dev_info_t *, int,
  87   87      ddi_iblock_cookie_t *);
  88   88  static int pseudonex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
  89   89      void *);
  90   90  
  91   91  static void *pseudonex_state;
  92   92  
  93   93  typedef struct pseudonex_state {
  94   94          dev_info_t *pnx_devi;
  95   95          int pnx_fmcap;
  96   96          ddi_iblock_cookie_t pnx_fm_ibc;
  97   97  } pseudonex_state_t;
  98   98  
  99   99  static struct bus_ops pseudonex_bus_ops = {
 100  100          BUSO_REV,
 101  101          nullbusmap,             /* bus_map */
 102  102          NULL,                   /* bus_get_intrspec */
 103  103          NULL,                   /* bus_add_intrspec */
 104  104          NULL,                   /* bus_remove_intrspec */
 105  105          i_ddi_map_fault,        /* bus_map_fault */
 106  106          ddi_no_dma_map,         /* bus_dma_map */
 107  107          ddi_no_dma_allochdl,    /* bus_dma_allochdl */
 108  108          NULL,                   /* bus_dma_freehdl */
 109  109          NULL,                   /* bus_dma_bindhdl */
 110  110          NULL,                   /* bus_dma_unbindhdl */
 111  111          NULL,                   /* bus_dma_flush */
 112  112          NULL,                   /* bus_dma_win */
 113  113          NULL,                   /* bus_dma_ctl */
 114  114          pseudonex_ctl,          /* bus_ctl */
 115  115          ddi_bus_prop_op,        /* bus_prop_op */
 116  116          0,                      /* bus_get_eventcookie */
 117  117          0,                      /* bus_add_eventcall */
 118  118          0,                      /* bus_remove_eventcall */
 119  119          0,                      /* bus_post_event */
 120  120          NULL,                   /* bus_intr_ctl */
 121  121          NULL,                   /* bus_config */
 122  122          NULL,                   /* bus_unconfig */
 123  123          pseudonex_fm_init,      /* bus_fm_init */
 124  124          NULL,                   /* bus_fm_fini */
 125  125          NULL,                   /* bus_fm_access_enter */
 126  126          NULL,                   /* bus_fm_access_exit */
 127  127          NULL,                   /* bus_power */
 128  128          pseudonex_intr_op       /* bus_intr_op */
 129  129  };
 130  130  
 131  131  static struct cb_ops pseudonex_cb_ops = {
 132  132          pseudonex_open,                 /* open */
 133  133          pseudonex_close,                /* close */
 134  134          nodev,                          /* strategy */
 135  135          nodev,                          /* print */
 136  136          nodev,                          /* dump */
 137  137          nodev,                          /* read */
 138  138          nodev,                          /* write */
 139  139          pseudonex_ioctl,                /* ioctl */
 140  140          nodev,                          /* devmap */
 141  141          nodev,                          /* mmap */
 142  142          nodev,                          /* segmap */
 143  143          nochpoll,                       /* poll */
 144  144          ddi_prop_op,                    /* cb_prop_op */
 145  145          0,                              /* streamtab  */
 146  146          D_MP | D_NEW | D_HOTPLUG        /* Driver compatibility flag */
 147  147  };
 148  148  
 149  149  static struct dev_ops pseudo_ops = {
 150  150          DEVO_REV,               /* devo_rev, */
 151  151          0,                      /* refcnt  */
 152  152          ddi_getinfo_1to1,       /* info */
 153  153          nulldev,                /* identify */
 154  154          nulldev,                /* probe */
 155  155          pseudonex_attach,       /* attach */
 156  156          pseudonex_detach,       /* detach */
 157  157          nodev,                  /* reset */
 158  158          &pseudonex_cb_ops,      /* driver operations */
 159  159          &pseudonex_bus_ops,     /* bus operations */
 160  160          nulldev,                /* power */
 161  161          ddi_quiesce_not_needed,         /* quiesce */
 162  162  };
 163  163  
 164  164  /*
 165  165   * Module linkage information for the kernel.
 166  166   */
 167  167  static struct modldrv modldrv = {
 168  168          &mod_driverops,
 169  169          "nexus driver for 'pseudo' 1.31",
 170  170          &pseudo_ops,
 171  171  };
 172  172  
 173  173  static struct modlinkage modlinkage = {
 174  174          MODREV_1, (void *)&modldrv, NULL
 175  175  };
 176  176  
 177  177  int
 178  178  _init(void)
 179  179  {
 180  180          int err;
 181  181  
 182  182          if ((err = ddi_soft_state_init(&pseudonex_state,
 183  183              sizeof (pseudonex_state_t), 0)) != 0) {
 184  184                  return (err);
 185  185          }
 186  186          if ((err = mod_install(&modlinkage)) != 0) {
 187  187                  ddi_soft_state_fini(&pseudonex_state);
 188  188                  return (err);
 189  189          }
 190  190          return (0);
 191  191  }
 192  192  
 193  193  int
 194  194  _fini(void)
 195  195  {
 196  196          int err;
 197  197  
 198  198          if ((err = mod_remove(&modlinkage)) != 0)
 199  199                  return (err);
 200  200          ddi_soft_state_fini(&pseudonex_state);
 201  201          return (0);
 202  202  }
 203  203  
 204  204  int
 205  205  _info(struct modinfo *modinfop)
 206  206  {
 207  207          return (mod_info(&modlinkage, modinfop));
 208  208  }
 209  209  
 210  210  /*ARGSUSED*/
 211  211  static int
 212  212  pseudonex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 213  213  {
 214  214          int instance;
 215  215          pseudonex_state_t *pnx_state;
 216  216  
 217  217          switch (cmd) {
 218  218          case DDI_ATTACH:
 219  219                  break;
 220  220          case DDI_RESUME:
 221  221                  return (DDI_SUCCESS);
 222  222          default:
 223  223                  return (DDI_FAILURE);
 224  224          }
 225  225  
 226  226          /*
 227  227           * Save the devi for this instance in the soft_state data.
 228  228           */
 229  229          instance = ddi_get_instance(devi);
 230  230          if (ddi_soft_state_zalloc(pseudonex_state, instance) != DDI_SUCCESS)
 231  231                  return (DDI_FAILURE);
 232  232          pnx_state = ddi_get_soft_state(pseudonex_state, instance);
 233  233          pnx_state->pnx_devi = devi;
 234  234  
 235  235          pnx_state->pnx_fmcap = DDI_FM_EREPORT_CAPABLE;
 236  236          ddi_fm_init(devi, &pnx_state->pnx_fmcap, &pnx_state->pnx_fm_ibc);
 237  237  
 238  238          if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance,
 239  239              DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
 240  240                  ddi_remove_minor_node(devi, NULL);
 241  241                  ddi_soft_state_free(pseudonex_state, instance);
 242  242                  return (DDI_FAILURE);
 243  243          }
 244  244          ddi_report_dev(devi);
 245  245          return (DDI_SUCCESS);
 246  246  }
 247  247  
 248  248  /*ARGSUSED*/
 249  249  static int
 250  250  pseudonex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 251  251  {
 252  252          int instance = ddi_get_instance(devi);
 253  253  
 254  254          if (cmd == DDI_SUSPEND)
 255  255                  return (DDI_SUCCESS);
 256  256  
 257  257          if (cmd != DDI_DETACH)
 258  258                  return (DDI_FAILURE);
 259  259  
 260  260          ddi_fm_fini(devi);
 261  261          ddi_remove_minor_node(devi, NULL);
 262  262          ddi_soft_state_free(pseudonex_state, instance);
 263  263          return (DDI_SUCCESS);
 264  264  }
 265  265  
 266  266  /*ARGSUSED*/
 267  267  static int
 268  268  pseudonex_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 269  269  {
 270  270          int instance;
 271  271  
 272  272          if (otyp != OTYP_CHR)
 273  273                  return (EINVAL);
 274  274  
 275  275          instance = getminor(*devp);
 276  276          if (ddi_get_soft_state(pseudonex_state, instance) == NULL)
 277  277                  return (ENXIO);
 278  278  
 279  279          return (0);
 280  280  }
 281  281  
 282  282  /*ARGSUSED*/
 283  283  static int
 284  284  pseudonex_close(dev_t dev, int flags, int otyp, cred_t *credp)
 285  285  {
 286  286          int instance;
 287  287  
 288  288          if (otyp != OTYP_CHR)
 289  289                  return (EINVAL);
 290  290  
 291  291          instance = getminor(dev);
 292  292          if (ddi_get_soft_state(pseudonex_state, instance) == NULL)
 293  293                  return (ENXIO);
 294  294  
 295  295          return (0);
 296  296  }
 297  297  
 298  298  /*ARGSUSED*/
 299  299  static int
 300  300  pseudonex_ioctl(dev_t dev,
 301  301      int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
 302  302  {
 303  303          int instance;
 304  304          pseudonex_state_t *pnx_state;
 305  305  
 306  306          instance = getminor(dev);
 307  307          if ((pnx_state = ddi_get_soft_state(pseudonex_state, instance)) == NULL)
 308  308                  return (ENXIO);
 309  309          ASSERT(pnx_state->pnx_devi);
 310  310          return (ndi_devctl_ioctl(pnx_state->pnx_devi, cmd, arg, mode, 0));
 311  311  }
 312  312  
 313  313  /*
 314  314   * pseudonex_intr_op: pseudonex convert an interrupt number to an
 315  315   *                      interrupt. NO OP for pseudo drivers.
 316  316   */
 317  317  /*ARGSUSED*/
 318  318  static int
 319  319  pseudonex_intr_op(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
 320  320      ddi_intr_handle_impl_t *hdlp, void *result)
 321  321  {
 322  322          return (DDI_FAILURE);
 323  323  }
 324  324  
 325  325  static int
 326  326  pseudonex_check_assignment(dev_info_t *child, int test_inst)
 327  327  {
 328  328          dev_info_t      *tdip;
 329  329          kmutex_t        *dmp;
 330  330          const char      *childname = ddi_driver_name(child);
 331  331          major_t         childmaj = ddi_name_to_major((char *)childname);
 332  332  
 333  333          dmp = &devnamesp[childmaj].dn_lock;
 334  334          LOCK_DEV_OPS(dmp);
 335  335          for (tdip = devnamesp[childmaj].dn_head;
 336  336              tdip != NULL; tdip = ddi_get_next(tdip)) {
 337  337                  /* is this the current node? */
 338  338                  if (tdip == child)
 339  339                          continue;
 340  340                  /* is this a duplicate instance? */
 341  341                  if (test_inst == ddi_get_instance(tdip)) {
 342  342                          UNLOCK_DEV_OPS(dmp);
 343  343                          return (DDI_FAILURE);
 344  344                  }
 345  345          }
 346  346          UNLOCK_DEV_OPS(dmp);
 347  347          return (DDI_SUCCESS);
 348  348  }
 349  349  
 350  350  /*
 351  351   * This is a nasty, slow hack.  But we're stuck with it until we do some
 352  352   * major surgery on the instance assignment subsystem, to allow pseudonode
 353  353   * instance assignment to be tracked there.
 354  354   *
 355  355   * To auto-assign an instance number, we exhaustively search the instance
 356  356   * list for each possible instance number until we find one which is unused.
 357  357   */
 358  358  static int
 359  359  pseudonex_auto_assign(dev_info_t *child)
 360  360  {
 361  361          dev_info_t      *tdip;
 362  362          kmutex_t        *dmp;
 363  363          const char      *childname = ddi_driver_name(child);
 364  364          major_t         childmaj = ddi_name_to_major((char *)childname);
 365  365          int inst = 0;
 366  366  
 367  367          dmp = &devnamesp[childmaj].dn_lock;
 368  368          LOCK_DEV_OPS(dmp);
 369  369          for (inst = 0; inst <= MAXMIN32; inst++) {
 370  370                  for (tdip = devnamesp[childmaj].dn_head; tdip != NULL;
 371  371                      tdip = ddi_get_next(tdip)) {
 372  372                          /* is this the current node? */
 373  373                          if (tdip == child)
 374  374                                  continue;
 375  375                          if (inst == ddi_get_instance(tdip)) {
 376  376                                  break;
 377  377                          }
  
    | 
      ↓ open down ↓ | 
    377 lines elided | 
    
      ↑ open up ↑ | 
  
 378  378                  }
 379  379                  if (tdip == NULL) {
 380  380                          UNLOCK_DEV_OPS(dmp);
 381  381                          return (inst);
 382  382                  }
 383  383          }
 384  384          UNLOCK_DEV_OPS(dmp);
 385  385          return (-1);
 386  386  }
 387  387  
      388 +/* ARGSUSED */
 388  389  static int
 389  390  pseudonex_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
 390  391      ddi_iblock_cookie_t *ibc)
 391  392  {
 392  393          pseudonex_state_t *pnx_state;
 393  394  
 394  395          pnx_state = ddi_get_soft_state(pseudonex_state, ddi_get_instance(dip));
 395  396          ASSERT(pnx_state != NULL);
 396  397          ASSERT(ibc != NULL);
 397  398          *ibc = pnx_state->pnx_fm_ibc;
 398  399          return (pnx_state->pnx_fmcap & cap);
 399  400  }
 400  401  
 401  402  static int
 402  403  pseudonex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
 403  404      void *arg, void *result)
 404  405  {
 405  406          switch (ctlop) {
 406  407          case DDI_CTLOPS_REPORTDEV:
 407  408                  if (rdip == NULL)
 408  409                          return (DDI_FAILURE);
 409  410                  cmn_err(CE_CONT, "?pseudo-device: %s%d\n",
 410  411                      ddi_driver_name(rdip), ddi_get_instance(rdip));
 411  412                  return (DDI_SUCCESS);
 412  413  
 413  414          case DDI_CTLOPS_INITCHILD:
 414  415          {
 415  416                  char name[12];  /* enough for a decimal integer */
 416  417                  int instance = -1;
 417  418                  dev_info_t *child = (dev_info_t *)arg;
 418  419                  const char *childname = ddi_driver_name(child);
 419  420                  char **childlist;
 420  421                  uint_t nelems;
 421  422                  int auto_assign = 0;
 422  423  
 423  424                  /*
 424  425                   * If this pseudonex node has a valid-children property,
 425  426                   * then that acts as an access control list for children
 426  427                   * allowed to attach beneath this node.  Honor it.
 427  428                   */
 428  429                  if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
 429  430                      DDI_PROP_DONTPASS, "valid-children", &childlist,
 430  431                      &nelems) == DDI_PROP_SUCCESS) {
 431  432                          int i, ok = 0;
 432  433                          for (i = 0; i < nelems; i++) {
 433  434                                  if (strcmp(childlist[i], childname) == 0) {
 434  435                                          ok = 1;
 435  436                                          break;
 436  437                                  }
 437  438                          }
 438  439                          ddi_prop_free(childlist);
 439  440                          if (!ok)
 440  441                                  return (DDI_FAILURE);
 441  442                  }
 442  443  
 443  444                  /*
 444  445                   * Look up the "instance" property. If it does not exist,
 445  446                   * check to see if the "auto-assign-instance" property is set.
 446  447                   * If not, default to using instance 0; while not ideal, this
 447  448                   * is a legacy behavior we must continue to support.
 448  449                   */
 449  450                  instance = ddi_prop_get_int(DDI_DEV_T_ANY, child,
 450  451                      DDI_PROP_DONTPASS, "instance", -1);
 451  452                  auto_assign = ddi_prop_exists(DDI_DEV_T_ANY, child,
 452  453                      DDI_PROP_DONTPASS, "auto-assign-instance");
 453  454                  NDI_CONFIG_DEBUG((CE_NOTE,
 454  455                      "pseudonex: DDI_CTLOPS_INITCHILD(instance=%d, "
 455  456                      "auto-assign=%d)", instance, auto_assign));
 456  457  
 457  458                  if (instance != -1 && auto_assign != 0) {
 458  459                          NDI_CONFIG_DEBUG((CE_NOTE, "both instance and "
 459  460                              "auto-assign-instance properties specified. "
 460  461                              "Node rejected."));
 461  462                          return (DDI_FAILURE);
 462  463                  }
 463  464  
 464  465                  if (instance == -1 && auto_assign == 0) {
 465  466                          /* default to instance 0 if not specified */
 466  467                          NDI_CONFIG_DEBUG((CE_NOTE, "defaulting to 0"));
 467  468                          instance = 0;
 468  469                  }
 469  470  
 470  471                  /*
 471  472                   * If an instance has been specified, determine if this
 472  473                   * instance is already in use; if we need to pick an instance,
 473  474                   * we do it here.
 474  475                   */
 475  476                  if (auto_assign) {
 476  477                          if ((instance = pseudonex_auto_assign(child)) == -1) {
 477  478                                  NDI_CONFIG_DEBUG((CE_NOTE, "failed to "
 478  479                                      "auto-select instance for %s", childname));
 479  480                                  return (DDI_FAILURE);
 480  481                          }
 481  482                          NDI_CONFIG_DEBUG((CE_NOTE,
 482  483                              "auto-selected instance for %s: %d",
 483  484                              childname, instance));
 484  485                  } else {
 485  486                          if (pseudonex_check_assignment(child, instance) ==
 486  487                              DDI_FAILURE) {
 487  488                                  NDI_CONFIG_DEBUG((CE_WARN,
 488  489                                      "Duplicate instance %d of node \"%s\" "
 489  490                                      "ignored.", instance, childname));
 490  491                                  return (DDI_FAILURE);
 491  492                          }
 492  493                          NDI_CONFIG_DEBUG((CE_NOTE,
 493  494                              "using fixed-assignment instance for %s: %d",
 494  495                              childname, instance));
 495  496                  }
 496  497  
 497  498                  /*
 498  499                   * Attach the instance number to the node. This allows
 499  500                   * us to have multiple instances of the same pseudo
 500  501                   * device, they will be named 'device@instance'. If this
 501  502                   * breaks programs, we may need to special-case instance 0
 502  503                   * into 'device'. Ick. devlinks appears to handle the
 503  504                   * new names ok, so if only names in /dev are used
 504  505                   * this may not be necessary.
 505  506                   */
 506  507                  (void) snprintf(name, sizeof (name), "%d", instance);
 507  508                  DEVI(child)->devi_instance = instance;
 508  509                  ddi_set_name_addr(child, name);
 509  510                  return (DDI_SUCCESS);
 510  511          }
 511  512  
 512  513          case DDI_CTLOPS_UNINITCHILD:
 513  514          {
 514  515                  dev_info_t *child = (dev_info_t *)arg;
 515  516  
 516  517                  NDI_CONFIG_DEBUG((CE_NOTE,
 517  518                      "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)",
 518  519                      ddi_driver_name(child), DEVI(child)->devi_instance));
 519  520  
 520  521                  ddi_set_name_addr(child, NULL);
 521  522  
 522  523                  return (DDI_SUCCESS);
 523  524          }
 524  525  
 525  526          case DDI_CTLOPS_DMAPMAPC:
 526  527          case DDI_CTLOPS_REPORTINT:
 527  528          case DDI_CTLOPS_REGSIZE:
 528  529          case DDI_CTLOPS_NREGS:
 529  530          case DDI_CTLOPS_SIDDEV:
 530  531          case DDI_CTLOPS_SLAVEONLY:
 531  532          case DDI_CTLOPS_AFFINITY:
 532  533          case DDI_CTLOPS_POKE:
 533  534          case DDI_CTLOPS_PEEK:
 534  535                  /*
 535  536                   * These ops correspond to functions that "shouldn't" be called
 536  537                   * by a pseudo driver.  So we whine when we're called.
 537  538                   */
 538  539                  cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
 539  540                      ddi_driver_name(dip), ddi_get_instance(dip), ctlop,
 540  541                      ddi_driver_name(rdip), ddi_get_instance(rdip));
 541  542                  return (DDI_FAILURE);
 542  543  
 543  544          case DDI_CTLOPS_ATTACH:
 544  545          case DDI_CTLOPS_BTOP:
 545  546          case DDI_CTLOPS_BTOPR:
 546  547          case DDI_CTLOPS_DETACH:
 547  548          case DDI_CTLOPS_DVMAPAGESIZE:
 548  549          case DDI_CTLOPS_IOMIN:
 549  550          case DDI_CTLOPS_POWER:
 550  551          case DDI_CTLOPS_PTOB:
 551  552          default:
 552  553                  /*
 553  554                   * The ops that we pass up (default).  We pass up memory
 554  555                   * allocation oriented ops that we receive - these may be
 555  556                   * associated with pseudo HBA drivers below us with target
 556  557                   * drivers below them that use ddi memory allocation
 557  558                   * interfaces like scsi_alloc_consistent_buf.
 558  559                   */
 559  560                  return (ddi_ctlops(dip, rdip, ctlop, arg, result));
 560  561          }
 561  562  }
  
    | 
      ↓ open down ↓ | 
    164 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX