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