Print this page
    
1402 ixgbe intel 10gbit driver very slow (backs out 534)
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/os/sunddi.c
          +++ new/usr/src/uts/common/os/sunddi.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 (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   */
  25   25  
  26   26  #include <sys/note.h>
  27   27  #include <sys/types.h>
  28   28  #include <sys/param.h>
  29   29  #include <sys/systm.h>
  30   30  #include <sys/buf.h>
  31   31  #include <sys/uio.h>
  32   32  #include <sys/cred.h>
  33   33  #include <sys/poll.h>
  34   34  #include <sys/mman.h>
  35   35  #include <sys/kmem.h>
  36   36  #include <sys/model.h>
  37   37  #include <sys/file.h>
  38   38  #include <sys/proc.h>
  39   39  #include <sys/open.h>
  40   40  #include <sys/user.h>
  41   41  #include <sys/t_lock.h>
  42   42  #include <sys/vm.h>
  43   43  #include <sys/stat.h>
  44   44  #include <vm/hat.h>
  45   45  #include <vm/seg.h>
  46   46  #include <vm/seg_vn.h>
  47   47  #include <vm/seg_dev.h>
  48   48  #include <vm/as.h>
  49   49  #include <sys/cmn_err.h>
  50   50  #include <sys/cpuvar.h>
  51   51  #include <sys/debug.h>
  52   52  #include <sys/autoconf.h>
  53   53  #include <sys/sunddi.h>
  54   54  #include <sys/esunddi.h>
  55   55  #include <sys/sunndi.h>
  56   56  #include <sys/kstat.h>
  57   57  #include <sys/conf.h>
  58   58  #include <sys/ddi_impldefs.h>   /* include implementation structure defs */
  59   59  #include <sys/ndi_impldefs.h>   /* include prototypes */
  60   60  #include <sys/ddi_timer.h>
  61   61  #include <sys/hwconf.h>
  62   62  #include <sys/pathname.h>
  63   63  #include <sys/modctl.h>
  64   64  #include <sys/epm.h>
  65   65  #include <sys/devctl.h>
  66   66  #include <sys/callb.h>
  67   67  #include <sys/cladm.h>
  68   68  #include <sys/sysevent.h>
  69   69  #include <sys/dacf_impl.h>
  70   70  #include <sys/ddidevmap.h>
  71   71  #include <sys/bootconf.h>
  72   72  #include <sys/disp.h>
  73   73  #include <sys/atomic.h>
  74   74  #include <sys/promif.h>
  75   75  #include <sys/instance.h>
  76   76  #include <sys/sysevent/eventdefs.h>
  77   77  #include <sys/task.h>
  78   78  #include <sys/project.h>
  79   79  #include <sys/taskq.h>
  80   80  #include <sys/devpolicy.h>
  81   81  #include <sys/ctype.h>
  82   82  #include <net/if.h>
  83   83  #include <sys/rctl.h>
  84   84  #include <sys/zone.h>
  85   85  #include <sys/clock_impl.h>
  86   86  #include <sys/ddi.h>
  87   87  #include <sys/modhash.h>
  88   88  #include <sys/sunldi_impl.h>
  89   89  #include <sys/fs/dv_node.h>
  90   90  #include <sys/fs/snode.h>
  91   91  
  92   92  extern  pri_t   minclsyspri;
  93   93  
  94   94  extern  rctl_hndl_t rc_project_locked_mem;
  95   95  extern  rctl_hndl_t rc_zone_locked_mem;
  96   96  
  97   97  #ifdef DEBUG
  98   98  static int sunddi_debug = 0;
  99   99  #endif /* DEBUG */
 100  100  
 101  101  /* ddi_umem_unlock miscellaneous */
 102  102  
 103  103  static  void    i_ddi_umem_unlock_thread_start(void);
 104  104  
 105  105  static  kmutex_t        ddi_umem_unlock_mutex; /* unlock list mutex */
 106  106  static  kcondvar_t      ddi_umem_unlock_cv; /* unlock list block/unblock */
 107  107  static  kthread_t       *ddi_umem_unlock_thread;
 108  108  /*
 109  109   * The ddi_umem_unlock FIFO list.  NULL head pointer indicates empty list.
 110  110   */
 111  111  static  struct  ddi_umem_cookie *ddi_umem_unlock_head = NULL;
 112  112  static  struct  ddi_umem_cookie *ddi_umem_unlock_tail = NULL;
 113  113  
 114  114  /*
 115  115   * DDI(Sun) Function and flag definitions:
 116  116   */
 117  117  
 118  118  #if defined(__x86)
 119  119  /*
 120  120   * Used to indicate which entries were chosen from a range.
 121  121   */
 122  122  char    *chosen_reg = "chosen-reg";
 123  123  #endif
 124  124  
 125  125  /*
 126  126   * Function used to ring system console bell
 127  127   */
 128  128  void (*ddi_console_bell_func)(clock_t duration);
 129  129  
 130  130  /*
 131  131   * Creating register mappings and handling interrupts:
 132  132   */
 133  133  
 134  134  /*
 135  135   * Generic ddi_map: Call parent to fulfill request...
 136  136   */
 137  137  
 138  138  int
 139  139  ddi_map(dev_info_t *dp, ddi_map_req_t *mp, off_t offset,
 140  140      off_t len, caddr_t *addrp)
 141  141  {
 142  142          dev_info_t *pdip;
 143  143  
 144  144          ASSERT(dp);
 145  145          pdip = (dev_info_t *)DEVI(dp)->devi_parent;
 146  146          return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip,
 147  147              dp, mp, offset, len, addrp));
 148  148  }
 149  149  
 150  150  /*
 151  151   * ddi_apply_range: (Called by nexi only.)
 152  152   * Apply ranges in parent node dp, to child regspec rp...
 153  153   */
 154  154  
 155  155  int
 156  156  ddi_apply_range(dev_info_t *dp, dev_info_t *rdip, struct regspec *rp)
 157  157  {
 158  158          return (i_ddi_apply_range(dp, rdip, rp));
 159  159  }
 160  160  
 161  161  int
 162  162  ddi_map_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
 163  163      off_t len)
 164  164  {
 165  165          ddi_map_req_t mr;
 166  166  #if defined(__x86)
 167  167          struct {
 168  168                  int     bus;
 169  169                  int     addr;
 170  170                  int     size;
 171  171          } reg, *reglist;
 172  172          uint_t  length;
 173  173          int     rc;
 174  174  
 175  175          /*
 176  176           * get the 'registers' or the 'reg' property.
 177  177           * We look up the reg property as an array of
 178  178           * int's.
 179  179           */
 180  180          rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
 181  181              DDI_PROP_DONTPASS, "registers", (int **)®list, &length);
 182  182          if (rc != DDI_PROP_SUCCESS)
 183  183                  rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
 184  184                      DDI_PROP_DONTPASS, "reg", (int **)®list, &length);
 185  185          if (rc == DDI_PROP_SUCCESS) {
 186  186                  /*
 187  187                   * point to the required entry.
 188  188                   */
 189  189                  reg = reglist[rnumber];
 190  190                  reg.addr += offset;
 191  191                  if (len != 0)
 192  192                          reg.size = len;
 193  193                  /*
 194  194                   * make a new property containing ONLY the required tuple.
 195  195                   */
 196  196                  if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
 197  197                      chosen_reg, (int *)®, (sizeof (reg)/sizeof (int)))
 198  198                      != DDI_PROP_SUCCESS) {
 199  199                          cmn_err(CE_WARN, "%s%d: cannot create '%s' "
 200  200                              "property", DEVI(dip)->devi_name,
 201  201                              DEVI(dip)->devi_instance, chosen_reg);
 202  202                  }
 203  203                  /*
 204  204                   * free the memory allocated by
 205  205                   * ddi_prop_lookup_int_array ().
 206  206                   */
 207  207                  ddi_prop_free((void *)reglist);
 208  208          }
 209  209  #endif
 210  210          mr.map_op = DDI_MO_MAP_LOCKED;
 211  211          mr.map_type = DDI_MT_RNUMBER;
 212  212          mr.map_obj.rnumber = rnumber;
 213  213          mr.map_prot = PROT_READ | PROT_WRITE;
 214  214          mr.map_flags = DDI_MF_KERNEL_MAPPING;
 215  215          mr.map_handlep = NULL;
 216  216          mr.map_vers = DDI_MAP_VERSION;
 217  217  
 218  218          /*
 219  219           * Call my parent to map in my regs.
 220  220           */
 221  221  
 222  222          return (ddi_map(dip, &mr, offset, len, kaddrp));
 223  223  }
 224  224  
 225  225  void
 226  226  ddi_unmap_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
 227  227      off_t len)
 228  228  {
 229  229          ddi_map_req_t mr;
 230  230  
 231  231          mr.map_op = DDI_MO_UNMAP;
 232  232          mr.map_type = DDI_MT_RNUMBER;
 233  233          mr.map_flags = DDI_MF_KERNEL_MAPPING;
 234  234          mr.map_prot = PROT_READ | PROT_WRITE;   /* who cares? */
 235  235          mr.map_obj.rnumber = rnumber;
 236  236          mr.map_handlep = NULL;
 237  237          mr.map_vers = DDI_MAP_VERSION;
 238  238  
 239  239          /*
 240  240           * Call my parent to unmap my regs.
 241  241           */
 242  242  
 243  243          (void) ddi_map(dip, &mr, offset, len, kaddrp);
 244  244          *kaddrp = (caddr_t)0;
 245  245  #if defined(__x86)
 246  246          (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, chosen_reg);
 247  247  #endif
 248  248  }
 249  249  
 250  250  int
 251  251  ddi_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
 252  252          off_t offset, off_t len, caddr_t *vaddrp)
 253  253  {
 254  254          return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp));
 255  255  }
 256  256  
 257  257  /*
 258  258   * nullbusmap:  The/DDI default bus_map entry point for nexi
 259  259   *              not conforming to the reg/range paradigm (i.e. scsi, etc.)
 260  260   *              with no HAT/MMU layer to be programmed at this level.
 261  261   *
 262  262   *              If the call is to map by rnumber, return an error,
 263  263   *              otherwise pass anything else up the tree to my parent.
 264  264   */
 265  265  int
 266  266  nullbusmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
 267  267          off_t offset, off_t len, caddr_t *vaddrp)
 268  268  {
 269  269          _NOTE(ARGUNUSED(rdip))
 270  270          if (mp->map_type == DDI_MT_RNUMBER)
 271  271                  return (DDI_ME_UNSUPPORTED);
 272  272  
 273  273          return (ddi_map(dip, mp, offset, len, vaddrp));
 274  274  }
 275  275  
 276  276  /*
 277  277   * ddi_rnumber_to_regspec: Not for use by leaf drivers.
 278  278   *                         Only for use by nexi using the reg/range paradigm.
 279  279   */
 280  280  struct regspec *
 281  281  ddi_rnumber_to_regspec(dev_info_t *dip, int rnumber)
 282  282  {
 283  283          return (i_ddi_rnumber_to_regspec(dip, rnumber));
 284  284  }
 285  285  
 286  286  
 287  287  /*
 288  288   * Note that we allow the dip to be nil because we may be called
 289  289   * prior even to the instantiation of the devinfo tree itself - all
 290  290   * regular leaf and nexus drivers should always use a non-nil dip!
 291  291   *
 292  292   * We treat peek in a somewhat cavalier fashion .. assuming that we'll
 293  293   * simply get a synchronous fault as soon as we touch a missing address.
 294  294   *
 295  295   * Poke is rather more carefully handled because we might poke to a write
 296  296   * buffer, "succeed", then only find some time later that we got an
 297  297   * asynchronous fault that indicated that the address we were writing to
 298  298   * was not really backed by hardware.
 299  299   */
 300  300  
 301  301  static int
 302  302  i_ddi_peekpoke(dev_info_t *devi, ddi_ctl_enum_t cmd, size_t size,
 303  303      void *addr, void *value_p)
 304  304  {
 305  305          union {
 306  306                  uint64_t        u64;
 307  307                  uint32_t        u32;
 308  308                  uint16_t        u16;
 309  309                  uint8_t         u8;
 310  310          } peekpoke_value;
 311  311  
 312  312          peekpoke_ctlops_t peekpoke_args;
 313  313          uint64_t dummy_result;
 314  314          int rval;
 315  315  
 316  316          /* Note: size is assumed to be correct;  it is not checked. */
 317  317          peekpoke_args.size = size;
 318  318          peekpoke_args.dev_addr = (uintptr_t)addr;
 319  319          peekpoke_args.handle = NULL;
 320  320          peekpoke_args.repcount = 1;
 321  321          peekpoke_args.flags = 0;
 322  322  
 323  323          if (cmd == DDI_CTLOPS_POKE) {
 324  324                  switch (size) {
 325  325                  case sizeof (uint8_t):
 326  326                          peekpoke_value.u8 = *(uint8_t *)value_p;
 327  327                          break;
 328  328                  case sizeof (uint16_t):
 329  329                          peekpoke_value.u16 = *(uint16_t *)value_p;
 330  330                          break;
 331  331                  case sizeof (uint32_t):
 332  332                          peekpoke_value.u32 = *(uint32_t *)value_p;
 333  333                          break;
 334  334                  case sizeof (uint64_t):
 335  335                          peekpoke_value.u64 = *(uint64_t *)value_p;
 336  336                          break;
 337  337                  }
 338  338          }
 339  339  
 340  340          peekpoke_args.host_addr = (uintptr_t)&peekpoke_value.u64;
 341  341  
 342  342          if (devi != NULL)
 343  343                  rval = ddi_ctlops(devi, devi, cmd, &peekpoke_args,
 344  344                      &dummy_result);
 345  345          else
 346  346                  rval = peekpoke_mem(cmd, &peekpoke_args);
 347  347  
 348  348          /*
 349  349           * A NULL value_p is permitted by ddi_peek(9F); discard the result.
 350  350           */
 351  351          if ((cmd == DDI_CTLOPS_PEEK) & (value_p != NULL)) {
 352  352                  switch (size) {
 353  353                  case sizeof (uint8_t):
 354  354                          *(uint8_t *)value_p = peekpoke_value.u8;
 355  355                          break;
 356  356                  case sizeof (uint16_t):
 357  357                          *(uint16_t *)value_p = peekpoke_value.u16;
 358  358                          break;
 359  359                  case sizeof (uint32_t):
 360  360                          *(uint32_t *)value_p = peekpoke_value.u32;
 361  361                          break;
 362  362                  case sizeof (uint64_t):
 363  363                          *(uint64_t *)value_p = peekpoke_value.u64;
 364  364                          break;
 365  365                  }
 366  366          }
 367  367  
 368  368          return (rval);
 369  369  }
 370  370  
 371  371  /*
 372  372   * Keep ddi_peek() and ddi_poke() in case 3rd parties are calling this.
 373  373   * they shouldn't be, but the 9f manpage kind of pseudo exposes it.
 374  374   */
 375  375  int
 376  376  ddi_peek(dev_info_t *devi, size_t size, void *addr, void *value_p)
 377  377  {
 378  378          switch (size) {
 379  379          case sizeof (uint8_t):
 380  380          case sizeof (uint16_t):
 381  381          case sizeof (uint32_t):
 382  382          case sizeof (uint64_t):
 383  383                  break;
 384  384          default:
 385  385                  return (DDI_FAILURE);
 386  386          }
 387  387  
 388  388          return (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, size, addr, value_p));
 389  389  }
 390  390  
 391  391  int
 392  392  ddi_poke(dev_info_t *devi, size_t size, void *addr, void *value_p)
 393  393  {
 394  394          switch (size) {
 395  395          case sizeof (uint8_t):
 396  396          case sizeof (uint16_t):
 397  397          case sizeof (uint32_t):
 398  398          case sizeof (uint64_t):
 399  399                  break;
 400  400          default:
 401  401                  return (DDI_FAILURE);
 402  402          }
 403  403  
 404  404          return (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, size, addr, value_p));
 405  405  }
 406  406  
 407  407  int
 408  408  ddi_peek8(dev_info_t *dip, int8_t *addr, int8_t *val_p)
 409  409  {
 410  410          return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
 411  411              val_p));
 412  412  }
 413  413  
 414  414  int
 415  415  ddi_peek16(dev_info_t *dip, int16_t *addr, int16_t *val_p)
 416  416  {
 417  417          return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
 418  418              val_p));
 419  419  }
 420  420  
 421  421  int
 422  422  ddi_peek32(dev_info_t *dip, int32_t *addr, int32_t *val_p)
 423  423  {
 424  424          return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
 425  425              val_p));
 426  426  }
 427  427  
 428  428  int
 429  429  ddi_peek64(dev_info_t *dip, int64_t *addr, int64_t *val_p)
 430  430  {
 431  431          return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
 432  432              val_p));
 433  433  }
 434  434  
 435  435  
 436  436  /*
 437  437   * We need to separate the old interfaces from the new ones and leave them
 438  438   * in here for a while. Previous versions of the OS defined the new interfaces
 439  439   * to the old interfaces. This way we can fix things up so that we can
 440  440   * eventually remove these interfaces.
 441  441   * e.g. A 3rd party module/driver using ddi_peek8 and built against S10
 442  442   * or earlier will actually have a reference to ddi_peekc in the binary.
 443  443   */
 444  444  #ifdef _ILP32
 445  445  int
 446  446  ddi_peekc(dev_info_t *dip, int8_t *addr, int8_t *val_p)
 447  447  {
 448  448          return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
 449  449              val_p));
 450  450  }
 451  451  
 452  452  int
 453  453  ddi_peeks(dev_info_t *dip, int16_t *addr, int16_t *val_p)
 454  454  {
 455  455          return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
 456  456              val_p));
 457  457  }
 458  458  
 459  459  int
 460  460  ddi_peekl(dev_info_t *dip, int32_t *addr, int32_t *val_p)
 461  461  {
 462  462          return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
 463  463              val_p));
 464  464  }
 465  465  
 466  466  int
 467  467  ddi_peekd(dev_info_t *dip, int64_t *addr, int64_t *val_p)
 468  468  {
 469  469          return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
 470  470              val_p));
 471  471  }
 472  472  #endif /* _ILP32 */
 473  473  
 474  474  int
 475  475  ddi_poke8(dev_info_t *dip, int8_t *addr, int8_t val)
 476  476  {
 477  477          return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
 478  478  }
 479  479  
 480  480  int
 481  481  ddi_poke16(dev_info_t *dip, int16_t *addr, int16_t val)
 482  482  {
 483  483          return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
 484  484  }
 485  485  
 486  486  int
 487  487  ddi_poke32(dev_info_t *dip, int32_t *addr, int32_t val)
 488  488  {
 489  489          return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
 490  490  }
 491  491  
 492  492  int
 493  493  ddi_poke64(dev_info_t *dip, int64_t *addr, int64_t val)
 494  494  {
 495  495          return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
 496  496  }
 497  497  
 498  498  /*
 499  499   * We need to separate the old interfaces from the new ones and leave them
 500  500   * in here for a while. Previous versions of the OS defined the new interfaces
 501  501   * to the old interfaces. This way we can fix things up so that we can
 502  502   * eventually remove these interfaces.
 503  503   * e.g. A 3rd party module/driver using ddi_poke8 and built against S10
 504  504   * or earlier will actually have a reference to ddi_pokec in the binary.
 505  505   */
 506  506  #ifdef _ILP32
 507  507  int
 508  508  ddi_pokec(dev_info_t *dip, int8_t *addr, int8_t val)
 509  509  {
 510  510          return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
 511  511  }
 512  512  
 513  513  int
 514  514  ddi_pokes(dev_info_t *dip, int16_t *addr, int16_t val)
 515  515  {
 516  516          return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
 517  517  }
 518  518  
 519  519  int
 520  520  ddi_pokel(dev_info_t *dip, int32_t *addr, int32_t val)
 521  521  {
 522  522          return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
 523  523  }
 524  524  
 525  525  int
 526  526  ddi_poked(dev_info_t *dip, int64_t *addr, int64_t val)
 527  527  {
 528  528          return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
 529  529  }
 530  530  #endif /* _ILP32 */
 531  531  
 532  532  /*
 533  533   * ddi_peekpokeio() is used primarily by the mem drivers for moving
 534  534   * data to and from uio structures via peek and poke.  Note that we
 535  535   * use "internal" routines ddi_peek and ddi_poke to make this go
 536  536   * slightly faster, avoiding the call overhead ..
 537  537   */
 538  538  int
 539  539  ddi_peekpokeio(dev_info_t *devi, struct uio *uio, enum uio_rw rw,
 540  540      caddr_t addr, size_t len, uint_t xfersize)
 541  541  {
 542  542          int64_t ibuffer;
 543  543          int8_t w8;
 544  544          size_t sz;
 545  545          int o;
 546  546  
 547  547          if (xfersize > sizeof (long))
 548  548                  xfersize = sizeof (long);
 549  549  
 550  550          while (len != 0) {
 551  551                  if ((len | (uintptr_t)addr) & 1) {
 552  552                          sz = sizeof (int8_t);
 553  553                          if (rw == UIO_WRITE) {
 554  554                                  if ((o = uwritec(uio)) == -1)
 555  555                                          return (DDI_FAILURE);
 556  556                                  if (ddi_poke8(devi, (int8_t *)addr,
 557  557                                      (int8_t)o) != DDI_SUCCESS)
 558  558                                          return (DDI_FAILURE);
 559  559                          } else {
 560  560                                  if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
 561  561                                      (int8_t *)addr, &w8) != DDI_SUCCESS)
 562  562                                          return (DDI_FAILURE);
 563  563                                  if (ureadc(w8, uio))
 564  564                                          return (DDI_FAILURE);
 565  565                          }
 566  566                  } else {
 567  567                          switch (xfersize) {
 568  568                          case sizeof (int64_t):
 569  569                                  if (((len | (uintptr_t)addr) &
 570  570                                      (sizeof (int64_t) - 1)) == 0) {
 571  571                                          sz = xfersize;
 572  572                                          break;
 573  573                                  }
 574  574                                  /*FALLTHROUGH*/
 575  575                          case sizeof (int32_t):
 576  576                                  if (((len | (uintptr_t)addr) &
 577  577                                      (sizeof (int32_t) - 1)) == 0) {
 578  578                                          sz = xfersize;
 579  579                                          break;
 580  580                                  }
 581  581                                  /*FALLTHROUGH*/
 582  582                          default:
 583  583                                  /*
 584  584                                   * This still assumes that we might have an
 585  585                                   * I/O bus out there that permits 16-bit
 586  586                                   * transfers (and that it would be upset by
 587  587                                   * 32-bit transfers from such locations).
 588  588                                   */
 589  589                                  sz = sizeof (int16_t);
 590  590                                  break;
 591  591                          }
 592  592  
 593  593                          if (rw == UIO_READ) {
 594  594                                  if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
 595  595                                      addr, &ibuffer) != DDI_SUCCESS)
 596  596                                          return (DDI_FAILURE);
 597  597                          }
 598  598  
 599  599                          if (uiomove(&ibuffer, sz, rw, uio))
 600  600                                  return (DDI_FAILURE);
 601  601  
 602  602                          if (rw == UIO_WRITE) {
 603  603                                  if (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, sz,
 604  604                                      addr, &ibuffer) != DDI_SUCCESS)
 605  605                                          return (DDI_FAILURE);
 606  606                          }
 607  607                  }
 608  608                  addr += sz;
 609  609                  len -= sz;
 610  610          }
 611  611          return (DDI_SUCCESS);
 612  612  }
 613  613  
 614  614  /*
 615  615   * These routines are used by drivers that do layered ioctls
 616  616   * On sparc, they're implemented in assembler to avoid spilling
 617  617   * register windows in the common (copyin) case ..
 618  618   */
 619  619  #if !defined(__sparc)
 620  620  int
 621  621  ddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
 622  622  {
 623  623          if (flags & FKIOCTL)
 624  624                  return (kcopy(buf, kernbuf, size) ? -1 : 0);
 625  625          return (copyin(buf, kernbuf, size));
 626  626  }
 627  627  
 628  628  int
 629  629  ddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
 630  630  {
 631  631          if (flags & FKIOCTL)
 632  632                  return (kcopy(buf, kernbuf, size) ? -1 : 0);
 633  633          return (copyout(buf, kernbuf, size));
 634  634  }
 635  635  #endif  /* !__sparc */
 636  636  
 637  637  /*
 638  638   * Conversions in nexus pagesize units.  We don't duplicate the
 639  639   * 'nil dip' semantics of peek/poke because btopr/btop/ptob are DDI/DKI
 640  640   * routines anyway.
 641  641   */
 642  642  unsigned long
 643  643  ddi_btop(dev_info_t *dip, unsigned long bytes)
 644  644  {
 645  645          unsigned long pages;
 646  646  
 647  647          (void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOP, &bytes, &pages);
 648  648          return (pages);
 649  649  }
 650  650  
 651  651  unsigned long
 652  652  ddi_btopr(dev_info_t *dip, unsigned long bytes)
 653  653  {
 654  654          unsigned long pages;
 655  655  
 656  656          (void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOPR, &bytes, &pages);
 657  657          return (pages);
 658  658  }
 659  659  
 660  660  unsigned long
 661  661  ddi_ptob(dev_info_t *dip, unsigned long pages)
 662  662  {
 663  663          unsigned long bytes;
 664  664  
 665  665          (void) ddi_ctlops(dip, dip, DDI_CTLOPS_PTOB, &pages, &bytes);
 666  666          return (bytes);
 667  667  }
 668  668  
 669  669  unsigned int
 670  670  ddi_enter_critical(void)
 671  671  {
 672  672          return ((uint_t)spl7());
 673  673  }
 674  674  
 675  675  void
 676  676  ddi_exit_critical(unsigned int spl)
 677  677  {
 678  678          splx((int)spl);
 679  679  }
 680  680  
 681  681  /*
 682  682   * Nexus ctlops punter
 683  683   */
 684  684  
 685  685  #if !defined(__sparc)
 686  686  /*
 687  687   * Request bus_ctl parent to handle a bus_ctl request
 688  688   *
 689  689   * (The sparc version is in sparc_ddi.s)
 690  690   */
 691  691  int
 692  692  ddi_ctlops(dev_info_t *d, dev_info_t *r, ddi_ctl_enum_t op, void *a, void *v)
 693  693  {
 694  694          int (*fp)();
 695  695  
 696  696          if (!d || !r)
 697  697                  return (DDI_FAILURE);
 698  698  
 699  699          if ((d = (dev_info_t *)DEVI(d)->devi_bus_ctl) == NULL)
 700  700                  return (DDI_FAILURE);
 701  701  
 702  702          fp = DEVI(d)->devi_ops->devo_bus_ops->bus_ctl;
 703  703          return ((*fp)(d, r, op, a, v));
 704  704  }
 705  705  
 706  706  #endif
 707  707  
 708  708  /*
 709  709   * DMA/DVMA setup
 710  710   */
 711  711  
 712  712  #if defined(__sparc)
 713  713  static ddi_dma_lim_t standard_limits = {
 714  714          (uint_t)0,      /* addr_t dlim_addr_lo */
 715  715          (uint_t)-1,     /* addr_t dlim_addr_hi */
 716  716          (uint_t)-1,     /* uint_t dlim_cntr_max */
 717  717          (uint_t)1,      /* uint_t dlim_burstsizes */
 718  718          (uint_t)1,      /* uint_t dlim_minxfer */
 719  719          0               /* uint_t dlim_dmaspeed */
 720  720  };
 721  721  #elif defined(__x86)
 722  722  static ddi_dma_lim_t standard_limits = {
 723  723          (uint_t)0,              /* addr_t dlim_addr_lo */
 724  724          (uint_t)0xffffff,       /* addr_t dlim_addr_hi */
 725  725          (uint_t)0,              /* uint_t dlim_cntr_max */
 726  726          (uint_t)0x00000001,     /* uint_t dlim_burstsizes */
 727  727          (uint_t)DMA_UNIT_8,     /* uint_t dlim_minxfer */
 728  728          (uint_t)0,              /* uint_t dlim_dmaspeed */
 729  729          (uint_t)0x86<<24+0,     /* uint_t dlim_version */
 730  730          (uint_t)0xffff,         /* uint_t dlim_adreg_max */
 731  731          (uint_t)0xffff,         /* uint_t dlim_ctreg_max */
 732  732          (uint_t)512,            /* uint_t dlim_granular */
 733  733          (int)1,                 /* int dlim_sgllen */
 734  734          (uint_t)0xffffffff      /* uint_t dlim_reqsizes */
 735  735  };
 736  736  
 737  737  #endif
 738  738  
 739  739  int
 740  740  ddi_dma_setup(dev_info_t *dip, struct ddi_dma_req *dmareqp,
 741  741      ddi_dma_handle_t *handlep)
 742  742  {
 743  743          int (*funcp)() = ddi_dma_map;
 744  744          struct bus_ops *bop;
 745  745  #if defined(__sparc)
 746  746          auto ddi_dma_lim_t dma_lim;
 747  747  
 748  748          if (dmareqp->dmar_limits == (ddi_dma_lim_t *)0) {
 749  749                  dma_lim = standard_limits;
 750  750          } else {
 751  751                  dma_lim = *dmareqp->dmar_limits;
 752  752          }
 753  753          dmareqp->dmar_limits = &dma_lim;
 754  754  #endif
 755  755  #if defined(__x86)
 756  756          if (dmareqp->dmar_limits == (ddi_dma_lim_t *)0)
 757  757                  return (DDI_FAILURE);
 758  758  #endif
 759  759  
 760  760          /*
 761  761           * Handle the case that the requester is both a leaf
 762  762           * and a nexus driver simultaneously by calling the
 763  763           * requester's bus_dma_map function directly instead
 764  764           * of ddi_dma_map.
 765  765           */
 766  766          bop = DEVI(dip)->devi_ops->devo_bus_ops;
 767  767          if (bop && bop->bus_dma_map)
 768  768                  funcp = bop->bus_dma_map;
 769  769          return ((*funcp)(dip, dip, dmareqp, handlep));
 770  770  }
 771  771  
 772  772  int
 773  773  ddi_dma_addr_setup(dev_info_t *dip, struct as *as, caddr_t addr, size_t len,
 774  774      uint_t flags, int (*waitfp)(), caddr_t arg,
 775  775      ddi_dma_lim_t *limits, ddi_dma_handle_t *handlep)
 776  776  {
 777  777          int (*funcp)() = ddi_dma_map;
 778  778          ddi_dma_lim_t dma_lim;
 779  779          struct ddi_dma_req dmareq;
 780  780          struct bus_ops *bop;
 781  781  
 782  782          if (len == 0) {
 783  783                  return (DDI_DMA_NOMAPPING);
 784  784          }
 785  785          if (limits == (ddi_dma_lim_t *)0) {
 786  786                  dma_lim = standard_limits;
 787  787          } else {
 788  788                  dma_lim = *limits;
 789  789          }
 790  790          dmareq.dmar_limits = &dma_lim;
 791  791          dmareq.dmar_flags = flags;
 792  792          dmareq.dmar_fp = waitfp;
 793  793          dmareq.dmar_arg = arg;
 794  794          dmareq.dmar_object.dmao_size = len;
 795  795          dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR;
 796  796          dmareq.dmar_object.dmao_obj.virt_obj.v_as = as;
 797  797          dmareq.dmar_object.dmao_obj.virt_obj.v_addr = addr;
 798  798          dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
 799  799  
 800  800          /*
 801  801           * Handle the case that the requester is both a leaf
 802  802           * and a nexus driver simultaneously by calling the
 803  803           * requester's bus_dma_map function directly instead
 804  804           * of ddi_dma_map.
 805  805           */
 806  806          bop = DEVI(dip)->devi_ops->devo_bus_ops;
 807  807          if (bop && bop->bus_dma_map)
 808  808                  funcp = bop->bus_dma_map;
 809  809  
 810  810          return ((*funcp)(dip, dip, &dmareq, handlep));
 811  811  }
 812  812  
 813  813  int
 814  814  ddi_dma_buf_setup(dev_info_t *dip, struct buf *bp, uint_t flags,
 815  815      int (*waitfp)(), caddr_t arg, ddi_dma_lim_t *limits,
 816  816      ddi_dma_handle_t *handlep)
 817  817  {
 818  818          int (*funcp)() = ddi_dma_map;
 819  819          ddi_dma_lim_t dma_lim;
 820  820          struct ddi_dma_req dmareq;
 821  821          struct bus_ops *bop;
 822  822  
 823  823          if (limits == (ddi_dma_lim_t *)0) {
 824  824                  dma_lim = standard_limits;
 825  825          } else {
 826  826                  dma_lim = *limits;
 827  827          }
 828  828          dmareq.dmar_limits = &dma_lim;
 829  829          dmareq.dmar_flags = flags;
 830  830          dmareq.dmar_fp = waitfp;
 831  831          dmareq.dmar_arg = arg;
 832  832          dmareq.dmar_object.dmao_size = (uint_t)bp->b_bcount;
 833  833  
 834  834          if (bp->b_flags & B_PAGEIO) {
 835  835                  dmareq.dmar_object.dmao_type = DMA_OTYP_PAGES;
 836  836                  dmareq.dmar_object.dmao_obj.pp_obj.pp_pp = bp->b_pages;
 837  837                  dmareq.dmar_object.dmao_obj.pp_obj.pp_offset =
 838  838                      (uint_t)(((uintptr_t)bp->b_un.b_addr) & MMU_PAGEOFFSET);
 839  839          } else {
 840  840                  dmareq.dmar_object.dmao_type = DMA_OTYP_BUFVADDR;
 841  841                  dmareq.dmar_object.dmao_obj.virt_obj.v_addr = bp->b_un.b_addr;
 842  842                  if (bp->b_flags & B_SHADOW) {
 843  843                          dmareq.dmar_object.dmao_obj.virt_obj.v_priv =
 844  844                              bp->b_shadow;
 845  845                  } else {
 846  846                          dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
 847  847                  }
 848  848  
 849  849                  /*
 850  850                   * If the buffer has no proc pointer, or the proc
 851  851                   * struct has the kernel address space, or the buffer has
 852  852                   * been marked B_REMAPPED (meaning that it is now
 853  853                   * mapped into the kernel's address space), then
 854  854                   * the address space is kas (kernel address space).
 855  855                   */
 856  856                  if ((bp->b_proc == NULL) || (bp->b_proc->p_as == &kas) ||
 857  857                      (bp->b_flags & B_REMAPPED)) {
 858  858                          dmareq.dmar_object.dmao_obj.virt_obj.v_as = 0;
 859  859                  } else {
 860  860                          dmareq.dmar_object.dmao_obj.virt_obj.v_as =
 861  861                              bp->b_proc->p_as;
 862  862                  }
 863  863          }
 864  864  
 865  865          /*
 866  866           * Handle the case that the requester is both a leaf
 867  867           * and a nexus driver simultaneously by calling the
 868  868           * requester's bus_dma_map function directly instead
 869  869           * of ddi_dma_map.
 870  870           */
 871  871          bop = DEVI(dip)->devi_ops->devo_bus_ops;
 872  872          if (bop && bop->bus_dma_map)
 873  873                  funcp = bop->bus_dma_map;
 874  874  
 875  875          return ((*funcp)(dip, dip, &dmareq, handlep));
 876  876  }
 877  877  
 878  878  #if !defined(__sparc)
 879  879  /*
 880  880   * Request bus_dma_ctl parent to fiddle with a dma request.
 881  881   *
 882  882   * (The sparc version is in sparc_subr.s)
 883  883   */
 884  884  int
 885  885  ddi_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
 886  886      ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
 887  887      off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
 888  888  {
 889  889          int (*fp)();
 890  890  
 891  891          if (dip != ddi_root_node())
 892  892                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_ctl;
 893  893          fp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_ctl;
 894  894          return ((*fp) (dip, rdip, handle, request, offp, lenp, objp, flags));
 895  895  }
 896  896  #endif
 897  897  
 898  898  /*
 899  899   * For all DMA control functions, call the DMA control
 900  900   * routine and return status.
 901  901   *
 902  902   * Just plain assume that the parent is to be called.
 903  903   * If a nexus driver or a thread outside the framework
 904  904   * of a nexus driver or a leaf driver calls these functions,
 905  905   * it is up to them to deal with the fact that the parent's
 906  906   * bus_dma_ctl function will be the first one called.
 907  907   */
 908  908  
 909  909  #define HD      ((ddi_dma_impl_t *)h)->dmai_rdip
 910  910  
 911  911  int
 912  912  ddi_dma_kvaddrp(ddi_dma_handle_t h, off_t off, size_t len, caddr_t *kp)
 913  913  {
 914  914          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_KVADDR, &off, &len, kp, 0));
 915  915  }
 916  916  
 917  917  int
 918  918  ddi_dma_htoc(ddi_dma_handle_t h, off_t o, ddi_dma_cookie_t *c)
 919  919  {
 920  920          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_HTOC, &o, 0, (caddr_t *)c, 0));
 921  921  }
 922  922  
 923  923  int
 924  924  ddi_dma_coff(ddi_dma_handle_t h, ddi_dma_cookie_t *c, off_t *o)
 925  925  {
 926  926          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_COFF,
 927  927              (off_t *)c, 0, (caddr_t *)o, 0));
 928  928  }
 929  929  
 930  930  int
 931  931  ddi_dma_movwin(ddi_dma_handle_t h, off_t *o, size_t *l, ddi_dma_cookie_t *c)
 932  932  {
 933  933          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_MOVWIN, o,
 934  934              l, (caddr_t *)c, 0));
 935  935  }
 936  936  
 937  937  int
 938  938  ddi_dma_curwin(ddi_dma_handle_t h, off_t *o, size_t *l)
 939  939  {
 940  940          if ((((ddi_dma_impl_t *)h)->dmai_rflags & DDI_DMA_PARTIAL) == 0)
 941  941                  return (DDI_FAILURE);
 942  942          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_REPWIN, o, l, 0, 0));
 943  943  }
 944  944  
 945  945  int
 946  946  ddi_dma_nextwin(ddi_dma_handle_t h, ddi_dma_win_t win,
 947  947      ddi_dma_win_t *nwin)
 948  948  {
 949  949          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_NEXTWIN, (off_t *)&win, 0,
 950  950              (caddr_t *)nwin, 0));
 951  951  }
 952  952  
 953  953  int
 954  954  ddi_dma_nextseg(ddi_dma_win_t win, ddi_dma_seg_t seg, ddi_dma_seg_t *nseg)
 955  955  {
 956  956          ddi_dma_handle_t h = (ddi_dma_handle_t)win;
 957  957  
 958  958          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_NEXTSEG, (off_t *)&win,
 959  959              (size_t *)&seg, (caddr_t *)nseg, 0));
 960  960  }
 961  961  
 962  962  #if (defined(__i386) && !defined(__amd64)) || defined(__sparc)
 963  963  /*
 964  964   * This routine is Obsolete and should be removed from ALL architectures
 965  965   * in a future release of Solaris.
 966  966   *
 967  967   * It is deliberately NOT ported to amd64; please fix the code that
 968  968   * depends on this routine to use ddi_dma_nextcookie(9F).
 969  969   *
 970  970   * NOTE: even though we fixed the pointer through a 32-bit param issue (the fix
 971  971   * is a side effect to some other cleanup), we're still not going to support
 972  972   * this interface on x64.
 973  973   */
 974  974  int
 975  975  ddi_dma_segtocookie(ddi_dma_seg_t seg, off_t *o, off_t *l,
 976  976      ddi_dma_cookie_t *cookiep)
 977  977  {
 978  978          ddi_dma_handle_t h = (ddi_dma_handle_t)seg;
 979  979  
 980  980          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_SEGTOC, o, (size_t *)l,
 981  981              (caddr_t *)cookiep, 0));
 982  982  }
 983  983  #endif  /* (__i386 && !__amd64) || __sparc */
 984  984  
 985  985  #if !defined(__sparc)
 986  986  
 987  987  /*
 988  988   * The SPARC versions of these routines are done in assembler to
 989  989   * save register windows, so they're in sparc_subr.s.
 990  990   */
 991  991  
 992  992  int
 993  993  ddi_dma_map(dev_info_t *dip, dev_info_t *rdip,
 994  994          struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
 995  995  {
 996  996          int (*funcp)(dev_info_t *, dev_info_t *, struct ddi_dma_req *,
 997  997              ddi_dma_handle_t *);
 998  998  
 999  999          if (dip != ddi_root_node())
1000 1000                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_map;
1001 1001  
1002 1002          funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_map;
1003 1003          return ((*funcp)(dip, rdip, dmareqp, handlep));
1004 1004  }
1005 1005  
1006 1006  int
1007 1007  ddi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
1008 1008      int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
1009 1009  {
1010 1010          int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_attr_t *,
1011 1011              int (*)(caddr_t), caddr_t, ddi_dma_handle_t *);
1012 1012  
1013 1013          if (dip != ddi_root_node())
1014 1014                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
1015 1015  
1016 1016          funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_allochdl;
1017 1017          return ((*funcp)(dip, rdip, attr, waitfp, arg, handlep));
1018 1018  }
1019 1019  
1020 1020  int
1021 1021  ddi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handlep)
1022 1022  {
1023 1023          int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
1024 1024  
1025 1025          if (dip != ddi_root_node())
1026 1026                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
1027 1027  
1028 1028          funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_freehdl;
1029 1029          return ((*funcp)(dip, rdip, handlep));
1030 1030  }
1031 1031  
1032 1032  int
1033 1033  ddi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
1034 1034      ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
1035 1035      ddi_dma_cookie_t *cp, uint_t *ccountp)
1036 1036  {
1037 1037          int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
1038 1038              struct ddi_dma_req *, ddi_dma_cookie_t *, uint_t *);
1039 1039  
1040 1040          if (dip != ddi_root_node())
1041 1041                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
1042 1042  
1043 1043          funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_bindhdl;
1044 1044          return ((*funcp)(dip, rdip, handle, dmareq, cp, ccountp));
1045 1045  }
1046 1046  
1047 1047  int
1048 1048  ddi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
1049 1049      ddi_dma_handle_t handle)
1050 1050  {
1051 1051          int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
1052 1052  
1053 1053          if (dip != ddi_root_node())
1054 1054                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
1055 1055  
1056 1056          funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl;
1057 1057          return ((*funcp)(dip, rdip, handle));
1058 1058  }
1059 1059  
1060 1060  
1061 1061  int
1062 1062  ddi_dma_flush(dev_info_t *dip, dev_info_t *rdip,
1063 1063      ddi_dma_handle_t handle, off_t off, size_t len,
1064 1064      uint_t cache_flags)
1065 1065  {
1066 1066          int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
1067 1067              off_t, size_t, uint_t);
1068 1068  
1069 1069          if (dip != ddi_root_node())
1070 1070                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
1071 1071  
1072 1072          funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_flush;
1073 1073          return ((*funcp)(dip, rdip, handle, off, len, cache_flags));
1074 1074  }
1075 1075  
1076 1076  int
1077 1077  ddi_dma_win(dev_info_t *dip, dev_info_t *rdip,
1078 1078      ddi_dma_handle_t handle, uint_t win, off_t *offp,
1079 1079      size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
1080 1080  {
1081 1081          int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
1082 1082              uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *);
1083 1083  
1084 1084          if (dip != ddi_root_node())
1085 1085                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_win;
1086 1086  
1087 1087          funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_win;
1088 1088          return ((*funcp)(dip, rdip, handle, win, offp, lenp,
1089 1089              cookiep, ccountp));
1090 1090  }
1091 1091  
1092 1092  int
1093 1093  ddi_dma_sync(ddi_dma_handle_t h, off_t o, size_t l, uint_t whom)
1094 1094  {
1095 1095          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
1096 1096          dev_info_t *dip, *rdip;
1097 1097          int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t, off_t,
1098 1098              size_t, uint_t);
1099 1099  
1100 1100          /*
1101 1101           * the DMA nexus driver will set DMP_NOSYNC if the
1102 1102           * platform does not require any sync operation. For
1103 1103           * example if the memory is uncached or consistent
1104 1104           * and without any I/O write buffers involved.
1105 1105           */
1106 1106          if ((hp->dmai_rflags & DMP_NOSYNC) == DMP_NOSYNC)
1107 1107                  return (DDI_SUCCESS);
1108 1108  
1109 1109          dip = rdip = hp->dmai_rdip;
1110 1110          if (dip != ddi_root_node())
1111 1111                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
1112 1112          funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_flush;
1113 1113          return ((*funcp)(dip, rdip, h, o, l, whom));
1114 1114  }
1115 1115  
1116 1116  int
1117 1117  ddi_dma_unbind_handle(ddi_dma_handle_t h)
1118 1118  {
1119 1119          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
1120 1120          dev_info_t *dip, *rdip;
1121 1121          int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
1122 1122  
1123 1123          dip = rdip = hp->dmai_rdip;
1124 1124          if (dip != ddi_root_node())
1125 1125                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
1126 1126          funcp = DEVI(rdip)->devi_bus_dma_unbindfunc;
1127 1127          return ((*funcp)(dip, rdip, h));
1128 1128  }
1129 1129  
1130 1130  #endif  /* !__sparc */
1131 1131  
1132 1132  int
1133 1133  ddi_dma_free(ddi_dma_handle_t h)
1134 1134  {
1135 1135          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_FREE, 0, 0, 0, 0));
1136 1136  }
1137 1137  
1138 1138  int
1139 1139  ddi_iopb_alloc(dev_info_t *dip, ddi_dma_lim_t *limp, uint_t len, caddr_t *iopbp)
1140 1140  {
1141 1141          ddi_dma_lim_t defalt;
1142 1142          size_t size = len;
1143 1143  
1144 1144          if (!limp) {
1145 1145                  defalt = standard_limits;
1146 1146                  limp = &defalt;
1147 1147          }
1148 1148          return (i_ddi_mem_alloc_lim(dip, limp, size, 0, 0, 0,
1149 1149              iopbp, NULL, NULL));
1150 1150  }
1151 1151  
1152 1152  void
1153 1153  ddi_iopb_free(caddr_t iopb)
1154 1154  {
1155 1155          i_ddi_mem_free(iopb, NULL);
1156 1156  }
1157 1157  
1158 1158  int
1159 1159  ddi_mem_alloc(dev_info_t *dip, ddi_dma_lim_t *limits, uint_t length,
1160 1160          uint_t flags, caddr_t *kaddrp, uint_t *real_length)
1161 1161  {
1162 1162          ddi_dma_lim_t defalt;
1163 1163          size_t size = length;
1164 1164  
1165 1165          if (!limits) {
1166 1166                  defalt = standard_limits;
1167 1167                  limits = &defalt;
1168 1168          }
1169 1169          return (i_ddi_mem_alloc_lim(dip, limits, size, flags & 0x1,
1170 1170              1, 0, kaddrp, real_length, NULL));
1171 1171  }
1172 1172  
1173 1173  void
1174 1174  ddi_mem_free(caddr_t kaddr)
1175 1175  {
1176 1176          i_ddi_mem_free(kaddr, NULL);
1177 1177  }
1178 1178  
1179 1179  /*
1180 1180   * DMA attributes, alignment, burst sizes, and transfer minimums
1181 1181   */
1182 1182  int
1183 1183  ddi_dma_get_attr(ddi_dma_handle_t handle, ddi_dma_attr_t *attrp)
1184 1184  {
1185 1185          ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
1186 1186  
1187 1187          if (attrp == NULL)
1188 1188                  return (DDI_FAILURE);
1189 1189          *attrp = dimp->dmai_attr;
1190 1190          return (DDI_SUCCESS);
1191 1191  }
1192 1192  
1193 1193  int
1194 1194  ddi_dma_burstsizes(ddi_dma_handle_t handle)
1195 1195  {
1196 1196          ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
1197 1197  
1198 1198          if (!dimp)
1199 1199                  return (0);
1200 1200          else
1201 1201                  return (dimp->dmai_burstsizes);
1202 1202  }
1203 1203  
1204 1204  int
1205 1205  ddi_dma_devalign(ddi_dma_handle_t handle, uint_t *alignment, uint_t *mineffect)
1206 1206  {
1207 1207          ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
1208 1208  
1209 1209          if (!dimp || !alignment || !mineffect)
1210 1210                  return (DDI_FAILURE);
1211 1211          if (!(dimp->dmai_rflags & DDI_DMA_SBUS_64BIT)) {
1212 1212                  *alignment = 1 << ddi_ffs(dimp->dmai_burstsizes);
1213 1213          } else {
1214 1214                  if (dimp->dmai_burstsizes & 0xff0000) {
1215 1215                          *alignment = 1 << ddi_ffs(dimp->dmai_burstsizes >> 16);
1216 1216                  } else {
1217 1217                          *alignment = 1 << ddi_ffs(dimp->dmai_burstsizes);
1218 1218                  }
1219 1219          }
1220 1220          *mineffect = dimp->dmai_minxfer;
1221 1221          return (DDI_SUCCESS);
1222 1222  }
1223 1223  
1224 1224  int
1225 1225  ddi_iomin(dev_info_t *a, int i, int stream)
1226 1226  {
1227 1227          int r;
1228 1228  
1229 1229          /*
1230 1230           * Make sure that the initial value is sane
1231 1231           */
1232 1232          if (i & (i - 1))
1233 1233                  return (0);
1234 1234          if (i == 0)
1235 1235                  i = (stream) ? 4 : 1;
1236 1236  
1237 1237          r = ddi_ctlops(a, a,
1238 1238              DDI_CTLOPS_IOMIN, (void *)(uintptr_t)stream, (void *)&i);
1239 1239          if (r != DDI_SUCCESS || (i & (i - 1)))
1240 1240                  return (0);
1241 1241          return (i);
1242 1242  }
1243 1243  
1244 1244  /*
1245 1245   * Given two DMA attribute structures, apply the attributes
1246 1246   * of one to the other, following the rules of attributes
1247 1247   * and the wishes of the caller.
1248 1248   *
1249 1249   * The rules of DMA attribute structures are that you cannot
1250 1250   * make things *less* restrictive as you apply one set
1251 1251   * of attributes to another.
1252 1252   *
1253 1253   */
1254 1254  void
1255 1255  ddi_dma_attr_merge(ddi_dma_attr_t *attr, ddi_dma_attr_t *mod)
1256 1256  {
1257 1257          attr->dma_attr_addr_lo =
1258 1258              MAX(attr->dma_attr_addr_lo, mod->dma_attr_addr_lo);
1259 1259          attr->dma_attr_addr_hi =
1260 1260              MIN(attr->dma_attr_addr_hi, mod->dma_attr_addr_hi);
1261 1261          attr->dma_attr_count_max =
1262 1262              MIN(attr->dma_attr_count_max, mod->dma_attr_count_max);
1263 1263          attr->dma_attr_align =
1264 1264              MAX(attr->dma_attr_align,  mod->dma_attr_align);
1265 1265          attr->dma_attr_burstsizes =
1266 1266              (uint_t)(attr->dma_attr_burstsizes & mod->dma_attr_burstsizes);
1267 1267          attr->dma_attr_minxfer =
1268 1268              maxbit(attr->dma_attr_minxfer, mod->dma_attr_minxfer);
1269 1269          attr->dma_attr_maxxfer =
1270 1270              MIN(attr->dma_attr_maxxfer, mod->dma_attr_maxxfer);
1271 1271          attr->dma_attr_seg = MIN(attr->dma_attr_seg, mod->dma_attr_seg);
1272 1272          attr->dma_attr_sgllen = MIN((uint_t)attr->dma_attr_sgllen,
1273 1273              (uint_t)mod->dma_attr_sgllen);
1274 1274          attr->dma_attr_granular =
1275 1275              MAX(attr->dma_attr_granular, mod->dma_attr_granular);
1276 1276  }
1277 1277  
1278 1278  /*
1279 1279   * mmap/segmap interface:
1280 1280   */
1281 1281  
1282 1282  /*
1283 1283   * ddi_segmap:          setup the default segment driver. Calls the drivers
1284 1284   *                      XXmmap routine to validate the range to be mapped.
1285 1285   *                      Return ENXIO of the range is not valid.  Create
1286 1286   *                      a seg_dev segment that contains all of the
1287 1287   *                      necessary information and will reference the
1288 1288   *                      default segment driver routines. It returns zero
1289 1289   *                      on success or non-zero on failure.
1290 1290   */
1291 1291  int
1292 1292  ddi_segmap(dev_t dev, off_t offset, struct as *asp, caddr_t *addrp, off_t len,
1293 1293      uint_t prot, uint_t maxprot, uint_t flags, cred_t *credp)
1294 1294  {
1295 1295          extern int spec_segmap(dev_t, off_t, struct as *, caddr_t *,
1296 1296              off_t, uint_t, uint_t, uint_t, struct cred *);
1297 1297  
1298 1298          return (spec_segmap(dev, offset, asp, addrp, len,
1299 1299              prot, maxprot, flags, credp));
1300 1300  }
1301 1301  
1302 1302  /*
1303 1303   * ddi_map_fault:       Resolve mappings at fault time.  Used by segment
1304 1304   *                      drivers. Allows each successive parent to resolve
1305 1305   *                      address translations and add its mappings to the
1306 1306   *                      mapping list supplied in the page structure. It
1307 1307   *                      returns zero on success or non-zero on failure.
1308 1308   */
1309 1309  
1310 1310  int
1311 1311  ddi_map_fault(dev_info_t *dip, struct hat *hat, struct seg *seg,
1312 1312      caddr_t addr, struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock)
1313 1313  {
1314 1314          return (i_ddi_map_fault(dip, dip, hat, seg, addr, dp, pfn, prot, lock));
1315 1315  }
1316 1316  
1317 1317  /*
1318 1318   * ddi_device_mapping_check:    Called from ddi_segmap_setup.
1319 1319   *      Invokes platform specific DDI to determine whether attributes specified
1320 1320   *      in attr(9s) are valid for the region of memory that will be made
1321 1321   *      available for direct access to user process via the mmap(2) system call.
1322 1322   */
1323 1323  int
1324 1324  ddi_device_mapping_check(dev_t dev, ddi_device_acc_attr_t *accattrp,
1325 1325      uint_t rnumber, uint_t *hat_flags)
1326 1326  {
1327 1327          ddi_acc_handle_t handle;
1328 1328          ddi_map_req_t mr;
1329 1329          ddi_acc_hdl_t *hp;
1330 1330          int result;
1331 1331          dev_info_t *dip;
1332 1332  
1333 1333          /*
1334 1334           * we use e_ddi_hold_devi_by_dev to search for the devi.  We
1335 1335           * release it immediately since it should already be held by
1336 1336           * a devfs vnode.
1337 1337           */
1338 1338          if ((dip =
1339 1339              e_ddi_hold_devi_by_dev(dev, E_DDI_HOLD_DEVI_NOATTACH)) == NULL)
1340 1340                  return (-1);
1341 1341          ddi_release_devi(dip);          /* for e_ddi_hold_devi_by_dev() */
1342 1342  
1343 1343          /*
1344 1344           * Allocate and initialize the common elements of data
1345 1345           * access handle.
1346 1346           */
1347 1347          handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
1348 1348          if (handle == NULL)
1349 1349                  return (-1);
1350 1350  
1351 1351          hp = impl_acc_hdl_get(handle);
1352 1352          hp->ah_vers = VERS_ACCHDL;
1353 1353          hp->ah_dip = dip;
1354 1354          hp->ah_rnumber = rnumber;
1355 1355          hp->ah_offset = 0;
1356 1356          hp->ah_len = 0;
1357 1357          hp->ah_acc = *accattrp;
1358 1358  
1359 1359          /*
1360 1360           * Set up the mapping request and call to parent.
1361 1361           */
1362 1362          mr.map_op = DDI_MO_MAP_HANDLE;
1363 1363          mr.map_type = DDI_MT_RNUMBER;
1364 1364          mr.map_obj.rnumber = rnumber;
1365 1365          mr.map_prot = PROT_READ | PROT_WRITE;
1366 1366          mr.map_flags = DDI_MF_KERNEL_MAPPING;
1367 1367          mr.map_handlep = hp;
1368 1368          mr.map_vers = DDI_MAP_VERSION;
1369 1369          result = ddi_map(dip, &mr, 0, 0, NULL);
1370 1370  
1371 1371          /*
1372 1372           * Region must be mappable, pick up flags from the framework.
1373 1373           */
1374 1374          *hat_flags = hp->ah_hat_flags;
1375 1375  
1376 1376          impl_acc_hdl_free(handle);
1377 1377  
1378 1378          /*
1379 1379           * check for end result.
1380 1380           */
1381 1381          if (result != DDI_SUCCESS)
1382 1382                  return (-1);
1383 1383          return (0);
1384 1384  }
1385 1385  
1386 1386  
1387 1387  /*
1388 1388   * Property functions:   See also, ddipropdefs.h.
1389 1389   *
1390 1390   * These functions are the framework for the property functions,
1391 1391   * i.e. they support software defined properties.  All implementation
1392 1392   * specific property handling (i.e.: self-identifying devices and
1393 1393   * PROM defined properties are handled in the implementation specific
1394 1394   * functions (defined in ddi_implfuncs.h).
1395 1395   */
1396 1396  
1397 1397  /*
1398 1398   * nopropop:    Shouldn't be called, right?
1399 1399   */
1400 1400  int
1401 1401  nopropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
1402 1402      char *name, caddr_t valuep, int *lengthp)
1403 1403  {
1404 1404          _NOTE(ARGUNUSED(dev, dip, prop_op, mod_flags, name, valuep, lengthp))
1405 1405          return (DDI_PROP_NOT_FOUND);
1406 1406  }
1407 1407  
1408 1408  #ifdef  DDI_PROP_DEBUG
1409 1409  int ddi_prop_debug_flag = 0;
1410 1410  
1411 1411  int
1412 1412  ddi_prop_debug(int enable)
1413 1413  {
1414 1414          int prev = ddi_prop_debug_flag;
1415 1415  
1416 1416          if ((enable != 0) || (prev != 0))
1417 1417                  printf("ddi_prop_debug: debugging %s\n",
1418 1418                      enable ? "enabled" : "disabled");
1419 1419          ddi_prop_debug_flag = enable;
1420 1420          return (prev);
1421 1421  }
1422 1422  
1423 1423  #endif  /* DDI_PROP_DEBUG */
1424 1424  
1425 1425  /*
1426 1426   * Search a property list for a match, if found return pointer
1427 1427   * to matching prop struct, else return NULL.
1428 1428   */
1429 1429  
1430 1430  ddi_prop_t *
1431 1431  i_ddi_prop_search(dev_t dev, char *name, uint_t flags, ddi_prop_t **list_head)
1432 1432  {
1433 1433          ddi_prop_t      *propp;
1434 1434  
1435 1435          /*
1436 1436           * find the property in child's devinfo:
1437 1437           * Search order defined by this search function is first matching
1438 1438           * property with input dev == DDI_DEV_T_ANY matching any dev or
1439 1439           * dev == propp->prop_dev, name == propp->name, and the correct
1440 1440           * data type as specified in the flags.  If a DDI_DEV_T_NONE dev
1441 1441           * value made it this far then it implies a DDI_DEV_T_ANY search.
1442 1442           */
1443 1443          if (dev == DDI_DEV_T_NONE)
1444 1444                  dev = DDI_DEV_T_ANY;
1445 1445  
1446 1446          for (propp = *list_head; propp != NULL; propp = propp->prop_next)  {
1447 1447  
1448 1448                  if (!DDI_STRSAME(propp->prop_name, name))
1449 1449                          continue;
1450 1450  
1451 1451                  if ((dev != DDI_DEV_T_ANY) && (propp->prop_dev != dev))
1452 1452                          continue;
1453 1453  
1454 1454                  if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
1455 1455                          continue;
1456 1456  
1457 1457                  return (propp);
1458 1458          }
1459 1459  
1460 1460          return ((ddi_prop_t *)0);
1461 1461  }
1462 1462  
1463 1463  /*
1464 1464   * Search for property within devnames structures
1465 1465   */
1466 1466  ddi_prop_t *
1467 1467  i_ddi_search_global_prop(dev_t dev, char *name, uint_t flags)
1468 1468  {
1469 1469          major_t         major;
1470 1470          struct devnames *dnp;
1471 1471          ddi_prop_t      *propp;
1472 1472  
1473 1473          /*
1474 1474           * Valid dev_t value is needed to index into the
1475 1475           * correct devnames entry, therefore a dev_t
1476 1476           * value of DDI_DEV_T_ANY is not appropriate.
1477 1477           */
1478 1478          ASSERT(dev != DDI_DEV_T_ANY);
1479 1479          if (dev == DDI_DEV_T_ANY) {
1480 1480                  return ((ddi_prop_t *)0);
1481 1481          }
1482 1482  
1483 1483          major = getmajor(dev);
1484 1484          dnp = &(devnamesp[major]);
1485 1485  
1486 1486          if (dnp->dn_global_prop_ptr == NULL)
1487 1487                  return ((ddi_prop_t *)0);
1488 1488  
1489 1489          LOCK_DEV_OPS(&dnp->dn_lock);
1490 1490  
1491 1491          for (propp = dnp->dn_global_prop_ptr->prop_list;
1492 1492              propp != NULL;
1493 1493              propp = (ddi_prop_t *)propp->prop_next) {
1494 1494  
1495 1495                  if (!DDI_STRSAME(propp->prop_name, name))
1496 1496                          continue;
1497 1497  
1498 1498                  if ((!(flags & DDI_PROP_ROOTNEX_GLOBAL)) &&
1499 1499                      (!(flags & LDI_DEV_T_ANY)) && (propp->prop_dev != dev))
1500 1500                          continue;
1501 1501  
1502 1502                  if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
1503 1503                          continue;
1504 1504  
1505 1505                  /* Property found, return it */
1506 1506                  UNLOCK_DEV_OPS(&dnp->dn_lock);
1507 1507                  return (propp);
1508 1508          }
1509 1509  
1510 1510          UNLOCK_DEV_OPS(&dnp->dn_lock);
1511 1511          return ((ddi_prop_t *)0);
1512 1512  }
1513 1513  
1514 1514  static char prop_no_mem_msg[] = "can't allocate memory for ddi property <%s>";
1515 1515  
1516 1516  /*
1517 1517   * ddi_prop_search_global:
1518 1518   *      Search the global property list within devnames
1519 1519   *      for the named property.  Return the encoded value.
1520 1520   */
1521 1521  static int
1522 1522  i_ddi_prop_search_global(dev_t dev, uint_t flags, char *name,
1523 1523      void *valuep, uint_t *lengthp)
1524 1524  {
1525 1525          ddi_prop_t      *propp;
1526 1526          caddr_t         buffer;
1527 1527  
1528 1528          propp =  i_ddi_search_global_prop(dev, name, flags);
1529 1529  
1530 1530          /* Property NOT found, bail */
1531 1531          if (propp == (ddi_prop_t *)0)
1532 1532                  return (DDI_PROP_NOT_FOUND);
1533 1533  
1534 1534          if (propp->prop_flags & DDI_PROP_UNDEF_IT)
1535 1535                  return (DDI_PROP_UNDEFINED);
1536 1536  
1537 1537          if ((buffer = kmem_alloc(propp->prop_len,
1538 1538              (flags & DDI_PROP_CANSLEEP) ? KM_SLEEP : KM_NOSLEEP)) == NULL) {
1539 1539                  cmn_err(CE_CONT, prop_no_mem_msg, name);
1540 1540                  return (DDI_PROP_NO_MEMORY);
1541 1541          }
1542 1542  
1543 1543          /*
1544 1544           * Return the encoded data
1545 1545           */
1546 1546          *(caddr_t *)valuep = buffer;
1547 1547          *lengthp = propp->prop_len;
1548 1548          bcopy(propp->prop_val, buffer, propp->prop_len);
1549 1549  
1550 1550          return (DDI_PROP_SUCCESS);
1551 1551  }
1552 1552  
1553 1553  /*
1554 1554   * ddi_prop_search_common:      Lookup and return the encoded value
1555 1555   */
1556 1556  int
1557 1557  ddi_prop_search_common(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1558 1558      uint_t flags, char *name, void *valuep, uint_t *lengthp)
1559 1559  {
1560 1560          ddi_prop_t      *propp;
1561 1561          int             i;
1562 1562          caddr_t         buffer;
1563 1563          caddr_t         prealloc = NULL;
1564 1564          int             plength = 0;
1565 1565          dev_info_t      *pdip;
1566 1566          int             (*bop)();
1567 1567  
1568 1568          /*CONSTANTCONDITION*/
1569 1569          while (1)  {
1570 1570  
1571 1571                  mutex_enter(&(DEVI(dip)->devi_lock));
1572 1572  
1573 1573  
1574 1574                  /*
1575 1575                   * find the property in child's devinfo:
1576 1576                   * Search order is:
1577 1577                   *      1. driver defined properties
1578 1578                   *      2. system defined properties
1579 1579                   *      3. driver global properties
1580 1580                   *      4. boot defined properties
1581 1581                   */
1582 1582  
1583 1583                  propp = i_ddi_prop_search(dev, name, flags,
1584 1584                      &(DEVI(dip)->devi_drv_prop_ptr));
1585 1585                  if (propp == NULL)  {
1586 1586                          propp = i_ddi_prop_search(dev, name, flags,
1587 1587                              &(DEVI(dip)->devi_sys_prop_ptr));
1588 1588                  }
1589 1589                  if ((propp == NULL) && DEVI(dip)->devi_global_prop_list) {
1590 1590                          propp = i_ddi_prop_search(dev, name, flags,
1591 1591                              &DEVI(dip)->devi_global_prop_list->prop_list);
1592 1592                  }
1593 1593  
1594 1594                  if (propp == NULL)  {
1595 1595                          propp = i_ddi_prop_search(dev, name, flags,
1596 1596                              &(DEVI(dip)->devi_hw_prop_ptr));
1597 1597                  }
1598 1598  
1599 1599                  /*
1600 1600                   * Software property found?
1601 1601                   */
1602 1602                  if (propp != (ddi_prop_t *)0)   {
1603 1603  
1604 1604                          /*
1605 1605                           * If explicit undefine, return now.
1606 1606                           */
1607 1607                          if (propp->prop_flags & DDI_PROP_UNDEF_IT) {
1608 1608                                  mutex_exit(&(DEVI(dip)->devi_lock));
1609 1609                                  if (prealloc)
1610 1610                                          kmem_free(prealloc, plength);
1611 1611                                  return (DDI_PROP_UNDEFINED);
1612 1612                          }
1613 1613  
1614 1614                          /*
1615 1615                           * If we only want to know if it exists, return now
1616 1616                           */
1617 1617                          if (prop_op == PROP_EXISTS) {
1618 1618                                  mutex_exit(&(DEVI(dip)->devi_lock));
1619 1619                                  ASSERT(prealloc == NULL);
1620 1620                                  return (DDI_PROP_SUCCESS);
1621 1621                          }
1622 1622  
1623 1623                          /*
1624 1624                           * If length only request or prop length == 0,
1625 1625                           * service request and return now.
1626 1626                           */
1627 1627                          if ((prop_op == PROP_LEN) ||(propp->prop_len == 0)) {
1628 1628                                  *lengthp = propp->prop_len;
1629 1629  
1630 1630                                  /*
1631 1631                                   * if prop_op is PROP_LEN_AND_VAL_ALLOC
1632 1632                                   * that means prop_len is 0, so set valuep
1633 1633                                   * also to NULL
1634 1634                                   */
1635 1635                                  if (prop_op == PROP_LEN_AND_VAL_ALLOC)
1636 1636                                          *(caddr_t *)valuep = NULL;
1637 1637  
1638 1638                                  mutex_exit(&(DEVI(dip)->devi_lock));
1639 1639                                  if (prealloc)
1640 1640                                          kmem_free(prealloc, plength);
1641 1641                                  return (DDI_PROP_SUCCESS);
1642 1642                          }
1643 1643  
1644 1644                          /*
1645 1645                           * If LEN_AND_VAL_ALLOC and the request can sleep,
1646 1646                           * drop the mutex, allocate the buffer, and go
1647 1647                           * through the loop again.  If we already allocated
1648 1648                           * the buffer, and the size of the property changed,
1649 1649                           * keep trying...
1650 1650                           */
1651 1651                          if ((prop_op == PROP_LEN_AND_VAL_ALLOC) &&
1652 1652                              (flags & DDI_PROP_CANSLEEP))  {
1653 1653                                  if (prealloc && (propp->prop_len != plength)) {
1654 1654                                          kmem_free(prealloc, plength);
1655 1655                                          prealloc = NULL;
1656 1656                                  }
1657 1657                                  if (prealloc == NULL)  {
1658 1658                                          plength = propp->prop_len;
1659 1659                                          mutex_exit(&(DEVI(dip)->devi_lock));
1660 1660                                          prealloc = kmem_alloc(plength,
1661 1661                                              KM_SLEEP);
1662 1662                                          continue;
1663 1663                                  }
1664 1664                          }
1665 1665  
1666 1666                          /*
1667 1667                           * Allocate buffer, if required.  Either way,
1668 1668                           * set `buffer' variable.
1669 1669                           */
1670 1670                          i = *lengthp;                   /* Get callers length */
1671 1671                          *lengthp = propp->prop_len;     /* Set callers length */
1672 1672  
1673 1673                          switch (prop_op) {
1674 1674  
1675 1675                          case PROP_LEN_AND_VAL_ALLOC:
1676 1676  
1677 1677                                  if (prealloc == NULL) {
1678 1678                                          buffer = kmem_alloc(propp->prop_len,
1679 1679                                              KM_NOSLEEP);
1680 1680                                  } else {
1681 1681                                          buffer = prealloc;
1682 1682                                  }
1683 1683  
1684 1684                                  if (buffer == NULL)  {
1685 1685                                          mutex_exit(&(DEVI(dip)->devi_lock));
1686 1686                                          cmn_err(CE_CONT, prop_no_mem_msg, name);
1687 1687                                          return (DDI_PROP_NO_MEMORY);
1688 1688                                  }
1689 1689                                  /* Set callers buf ptr */
1690 1690                                  *(caddr_t *)valuep = buffer;
1691 1691                                  break;
1692 1692  
1693 1693                          case PROP_LEN_AND_VAL_BUF:
1694 1694  
1695 1695                                  if (propp->prop_len > (i)) {
1696 1696                                          mutex_exit(&(DEVI(dip)->devi_lock));
1697 1697                                          return (DDI_PROP_BUF_TOO_SMALL);
1698 1698                                  }
1699 1699  
1700 1700                                  buffer = valuep;  /* Get callers buf ptr */
1701 1701                                  break;
1702 1702  
1703 1703                          default:
1704 1704                                  break;
1705 1705                          }
1706 1706  
1707 1707                          /*
1708 1708                           * Do the copy.
1709 1709                           */
1710 1710                          bcopy(propp->prop_val, buffer, propp->prop_len);
1711 1711                          mutex_exit(&(DEVI(dip)->devi_lock));
1712 1712                          return (DDI_PROP_SUCCESS);
1713 1713                  }
1714 1714  
1715 1715                  mutex_exit(&(DEVI(dip)->devi_lock));
1716 1716                  if (prealloc)
1717 1717                          kmem_free(prealloc, plength);
1718 1718                  prealloc = NULL;
1719 1719  
1720 1720                  /*
1721 1721                   * Prop not found, call parent bus_ops to deal with possible
1722 1722                   * h/w layer (possible PROM defined props, etc.) and to
1723 1723                   * possibly ascend the hierarchy, if allowed by flags.
1724 1724                   */
1725 1725                  pdip = (dev_info_t *)DEVI(dip)->devi_parent;
1726 1726  
1727 1727                  /*
1728 1728                   * One last call for the root driver PROM props?
1729 1729                   */
1730 1730                  if (dip == ddi_root_node())  {
1731 1731                          return (ddi_bus_prop_op(dev, dip, dip, prop_op,
1732 1732                              flags, name, valuep, (int *)lengthp));
1733 1733                  }
1734 1734  
1735 1735                  /*
1736 1736                   * We may have been called to check for properties
1737 1737                   * within a single devinfo node that has no parent -
1738 1738                   * see make_prop()
1739 1739                   */
1740 1740                  if (pdip == NULL) {
1741 1741                          ASSERT((flags &
1742 1742                              (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM)) ==
1743 1743                              (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM));
1744 1744                          return (DDI_PROP_NOT_FOUND);
1745 1745                  }
1746 1746  
1747 1747                  /*
1748 1748                   * Instead of recursing, we do iterative calls up the tree.
1749 1749                   * As a bit of optimization, skip the bus_op level if the
1750 1750                   * node is a s/w node and if the parent's bus_prop_op function
1751 1751                   * is `ddi_bus_prop_op', because we know that in this case,
1752 1752                   * this function does nothing.
1753 1753                   *
1754 1754                   * 4225415: If the parent isn't attached, or the child
1755 1755                   * hasn't been named by the parent yet, use the default
1756 1756                   * ddi_bus_prop_op as a proxy for the parent.  This
1757 1757                   * allows property lookups in any child/parent state to
1758 1758                   * include 'prom' and inherited properties, even when
1759 1759                   * there are no drivers attached to the child or parent.
1760 1760                   */
1761 1761  
1762 1762                  bop = ddi_bus_prop_op;
1763 1763                  if (i_ddi_devi_attached(pdip) &&
1764 1764                      (i_ddi_node_state(dip) >= DS_INITIALIZED))
1765 1765                          bop = DEVI(pdip)->devi_ops->devo_bus_ops->bus_prop_op;
1766 1766  
1767 1767                  i = DDI_PROP_NOT_FOUND;
1768 1768  
1769 1769                  if ((bop != ddi_bus_prop_op) || ndi_dev_is_prom_node(dip)) {
1770 1770                          i = (*bop)(dev, pdip, dip, prop_op,
1771 1771                              flags | DDI_PROP_DONTPASS,
1772 1772                              name, valuep, lengthp);
1773 1773                  }
1774 1774  
1775 1775                  if ((flags & DDI_PROP_DONTPASS) ||
1776 1776                      (i != DDI_PROP_NOT_FOUND))
1777 1777                          return (i);
1778 1778  
1779 1779                  dip = pdip;
1780 1780          }
1781 1781          /*NOTREACHED*/
1782 1782  }
1783 1783  
1784 1784  
1785 1785  /*
1786 1786   * ddi_prop_op: The basic property operator for drivers.
1787 1787   *
1788 1788   * In ddi_prop_op, the type of valuep is interpreted based on prop_op:
1789 1789   *
1790 1790   *      prop_op                 valuep
1791 1791   *      ------                  ------
1792 1792   *
1793 1793   *      PROP_LEN                <unused>
1794 1794   *
1795 1795   *      PROP_LEN_AND_VAL_BUF    Pointer to callers buffer
1796 1796   *
1797 1797   *      PROP_LEN_AND_VAL_ALLOC  Address of callers pointer (will be set to
1798 1798   *                              address of allocated buffer, if successful)
1799 1799   */
1800 1800  int
1801 1801  ddi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
1802 1802      char *name, caddr_t valuep, int *lengthp)
1803 1803  {
1804 1804          int     i;
1805 1805  
1806 1806          ASSERT((mod_flags & DDI_PROP_TYPE_MASK) == 0);
1807 1807  
1808 1808          /*
1809 1809           * If this was originally an LDI prop lookup then we bail here.
1810 1810           * The reason is that the LDI property lookup interfaces first call
1811 1811           * a drivers prop_op() entry point to allow it to override
1812 1812           * properties.  But if we've made it here, then the driver hasn't
1813 1813           * overriden any properties.  We don't want to continue with the
1814 1814           * property search here because we don't have any type inforamtion.
1815 1815           * When we return failure, the LDI interfaces will then proceed to
1816 1816           * call the typed property interfaces to look up the property.
1817 1817           */
1818 1818          if (mod_flags & DDI_PROP_DYNAMIC)
1819 1819                  return (DDI_PROP_NOT_FOUND);
1820 1820  
1821 1821          /*
1822 1822           * check for pre-typed property consumer asking for typed property:
1823 1823           * see e_ddi_getprop_int64.
1824 1824           */
1825 1825          if (mod_flags & DDI_PROP_CONSUMER_TYPED)
1826 1826                  mod_flags |= DDI_PROP_TYPE_INT64;
1827 1827          mod_flags |= DDI_PROP_TYPE_ANY;
1828 1828  
1829 1829          i = ddi_prop_search_common(dev, dip, prop_op,
1830 1830              mod_flags, name, valuep, (uint_t *)lengthp);
1831 1831          if (i == DDI_PROP_FOUND_1275)
1832 1832                  return (DDI_PROP_SUCCESS);
1833 1833          return (i);
1834 1834  }
1835 1835  
1836 1836  /*
1837 1837   * ddi_prop_op_nblocks_blksize: The basic property operator for drivers that
1838 1838   * maintain size in number of blksize blocks.  Provides a dynamic property
1839 1839   * implementation for size oriented properties based on nblocks64 and blksize
1840 1840   * values passed in by the driver.  Fallback to ddi_prop_op if the nblocks64
1841 1841   * is too large.  This interface should not be used with a nblocks64 that
1842 1842   * represents the driver's idea of how to represent unknown, if nblocks is
1843 1843   * unknown use ddi_prop_op.
1844 1844   */
1845 1845  int
1846 1846  ddi_prop_op_nblocks_blksize(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1847 1847      int mod_flags, char *name, caddr_t valuep, int *lengthp,
1848 1848      uint64_t nblocks64, uint_t blksize)
1849 1849  {
1850 1850          uint64_t size64;
1851 1851          int     blkshift;
1852 1852  
1853 1853          /* convert block size to shift value */
1854 1854          ASSERT(BIT_ONLYONESET(blksize));
1855 1855          blkshift = highbit(blksize) - 1;
1856 1856  
1857 1857          /*
1858 1858           * There is no point in supporting nblocks64 values that don't have
1859 1859           * an accurate uint64_t byte count representation.
1860 1860           */
1861 1861          if (nblocks64 >= (UINT64_MAX >> blkshift))
1862 1862                  return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1863 1863                      name, valuep, lengthp));
1864 1864  
1865 1865          size64 = nblocks64 << blkshift;
1866 1866          return (ddi_prop_op_size_blksize(dev, dip, prop_op, mod_flags,
1867 1867              name, valuep, lengthp, size64, blksize));
1868 1868  }
1869 1869  
1870 1870  /*
1871 1871   * ddi_prop_op_nblocks: ddi_prop_op_nblocks_blksize with DEV_BSIZE blksize.
1872 1872   */
1873 1873  int
1874 1874  ddi_prop_op_nblocks(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1875 1875      int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t nblocks64)
1876 1876  {
1877 1877          return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op,
1878 1878              mod_flags, name, valuep, lengthp, nblocks64, DEV_BSIZE));
1879 1879  }
1880 1880  
1881 1881  /*
1882 1882   * ddi_prop_op_size_blksize: The basic property operator for block drivers that
1883 1883   * maintain size in bytes. Provides a of dynamic property implementation for
1884 1884   * size oriented properties based on size64 value and blksize passed in by the
1885 1885   * driver.  Fallback to ddi_prop_op if the size64 is too large. This interface
1886 1886   * should not be used with a size64 that represents the driver's idea of how
1887 1887   * to represent unknown, if size is unknown use ddi_prop_op.
1888 1888   *
1889 1889   * NOTE: the legacy "nblocks"/"size" properties are treated as 32-bit unsigned
1890 1890   * integers. While the most likely interface to request them ([bc]devi_size)
1891 1891   * is declared int (signed) there is no enforcement of this, which means we
1892 1892   * can't enforce limitations here without risking regression.
1893 1893   */
1894 1894  int
1895 1895  ddi_prop_op_size_blksize(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1896 1896      int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t size64,
1897 1897      uint_t blksize)
1898 1898  {
1899 1899          uint64_t nblocks64;
1900 1900          int     callers_length;
1901 1901          caddr_t buffer;
1902 1902          int     blkshift;
1903 1903  
1904 1904          /*
1905 1905           * This is a kludge to support capture of size(9P) pure dynamic
1906 1906           * properties in snapshots for non-cmlb code (without exposing
1907 1907           * i_ddi_prop_dyn changes). When everyone uses cmlb, this code
1908 1908           * should be removed.
1909 1909           */
1910 1910          if (i_ddi_prop_dyn_driver_get(dip) == NULL) {
1911 1911                  static i_ddi_prop_dyn_t prop_dyn_size[] = {
1912 1912                      {"Size",            DDI_PROP_TYPE_INT64,    S_IFCHR},
1913 1913                      {"Nblocks",         DDI_PROP_TYPE_INT64,    S_IFBLK},
1914 1914                      {NULL}
1915 1915                  };
1916 1916                  i_ddi_prop_dyn_driver_set(dip, prop_dyn_size);
1917 1917          }
1918 1918  
1919 1919          /* convert block size to shift value */
1920 1920          ASSERT(BIT_ONLYONESET(blksize));
1921 1921          blkshift = highbit(blksize) - 1;
1922 1922  
1923 1923          /* compute DEV_BSIZE nblocks value */
1924 1924          nblocks64 = size64 >> blkshift;
1925 1925  
1926 1926          /* get callers length, establish length of our dynamic properties */
1927 1927          callers_length = *lengthp;
1928 1928  
1929 1929          if (strcmp(name, "Nblocks") == 0)
1930 1930                  *lengthp = sizeof (uint64_t);
1931 1931          else if (strcmp(name, "Size") == 0)
1932 1932                  *lengthp = sizeof (uint64_t);
1933 1933          else if ((strcmp(name, "nblocks") == 0) && (nblocks64 < UINT_MAX))
1934 1934                  *lengthp = sizeof (uint32_t);
1935 1935          else if ((strcmp(name, "size") == 0) && (size64 < UINT_MAX))
1936 1936                  *lengthp = sizeof (uint32_t);
1937 1937          else if ((strcmp(name, "blksize") == 0) && (blksize < UINT_MAX))
1938 1938                  *lengthp = sizeof (uint32_t);
1939 1939          else {
1940 1940                  /* fallback to ddi_prop_op */
1941 1941                  return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1942 1942                      name, valuep, lengthp));
1943 1943          }
1944 1944  
1945 1945          /* service request for the length of the property */
1946 1946          if (prop_op == PROP_LEN)
1947 1947                  return (DDI_PROP_SUCCESS);
1948 1948  
1949 1949          switch (prop_op) {
1950 1950          case PROP_LEN_AND_VAL_ALLOC:
1951 1951                  if ((buffer = kmem_alloc(*lengthp,
1952 1952                      (mod_flags & DDI_PROP_CANSLEEP) ?
1953 1953                      KM_SLEEP : KM_NOSLEEP)) == NULL)
1954 1954                          return (DDI_PROP_NO_MEMORY);
1955 1955  
1956 1956                  *(caddr_t *)valuep = buffer;    /* set callers buf ptr */
1957 1957                  break;
1958 1958  
1959 1959          case PROP_LEN_AND_VAL_BUF:
1960 1960                  /* the length of the property and the request must match */
1961 1961                  if (callers_length != *lengthp)
1962 1962                          return (DDI_PROP_INVAL_ARG);
1963 1963  
1964 1964                  buffer = valuep;                /* get callers buf ptr */
1965 1965                  break;
1966 1966  
1967 1967          default:
1968 1968                  return (DDI_PROP_INVAL_ARG);
1969 1969          }
1970 1970  
1971 1971          /* transfer the value into the buffer */
1972 1972          if (strcmp(name, "Nblocks") == 0)
1973 1973                  *((uint64_t *)buffer) = nblocks64;
1974 1974          else if (strcmp(name, "Size") == 0)
1975 1975                  *((uint64_t *)buffer) = size64;
1976 1976          else if (strcmp(name, "nblocks") == 0)
1977 1977                  *((uint32_t *)buffer) = (uint32_t)nblocks64;
1978 1978          else if (strcmp(name, "size") == 0)
1979 1979                  *((uint32_t *)buffer) = (uint32_t)size64;
1980 1980          else if (strcmp(name, "blksize") == 0)
1981 1981                  *((uint32_t *)buffer) = (uint32_t)blksize;
1982 1982          return (DDI_PROP_SUCCESS);
1983 1983  }
1984 1984  
1985 1985  /*
1986 1986   * ddi_prop_op_size: ddi_prop_op_size_blksize with DEV_BSIZE block size.
1987 1987   */
1988 1988  int
1989 1989  ddi_prop_op_size(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1990 1990      int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t size64)
1991 1991  {
1992 1992          return (ddi_prop_op_size_blksize(dev, dip, prop_op,
1993 1993              mod_flags, name, valuep, lengthp, size64, DEV_BSIZE));
1994 1994  }
1995 1995  
1996 1996  /*
1997 1997   * Variable length props...
1998 1998   */
1999 1999  
2000 2000  /*
2001 2001   * ddi_getlongprop:     Get variable length property len+val into a buffer
2002 2002   *              allocated by property provider via kmem_alloc. Requester
2003 2003   *              is responsible for freeing returned property via kmem_free.
2004 2004   *
2005 2005   *      Arguments:
2006 2006   *
2007 2007   *      dev_t:  Input:  dev_t of property.
2008 2008   *      dip:    Input:  dev_info_t pointer of child.
2009 2009   *      flags:  Input:  Possible flag modifiers are:
2010 2010   *              DDI_PROP_DONTPASS:      Don't pass to parent if prop not found.
2011 2011   *              DDI_PROP_CANSLEEP:      Memory allocation may sleep.
2012 2012   *      name:   Input:  name of property.
2013 2013   *      valuep: Output: Addr of callers buffer pointer.
2014 2014   *      lengthp:Output: *lengthp will contain prop length on exit.
2015 2015   *
2016 2016   *      Possible Returns:
2017 2017   *
2018 2018   *              DDI_PROP_SUCCESS:       Prop found and returned.
2019 2019   *              DDI_PROP_NOT_FOUND:     Prop not found
2020 2020   *              DDI_PROP_UNDEFINED:     Prop explicitly undefined.
2021 2021   *              DDI_PROP_NO_MEMORY:     Prop found, but unable to alloc mem.
2022 2022   */
2023 2023  
2024 2024  int
2025 2025  ddi_getlongprop(dev_t dev, dev_info_t *dip, int flags,
2026 2026      char *name, caddr_t valuep, int *lengthp)
2027 2027  {
2028 2028          return (ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_ALLOC,
2029 2029              flags, name, valuep, lengthp));
2030 2030  }
2031 2031  
2032 2032  /*
2033 2033   *
2034 2034   * ddi_getlongprop_buf:         Get long prop into pre-allocated callers
2035 2035   *                              buffer. (no memory allocation by provider).
2036 2036   *
2037 2037   *      dev_t:  Input:  dev_t of property.
2038 2038   *      dip:    Input:  dev_info_t pointer of child.
2039 2039   *      flags:  Input:  DDI_PROP_DONTPASS or NULL
2040 2040   *      name:   Input:  name of property
2041 2041   *      valuep: Input:  ptr to callers buffer.
2042 2042   *      lengthp:I/O:    ptr to length of callers buffer on entry,
2043 2043   *                      actual length of property on exit.
2044 2044   *
2045 2045   *      Possible returns:
2046 2046   *
2047 2047   *              DDI_PROP_SUCCESS        Prop found and returned
2048 2048   *              DDI_PROP_NOT_FOUND      Prop not found
2049 2049   *              DDI_PROP_UNDEFINED      Prop explicitly undefined.
2050 2050   *              DDI_PROP_BUF_TOO_SMALL  Prop found, callers buf too small,
2051 2051   *                                      no value returned, but actual prop
2052 2052   *                                      length returned in *lengthp
2053 2053   *
2054 2054   */
2055 2055  
2056 2056  int
2057 2057  ddi_getlongprop_buf(dev_t dev, dev_info_t *dip, int flags,
2058 2058      char *name, caddr_t valuep, int *lengthp)
2059 2059  {
2060 2060          return (ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2061 2061              flags, name, valuep, lengthp));
2062 2062  }
2063 2063  
2064 2064  /*
2065 2065   * Integer/boolean sized props.
2066 2066   *
2067 2067   * Call is value only... returns found boolean or int sized prop value or
2068 2068   * defvalue if prop not found or is wrong length or is explicitly undefined.
2069 2069   * Only flag is DDI_PROP_DONTPASS...
2070 2070   *
2071 2071   * By convention, this interface returns boolean (0) sized properties
2072 2072   * as value (int)1.
2073 2073   *
2074 2074   * This never returns an error, if property not found or specifically
2075 2075   * undefined, the input `defvalue' is returned.
2076 2076   */
2077 2077  
2078 2078  int
2079 2079  ddi_getprop(dev_t dev, dev_info_t *dip, int flags, char *name, int defvalue)
2080 2080  {
2081 2081          int     propvalue = defvalue;
2082 2082          int     proplength = sizeof (int);
2083 2083          int     error;
2084 2084  
2085 2085          error = ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2086 2086              flags, name, (caddr_t)&propvalue, &proplength);
2087 2087  
2088 2088          if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
2089 2089                  propvalue = 1;
2090 2090  
2091 2091          return (propvalue);
2092 2092  }
2093 2093  
2094 2094  /*
2095 2095   * Get prop length interface: flags are 0 or DDI_PROP_DONTPASS
2096 2096   * if returns DDI_PROP_SUCCESS, length returned in *lengthp.
2097 2097   */
2098 2098  
2099 2099  int
2100 2100  ddi_getproplen(dev_t dev, dev_info_t *dip, int flags, char *name, int *lengthp)
2101 2101  {
2102 2102          return (ddi_prop_op(dev, dip, PROP_LEN, flags, name, NULL, lengthp));
2103 2103  }
2104 2104  
2105 2105  /*
2106 2106   * Allocate a struct prop_driver_data, along with 'size' bytes
2107 2107   * for decoded property data.  This structure is freed by
2108 2108   * calling ddi_prop_free(9F).
2109 2109   */
2110 2110  static void *
2111 2111  ddi_prop_decode_alloc(size_t size, void (*prop_free)(struct prop_driver_data *))
2112 2112  {
2113 2113          struct prop_driver_data *pdd;
2114 2114  
2115 2115          /*
2116 2116           * Allocate a structure with enough memory to store the decoded data.
2117 2117           */
2118 2118          pdd = kmem_zalloc(sizeof (struct prop_driver_data) + size, KM_SLEEP);
2119 2119          pdd->pdd_size = (sizeof (struct prop_driver_data) + size);
2120 2120          pdd->pdd_prop_free = prop_free;
2121 2121  
2122 2122          /*
2123 2123           * Return a pointer to the location to put the decoded data.
2124 2124           */
2125 2125          return ((void *)((caddr_t)pdd + sizeof (struct prop_driver_data)));
2126 2126  }
2127 2127  
2128 2128  /*
2129 2129   * Allocated the memory needed to store the encoded data in the property
2130 2130   * handle.
2131 2131   */
2132 2132  static int
2133 2133  ddi_prop_encode_alloc(prop_handle_t *ph, size_t size)
2134 2134  {
2135 2135          /*
2136 2136           * If size is zero, then set data to NULL and size to 0.  This
2137 2137           * is a boolean property.
2138 2138           */
2139 2139          if (size == 0) {
2140 2140                  ph->ph_size = 0;
2141 2141                  ph->ph_data = NULL;
2142 2142                  ph->ph_cur_pos = NULL;
2143 2143                  ph->ph_save_pos = NULL;
2144 2144          } else {
2145 2145                  if (ph->ph_flags == DDI_PROP_DONTSLEEP) {
2146 2146                          ph->ph_data = kmem_zalloc(size, KM_NOSLEEP);
2147 2147                          if (ph->ph_data == NULL)
2148 2148                                  return (DDI_PROP_NO_MEMORY);
2149 2149                  } else
2150 2150                          ph->ph_data = kmem_zalloc(size, KM_SLEEP);
2151 2151                  ph->ph_size = size;
2152 2152                  ph->ph_cur_pos = ph->ph_data;
2153 2153                  ph->ph_save_pos = ph->ph_data;
2154 2154          }
2155 2155          return (DDI_PROP_SUCCESS);
2156 2156  }
2157 2157  
2158 2158  /*
2159 2159   * Free the space allocated by the lookup routines.  Each lookup routine
2160 2160   * returns a pointer to the decoded data to the driver.  The driver then
2161 2161   * passes this pointer back to us.  This data actually lives in a struct
2162 2162   * prop_driver_data.  We use negative indexing to find the beginning of
2163 2163   * the structure and then free the entire structure using the size and
2164 2164   * the free routine stored in the structure.
2165 2165   */
2166 2166  void
2167 2167  ddi_prop_free(void *datap)
2168 2168  {
2169 2169          struct prop_driver_data *pdd;
2170 2170  
2171 2171          /*
2172 2172           * Get the structure
2173 2173           */
2174 2174          pdd = (struct prop_driver_data *)
2175 2175              ((caddr_t)datap - sizeof (struct prop_driver_data));
2176 2176          /*
2177 2177           * Call the free routine to free it
2178 2178           */
2179 2179          (*pdd->pdd_prop_free)(pdd);
2180 2180  }
2181 2181  
2182 2182  /*
2183 2183   * Free the data associated with an array of ints,
2184 2184   * allocated with ddi_prop_decode_alloc().
2185 2185   */
2186 2186  static void
2187 2187  ddi_prop_free_ints(struct prop_driver_data *pdd)
2188 2188  {
2189 2189          kmem_free(pdd, pdd->pdd_size);
2190 2190  }
2191 2191  
2192 2192  /*
2193 2193   * Free a single string property or a single string contained within
2194 2194   * the argv style return value of an array of strings.
2195 2195   */
2196 2196  static void
2197 2197  ddi_prop_free_string(struct prop_driver_data *pdd)
2198 2198  {
2199 2199          kmem_free(pdd, pdd->pdd_size);
2200 2200  
2201 2201  }
2202 2202  
2203 2203  /*
2204 2204   * Free an array of strings.
2205 2205   */
2206 2206  static void
2207 2207  ddi_prop_free_strings(struct prop_driver_data *pdd)
2208 2208  {
2209 2209          kmem_free(pdd, pdd->pdd_size);
2210 2210  }
2211 2211  
2212 2212  /*
2213 2213   * Free the data associated with an array of bytes.
2214 2214   */
2215 2215  static void
2216 2216  ddi_prop_free_bytes(struct prop_driver_data *pdd)
2217 2217  {
2218 2218          kmem_free(pdd, pdd->pdd_size);
2219 2219  }
2220 2220  
2221 2221  /*
2222 2222   * Reset the current location pointer in the property handle to the
2223 2223   * beginning of the data.
2224 2224   */
2225 2225  void
2226 2226  ddi_prop_reset_pos(prop_handle_t *ph)
2227 2227  {
2228 2228          ph->ph_cur_pos = ph->ph_data;
2229 2229          ph->ph_save_pos = ph->ph_data;
2230 2230  }
2231 2231  
2232 2232  /*
2233 2233   * Restore the current location pointer in the property handle to the
2234 2234   * saved position.
2235 2235   */
2236 2236  void
2237 2237  ddi_prop_save_pos(prop_handle_t *ph)
2238 2238  {
2239 2239          ph->ph_save_pos = ph->ph_cur_pos;
2240 2240  }
2241 2241  
2242 2242  /*
2243 2243   * Save the location that the current location pointer is pointing to..
2244 2244   */
2245 2245  void
2246 2246  ddi_prop_restore_pos(prop_handle_t *ph)
2247 2247  {
2248 2248          ph->ph_cur_pos = ph->ph_save_pos;
2249 2249  }
2250 2250  
2251 2251  /*
2252 2252   * Property encode/decode functions
2253 2253   */
2254 2254  
2255 2255  /*
2256 2256   * Decode a single integer property
2257 2257   */
2258 2258  static int
2259 2259  ddi_prop_fm_decode_int(prop_handle_t *ph, void *data, uint_t *nelements)
2260 2260  {
2261 2261          int     i;
2262 2262          int     tmp;
2263 2263  
2264 2264          /*
2265 2265           * If there is nothing to decode return an error
2266 2266           */
2267 2267          if (ph->ph_size == 0)
2268 2268                  return (DDI_PROP_END_OF_DATA);
2269 2269  
2270 2270          /*
2271 2271           * Decode the property as a single integer and return it
2272 2272           * in data if we were able to decode it.
2273 2273           */
2274 2274          i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, &tmp);
2275 2275          if (i < DDI_PROP_RESULT_OK) {
2276 2276                  switch (i) {
2277 2277                  case DDI_PROP_RESULT_EOF:
2278 2278                          return (DDI_PROP_END_OF_DATA);
2279 2279  
2280 2280                  case DDI_PROP_RESULT_ERROR:
2281 2281                          return (DDI_PROP_CANNOT_DECODE);
2282 2282                  }
2283 2283          }
2284 2284  
2285 2285          *(int *)data = tmp;
2286 2286          *nelements = 1;
2287 2287          return (DDI_PROP_SUCCESS);
2288 2288  }
2289 2289  
2290 2290  /*
2291 2291   * Decode a single 64 bit integer property
2292 2292   */
2293 2293  static int
2294 2294  ddi_prop_fm_decode_int64(prop_handle_t *ph, void *data, uint_t *nelements)
2295 2295  {
2296 2296          int     i;
2297 2297          int64_t tmp;
2298 2298  
2299 2299          /*
2300 2300           * If there is nothing to decode return an error
2301 2301           */
2302 2302          if (ph->ph_size == 0)
2303 2303                  return (DDI_PROP_END_OF_DATA);
2304 2304  
2305 2305          /*
2306 2306           * Decode the property as a single integer and return it
2307 2307           * in data if we were able to decode it.
2308 2308           */
2309 2309          i = DDI_PROP_INT64(ph, DDI_PROP_CMD_DECODE, &tmp);
2310 2310          if (i < DDI_PROP_RESULT_OK) {
2311 2311                  switch (i) {
2312 2312                  case DDI_PROP_RESULT_EOF:
2313 2313                          return (DDI_PROP_END_OF_DATA);
2314 2314  
2315 2315                  case DDI_PROP_RESULT_ERROR:
2316 2316                          return (DDI_PROP_CANNOT_DECODE);
2317 2317                  }
2318 2318          }
2319 2319  
2320 2320          *(int64_t *)data = tmp;
2321 2321          *nelements = 1;
2322 2322          return (DDI_PROP_SUCCESS);
2323 2323  }
2324 2324  
2325 2325  /*
2326 2326   * Decode an array of integers property
2327 2327   */
2328 2328  static int
2329 2329  ddi_prop_fm_decode_ints(prop_handle_t *ph, void *data, uint_t *nelements)
2330 2330  {
2331 2331          int     i;
2332 2332          int     cnt = 0;
2333 2333          int     *tmp;
2334 2334          int     *intp;
2335 2335          int     n;
2336 2336  
2337 2337          /*
2338 2338           * Figure out how many array elements there are by going through the
2339 2339           * data without decoding it first and counting.
2340 2340           */
2341 2341          for (;;) {
2342 2342                  i = DDI_PROP_INT(ph, DDI_PROP_CMD_SKIP, NULL);
2343 2343                  if (i < 0)
2344 2344                          break;
2345 2345                  cnt++;
2346 2346          }
2347 2347  
2348 2348          /*
2349 2349           * If there are no elements return an error
2350 2350           */
2351 2351          if (cnt == 0)
2352 2352                  return (DDI_PROP_END_OF_DATA);
2353 2353  
2354 2354          /*
2355 2355           * If we cannot skip through the data, we cannot decode it
2356 2356           */
2357 2357          if (i == DDI_PROP_RESULT_ERROR)
2358 2358                  return (DDI_PROP_CANNOT_DECODE);
2359 2359  
2360 2360          /*
2361 2361           * Reset the data pointer to the beginning of the encoded data
2362 2362           */
2363 2363          ddi_prop_reset_pos(ph);
2364 2364  
2365 2365          /*
2366 2366           * Allocated memory to store the decoded value in.
2367 2367           */
2368 2368          intp = ddi_prop_decode_alloc((cnt * sizeof (int)),
2369 2369              ddi_prop_free_ints);
2370 2370  
2371 2371          /*
2372 2372           * Decode each element and place it in the space we just allocated
2373 2373           */
2374 2374          tmp = intp;
2375 2375          for (n = 0; n < cnt; n++, tmp++) {
2376 2376                  i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, tmp);
2377 2377                  if (i < DDI_PROP_RESULT_OK) {
2378 2378                          /*
2379 2379                           * Free the space we just allocated
2380 2380                           * and return an error.
2381 2381                           */
2382 2382                          ddi_prop_free(intp);
2383 2383                          switch (i) {
2384 2384                          case DDI_PROP_RESULT_EOF:
2385 2385                                  return (DDI_PROP_END_OF_DATA);
2386 2386  
2387 2387                          case DDI_PROP_RESULT_ERROR:
2388 2388                                  return (DDI_PROP_CANNOT_DECODE);
2389 2389                          }
2390 2390                  }
2391 2391          }
2392 2392  
2393 2393          *nelements = cnt;
2394 2394          *(int **)data = intp;
2395 2395  
2396 2396          return (DDI_PROP_SUCCESS);
2397 2397  }
2398 2398  
2399 2399  /*
2400 2400   * Decode a 64 bit integer array property
2401 2401   */
2402 2402  static int
2403 2403  ddi_prop_fm_decode_int64_array(prop_handle_t *ph, void *data, uint_t *nelements)
2404 2404  {
2405 2405          int     i;
2406 2406          int     n;
2407 2407          int     cnt = 0;
2408 2408          int64_t *tmp;
2409 2409          int64_t *intp;
2410 2410  
2411 2411          /*
2412 2412           * Count the number of array elements by going
2413 2413           * through the data without decoding it.
2414 2414           */
2415 2415          for (;;) {
2416 2416                  i = DDI_PROP_INT64(ph, DDI_PROP_CMD_SKIP, NULL);
2417 2417                  if (i < 0)
2418 2418                          break;
2419 2419                  cnt++;
2420 2420          }
2421 2421  
2422 2422          /*
2423 2423           * If there are no elements return an error
2424 2424           */
2425 2425          if (cnt == 0)
2426 2426                  return (DDI_PROP_END_OF_DATA);
2427 2427  
2428 2428          /*
2429 2429           * If we cannot skip through the data, we cannot decode it
2430 2430           */
2431 2431          if (i == DDI_PROP_RESULT_ERROR)
2432 2432                  return (DDI_PROP_CANNOT_DECODE);
2433 2433  
2434 2434          /*
2435 2435           * Reset the data pointer to the beginning of the encoded data
2436 2436           */
2437 2437          ddi_prop_reset_pos(ph);
2438 2438  
2439 2439          /*
2440 2440           * Allocate memory to store the decoded value.
2441 2441           */
2442 2442          intp = ddi_prop_decode_alloc((cnt * sizeof (int64_t)),
2443 2443              ddi_prop_free_ints);
2444 2444  
2445 2445          /*
2446 2446           * Decode each element and place it in the space allocated
2447 2447           */
2448 2448          tmp = intp;
2449 2449          for (n = 0; n < cnt; n++, tmp++) {
2450 2450                  i = DDI_PROP_INT64(ph, DDI_PROP_CMD_DECODE, tmp);
2451 2451                  if (i < DDI_PROP_RESULT_OK) {
2452 2452                          /*
2453 2453                           * Free the space we just allocated
2454 2454                           * and return an error.
2455 2455                           */
2456 2456                          ddi_prop_free(intp);
2457 2457                          switch (i) {
2458 2458                          case DDI_PROP_RESULT_EOF:
2459 2459                                  return (DDI_PROP_END_OF_DATA);
2460 2460  
2461 2461                          case DDI_PROP_RESULT_ERROR:
2462 2462                                  return (DDI_PROP_CANNOT_DECODE);
2463 2463                          }
2464 2464                  }
2465 2465          }
2466 2466  
2467 2467          *nelements = cnt;
2468 2468          *(int64_t **)data = intp;
2469 2469  
2470 2470          return (DDI_PROP_SUCCESS);
2471 2471  }
2472 2472  
2473 2473  /*
2474 2474   * Encode an array of integers property (Can be one element)
2475 2475   */
2476 2476  int
2477 2477  ddi_prop_fm_encode_ints(prop_handle_t *ph, void *data, uint_t nelements)
2478 2478  {
2479 2479          int     i;
2480 2480          int     *tmp;
2481 2481          int     cnt;
2482 2482          int     size;
2483 2483  
2484 2484          /*
2485 2485           * If there is no data, we cannot do anything
2486 2486           */
2487 2487          if (nelements == 0)
2488 2488                  return (DDI_PROP_CANNOT_ENCODE);
2489 2489  
2490 2490          /*
2491 2491           * Get the size of an encoded int.
2492 2492           */
2493 2493          size = DDI_PROP_INT(ph, DDI_PROP_CMD_GET_ESIZE, NULL);
2494 2494  
2495 2495          if (size < DDI_PROP_RESULT_OK) {
2496 2496                  switch (size) {
2497 2497                  case DDI_PROP_RESULT_EOF:
2498 2498                          return (DDI_PROP_END_OF_DATA);
2499 2499  
2500 2500                  case DDI_PROP_RESULT_ERROR:
2501 2501                          return (DDI_PROP_CANNOT_ENCODE);
2502 2502                  }
2503 2503          }
2504 2504  
2505 2505          /*
2506 2506           * Allocate space in the handle to store the encoded int.
2507 2507           */
2508 2508          if (ddi_prop_encode_alloc(ph, size * nelements) !=
2509 2509              DDI_PROP_SUCCESS)
2510 2510                  return (DDI_PROP_NO_MEMORY);
2511 2511  
2512 2512          /*
2513 2513           * Encode the array of ints.
2514 2514           */
2515 2515          tmp = (int *)data;
2516 2516          for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2517 2517                  i = DDI_PROP_INT(ph, DDI_PROP_CMD_ENCODE, tmp);
2518 2518                  if (i < DDI_PROP_RESULT_OK) {
2519 2519                          switch (i) {
2520 2520                          case DDI_PROP_RESULT_EOF:
2521 2521                                  return (DDI_PROP_END_OF_DATA);
2522 2522  
2523 2523                          case DDI_PROP_RESULT_ERROR:
2524 2524                                  return (DDI_PROP_CANNOT_ENCODE);
2525 2525                          }
2526 2526                  }
2527 2527          }
2528 2528  
2529 2529          return (DDI_PROP_SUCCESS);
2530 2530  }
2531 2531  
2532 2532  
2533 2533  /*
2534 2534   * Encode a 64 bit integer array property
2535 2535   */
2536 2536  int
2537 2537  ddi_prop_fm_encode_int64(prop_handle_t *ph, void *data, uint_t nelements)
2538 2538  {
2539 2539          int i;
2540 2540          int cnt;
2541 2541          int size;
2542 2542          int64_t *tmp;
2543 2543  
2544 2544          /*
2545 2545           * If there is no data, we cannot do anything
2546 2546           */
2547 2547          if (nelements == 0)
2548 2548                  return (DDI_PROP_CANNOT_ENCODE);
2549 2549  
2550 2550          /*
2551 2551           * Get the size of an encoded 64 bit int.
2552 2552           */
2553 2553          size = DDI_PROP_INT64(ph, DDI_PROP_CMD_GET_ESIZE, NULL);
2554 2554  
2555 2555          if (size < DDI_PROP_RESULT_OK) {
2556 2556                  switch (size) {
2557 2557                  case DDI_PROP_RESULT_EOF:
2558 2558                          return (DDI_PROP_END_OF_DATA);
2559 2559  
2560 2560                  case DDI_PROP_RESULT_ERROR:
2561 2561                          return (DDI_PROP_CANNOT_ENCODE);
2562 2562                  }
2563 2563          }
2564 2564  
2565 2565          /*
2566 2566           * Allocate space in the handle to store the encoded int.
2567 2567           */
2568 2568          if (ddi_prop_encode_alloc(ph, size * nelements) !=
2569 2569              DDI_PROP_SUCCESS)
2570 2570                  return (DDI_PROP_NO_MEMORY);
2571 2571  
2572 2572          /*
2573 2573           * Encode the array of ints.
2574 2574           */
2575 2575          tmp = (int64_t *)data;
2576 2576          for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2577 2577                  i = DDI_PROP_INT64(ph, DDI_PROP_CMD_ENCODE, tmp);
2578 2578                  if (i < DDI_PROP_RESULT_OK) {
2579 2579                          switch (i) {
2580 2580                          case DDI_PROP_RESULT_EOF:
2581 2581                                  return (DDI_PROP_END_OF_DATA);
2582 2582  
2583 2583                          case DDI_PROP_RESULT_ERROR:
2584 2584                                  return (DDI_PROP_CANNOT_ENCODE);
2585 2585                          }
2586 2586                  }
2587 2587          }
2588 2588  
2589 2589          return (DDI_PROP_SUCCESS);
2590 2590  }
2591 2591  
2592 2592  /*
2593 2593   * Decode a single string property
2594 2594   */
2595 2595  static int
2596 2596  ddi_prop_fm_decode_string(prop_handle_t *ph, void *data, uint_t *nelements)
2597 2597  {
2598 2598          char            *tmp;
2599 2599          char            *str;
2600 2600          int             i;
2601 2601          int             size;
2602 2602  
2603 2603          /*
2604 2604           * If there is nothing to decode return an error
2605 2605           */
2606 2606          if (ph->ph_size == 0)
2607 2607                  return (DDI_PROP_END_OF_DATA);
2608 2608  
2609 2609          /*
2610 2610           * Get the decoded size of the encoded string.
2611 2611           */
2612 2612          size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
2613 2613          if (size < DDI_PROP_RESULT_OK) {
2614 2614                  switch (size) {
2615 2615                  case DDI_PROP_RESULT_EOF:
2616 2616                          return (DDI_PROP_END_OF_DATA);
2617 2617  
2618 2618                  case DDI_PROP_RESULT_ERROR:
2619 2619                          return (DDI_PROP_CANNOT_DECODE);
2620 2620                  }
2621 2621          }
2622 2622  
2623 2623          /*
2624 2624           * Allocated memory to store the decoded value in.
2625 2625           */
2626 2626          str = ddi_prop_decode_alloc((size_t)size, ddi_prop_free_string);
2627 2627  
2628 2628          ddi_prop_reset_pos(ph);
2629 2629  
2630 2630          /*
2631 2631           * Decode the str and place it in the space we just allocated
2632 2632           */
2633 2633          tmp = str;
2634 2634          i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, tmp);
2635 2635          if (i < DDI_PROP_RESULT_OK) {
2636 2636                  /*
2637 2637                   * Free the space we just allocated
2638 2638                   * and return an error.
2639 2639                   */
2640 2640                  ddi_prop_free(str);
2641 2641                  switch (i) {
2642 2642                  case DDI_PROP_RESULT_EOF:
2643 2643                          return (DDI_PROP_END_OF_DATA);
2644 2644  
2645 2645                  case DDI_PROP_RESULT_ERROR:
2646 2646                          return (DDI_PROP_CANNOT_DECODE);
2647 2647                  }
2648 2648          }
2649 2649  
2650 2650          *(char **)data = str;
2651 2651          *nelements = 1;
2652 2652  
2653 2653          return (DDI_PROP_SUCCESS);
2654 2654  }
2655 2655  
2656 2656  /*
2657 2657   * Decode an array of strings.
2658 2658   */
2659 2659  int
2660 2660  ddi_prop_fm_decode_strings(prop_handle_t *ph, void *data, uint_t *nelements)
2661 2661  {
2662 2662          int             cnt = 0;
2663 2663          char            **strs;
2664 2664          char            **tmp;
2665 2665          char            *ptr;
2666 2666          int             i;
2667 2667          int             n;
2668 2668          int             size;
2669 2669          size_t          nbytes;
2670 2670  
2671 2671          /*
2672 2672           * Figure out how many array elements there are by going through the
2673 2673           * data without decoding it first and counting.
2674 2674           */
2675 2675          for (;;) {
2676 2676                  i = DDI_PROP_STR(ph, DDI_PROP_CMD_SKIP, NULL);
2677 2677                  if (i < 0)
2678 2678                          break;
2679 2679                  cnt++;
2680 2680          }
2681 2681  
2682 2682          /*
2683 2683           * If there are no elements return an error
2684 2684           */
2685 2685          if (cnt == 0)
2686 2686                  return (DDI_PROP_END_OF_DATA);
2687 2687  
2688 2688          /*
2689 2689           * If we cannot skip through the data, we cannot decode it
2690 2690           */
2691 2691          if (i == DDI_PROP_RESULT_ERROR)
2692 2692                  return (DDI_PROP_CANNOT_DECODE);
2693 2693  
2694 2694          /*
2695 2695           * Reset the data pointer to the beginning of the encoded data
2696 2696           */
2697 2697          ddi_prop_reset_pos(ph);
2698 2698  
2699 2699          /*
2700 2700           * Figure out how much memory we need for the sum total
2701 2701           */
2702 2702          nbytes = (cnt + 1) * sizeof (char *);
2703 2703  
2704 2704          for (n = 0; n < cnt; n++) {
2705 2705                  /*
2706 2706                   * Get the decoded size of the current encoded string.
2707 2707                   */
2708 2708                  size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
2709 2709                  if (size < DDI_PROP_RESULT_OK) {
2710 2710                          switch (size) {
2711 2711                          case DDI_PROP_RESULT_EOF:
2712 2712                                  return (DDI_PROP_END_OF_DATA);
2713 2713  
2714 2714                          case DDI_PROP_RESULT_ERROR:
2715 2715                                  return (DDI_PROP_CANNOT_DECODE);
2716 2716                          }
2717 2717                  }
2718 2718  
2719 2719                  nbytes += size;
2720 2720          }
2721 2721  
2722 2722          /*
2723 2723           * Allocate memory in which to store the decoded strings.
2724 2724           */
2725 2725          strs = ddi_prop_decode_alloc(nbytes, ddi_prop_free_strings);
2726 2726  
2727 2727          /*
2728 2728           * Set up pointers for each string by figuring out yet
2729 2729           * again how long each string is.
2730 2730           */
2731 2731          ddi_prop_reset_pos(ph);
2732 2732          ptr = (caddr_t)strs + ((cnt + 1) * sizeof (char *));
2733 2733          for (tmp = strs, n = 0; n < cnt; n++, tmp++) {
2734 2734                  /*
2735 2735                   * Get the decoded size of the current encoded string.
2736 2736                   */
2737 2737                  size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
2738 2738                  if (size < DDI_PROP_RESULT_OK) {
2739 2739                          ddi_prop_free(strs);
2740 2740                          switch (size) {
2741 2741                          case DDI_PROP_RESULT_EOF:
2742 2742                                  return (DDI_PROP_END_OF_DATA);
2743 2743  
2744 2744                          case DDI_PROP_RESULT_ERROR:
2745 2745                                  return (DDI_PROP_CANNOT_DECODE);
2746 2746                          }
2747 2747                  }
2748 2748  
2749 2749                  *tmp = ptr;
2750 2750                  ptr += size;
2751 2751          }
2752 2752  
2753 2753          /*
2754 2754           * String array is terminated by a NULL
2755 2755           */
2756 2756          *tmp = NULL;
2757 2757  
2758 2758          /*
2759 2759           * Finally, we can decode each string
2760 2760           */
2761 2761          ddi_prop_reset_pos(ph);
2762 2762          for (tmp = strs, n = 0; n < cnt; n++, tmp++) {
2763 2763                  i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, *tmp);
2764 2764                  if (i < DDI_PROP_RESULT_OK) {
2765 2765                          /*
2766 2766                           * Free the space we just allocated
2767 2767                           * and return an error
2768 2768                           */
2769 2769                          ddi_prop_free(strs);
2770 2770                          switch (i) {
2771 2771                          case DDI_PROP_RESULT_EOF:
2772 2772                                  return (DDI_PROP_END_OF_DATA);
2773 2773  
2774 2774                          case DDI_PROP_RESULT_ERROR:
2775 2775                                  return (DDI_PROP_CANNOT_DECODE);
2776 2776                          }
2777 2777                  }
2778 2778          }
2779 2779  
2780 2780          *(char ***)data = strs;
2781 2781          *nelements = cnt;
2782 2782  
2783 2783          return (DDI_PROP_SUCCESS);
2784 2784  }
2785 2785  
2786 2786  /*
2787 2787   * Encode a string.
2788 2788   */
2789 2789  int
2790 2790  ddi_prop_fm_encode_string(prop_handle_t *ph, void *data, uint_t nelements)
2791 2791  {
2792 2792          char            **tmp;
2793 2793          int             size;
2794 2794          int             i;
2795 2795  
2796 2796          /*
2797 2797           * If there is no data, we cannot do anything
2798 2798           */
2799 2799          if (nelements == 0)
2800 2800                  return (DDI_PROP_CANNOT_ENCODE);
2801 2801  
2802 2802          /*
2803 2803           * Get the size of the encoded string.
2804 2804           */
2805 2805          tmp = (char **)data;
2806 2806          size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_ESIZE, *tmp);
2807 2807          if (size < DDI_PROP_RESULT_OK) {
2808 2808                  switch (size) {
2809 2809                  case DDI_PROP_RESULT_EOF:
2810 2810                          return (DDI_PROP_END_OF_DATA);
2811 2811  
2812 2812                  case DDI_PROP_RESULT_ERROR:
2813 2813                          return (DDI_PROP_CANNOT_ENCODE);
2814 2814                  }
2815 2815          }
2816 2816  
2817 2817          /*
2818 2818           * Allocate space in the handle to store the encoded string.
2819 2819           */
2820 2820          if (ddi_prop_encode_alloc(ph, size) != DDI_PROP_SUCCESS)
2821 2821                  return (DDI_PROP_NO_MEMORY);
2822 2822  
2823 2823          ddi_prop_reset_pos(ph);
2824 2824  
2825 2825          /*
2826 2826           * Encode the string.
2827 2827           */
2828 2828          tmp = (char **)data;
2829 2829          i = DDI_PROP_STR(ph, DDI_PROP_CMD_ENCODE, *tmp);
2830 2830          if (i < DDI_PROP_RESULT_OK) {
2831 2831                  switch (i) {
2832 2832                  case DDI_PROP_RESULT_EOF:
2833 2833                          return (DDI_PROP_END_OF_DATA);
2834 2834  
2835 2835                  case DDI_PROP_RESULT_ERROR:
2836 2836                          return (DDI_PROP_CANNOT_ENCODE);
2837 2837                  }
2838 2838          }
2839 2839  
2840 2840          return (DDI_PROP_SUCCESS);
2841 2841  }
2842 2842  
2843 2843  
2844 2844  /*
2845 2845   * Encode an array of strings.
2846 2846   */
2847 2847  int
2848 2848  ddi_prop_fm_encode_strings(prop_handle_t *ph, void *data, uint_t nelements)
2849 2849  {
2850 2850          int             cnt = 0;
2851 2851          char            **tmp;
2852 2852          int             size;
2853 2853          uint_t          total_size;
2854 2854          int             i;
2855 2855  
2856 2856          /*
2857 2857           * If there is no data, we cannot do anything
2858 2858           */
2859 2859          if (nelements == 0)
2860 2860                  return (DDI_PROP_CANNOT_ENCODE);
2861 2861  
2862 2862          /*
2863 2863           * Get the total size required to encode all the strings.
2864 2864           */
2865 2865          total_size = 0;
2866 2866          tmp = (char **)data;
2867 2867          for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2868 2868                  size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_ESIZE, *tmp);
2869 2869                  if (size < DDI_PROP_RESULT_OK) {
2870 2870                          switch (size) {
2871 2871                          case DDI_PROP_RESULT_EOF:
2872 2872                                  return (DDI_PROP_END_OF_DATA);
2873 2873  
2874 2874                          case DDI_PROP_RESULT_ERROR:
2875 2875                                  return (DDI_PROP_CANNOT_ENCODE);
2876 2876                          }
2877 2877                  }
2878 2878                  total_size += (uint_t)size;
2879 2879          }
2880 2880  
2881 2881          /*
2882 2882           * Allocate space in the handle to store the encoded strings.
2883 2883           */
2884 2884          if (ddi_prop_encode_alloc(ph, total_size) != DDI_PROP_SUCCESS)
2885 2885                  return (DDI_PROP_NO_MEMORY);
2886 2886  
2887 2887          ddi_prop_reset_pos(ph);
2888 2888  
2889 2889          /*
2890 2890           * Encode the array of strings.
2891 2891           */
2892 2892          tmp = (char **)data;
2893 2893          for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2894 2894                  i = DDI_PROP_STR(ph, DDI_PROP_CMD_ENCODE, *tmp);
2895 2895                  if (i < DDI_PROP_RESULT_OK) {
2896 2896                          switch (i) {
2897 2897                          case DDI_PROP_RESULT_EOF:
2898 2898                                  return (DDI_PROP_END_OF_DATA);
2899 2899  
2900 2900                          case DDI_PROP_RESULT_ERROR:
2901 2901                                  return (DDI_PROP_CANNOT_ENCODE);
2902 2902                          }
2903 2903                  }
2904 2904          }
2905 2905  
2906 2906          return (DDI_PROP_SUCCESS);
2907 2907  }
2908 2908  
2909 2909  
2910 2910  /*
2911 2911   * Decode an array of bytes.
2912 2912   */
2913 2913  static int
2914 2914  ddi_prop_fm_decode_bytes(prop_handle_t *ph, void *data, uint_t *nelements)
2915 2915  {
2916 2916          uchar_t         *tmp;
2917 2917          int             nbytes;
2918 2918          int             i;
2919 2919  
2920 2920          /*
2921 2921           * If there are no elements return an error
2922 2922           */
2923 2923          if (ph->ph_size == 0)
2924 2924                  return (DDI_PROP_END_OF_DATA);
2925 2925  
2926 2926          /*
2927 2927           * Get the size of the encoded array of bytes.
2928 2928           */
2929 2929          nbytes = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_DSIZE,
2930 2930              data, ph->ph_size);
2931 2931          if (nbytes < DDI_PROP_RESULT_OK) {
2932 2932                  switch (nbytes) {
2933 2933                  case DDI_PROP_RESULT_EOF:
2934 2934                          return (DDI_PROP_END_OF_DATA);
2935 2935  
2936 2936                  case DDI_PROP_RESULT_ERROR:
2937 2937                          return (DDI_PROP_CANNOT_DECODE);
2938 2938                  }
2939 2939          }
2940 2940  
2941 2941          /*
2942 2942           * Allocated memory to store the decoded value in.
2943 2943           */
2944 2944          tmp = ddi_prop_decode_alloc(nbytes, ddi_prop_free_bytes);
2945 2945  
2946 2946          /*
2947 2947           * Decode each element and place it in the space we just allocated
2948 2948           */
2949 2949          i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_DECODE, tmp, nbytes);
2950 2950          if (i < DDI_PROP_RESULT_OK) {
2951 2951                  /*
2952 2952                   * Free the space we just allocated
2953 2953                   * and return an error
2954 2954                   */
2955 2955                  ddi_prop_free(tmp);
2956 2956                  switch (i) {
2957 2957                  case DDI_PROP_RESULT_EOF:
2958 2958                          return (DDI_PROP_END_OF_DATA);
2959 2959  
2960 2960                  case DDI_PROP_RESULT_ERROR:
2961 2961                          return (DDI_PROP_CANNOT_DECODE);
2962 2962                  }
2963 2963          }
2964 2964  
2965 2965          *(uchar_t **)data = tmp;
2966 2966          *nelements = nbytes;
2967 2967  
2968 2968          return (DDI_PROP_SUCCESS);
2969 2969  }
2970 2970  
2971 2971  /*
2972 2972   * Encode an array of bytes.
2973 2973   */
2974 2974  int
2975 2975  ddi_prop_fm_encode_bytes(prop_handle_t *ph, void *data, uint_t nelements)
2976 2976  {
2977 2977          int             size;
2978 2978          int             i;
2979 2979  
2980 2980          /*
2981 2981           * If there are no elements, then this is a boolean property,
2982 2982           * so just create a property handle with no data and return.
2983 2983           */
2984 2984          if (nelements == 0) {
2985 2985                  (void) ddi_prop_encode_alloc(ph, 0);
2986 2986                  return (DDI_PROP_SUCCESS);
2987 2987          }
2988 2988  
2989 2989          /*
2990 2990           * Get the size of the encoded array of bytes.
2991 2991           */
2992 2992          size = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_ESIZE, (uchar_t *)data,
2993 2993              nelements);
2994 2994          if (size < DDI_PROP_RESULT_OK) {
2995 2995                  switch (size) {
2996 2996                  case DDI_PROP_RESULT_EOF:
2997 2997                          return (DDI_PROP_END_OF_DATA);
2998 2998  
2999 2999                  case DDI_PROP_RESULT_ERROR:
3000 3000                          return (DDI_PROP_CANNOT_DECODE);
3001 3001                  }
3002 3002          }
3003 3003  
3004 3004          /*
3005 3005           * Allocate space in the handle to store the encoded bytes.
3006 3006           */
3007 3007          if (ddi_prop_encode_alloc(ph, (uint_t)size) != DDI_PROP_SUCCESS)
3008 3008                  return (DDI_PROP_NO_MEMORY);
3009 3009  
3010 3010          /*
3011 3011           * Encode the array of bytes.
3012 3012           */
3013 3013          i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_ENCODE, (uchar_t *)data,
3014 3014              nelements);
3015 3015          if (i < DDI_PROP_RESULT_OK) {
3016 3016                  switch (i) {
3017 3017                  case DDI_PROP_RESULT_EOF:
3018 3018                          return (DDI_PROP_END_OF_DATA);
3019 3019  
3020 3020                  case DDI_PROP_RESULT_ERROR:
3021 3021                          return (DDI_PROP_CANNOT_ENCODE);
3022 3022                  }
3023 3023          }
3024 3024  
3025 3025          return (DDI_PROP_SUCCESS);
3026 3026  }
3027 3027  
3028 3028  /*
3029 3029   * OBP 1275 integer, string and byte operators.
3030 3030   *
3031 3031   * DDI_PROP_CMD_DECODE:
3032 3032   *
3033 3033   *      DDI_PROP_RESULT_ERROR:          cannot decode the data
3034 3034   *      DDI_PROP_RESULT_EOF:            end of data
3035 3035   *      DDI_PROP_OK:                    data was decoded
3036 3036   *
3037 3037   * DDI_PROP_CMD_ENCODE:
3038 3038   *
3039 3039   *      DDI_PROP_RESULT_ERROR:          cannot encode the data
3040 3040   *      DDI_PROP_RESULT_EOF:            end of data
3041 3041   *      DDI_PROP_OK:                    data was encoded
3042 3042   *
3043 3043   * DDI_PROP_CMD_SKIP:
3044 3044   *
3045 3045   *      DDI_PROP_RESULT_ERROR:          cannot skip the data
3046 3046   *      DDI_PROP_RESULT_EOF:            end of data
3047 3047   *      DDI_PROP_OK:                    data was skipped
3048 3048   *
3049 3049   * DDI_PROP_CMD_GET_ESIZE:
3050 3050   *
3051 3051   *      DDI_PROP_RESULT_ERROR:          cannot get encoded size
3052 3052   *      DDI_PROP_RESULT_EOF:            end of data
3053 3053   *      > 0:                            the encoded size
3054 3054   *
3055 3055   * DDI_PROP_CMD_GET_DSIZE:
3056 3056   *
3057 3057   *      DDI_PROP_RESULT_ERROR:          cannot get decoded size
3058 3058   *      DDI_PROP_RESULT_EOF:            end of data
3059 3059   *      > 0:                            the decoded size
3060 3060   */
3061 3061  
3062 3062  /*
3063 3063   * OBP 1275 integer operator
3064 3064   *
3065 3065   * OBP properties are a byte stream of data, so integers may not be
3066 3066   * properly aligned.  Therefore we need to copy them one byte at a time.
3067 3067   */
3068 3068  int
3069 3069  ddi_prop_1275_int(prop_handle_t *ph, uint_t cmd, int *data)
3070 3070  {
3071 3071          int     i;
3072 3072  
3073 3073          switch (cmd) {
3074 3074          case DDI_PROP_CMD_DECODE:
3075 3075                  /*
3076 3076                   * Check that there is encoded data
3077 3077                   */
3078 3078                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
3079 3079                          return (DDI_PROP_RESULT_ERROR);
3080 3080                  if (ph->ph_flags & PH_FROM_PROM) {
3081 3081                          i = MIN(ph->ph_size, PROP_1275_INT_SIZE);
3082 3082                          if ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
3083 3083                              ph->ph_size - i))
3084 3084                                  return (DDI_PROP_RESULT_ERROR);
3085 3085                  } else {
3086 3086                          if (ph->ph_size < sizeof (int) ||
3087 3087                              ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
3088 3088                              ph->ph_size - sizeof (int))))
3089 3089                                  return (DDI_PROP_RESULT_ERROR);
3090 3090                  }
3091 3091  
3092 3092                  /*
3093 3093                   * Copy the integer, using the implementation-specific
3094 3094                   * copy function if the property is coming from the PROM.
3095 3095                   */
3096 3096                  if (ph->ph_flags & PH_FROM_PROM) {
3097 3097                          *data = impl_ddi_prop_int_from_prom(
3098 3098                              (uchar_t *)ph->ph_cur_pos,
3099 3099                              (ph->ph_size < PROP_1275_INT_SIZE) ?
3100 3100                              ph->ph_size : PROP_1275_INT_SIZE);
3101 3101                  } else {
3102 3102                          bcopy(ph->ph_cur_pos, data, sizeof (int));
3103 3103                  }
3104 3104  
3105 3105                  /*
3106 3106                   * Move the current location to the start of the next
3107 3107                   * bit of undecoded data.
3108 3108                   */
3109 3109                  ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
3110 3110                      PROP_1275_INT_SIZE;
3111 3111                  return (DDI_PROP_RESULT_OK);
3112 3112  
3113 3113          case DDI_PROP_CMD_ENCODE:
3114 3114                  /*
3115 3115                   * Check that there is room to encoded the data
3116 3116                   */
3117 3117                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3118 3118                      ph->ph_size < PROP_1275_INT_SIZE ||
3119 3119                      ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
3120 3120                      ph->ph_size - sizeof (int))))
3121 3121                          return (DDI_PROP_RESULT_ERROR);
3122 3122  
3123 3123                  /*
3124 3124                   * Encode the integer into the byte stream one byte at a
3125 3125                   * time.
3126 3126                   */
3127 3127                  bcopy(data, ph->ph_cur_pos, sizeof (int));
3128 3128  
3129 3129                  /*
3130 3130                   * Move the current location to the start of the next bit of
3131 3131                   * space where we can store encoded data.
3132 3132                   */
3133 3133                  ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
3134 3134                  return (DDI_PROP_RESULT_OK);
3135 3135  
3136 3136          case DDI_PROP_CMD_SKIP:
3137 3137                  /*
3138 3138                   * Check that there is encoded data
3139 3139                   */
3140 3140                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3141 3141                      ph->ph_size < PROP_1275_INT_SIZE)
3142 3142                          return (DDI_PROP_RESULT_ERROR);
3143 3143  
3144 3144  
3145 3145                  if ((caddr_t)ph->ph_cur_pos ==
3146 3146                      (caddr_t)ph->ph_data + ph->ph_size) {
3147 3147                          return (DDI_PROP_RESULT_EOF);
3148 3148                  } else if ((caddr_t)ph->ph_cur_pos >
3149 3149                      (caddr_t)ph->ph_data + ph->ph_size) {
3150 3150                          return (DDI_PROP_RESULT_EOF);
3151 3151                  }
3152 3152  
3153 3153                  /*
3154 3154                   * Move the current location to the start of the next bit of
3155 3155                   * undecoded data.
3156 3156                   */
3157 3157                  ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
3158 3158                  return (DDI_PROP_RESULT_OK);
3159 3159  
3160 3160          case DDI_PROP_CMD_GET_ESIZE:
3161 3161                  /*
3162 3162                   * Return the size of an encoded integer on OBP
3163 3163                   */
3164 3164                  return (PROP_1275_INT_SIZE);
3165 3165  
3166 3166          case DDI_PROP_CMD_GET_DSIZE:
3167 3167                  /*
3168 3168                   * Return the size of a decoded integer on the system.
3169 3169                   */
3170 3170                  return (sizeof (int));
3171 3171  
3172 3172          default:
3173 3173  #ifdef DEBUG
3174 3174                  panic("ddi_prop_1275_int: %x impossible", cmd);
3175 3175                  /*NOTREACHED*/
3176 3176  #else
3177 3177                  return (DDI_PROP_RESULT_ERROR);
3178 3178  #endif  /* DEBUG */
3179 3179          }
3180 3180  }
3181 3181  
3182 3182  /*
3183 3183   * 64 bit integer operator.
3184 3184   *
3185 3185   * This is an extension, defined by Sun, to the 1275 integer
3186 3186   * operator.  This routine handles the encoding/decoding of
3187 3187   * 64 bit integer properties.
3188 3188   */
3189 3189  int
3190 3190  ddi_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
3191 3191  {
3192 3192  
3193 3193          switch (cmd) {
3194 3194          case DDI_PROP_CMD_DECODE:
3195 3195                  /*
3196 3196                   * Check that there is encoded data
3197 3197                   */
3198 3198                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
3199 3199                          return (DDI_PROP_RESULT_ERROR);
3200 3200                  if (ph->ph_flags & PH_FROM_PROM) {
3201 3201                          return (DDI_PROP_RESULT_ERROR);
3202 3202                  } else {
3203 3203                          if (ph->ph_size < sizeof (int64_t) ||
3204 3204                              ((int64_t *)ph->ph_cur_pos >
3205 3205                              ((int64_t *)ph->ph_data +
3206 3206                              ph->ph_size - sizeof (int64_t))))
3207 3207                                  return (DDI_PROP_RESULT_ERROR);
3208 3208                  }
3209 3209                  /*
3210 3210                   * Copy the integer, using the implementation-specific
3211 3211                   * copy function if the property is coming from the PROM.
3212 3212                   */
3213 3213                  if (ph->ph_flags & PH_FROM_PROM) {
3214 3214                          return (DDI_PROP_RESULT_ERROR);
3215 3215                  } else {
3216 3216                          bcopy(ph->ph_cur_pos, data, sizeof (int64_t));
3217 3217                  }
3218 3218  
3219 3219                  /*
3220 3220                   * Move the current location to the start of the next
3221 3221                   * bit of undecoded data.
3222 3222                   */
3223 3223                  ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
3224 3224                      sizeof (int64_t);
3225 3225                          return (DDI_PROP_RESULT_OK);
3226 3226  
3227 3227          case DDI_PROP_CMD_ENCODE:
3228 3228                  /*
3229 3229                   * Check that there is room to encoded the data
3230 3230                   */
3231 3231                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3232 3232                      ph->ph_size < sizeof (int64_t) ||
3233 3233                      ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
3234 3234                      ph->ph_size - sizeof (int64_t))))
3235 3235                          return (DDI_PROP_RESULT_ERROR);
3236 3236  
3237 3237                  /*
3238 3238                   * Encode the integer into the byte stream one byte at a
3239 3239                   * time.
3240 3240                   */
3241 3241                  bcopy(data, ph->ph_cur_pos, sizeof (int64_t));
3242 3242  
3243 3243                  /*
3244 3244                   * Move the current location to the start of the next bit of
3245 3245                   * space where we can store encoded data.
3246 3246                   */
3247 3247                  ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
3248 3248                      sizeof (int64_t);
3249 3249                  return (DDI_PROP_RESULT_OK);
3250 3250  
3251 3251          case DDI_PROP_CMD_SKIP:
3252 3252                  /*
3253 3253                   * Check that there is encoded data
3254 3254                   */
3255 3255                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3256 3256                      ph->ph_size < sizeof (int64_t))
3257 3257                          return (DDI_PROP_RESULT_ERROR);
3258 3258  
3259 3259                  if ((caddr_t)ph->ph_cur_pos ==
3260 3260                      (caddr_t)ph->ph_data + ph->ph_size) {
3261 3261                          return (DDI_PROP_RESULT_EOF);
3262 3262                  } else if ((caddr_t)ph->ph_cur_pos >
3263 3263                      (caddr_t)ph->ph_data + ph->ph_size) {
3264 3264                          return (DDI_PROP_RESULT_EOF);
3265 3265                  }
3266 3266  
3267 3267                  /*
3268 3268                   * Move the current location to the start of
3269 3269                   * the next bit of undecoded data.
3270 3270                   */
3271 3271                  ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
3272 3272                      sizeof (int64_t);
3273 3273                          return (DDI_PROP_RESULT_OK);
3274 3274  
3275 3275          case DDI_PROP_CMD_GET_ESIZE:
3276 3276                  /*
3277 3277                   * Return the size of an encoded integer on OBP
3278 3278                   */
3279 3279                  return (sizeof (int64_t));
3280 3280  
3281 3281          case DDI_PROP_CMD_GET_DSIZE:
3282 3282                  /*
3283 3283                   * Return the size of a decoded integer on the system.
3284 3284                   */
3285 3285                  return (sizeof (int64_t));
3286 3286  
3287 3287          default:
3288 3288  #ifdef DEBUG
3289 3289                  panic("ddi_prop_int64_op: %x impossible", cmd);
3290 3290                  /*NOTREACHED*/
3291 3291  #else
3292 3292                  return (DDI_PROP_RESULT_ERROR);
3293 3293  #endif  /* DEBUG */
3294 3294          }
3295 3295  }
3296 3296  
3297 3297  /*
3298 3298   * OBP 1275 string operator.
3299 3299   *
3300 3300   * OBP strings are NULL terminated.
3301 3301   */
3302 3302  int
3303 3303  ddi_prop_1275_string(prop_handle_t *ph, uint_t cmd, char *data)
3304 3304  {
3305 3305          int     n;
3306 3306          char    *p;
3307 3307          char    *end;
3308 3308  
3309 3309          switch (cmd) {
3310 3310          case DDI_PROP_CMD_DECODE:
3311 3311                  /*
3312 3312                   * Check that there is encoded data
3313 3313                   */
3314 3314                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
3315 3315                          return (DDI_PROP_RESULT_ERROR);
3316 3316                  }
3317 3317  
3318 3318                  /*
3319 3319                   * Match DDI_PROP_CMD_GET_DSIZE logic for when to stop and
3320 3320                   * how to NULL terminate result.
3321 3321                   */
3322 3322                  p = (char *)ph->ph_cur_pos;
3323 3323                  end = (char *)ph->ph_data + ph->ph_size;
3324 3324                  if (p >= end)
3325 3325                          return (DDI_PROP_RESULT_EOF);
3326 3326  
3327 3327                  while (p < end) {
3328 3328                          *data++ = *p;
3329 3329                          if (*p++ == 0) {        /* NULL from OBP */
3330 3330                                  ph->ph_cur_pos = p;
3331 3331                                  return (DDI_PROP_RESULT_OK);
3332 3332                          }
3333 3333                  }
3334 3334  
3335 3335                  /*
3336 3336                   * If OBP did not NULL terminate string, which happens
3337 3337                   * (at least) for 'true'/'false' boolean values, account for
3338 3338                   * the space and store null termination on decode.
3339 3339                   */
3340 3340                  ph->ph_cur_pos = p;
3341 3341                  *data = 0;
3342 3342                  return (DDI_PROP_RESULT_OK);
3343 3343  
3344 3344          case DDI_PROP_CMD_ENCODE:
3345 3345                  /*
3346 3346                   * Check that there is room to encoded the data
3347 3347                   */
3348 3348                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
3349 3349                          return (DDI_PROP_RESULT_ERROR);
3350 3350                  }
3351 3351  
3352 3352                  n = strlen(data) + 1;
3353 3353                  if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3354 3354                      ph->ph_size - n)) {
3355 3355                          return (DDI_PROP_RESULT_ERROR);
3356 3356                  }
3357 3357  
3358 3358                  /*
3359 3359                   * Copy the NULL terminated string
3360 3360                   */
3361 3361                  bcopy(data, ph->ph_cur_pos, n);
3362 3362  
3363 3363                  /*
3364 3364                   * Move the current location to the start of the next bit of
3365 3365                   * space where we can store encoded data.
3366 3366                   */
3367 3367                  ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
3368 3368                  return (DDI_PROP_RESULT_OK);
3369 3369  
3370 3370          case DDI_PROP_CMD_SKIP:
3371 3371                  /*
3372 3372                   * Check that there is encoded data
3373 3373                   */
3374 3374                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
3375 3375                          return (DDI_PROP_RESULT_ERROR);
3376 3376                  }
3377 3377  
3378 3378                  /*
3379 3379                   * Return the string length plus one for the NULL
3380 3380                   * We know the size of the property, we need to
3381 3381                   * ensure that the string is properly formatted,
3382 3382                   * since we may be looking up random OBP data.
3383 3383                   */
3384 3384                  p = (char *)ph->ph_cur_pos;
3385 3385                  end = (char *)ph->ph_data + ph->ph_size;
3386 3386                  if (p >= end)
3387 3387                          return (DDI_PROP_RESULT_EOF);
3388 3388  
3389 3389                  while (p < end) {
3390 3390                          if (*p++ == 0) {        /* NULL from OBP */
3391 3391                                  ph->ph_cur_pos = p;
3392 3392                                  return (DDI_PROP_RESULT_OK);
3393 3393                          }
3394 3394                  }
3395 3395  
3396 3396                  /*
3397 3397                   * Accommodate the fact that OBP does not always NULL
3398 3398                   * terminate strings.
3399 3399                   */
3400 3400                  ph->ph_cur_pos = p;
3401 3401                  return (DDI_PROP_RESULT_OK);
3402 3402  
3403 3403          case DDI_PROP_CMD_GET_ESIZE:
3404 3404                  /*
3405 3405                   * Return the size of the encoded string on OBP.
3406 3406                   */
3407 3407                  return (strlen(data) + 1);
3408 3408  
3409 3409          case DDI_PROP_CMD_GET_DSIZE:
3410 3410                  /*
3411 3411                   * Return the string length plus one for the NULL.
3412 3412                   * We know the size of the property, we need to
3413 3413                   * ensure that the string is properly formatted,
3414 3414                   * since we may be looking up random OBP data.
3415 3415                   */
3416 3416                  p = (char *)ph->ph_cur_pos;
3417 3417                  end = (char *)ph->ph_data + ph->ph_size;
3418 3418                  if (p >= end)
3419 3419                          return (DDI_PROP_RESULT_EOF);
3420 3420  
3421 3421                  for (n = 0; p < end; n++) {
3422 3422                          if (*p++ == 0) {        /* NULL from OBP */
3423 3423                                  ph->ph_cur_pos = p;
3424 3424                                  return (n + 1);
3425 3425                          }
3426 3426                  }
3427 3427  
3428 3428                  /*
3429 3429                   * If OBP did not NULL terminate string, which happens for
3430 3430                   * 'true'/'false' boolean values, account for the space
3431 3431                   * to store null termination here.
3432 3432                   */
3433 3433                  ph->ph_cur_pos = p;
3434 3434                  return (n + 1);
3435 3435  
3436 3436          default:
3437 3437  #ifdef DEBUG
3438 3438                  panic("ddi_prop_1275_string: %x impossible", cmd);
3439 3439                  /*NOTREACHED*/
3440 3440  #else
3441 3441                  return (DDI_PROP_RESULT_ERROR);
3442 3442  #endif  /* DEBUG */
3443 3443          }
3444 3444  }
3445 3445  
3446 3446  /*
3447 3447   * OBP 1275 byte operator
3448 3448   *
3449 3449   * Caller must specify the number of bytes to get.  OBP encodes bytes
3450 3450   * as a byte so there is a 1-to-1 translation.
3451 3451   */
3452 3452  int
3453 3453  ddi_prop_1275_bytes(prop_handle_t *ph, uint_t cmd, uchar_t *data,
3454 3454          uint_t nelements)
3455 3455  {
3456 3456          switch (cmd) {
3457 3457          case DDI_PROP_CMD_DECODE:
3458 3458                  /*
3459 3459                   * Check that there is encoded data
3460 3460                   */
3461 3461                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3462 3462                      ph->ph_size < nelements ||
3463 3463                      ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3464 3464                      ph->ph_size - nelements)))
3465 3465                          return (DDI_PROP_RESULT_ERROR);
3466 3466  
3467 3467                  /*
3468 3468                   * Copy out the bytes
3469 3469                   */
3470 3470                  bcopy(ph->ph_cur_pos, data, nelements);
3471 3471  
3472 3472                  /*
3473 3473                   * Move the current location
3474 3474                   */
3475 3475                  ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
3476 3476                  return (DDI_PROP_RESULT_OK);
3477 3477  
3478 3478          case DDI_PROP_CMD_ENCODE:
3479 3479                  /*
3480 3480                   * Check that there is room to encode the data
3481 3481                   */
3482 3482                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3483 3483                      ph->ph_size < nelements ||
3484 3484                      ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3485 3485                      ph->ph_size - nelements)))
3486 3486                          return (DDI_PROP_RESULT_ERROR);
3487 3487  
3488 3488                  /*
3489 3489                   * Copy in the bytes
3490 3490                   */
3491 3491                  bcopy(data, ph->ph_cur_pos, nelements);
3492 3492  
3493 3493                  /*
3494 3494                   * Move the current location to the start of the next bit of
3495 3495                   * space where we can store encoded data.
3496 3496                   */
3497 3497                  ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
3498 3498                  return (DDI_PROP_RESULT_OK);
3499 3499  
3500 3500          case DDI_PROP_CMD_SKIP:
3501 3501                  /*
3502 3502                   * Check that there is encoded data
3503 3503                   */
3504 3504                  if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3505 3505                      ph->ph_size < nelements)
3506 3506                          return (DDI_PROP_RESULT_ERROR);
3507 3507  
3508 3508                  if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3509 3509                      ph->ph_size - nelements))
3510 3510                          return (DDI_PROP_RESULT_EOF);
3511 3511  
3512 3512                  /*
3513 3513                   * Move the current location
3514 3514                   */
3515 3515                  ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
3516 3516                  return (DDI_PROP_RESULT_OK);
3517 3517  
3518 3518          case DDI_PROP_CMD_GET_ESIZE:
3519 3519                  /*
3520 3520                   * The size in bytes of the encoded size is the
3521 3521                   * same as the decoded size provided by the caller.
3522 3522                   */
3523 3523                  return (nelements);
3524 3524  
3525 3525          case DDI_PROP_CMD_GET_DSIZE:
3526 3526                  /*
3527 3527                   * Just return the number of bytes specified by the caller.
3528 3528                   */
3529 3529                  return (nelements);
3530 3530  
3531 3531          default:
3532 3532  #ifdef DEBUG
3533 3533                  panic("ddi_prop_1275_bytes: %x impossible", cmd);
3534 3534                  /*NOTREACHED*/
3535 3535  #else
3536 3536                  return (DDI_PROP_RESULT_ERROR);
3537 3537  #endif  /* DEBUG */
3538 3538          }
3539 3539  }
3540 3540  
3541 3541  /*
3542 3542   * Used for properties that come from the OBP, hardware configuration files,
3543 3543   * or that are created by calls to ddi_prop_update(9F).
3544 3544   */
3545 3545  static struct prop_handle_ops prop_1275_ops = {
3546 3546          ddi_prop_1275_int,
3547 3547          ddi_prop_1275_string,
3548 3548          ddi_prop_1275_bytes,
3549 3549          ddi_prop_int64_op
3550 3550  };
3551 3551  
3552 3552  
3553 3553  /*
3554 3554   * Interface to create/modify a managed property on child's behalf...
3555 3555   * Flags interpreted are:
3556 3556   *      DDI_PROP_CANSLEEP:      Allow memory allocation to sleep.
3557 3557   *      DDI_PROP_SYSTEM_DEF:    Manipulate system list rather than driver list.
3558 3558   *
3559 3559   * Use same dev_t when modifying or undefining a property.
3560 3560   * Search for properties with DDI_DEV_T_ANY to match first named
3561 3561   * property on the list.
3562 3562   *
3563 3563   * Properties are stored LIFO and subsequently will match the first
3564 3564   * `matching' instance.
3565 3565   */
3566 3566  
3567 3567  /*
3568 3568   * ddi_prop_add:        Add a software defined property
3569 3569   */
3570 3570  
3571 3571  /*
3572 3572   * define to get a new ddi_prop_t.
3573 3573   * km_flags are KM_SLEEP or KM_NOSLEEP.
3574 3574   */
3575 3575  
3576 3576  #define DDI_NEW_PROP_T(km_flags)        \
3577 3577          (kmem_zalloc(sizeof (ddi_prop_t), km_flags))
3578 3578  
3579 3579  static int
3580 3580  ddi_prop_add(dev_t dev, dev_info_t *dip, int flags,
3581 3581      char *name, caddr_t value, int length)
3582 3582  {
3583 3583          ddi_prop_t      *new_propp, *propp;
3584 3584          ddi_prop_t      **list_head = &(DEVI(dip)->devi_drv_prop_ptr);
3585 3585          int             km_flags = KM_NOSLEEP;
3586 3586          int             name_buf_len;
3587 3587  
3588 3588          /*
3589 3589           * If dev_t is DDI_DEV_T_ANY or name's length is zero return error.
3590 3590           */
3591 3591  
3592 3592          if (dev == DDI_DEV_T_ANY || name == (char *)0 || strlen(name) == 0)
3593 3593                  return (DDI_PROP_INVAL_ARG);
3594 3594  
3595 3595          if (flags & DDI_PROP_CANSLEEP)
3596 3596                  km_flags = KM_SLEEP;
3597 3597  
3598 3598          if (flags & DDI_PROP_SYSTEM_DEF)
3599 3599                  list_head = &(DEVI(dip)->devi_sys_prop_ptr);
3600 3600          else if (flags & DDI_PROP_HW_DEF)
3601 3601                  list_head = &(DEVI(dip)->devi_hw_prop_ptr);
3602 3602  
3603 3603          if ((new_propp = DDI_NEW_PROP_T(km_flags)) == NULL)  {
3604 3604                  cmn_err(CE_CONT, prop_no_mem_msg, name);
3605 3605                  return (DDI_PROP_NO_MEMORY);
3606 3606          }
3607 3607  
3608 3608          /*
3609 3609           * If dev is major number 0, then we need to do a ddi_name_to_major
3610 3610           * to get the real major number for the device.  This needs to be
3611 3611           * done because some drivers need to call ddi_prop_create in their
3612 3612           * attach routines but they don't have a dev.  By creating the dev
3613 3613           * ourself if the major number is 0, drivers will not have to know what
3614 3614           * their major number.  They can just create a dev with major number
3615 3615           * 0 and pass it in.  For device 0, we will be doing a little extra
3616 3616           * work by recreating the same dev that we already have, but its the
3617 3617           * price you pay :-).
3618 3618           *
3619 3619           * This fixes bug #1098060.
3620 3620           */
3621 3621          if (getmajor(dev) == DDI_MAJOR_T_UNKNOWN) {
3622 3622                  new_propp->prop_dev =
3623 3623                      makedevice(ddi_name_to_major(DEVI(dip)->devi_binding_name),
3624 3624                      getminor(dev));
3625 3625          } else
3626 3626                  new_propp->prop_dev = dev;
3627 3627  
3628 3628          /*
3629 3629           * Allocate space for property name and copy it in...
3630 3630           */
3631 3631  
3632 3632          name_buf_len = strlen(name) + 1;
3633 3633          new_propp->prop_name = kmem_alloc(name_buf_len, km_flags);
3634 3634          if (new_propp->prop_name == 0)  {
3635 3635                  kmem_free(new_propp, sizeof (ddi_prop_t));
3636 3636                  cmn_err(CE_CONT, prop_no_mem_msg, name);
3637 3637                  return (DDI_PROP_NO_MEMORY);
3638 3638          }
3639 3639          bcopy(name, new_propp->prop_name, name_buf_len);
3640 3640  
3641 3641          /*
3642 3642           * Set the property type
3643 3643           */
3644 3644          new_propp->prop_flags = flags & DDI_PROP_TYPE_MASK;
3645 3645  
3646 3646          /*
3647 3647           * Set length and value ONLY if not an explicit property undefine:
3648 3648           * NOTE: value and length are zero for explicit undefines.
3649 3649           */
3650 3650  
3651 3651          if (flags & DDI_PROP_UNDEF_IT) {
3652 3652                  new_propp->prop_flags |= DDI_PROP_UNDEF_IT;
3653 3653          } else {
3654 3654                  if ((new_propp->prop_len = length) != 0) {
3655 3655                          new_propp->prop_val = kmem_alloc(length, km_flags);
3656 3656                          if (new_propp->prop_val == 0)  {
3657 3657                                  kmem_free(new_propp->prop_name, name_buf_len);
3658 3658                                  kmem_free(new_propp, sizeof (ddi_prop_t));
3659 3659                                  cmn_err(CE_CONT, prop_no_mem_msg, name);
3660 3660                                  return (DDI_PROP_NO_MEMORY);
3661 3661                          }
3662 3662                          bcopy(value, new_propp->prop_val, length);
3663 3663                  }
3664 3664          }
3665 3665  
3666 3666          /*
3667 3667           * Link property into beginning of list. (Properties are LIFO order.)
3668 3668           */
3669 3669  
3670 3670          mutex_enter(&(DEVI(dip)->devi_lock));
3671 3671          propp = *list_head;
3672 3672          new_propp->prop_next = propp;
3673 3673          *list_head = new_propp;
3674 3674          mutex_exit(&(DEVI(dip)->devi_lock));
3675 3675          return (DDI_PROP_SUCCESS);
3676 3676  }
3677 3677  
3678 3678  
3679 3679  /*
3680 3680   * ddi_prop_change:     Modify a software managed property value
3681 3681   *
3682 3682   *                      Set new length and value if found.
3683 3683   *                      returns DDI_PROP_INVAL_ARG if dev is DDI_DEV_T_ANY or
3684 3684   *                      input name is the NULL string.
3685 3685   *                      returns DDI_PROP_NO_MEMORY if unable to allocate memory
3686 3686   *
3687 3687   *                      Note: an undef can be modified to be a define,
3688 3688   *                      (you can't go the other way.)
3689 3689   */
3690 3690  
3691 3691  static int
3692 3692  ddi_prop_change(dev_t dev, dev_info_t *dip, int flags,
3693 3693      char *name, caddr_t value, int length)
3694 3694  {
3695 3695          ddi_prop_t      *propp;
3696 3696          ddi_prop_t      **ppropp;
3697 3697          caddr_t         p = NULL;
3698 3698  
3699 3699          if ((dev == DDI_DEV_T_ANY) || (name == NULL) || (strlen(name) == 0))
3700 3700                  return (DDI_PROP_INVAL_ARG);
3701 3701  
3702 3702          /*
3703 3703           * Preallocate buffer, even if we don't need it...
3704 3704           */
3705 3705          if (length != 0)  {
3706 3706                  p = kmem_alloc(length, (flags & DDI_PROP_CANSLEEP) ?
3707 3707                      KM_SLEEP : KM_NOSLEEP);
3708 3708                  if (p == NULL)  {
3709 3709                          cmn_err(CE_CONT, prop_no_mem_msg, name);
3710 3710                          return (DDI_PROP_NO_MEMORY);
3711 3711                  }
3712 3712          }
3713 3713  
3714 3714          /*
3715 3715           * If the dev_t value contains DDI_MAJOR_T_UNKNOWN for the major
3716 3716           * number, a real dev_t value should be created based upon the dip's
3717 3717           * binding driver.  See ddi_prop_add...
3718 3718           */
3719 3719          if (getmajor(dev) == DDI_MAJOR_T_UNKNOWN)
3720 3720                  dev = makedevice(
3721 3721                      ddi_name_to_major(DEVI(dip)->devi_binding_name),
3722 3722                      getminor(dev));
3723 3723  
3724 3724          /*
3725 3725           * Check to see if the property exists.  If so we modify it.
3726 3726           * Else we create it by calling ddi_prop_add().
3727 3727           */
3728 3728          mutex_enter(&(DEVI(dip)->devi_lock));
3729 3729          ppropp = &DEVI(dip)->devi_drv_prop_ptr;
3730 3730          if (flags & DDI_PROP_SYSTEM_DEF)
3731 3731                  ppropp = &DEVI(dip)->devi_sys_prop_ptr;
3732 3732          else if (flags & DDI_PROP_HW_DEF)
3733 3733                  ppropp = &DEVI(dip)->devi_hw_prop_ptr;
3734 3734  
3735 3735          if ((propp = i_ddi_prop_search(dev, name, flags, ppropp)) != NULL) {
3736 3736                  /*
3737 3737                   * Need to reallocate buffer?  If so, do it
3738 3738                   * carefully (reuse same space if new prop
3739 3739                   * is same size and non-NULL sized).
3740 3740                   */
3741 3741                  if (length != 0)
3742 3742                          bcopy(value, p, length);
3743 3743  
3744 3744                  if (propp->prop_len != 0)
3745 3745                          kmem_free(propp->prop_val, propp->prop_len);
3746 3746  
3747 3747                  propp->prop_len = length;
3748 3748                  propp->prop_val = p;
3749 3749                  propp->prop_flags &= ~DDI_PROP_UNDEF_IT;
3750 3750                  mutex_exit(&(DEVI(dip)->devi_lock));
3751 3751                  return (DDI_PROP_SUCCESS);
3752 3752          }
3753 3753  
3754 3754          mutex_exit(&(DEVI(dip)->devi_lock));
3755 3755          if (length != 0)
3756 3756                  kmem_free(p, length);
3757 3757  
3758 3758          return (ddi_prop_add(dev, dip, flags, name, value, length));
3759 3759  }
3760 3760  
3761 3761  /*
3762 3762   * Common update routine used to update and encode a property.  Creates
3763 3763   * a property handle, calls the property encode routine, figures out if
3764 3764   * the property already exists and updates if it does.  Otherwise it
3765 3765   * creates if it does not exist.
3766 3766   */
3767 3767  int
3768 3768  ddi_prop_update_common(dev_t match_dev, dev_info_t *dip, int flags,
3769 3769      char *name, void *data, uint_t nelements,
3770 3770      int (*prop_create)(prop_handle_t *, void *data, uint_t nelements))
3771 3771  {
3772 3772          prop_handle_t   ph;
3773 3773          int             rval;
3774 3774          uint_t          ourflags;
3775 3775  
3776 3776          /*
3777 3777           * If dev_t is DDI_DEV_T_ANY or name's length is zero,
3778 3778           * return error.
3779 3779           */
3780 3780          if (match_dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
3781 3781                  return (DDI_PROP_INVAL_ARG);
3782 3782  
3783 3783          /*
3784 3784           * Create the handle
3785 3785           */
3786 3786          ph.ph_data = NULL;
3787 3787          ph.ph_cur_pos = NULL;
3788 3788          ph.ph_save_pos = NULL;
3789 3789          ph.ph_size = 0;
3790 3790          ph.ph_ops = &prop_1275_ops;
3791 3791  
3792 3792          /*
3793 3793           * ourflags:
3794 3794           * For compatibility with the old interfaces.  The old interfaces
3795 3795           * didn't sleep by default and slept when the flag was set.  These
3796 3796           * interfaces to the opposite.  So the old interfaces now set the
3797 3797           * DDI_PROP_DONTSLEEP flag by default which tells us not to sleep.
3798 3798           *
3799 3799           * ph.ph_flags:
3800 3800           * Blocked data or unblocked data allocation
3801 3801           * for ph.ph_data in ddi_prop_encode_alloc()
3802 3802           */
3803 3803          if (flags & DDI_PROP_DONTSLEEP) {
3804 3804                  ourflags = flags;
3805 3805                  ph.ph_flags = DDI_PROP_DONTSLEEP;
3806 3806          } else {
3807 3807                  ourflags = flags | DDI_PROP_CANSLEEP;
3808 3808                  ph.ph_flags = DDI_PROP_CANSLEEP;
3809 3809          }
3810 3810  
3811 3811          /*
3812 3812           * Encode the data and store it in the property handle by
3813 3813           * calling the prop_encode routine.
3814 3814           */
3815 3815          if ((rval = (*prop_create)(&ph, data, nelements)) !=
3816 3816              DDI_PROP_SUCCESS) {
3817 3817                  if (rval == DDI_PROP_NO_MEMORY)
3818 3818                          cmn_err(CE_CONT, prop_no_mem_msg, name);
3819 3819                  if (ph.ph_size != 0)
3820 3820                          kmem_free(ph.ph_data, ph.ph_size);
3821 3821                  return (rval);
3822 3822          }
3823 3823  
3824 3824          /*
3825 3825           * The old interfaces use a stacking approach to creating
3826 3826           * properties.  If we are being called from the old interfaces,
3827 3827           * the DDI_PROP_STACK_CREATE flag will be set, so we just do a
3828 3828           * create without checking.
3829 3829           */
3830 3830          if (flags & DDI_PROP_STACK_CREATE) {
3831 3831                  rval = ddi_prop_add(match_dev, dip,
3832 3832                      ourflags, name, ph.ph_data, ph.ph_size);
3833 3833          } else {
3834 3834                  rval = ddi_prop_change(match_dev, dip,
3835 3835                      ourflags, name, ph.ph_data, ph.ph_size);
3836 3836          }
3837 3837  
3838 3838          /*
3839 3839           * Free the encoded data allocated in the prop_encode routine.
3840 3840           */
3841 3841          if (ph.ph_size != 0)
3842 3842                  kmem_free(ph.ph_data, ph.ph_size);
3843 3843  
3844 3844          return (rval);
3845 3845  }
3846 3846  
3847 3847  
3848 3848  /*
3849 3849   * ddi_prop_create:     Define a managed property:
3850 3850   *                      See above for details.
3851 3851   */
3852 3852  
3853 3853  int
3854 3854  ddi_prop_create(dev_t dev, dev_info_t *dip, int flag,
3855 3855      char *name, caddr_t value, int length)
3856 3856  {
3857 3857          if (!(flag & DDI_PROP_CANSLEEP)) {
3858 3858                  flag |= DDI_PROP_DONTSLEEP;
3859 3859  #ifdef DDI_PROP_DEBUG
3860 3860                  if (length != 0)
3861 3861                          cmn_err(CE_NOTE, "!ddi_prop_create: interface obsolete,"
3862 3862                              "use ddi_prop_update (prop = %s, node = %s%d)",
3863 3863                              name, ddi_driver_name(dip), ddi_get_instance(dip));
3864 3864  #endif /* DDI_PROP_DEBUG */
3865 3865          }
3866 3866          flag &= ~DDI_PROP_SYSTEM_DEF;
3867 3867          flag |= DDI_PROP_STACK_CREATE | DDI_PROP_TYPE_ANY;
3868 3868          return (ddi_prop_update_common(dev, dip, flag, name,
3869 3869              value, length, ddi_prop_fm_encode_bytes));
3870 3870  }
3871 3871  
3872 3872  int
3873 3873  e_ddi_prop_create(dev_t dev, dev_info_t *dip, int flag,
3874 3874      char *name, caddr_t value, int length)
3875 3875  {
3876 3876          if (!(flag & DDI_PROP_CANSLEEP))
3877 3877                  flag |= DDI_PROP_DONTSLEEP;
3878 3878          flag |= DDI_PROP_SYSTEM_DEF | DDI_PROP_STACK_CREATE | DDI_PROP_TYPE_ANY;
3879 3879          return (ddi_prop_update_common(dev, dip, flag,
3880 3880              name, value, length, ddi_prop_fm_encode_bytes));
3881 3881  }
3882 3882  
3883 3883  int
3884 3884  ddi_prop_modify(dev_t dev, dev_info_t *dip, int flag,
3885 3885      char *name, caddr_t value, int length)
3886 3886  {
3887 3887          ASSERT((flag & DDI_PROP_TYPE_MASK) == 0);
3888 3888  
3889 3889          /*
3890 3890           * If dev_t is DDI_DEV_T_ANY or name's length is zero,
3891 3891           * return error.
3892 3892           */
3893 3893          if (dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
3894 3894                  return (DDI_PROP_INVAL_ARG);
3895 3895  
3896 3896          if (!(flag & DDI_PROP_CANSLEEP))
3897 3897                  flag |= DDI_PROP_DONTSLEEP;
3898 3898          flag &= ~DDI_PROP_SYSTEM_DEF;
3899 3899          if (ddi_prop_exists(dev, dip, (flag | DDI_PROP_NOTPROM), name) == 0)
3900 3900                  return (DDI_PROP_NOT_FOUND);
3901 3901  
3902 3902          return (ddi_prop_update_common(dev, dip,
3903 3903              (flag | DDI_PROP_TYPE_BYTE), name,
3904 3904              value, length, ddi_prop_fm_encode_bytes));
3905 3905  }
3906 3906  
3907 3907  int
3908 3908  e_ddi_prop_modify(dev_t dev, dev_info_t *dip, int flag,
3909 3909      char *name, caddr_t value, int length)
3910 3910  {
3911 3911          ASSERT((flag & DDI_PROP_TYPE_MASK) == 0);
3912 3912  
3913 3913          /*
3914 3914           * If dev_t is DDI_DEV_T_ANY or name's length is zero,
3915 3915           * return error.
3916 3916           */
3917 3917          if (dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
3918 3918                  return (DDI_PROP_INVAL_ARG);
3919 3919  
3920 3920          if (ddi_prop_exists(dev, dip, (flag | DDI_PROP_SYSTEM_DEF), name) == 0)
3921 3921                  return (DDI_PROP_NOT_FOUND);
3922 3922  
3923 3923          if (!(flag & DDI_PROP_CANSLEEP))
3924 3924                  flag |= DDI_PROP_DONTSLEEP;
3925 3925          return (ddi_prop_update_common(dev, dip,
3926 3926              (flag | DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_BYTE),
3927 3927              name, value, length, ddi_prop_fm_encode_bytes));
3928 3928  }
3929 3929  
3930 3930  
3931 3931  /*
3932 3932   * Common lookup routine used to lookup and decode a property.
3933 3933   * Creates a property handle, searches for the raw encoded data,
3934 3934   * fills in the handle, and calls the property decode functions
3935 3935   * passed in.
3936 3936   *
3937 3937   * This routine is not static because ddi_bus_prop_op() which lives in
3938 3938   * ddi_impl.c calls it.  No driver should be calling this routine.
3939 3939   */
3940 3940  int
3941 3941  ddi_prop_lookup_common(dev_t match_dev, dev_info_t *dip,
3942 3942      uint_t flags, char *name, void *data, uint_t *nelements,
3943 3943      int (*prop_decoder)(prop_handle_t *, void *data, uint_t *nelements))
3944 3944  {
3945 3945          int             rval;
3946 3946          uint_t          ourflags;
3947 3947          prop_handle_t   ph;
3948 3948  
3949 3949          if ((match_dev == DDI_DEV_T_NONE) ||
3950 3950              (name == NULL) || (strlen(name) == 0))
3951 3951                  return (DDI_PROP_INVAL_ARG);
3952 3952  
3953 3953          ourflags = (flags & DDI_PROP_DONTSLEEP) ? flags :
3954 3954              flags | DDI_PROP_CANSLEEP;
3955 3955  
3956 3956          /*
3957 3957           * Get the encoded data
3958 3958           */
3959 3959          bzero(&ph, sizeof (prop_handle_t));
3960 3960  
3961 3961          if ((flags & DDI_UNBND_DLPI2) || (flags & DDI_PROP_ROOTNEX_GLOBAL)) {
3962 3962                  /*
3963 3963                   * For rootnex and unbound dlpi style-2 devices, index into
3964 3964                   * the devnames' array and search the global
3965 3965                   * property list.
3966 3966                   */
3967 3967                  ourflags &= ~DDI_UNBND_DLPI2;
3968 3968                  rval = i_ddi_prop_search_global(match_dev,
3969 3969                      ourflags, name, &ph.ph_data, &ph.ph_size);
3970 3970          } else {
3971 3971                  rval = ddi_prop_search_common(match_dev, dip,
3972 3972                      PROP_LEN_AND_VAL_ALLOC, ourflags, name,
3973 3973                      &ph.ph_data, &ph.ph_size);
3974 3974  
3975 3975          }
3976 3976  
3977 3977          if (rval != DDI_PROP_SUCCESS && rval != DDI_PROP_FOUND_1275) {
3978 3978                  ASSERT(ph.ph_data == NULL);
3979 3979                  ASSERT(ph.ph_size == 0);
3980 3980                  return (rval);
3981 3981          }
3982 3982  
3983 3983          /*
3984 3984           * If the encoded data came from a OBP or software
3985 3985           * use the 1275 OBP decode/encode routines.
3986 3986           */
3987 3987          ph.ph_cur_pos = ph.ph_data;
3988 3988          ph.ph_save_pos = ph.ph_data;
3989 3989          ph.ph_ops = &prop_1275_ops;
3990 3990          ph.ph_flags = (rval == DDI_PROP_FOUND_1275) ? PH_FROM_PROM : 0;
3991 3991  
3992 3992          rval = (*prop_decoder)(&ph, data, nelements);
3993 3993  
3994 3994          /*
3995 3995           * Free the encoded data
3996 3996           */
3997 3997          if (ph.ph_size != 0)
3998 3998                  kmem_free(ph.ph_data, ph.ph_size);
3999 3999  
4000 4000          return (rval);
4001 4001  }
4002 4002  
4003 4003  /*
4004 4004   * Lookup and return an array of composite properties.  The driver must
4005 4005   * provide the decode routine.
4006 4006   */
4007 4007  int
4008 4008  ddi_prop_lookup(dev_t match_dev, dev_info_t *dip,
4009 4009      uint_t flags, char *name, void *data, uint_t *nelements,
4010 4010      int (*prop_decoder)(prop_handle_t *, void *data, uint_t *nelements))
4011 4011  {
4012 4012          return (ddi_prop_lookup_common(match_dev, dip,
4013 4013              (flags | DDI_PROP_TYPE_COMPOSITE), name,
4014 4014              data, nelements, prop_decoder));
4015 4015  }
4016 4016  
4017 4017  /*
4018 4018   * Return 1 if a property exists (no type checking done).
4019 4019   * Return 0 if it does not exist.
4020 4020   */
4021 4021  int
4022 4022  ddi_prop_exists(dev_t match_dev, dev_info_t *dip, uint_t flags, char *name)
4023 4023  {
4024 4024          int     i;
4025 4025          uint_t  x = 0;
4026 4026  
4027 4027          i = ddi_prop_search_common(match_dev, dip, PROP_EXISTS,
4028 4028              flags | DDI_PROP_TYPE_MASK, name, NULL, &x);
4029 4029          return (i == DDI_PROP_SUCCESS || i == DDI_PROP_FOUND_1275);
4030 4030  }
4031 4031  
4032 4032  
4033 4033  /*
4034 4034   * Update an array of composite properties.  The driver must
4035 4035   * provide the encode routine.
4036 4036   */
4037 4037  int
4038 4038  ddi_prop_update(dev_t match_dev, dev_info_t *dip,
4039 4039      char *name, void *data, uint_t nelements,
4040 4040      int (*prop_create)(prop_handle_t *, void *data, uint_t nelements))
4041 4041  {
4042 4042          return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_COMPOSITE,
4043 4043              name, data, nelements, prop_create));
4044 4044  }
4045 4045  
4046 4046  /*
4047 4047   * Get a single integer or boolean property and return it.
4048 4048   * If the property does not exists, or cannot be decoded,
4049 4049   * then return the defvalue passed in.
4050 4050   *
4051 4051   * This routine always succeeds.
4052 4052   */
4053 4053  int
4054 4054  ddi_prop_get_int(dev_t match_dev, dev_info_t *dip, uint_t flags,
4055 4055      char *name, int defvalue)
4056 4056  {
4057 4057          int     data;
4058 4058          uint_t  nelements;
4059 4059          int     rval;
4060 4060  
4061 4061          if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4062 4062              LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
4063 4063  #ifdef DEBUG
4064 4064                  if (dip != NULL) {
4065 4065                          cmn_err(CE_WARN, "ddi_prop_get_int: invalid flag"
4066 4066                              " 0x%x (prop = %s, node = %s%d)", flags,
4067 4067                              name, ddi_driver_name(dip), ddi_get_instance(dip));
4068 4068                  }
4069 4069  #endif /* DEBUG */
4070 4070                  flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4071 4071                      LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4072 4072          }
4073 4073  
4074 4074          if ((rval = ddi_prop_lookup_common(match_dev, dip,
4075 4075              (flags | DDI_PROP_TYPE_INT), name, &data, &nelements,
4076 4076              ddi_prop_fm_decode_int)) != DDI_PROP_SUCCESS) {
4077 4077                  if (rval == DDI_PROP_END_OF_DATA)
4078 4078                          data = 1;
4079 4079                  else
4080 4080                          data = defvalue;
4081 4081          }
4082 4082          return (data);
4083 4083  }
4084 4084  
4085 4085  /*
4086 4086   * Get a single 64 bit integer or boolean property and return it.
4087 4087   * If the property does not exists, or cannot be decoded,
4088 4088   * then return the defvalue passed in.
4089 4089   *
4090 4090   * This routine always succeeds.
4091 4091   */
4092 4092  int64_t
4093 4093  ddi_prop_get_int64(dev_t match_dev, dev_info_t *dip, uint_t flags,
4094 4094      char *name, int64_t defvalue)
4095 4095  {
4096 4096          int64_t data;
4097 4097          uint_t  nelements;
4098 4098          int     rval;
4099 4099  
4100 4100          if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4101 4101              LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
4102 4102  #ifdef DEBUG
4103 4103                  if (dip != NULL) {
4104 4104                          cmn_err(CE_WARN, "ddi_prop_get_int64: invalid flag"
4105 4105                              " 0x%x (prop = %s, node = %s%d)", flags,
4106 4106                              name, ddi_driver_name(dip), ddi_get_instance(dip));
4107 4107                  }
4108 4108  #endif /* DEBUG */
4109 4109                  return (DDI_PROP_INVAL_ARG);
4110 4110          }
4111 4111  
4112 4112          if ((rval = ddi_prop_lookup_common(match_dev, dip,
4113 4113              (flags | DDI_PROP_TYPE_INT64 | DDI_PROP_NOTPROM),
4114 4114              name, &data, &nelements, ddi_prop_fm_decode_int64))
4115 4115              != DDI_PROP_SUCCESS) {
4116 4116                  if (rval == DDI_PROP_END_OF_DATA)
4117 4117                          data = 1;
4118 4118                  else
4119 4119                          data = defvalue;
4120 4120          }
4121 4121          return (data);
4122 4122  }
4123 4123  
4124 4124  /*
4125 4125   * Get an array of integer property
4126 4126   */
4127 4127  int
4128 4128  ddi_prop_lookup_int_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
4129 4129      char *name, int **data, uint_t *nelements)
4130 4130  {
4131 4131          if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4132 4132              LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
4133 4133  #ifdef DEBUG
4134 4134                  if (dip != NULL) {
4135 4135                          cmn_err(CE_WARN, "ddi_prop_lookup_int_array: "
4136 4136                              "invalid flag 0x%x (prop = %s, node = %s%d)",
4137 4137                              flags, name, ddi_driver_name(dip),
4138 4138                              ddi_get_instance(dip));
4139 4139                  }
4140 4140  #endif /* DEBUG */
4141 4141                  flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4142 4142                      LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4143 4143          }
4144 4144  
4145 4145          return (ddi_prop_lookup_common(match_dev, dip,
4146 4146              (flags | DDI_PROP_TYPE_INT), name, data,
4147 4147              nelements, ddi_prop_fm_decode_ints));
4148 4148  }
4149 4149  
4150 4150  /*
4151 4151   * Get an array of 64 bit integer properties
4152 4152   */
4153 4153  int
4154 4154  ddi_prop_lookup_int64_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
4155 4155      char *name, int64_t **data, uint_t *nelements)
4156 4156  {
4157 4157          if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4158 4158              LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
4159 4159  #ifdef DEBUG
4160 4160                  if (dip != NULL) {
4161 4161                          cmn_err(CE_WARN, "ddi_prop_lookup_int64_array: "
4162 4162                              "invalid flag 0x%x (prop = %s, node = %s%d)",
4163 4163                              flags, name, ddi_driver_name(dip),
4164 4164                              ddi_get_instance(dip));
4165 4165                  }
4166 4166  #endif /* DEBUG */
4167 4167                  return (DDI_PROP_INVAL_ARG);
4168 4168          }
4169 4169  
4170 4170          return (ddi_prop_lookup_common(match_dev, dip,
4171 4171              (flags | DDI_PROP_TYPE_INT64 | DDI_PROP_NOTPROM),
4172 4172              name, data, nelements, ddi_prop_fm_decode_int64_array));
4173 4173  }
4174 4174  
4175 4175  /*
4176 4176   * Update a single integer property.  If the property exists on the drivers
4177 4177   * property list it updates, else it creates it.
4178 4178   */
4179 4179  int
4180 4180  ddi_prop_update_int(dev_t match_dev, dev_info_t *dip,
4181 4181      char *name, int data)
4182 4182  {
4183 4183          return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT,
4184 4184              name, &data, 1, ddi_prop_fm_encode_ints));
4185 4185  }
4186 4186  
4187 4187  /*
4188 4188   * Update a single 64 bit integer property.
4189 4189   * Update the driver property list if it exists, else create it.
4190 4190   */
4191 4191  int
4192 4192  ddi_prop_update_int64(dev_t match_dev, dev_info_t *dip,
4193 4193      char *name, int64_t data)
4194 4194  {
4195 4195          return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT64,
4196 4196              name, &data, 1, ddi_prop_fm_encode_int64));
4197 4197  }
4198 4198  
4199 4199  int
4200 4200  e_ddi_prop_update_int(dev_t match_dev, dev_info_t *dip,
4201 4201      char *name, int data)
4202 4202  {
4203 4203          return (ddi_prop_update_common(match_dev, dip,
4204 4204              DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT,
4205 4205              name, &data, 1, ddi_prop_fm_encode_ints));
4206 4206  }
4207 4207  
4208 4208  int
4209 4209  e_ddi_prop_update_int64(dev_t match_dev, dev_info_t *dip,
4210 4210      char *name, int64_t data)
4211 4211  {
4212 4212          return (ddi_prop_update_common(match_dev, dip,
4213 4213              DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT64,
4214 4214              name, &data, 1, ddi_prop_fm_encode_int64));
4215 4215  }
4216 4216  
4217 4217  /*
4218 4218   * Update an array of integer property.  If the property exists on the drivers
4219 4219   * property list it updates, else it creates it.
4220 4220   */
4221 4221  int
4222 4222  ddi_prop_update_int_array(dev_t match_dev, dev_info_t *dip,
4223 4223      char *name, int *data, uint_t nelements)
4224 4224  {
4225 4225          return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT,
4226 4226              name, data, nelements, ddi_prop_fm_encode_ints));
4227 4227  }
4228 4228  
4229 4229  /*
4230 4230   * Update an array of 64 bit integer properties.
4231 4231   * Update the driver property list if it exists, else create it.
4232 4232   */
4233 4233  int
4234 4234  ddi_prop_update_int64_array(dev_t match_dev, dev_info_t *dip,
4235 4235      char *name, int64_t *data, uint_t nelements)
4236 4236  {
4237 4237          return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT64,
4238 4238              name, data, nelements, ddi_prop_fm_encode_int64));
4239 4239  }
4240 4240  
4241 4241  int
4242 4242  e_ddi_prop_update_int64_array(dev_t match_dev, dev_info_t *dip,
4243 4243      char *name, int64_t *data, uint_t nelements)
4244 4244  {
4245 4245          return (ddi_prop_update_common(match_dev, dip,
4246 4246              DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT64,
4247 4247              name, data, nelements, ddi_prop_fm_encode_int64));
4248 4248  }
4249 4249  
4250 4250  int
4251 4251  e_ddi_prop_update_int_array(dev_t match_dev, dev_info_t *dip,
4252 4252      char *name, int *data, uint_t nelements)
4253 4253  {
4254 4254          return (ddi_prop_update_common(match_dev, dip,
4255 4255              DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT,
4256 4256              name, data, nelements, ddi_prop_fm_encode_ints));
4257 4257  }
4258 4258  
4259 4259  /*
4260 4260   * Get a single string property.
4261 4261   */
4262 4262  int
4263 4263  ddi_prop_lookup_string(dev_t match_dev, dev_info_t *dip, uint_t flags,
4264 4264      char *name, char **data)
4265 4265  {
4266 4266          uint_t x;
4267 4267  
4268 4268          if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4269 4269              LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
4270 4270  #ifdef DEBUG
4271 4271                  if (dip != NULL) {
4272 4272                          cmn_err(CE_WARN, "%s: invalid flag 0x%x "
4273 4273                              "(prop = %s, node = %s%d); invalid bits ignored",
4274 4274                              "ddi_prop_lookup_string", flags, name,
4275 4275                              ddi_driver_name(dip), ddi_get_instance(dip));
4276 4276                  }
4277 4277  #endif /* DEBUG */
4278 4278                  flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4279 4279                      LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4280 4280          }
4281 4281  
4282 4282          return (ddi_prop_lookup_common(match_dev, dip,
4283 4283              (flags | DDI_PROP_TYPE_STRING), name, data,
4284 4284              &x, ddi_prop_fm_decode_string));
4285 4285  }
4286 4286  
4287 4287  /*
4288 4288   * Get an array of strings property.
4289 4289   */
4290 4290  int
4291 4291  ddi_prop_lookup_string_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
4292 4292      char *name, char ***data, uint_t *nelements)
4293 4293  {
4294 4294          if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4295 4295              LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
4296 4296  #ifdef DEBUG
4297 4297                  if (dip != NULL) {
4298 4298                          cmn_err(CE_WARN, "ddi_prop_lookup_string_array: "
4299 4299                              "invalid flag 0x%x (prop = %s, node = %s%d)",
4300 4300                              flags, name, ddi_driver_name(dip),
4301 4301                              ddi_get_instance(dip));
4302 4302                  }
4303 4303  #endif /* DEBUG */
4304 4304                  flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4305 4305                      LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4306 4306          }
4307 4307  
4308 4308          return (ddi_prop_lookup_common(match_dev, dip,
4309 4309              (flags | DDI_PROP_TYPE_STRING), name, data,
4310 4310              nelements, ddi_prop_fm_decode_strings));
4311 4311  }
4312 4312  
4313 4313  /*
4314 4314   * Update a single string property.
4315 4315   */
4316 4316  int
4317 4317  ddi_prop_update_string(dev_t match_dev, dev_info_t *dip,
4318 4318      char *name, char *data)
4319 4319  {
4320 4320          return (ddi_prop_update_common(match_dev, dip,
4321 4321              DDI_PROP_TYPE_STRING, name, &data, 1,
4322 4322              ddi_prop_fm_encode_string));
4323 4323  }
4324 4324  
4325 4325  int
4326 4326  e_ddi_prop_update_string(dev_t match_dev, dev_info_t *dip,
4327 4327      char *name, char *data)
4328 4328  {
4329 4329          return (ddi_prop_update_common(match_dev, dip,
4330 4330              DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_STRING,
4331 4331              name, &data, 1, ddi_prop_fm_encode_string));
4332 4332  }
4333 4333  
4334 4334  
4335 4335  /*
4336 4336   * Update an array of strings property.
4337 4337   */
4338 4338  int
4339 4339  ddi_prop_update_string_array(dev_t match_dev, dev_info_t *dip,
4340 4340      char *name, char **data, uint_t nelements)
4341 4341  {
4342 4342          return (ddi_prop_update_common(match_dev, dip,
4343 4343              DDI_PROP_TYPE_STRING, name, data, nelements,
4344 4344              ddi_prop_fm_encode_strings));
4345 4345  }
4346 4346  
4347 4347  int
4348 4348  e_ddi_prop_update_string_array(dev_t match_dev, dev_info_t *dip,
4349 4349      char *name, char **data, uint_t nelements)
4350 4350  {
4351 4351          return (ddi_prop_update_common(match_dev, dip,
4352 4352              DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_STRING,
4353 4353              name, data, nelements,
4354 4354              ddi_prop_fm_encode_strings));
4355 4355  }
4356 4356  
4357 4357  
4358 4358  /*
4359 4359   * Get an array of bytes property.
4360 4360   */
4361 4361  int
4362 4362  ddi_prop_lookup_byte_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
4363 4363      char *name, uchar_t **data, uint_t *nelements)
4364 4364  {
4365 4365          if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4366 4366              LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
4367 4367  #ifdef DEBUG
4368 4368                  if (dip != NULL) {
4369 4369                          cmn_err(CE_WARN, "ddi_prop_lookup_byte_array: "
4370 4370                              " invalid flag 0x%x (prop = %s, node = %s%d)",
4371 4371                              flags, name, ddi_driver_name(dip),
4372 4372                              ddi_get_instance(dip));
4373 4373                  }
4374 4374  #endif /* DEBUG */
4375 4375                  flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4376 4376                      LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4377 4377          }
4378 4378  
4379 4379          return (ddi_prop_lookup_common(match_dev, dip,
4380 4380              (flags | DDI_PROP_TYPE_BYTE), name, data,
4381 4381              nelements, ddi_prop_fm_decode_bytes));
4382 4382  }
4383 4383  
4384 4384  /*
4385 4385   * Update an array of bytes property.
4386 4386   */
4387 4387  int
4388 4388  ddi_prop_update_byte_array(dev_t match_dev, dev_info_t *dip,
4389 4389      char *name, uchar_t *data, uint_t nelements)
4390 4390  {
4391 4391          if (nelements == 0)
4392 4392                  return (DDI_PROP_INVAL_ARG);
4393 4393  
4394 4394          return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_BYTE,
4395 4395              name, data, nelements, ddi_prop_fm_encode_bytes));
4396 4396  }
4397 4397  
4398 4398  
4399 4399  int
4400 4400  e_ddi_prop_update_byte_array(dev_t match_dev, dev_info_t *dip,
4401 4401      char *name, uchar_t *data, uint_t nelements)
4402 4402  {
4403 4403          if (nelements == 0)
4404 4404                  return (DDI_PROP_INVAL_ARG);
4405 4405  
4406 4406          return (ddi_prop_update_common(match_dev, dip,
4407 4407              DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_BYTE,
4408 4408              name, data, nelements, ddi_prop_fm_encode_bytes));
4409 4409  }
4410 4410  
4411 4411  
4412 4412  /*
4413 4413   * ddi_prop_remove_common:      Undefine a managed property:
4414 4414   *                      Input dev_t must match dev_t when defined.
4415 4415   *                      Returns DDI_PROP_NOT_FOUND, possibly.
4416 4416   *                      DDI_PROP_INVAL_ARG is also possible if dev is
4417 4417   *                      DDI_DEV_T_ANY or incoming name is the NULL string.
4418 4418   */
4419 4419  int
4420 4420  ddi_prop_remove_common(dev_t dev, dev_info_t *dip, char *name, int flag)
4421 4421  {
4422 4422          ddi_prop_t      **list_head = &(DEVI(dip)->devi_drv_prop_ptr);
4423 4423          ddi_prop_t      *propp;
4424 4424          ddi_prop_t      *lastpropp = NULL;
4425 4425  
4426 4426          if ((dev == DDI_DEV_T_ANY) || (name == (char *)0) ||
4427 4427              (strlen(name) == 0)) {
4428 4428                  return (DDI_PROP_INVAL_ARG);
4429 4429          }
4430 4430  
4431 4431          if (flag & DDI_PROP_SYSTEM_DEF)
4432 4432                  list_head = &(DEVI(dip)->devi_sys_prop_ptr);
4433 4433          else if (flag & DDI_PROP_HW_DEF)
4434 4434                  list_head = &(DEVI(dip)->devi_hw_prop_ptr);
4435 4435  
4436 4436          mutex_enter(&(DEVI(dip)->devi_lock));
4437 4437  
4438 4438          for (propp = *list_head; propp != NULL; propp = propp->prop_next)  {
4439 4439                  if (DDI_STRSAME(propp->prop_name, name) &&
4440 4440                      (dev == propp->prop_dev)) {
4441 4441                          /*
4442 4442                           * Unlink this propp allowing for it to
4443 4443                           * be first in the list:
4444 4444                           */
4445 4445  
4446 4446                          if (lastpropp == NULL)
4447 4447                                  *list_head = propp->prop_next;
4448 4448                          else
4449 4449                                  lastpropp->prop_next = propp->prop_next;
4450 4450  
4451 4451                          mutex_exit(&(DEVI(dip)->devi_lock));
4452 4452  
4453 4453                          /*
4454 4454                           * Free memory and return...
4455 4455                           */
4456 4456                          kmem_free(propp->prop_name,
4457 4457                              strlen(propp->prop_name) + 1);
4458 4458                          if (propp->prop_len != 0)
4459 4459                                  kmem_free(propp->prop_val, propp->prop_len);
4460 4460                          kmem_free(propp, sizeof (ddi_prop_t));
4461 4461                          return (DDI_PROP_SUCCESS);
4462 4462                  }
4463 4463                  lastpropp = propp;
4464 4464          }
4465 4465          mutex_exit(&(DEVI(dip)->devi_lock));
4466 4466          return (DDI_PROP_NOT_FOUND);
4467 4467  }
4468 4468  
4469 4469  int
4470 4470  ddi_prop_remove(dev_t dev, dev_info_t *dip, char *name)
4471 4471  {
4472 4472          return (ddi_prop_remove_common(dev, dip, name, 0));
4473 4473  }
4474 4474  
4475 4475  int
4476 4476  e_ddi_prop_remove(dev_t dev, dev_info_t *dip, char *name)
4477 4477  {
4478 4478          return (ddi_prop_remove_common(dev, dip, name, DDI_PROP_SYSTEM_DEF));
4479 4479  }
4480 4480  
4481 4481  /*
4482 4482   * e_ddi_prop_list_delete: remove a list of properties
4483 4483   *      Note that the caller needs to provide the required protection
4484 4484   *      (eg. devi_lock if these properties are still attached to a devi)
4485 4485   */
4486 4486  void
4487 4487  e_ddi_prop_list_delete(ddi_prop_t *props)
4488 4488  {
4489 4489          i_ddi_prop_list_delete(props);
4490 4490  }
4491 4491  
4492 4492  /*
4493 4493   * ddi_prop_remove_all_common:
4494 4494   *      Used before unloading a driver to remove
4495 4495   *      all properties. (undefines all dev_t's props.)
4496 4496   *      Also removes `explicitly undefined' props.
4497 4497   *      No errors possible.
4498 4498   */
4499 4499  void
4500 4500  ddi_prop_remove_all_common(dev_info_t *dip, int flag)
4501 4501  {
4502 4502          ddi_prop_t      **list_head;
4503 4503  
4504 4504          mutex_enter(&(DEVI(dip)->devi_lock));
4505 4505          if (flag & DDI_PROP_SYSTEM_DEF) {
4506 4506                  list_head = &(DEVI(dip)->devi_sys_prop_ptr);
4507 4507          } else if (flag & DDI_PROP_HW_DEF) {
4508 4508                  list_head = &(DEVI(dip)->devi_hw_prop_ptr);
4509 4509          } else {
4510 4510                  list_head = &(DEVI(dip)->devi_drv_prop_ptr);
4511 4511          }
4512 4512          i_ddi_prop_list_delete(*list_head);
4513 4513          *list_head = NULL;
4514 4514          mutex_exit(&(DEVI(dip)->devi_lock));
4515 4515  }
4516 4516  
4517 4517  
4518 4518  /*
4519 4519   * ddi_prop_remove_all:         Remove all driver prop definitions.
4520 4520   */
4521 4521  
4522 4522  void
4523 4523  ddi_prop_remove_all(dev_info_t *dip)
4524 4524  {
4525 4525          i_ddi_prop_dyn_driver_set(dip, NULL);
4526 4526          ddi_prop_remove_all_common(dip, 0);
4527 4527  }
4528 4528  
4529 4529  /*
4530 4530   * e_ddi_prop_remove_all:       Remove all system prop definitions.
4531 4531   */
4532 4532  
4533 4533  void
4534 4534  e_ddi_prop_remove_all(dev_info_t *dip)
4535 4535  {
4536 4536          ddi_prop_remove_all_common(dip, (int)DDI_PROP_SYSTEM_DEF);
4537 4537  }
4538 4538  
4539 4539  
4540 4540  /*
4541 4541   * ddi_prop_undefine:   Explicitly undefine a property.  Property
4542 4542   *                      searches which match this property return
4543 4543   *                      the error code DDI_PROP_UNDEFINED.
4544 4544   *
4545 4545   *                      Use ddi_prop_remove to negate effect of
4546 4546   *                      ddi_prop_undefine
4547 4547   *
4548 4548   *                      See above for error returns.
4549 4549   */
4550 4550  
4551 4551  int
4552 4552  ddi_prop_undefine(dev_t dev, dev_info_t *dip, int flag, char *name)
4553 4553  {
4554 4554          if (!(flag & DDI_PROP_CANSLEEP))
4555 4555                  flag |= DDI_PROP_DONTSLEEP;
4556 4556          flag |= DDI_PROP_STACK_CREATE | DDI_PROP_UNDEF_IT | DDI_PROP_TYPE_ANY;
4557 4557          return (ddi_prop_update_common(dev, dip, flag,
4558 4558              name, NULL, 0, ddi_prop_fm_encode_bytes));
4559 4559  }
4560 4560  
4561 4561  int
4562 4562  e_ddi_prop_undefine(dev_t dev, dev_info_t *dip, int flag, char *name)
4563 4563  {
4564 4564          if (!(flag & DDI_PROP_CANSLEEP))
4565 4565                  flag |= DDI_PROP_DONTSLEEP;
4566 4566          flag |= DDI_PROP_SYSTEM_DEF | DDI_PROP_STACK_CREATE |
4567 4567              DDI_PROP_UNDEF_IT | DDI_PROP_TYPE_ANY;
4568 4568          return (ddi_prop_update_common(dev, dip, flag,
4569 4569              name, NULL, 0, ddi_prop_fm_encode_bytes));
4570 4570  }
4571 4571  
4572 4572  /*
4573 4573   * Support for gathering dynamic properties in devinfo snapshot.
4574 4574   */
4575 4575  void
4576 4576  i_ddi_prop_dyn_driver_set(dev_info_t *dip, i_ddi_prop_dyn_t *dp)
4577 4577  {
4578 4578          DEVI(dip)->devi_prop_dyn_driver = dp;
4579 4579  }
4580 4580  
4581 4581  i_ddi_prop_dyn_t *
4582 4582  i_ddi_prop_dyn_driver_get(dev_info_t *dip)
4583 4583  {
4584 4584          return (DEVI(dip)->devi_prop_dyn_driver);
4585 4585  }
4586 4586  
4587 4587  void
4588 4588  i_ddi_prop_dyn_parent_set(dev_info_t *dip, i_ddi_prop_dyn_t *dp)
4589 4589  {
4590 4590          DEVI(dip)->devi_prop_dyn_parent = dp;
4591 4591  }
4592 4592  
4593 4593  i_ddi_prop_dyn_t *
4594 4594  i_ddi_prop_dyn_parent_get(dev_info_t *dip)
4595 4595  {
4596 4596          return (DEVI(dip)->devi_prop_dyn_parent);
4597 4597  }
4598 4598  
4599 4599  void
4600 4600  i_ddi_prop_dyn_cache_invalidate(dev_info_t *dip, i_ddi_prop_dyn_t *dp)
4601 4601  {
4602 4602          /* for now we invalidate the entire cached snapshot */
4603 4603          if (dip && dp)
4604 4604                  i_ddi_di_cache_invalidate();
4605 4605  }
4606 4606  
4607 4607  /* ARGSUSED */
4608 4608  void
4609 4609  ddi_prop_cache_invalidate(dev_t dev, dev_info_t *dip, char *name, int flags)
4610 4610  {
4611 4611          /* for now we invalidate the entire cached snapshot */
4612 4612          i_ddi_di_cache_invalidate();
4613 4613  }
4614 4614  
4615 4615  
4616 4616  /*
4617 4617   * Code to search hardware layer (PROM), if it exists, on behalf of child.
4618 4618   *
4619 4619   * if input dip != child_dip, then call is on behalf of child
4620 4620   * to search PROM, do it via ddi_prop_search_common() and ascend only
4621 4621   * if allowed.
4622 4622   *
4623 4623   * if input dip == ch_dip (child_dip), call is on behalf of root driver,
4624 4624   * to search for PROM defined props only.
4625 4625   *
4626 4626   * Note that the PROM search is done only if the requested dev
4627 4627   * is either DDI_DEV_T_ANY or DDI_DEV_T_NONE. PROM properties
4628 4628   * have no associated dev, thus are automatically associated with
4629 4629   * DDI_DEV_T_NONE.
4630 4630   *
4631 4631   * Modifying flag DDI_PROP_NOTPROM inhibits the search in the h/w layer.
4632 4632   *
4633 4633   * Returns DDI_PROP_FOUND_1275 if found to indicate to framework
4634 4634   * that the property resides in the prom.
4635 4635   */
4636 4636  int
4637 4637  impl_ddi_bus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
4638 4638      ddi_prop_op_t prop_op, int mod_flags,
4639 4639      char *name, caddr_t valuep, int *lengthp)
4640 4640  {
4641 4641          int     len;
4642 4642          caddr_t buffer;
4643 4643  
4644 4644          /*
4645 4645           * If requested dev is DDI_DEV_T_NONE or DDI_DEV_T_ANY, then
4646 4646           * look in caller's PROM if it's a self identifying device...
4647 4647           *
4648 4648           * Note that this is very similar to ddi_prop_op, but we
4649 4649           * search the PROM instead of the s/w defined properties,
4650 4650           * and we are called on by the parent driver to do this for
4651 4651           * the child.
4652 4652           */
4653 4653  
4654 4654          if (((dev == DDI_DEV_T_NONE) || (dev == DDI_DEV_T_ANY)) &&
4655 4655              ndi_dev_is_prom_node(ch_dip) &&
4656 4656              ((mod_flags & DDI_PROP_NOTPROM) == 0)) {
4657 4657                  len = prom_getproplen((pnode_t)DEVI(ch_dip)->devi_nodeid, name);
4658 4658                  if (len == -1) {
4659 4659                          return (DDI_PROP_NOT_FOUND);
4660 4660                  }
4661 4661  
4662 4662                  /*
4663 4663                   * If exists only request, we're done
4664 4664                   */
4665 4665                  if (prop_op == PROP_EXISTS) {
4666 4666                          return (DDI_PROP_FOUND_1275);
4667 4667                  }
4668 4668  
4669 4669                  /*
4670 4670                   * If length only request or prop length == 0, get out
4671 4671                   */
4672 4672                  if ((prop_op == PROP_LEN) || (len == 0)) {
4673 4673                          *lengthp = len;
4674 4674                          return (DDI_PROP_FOUND_1275);
4675 4675                  }
4676 4676  
4677 4677                  /*
4678 4678                   * Allocate buffer if required... (either way `buffer'
4679 4679                   * is receiving address).
4680 4680                   */
4681 4681  
4682 4682                  switch (prop_op) {
4683 4683  
4684 4684                  case PROP_LEN_AND_VAL_ALLOC:
4685 4685  
4686 4686                          buffer = kmem_alloc((size_t)len,
4687 4687                              mod_flags & DDI_PROP_CANSLEEP ?
4688 4688                              KM_SLEEP : KM_NOSLEEP);
4689 4689                          if (buffer == NULL) {
4690 4690                                  return (DDI_PROP_NO_MEMORY);
4691 4691                          }
4692 4692                          *(caddr_t *)valuep = buffer;
4693 4693                          break;
4694 4694  
4695 4695                  case PROP_LEN_AND_VAL_BUF:
4696 4696  
4697 4697                          if (len > (*lengthp)) {
4698 4698                                  *lengthp = len;
4699 4699                                  return (DDI_PROP_BUF_TOO_SMALL);
4700 4700                          }
4701 4701  
4702 4702                          buffer = valuep;
4703 4703                          break;
4704 4704  
4705 4705                  default:
4706 4706                          break;
4707 4707                  }
4708 4708  
4709 4709                  /*
4710 4710                   * Call the PROM function to do the copy.
4711 4711                   */
4712 4712                  (void) prom_getprop((pnode_t)DEVI(ch_dip)->devi_nodeid,
4713 4713                      name, buffer);
4714 4714  
4715 4715                  *lengthp = len; /* return the actual length to the caller */
4716 4716                  (void) impl_fix_props(dip, ch_dip, name, len, buffer);
4717 4717                  return (DDI_PROP_FOUND_1275);
4718 4718          }
4719 4719  
4720 4720          return (DDI_PROP_NOT_FOUND);
4721 4721  }
4722 4722  
4723 4723  /*
4724 4724   * The ddi_bus_prop_op default bus nexus prop op function.
4725 4725   *
4726 4726   * Code to search hardware layer (PROM), if it exists,
4727 4727   * on behalf of child, then, if appropriate, ascend and check
4728 4728   * my own software defined properties...
4729 4729   */
4730 4730  int
4731 4731  ddi_bus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
4732 4732      ddi_prop_op_t prop_op, int mod_flags,
4733 4733      char *name, caddr_t valuep, int *lengthp)
4734 4734  {
4735 4735          int     error;
4736 4736  
4737 4737          error = impl_ddi_bus_prop_op(dev, dip, ch_dip, prop_op, mod_flags,
4738 4738              name, valuep, lengthp);
4739 4739  
4740 4740          if (error == DDI_PROP_SUCCESS || error == DDI_PROP_FOUND_1275 ||
4741 4741              error == DDI_PROP_BUF_TOO_SMALL)
4742 4742                  return (error);
4743 4743  
4744 4744          if (error == DDI_PROP_NO_MEMORY) {
4745 4745                  cmn_err(CE_CONT, prop_no_mem_msg, name);
4746 4746                  return (DDI_PROP_NO_MEMORY);
4747 4747          }
4748 4748  
4749 4749          /*
4750 4750           * Check the 'options' node as a last resort
4751 4751           */
4752 4752          if ((mod_flags & DDI_PROP_DONTPASS) != 0)
4753 4753                  return (DDI_PROP_NOT_FOUND);
4754 4754  
4755 4755          if (ch_dip == ddi_root_node())  {
4756 4756                  /*
4757 4757                   * As a last resort, when we've reached
4758 4758                   * the top and still haven't found the
4759 4759                   * property, see if the desired property
4760 4760                   * is attached to the options node.
4761 4761                   *
4762 4762                   * The options dip is attached right after boot.
4763 4763                   */
4764 4764                  ASSERT(options_dip != NULL);
4765 4765                  /*
4766 4766                   * Force the "don't pass" flag to *just* see
4767 4767                   * what the options node has to offer.
4768 4768                   */
4769 4769                  return (ddi_prop_search_common(dev, options_dip, prop_op,
4770 4770                      mod_flags|DDI_PROP_DONTPASS, name, valuep,
4771 4771                      (uint_t *)lengthp));
4772 4772          }
4773 4773  
4774 4774          /*
4775 4775           * Otherwise, continue search with parent's s/w defined properties...
4776 4776           * NOTE: Using `dip' in following call increments the level.
4777 4777           */
4778 4778  
4779 4779          return (ddi_prop_search_common(dev, dip, prop_op, mod_flags,
4780 4780              name, valuep, (uint_t *)lengthp));
4781 4781  }
4782 4782  
4783 4783  /*
4784 4784   * External property functions used by other parts of the kernel...
4785 4785   */
4786 4786  
4787 4787  /*
4788 4788   * e_ddi_getlongprop: See comments for ddi_get_longprop.
4789 4789   */
4790 4790  
4791 4791  int
4792 4792  e_ddi_getlongprop(dev_t dev, vtype_t type, char *name, int flags,
4793 4793      caddr_t valuep, int *lengthp)
4794 4794  {
4795 4795          _NOTE(ARGUNUSED(type))
4796 4796          dev_info_t *devi;
4797 4797          ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_ALLOC;
4798 4798          int error;
4799 4799  
4800 4800          if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4801 4801                  return (DDI_PROP_NOT_FOUND);
4802 4802  
4803 4803          error = cdev_prop_op(dev, devi, prop_op, flags, name, valuep, lengthp);
4804 4804          ddi_release_devi(devi);
4805 4805          return (error);
4806 4806  }
4807 4807  
4808 4808  /*
4809 4809   * e_ddi_getlongprop_buf:       See comments for ddi_getlongprop_buf.
4810 4810   */
4811 4811  
4812 4812  int
4813 4813  e_ddi_getlongprop_buf(dev_t dev, vtype_t type, char *name, int flags,
4814 4814      caddr_t valuep, int *lengthp)
4815 4815  {
4816 4816          _NOTE(ARGUNUSED(type))
4817 4817          dev_info_t *devi;
4818 4818          ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_BUF;
4819 4819          int error;
4820 4820  
4821 4821          if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4822 4822                  return (DDI_PROP_NOT_FOUND);
4823 4823  
4824 4824          error = cdev_prop_op(dev, devi, prop_op, flags, name, valuep, lengthp);
4825 4825          ddi_release_devi(devi);
4826 4826          return (error);
4827 4827  }
4828 4828  
4829 4829  /*
4830 4830   * e_ddi_getprop:       See comments for ddi_getprop.
4831 4831   */
4832 4832  int
4833 4833  e_ddi_getprop(dev_t dev, vtype_t type, char *name, int flags, int defvalue)
4834 4834  {
4835 4835          _NOTE(ARGUNUSED(type))
4836 4836          dev_info_t *devi;
4837 4837          ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_BUF;
4838 4838          int     propvalue = defvalue;
4839 4839          int     proplength = sizeof (int);
4840 4840          int     error;
4841 4841  
4842 4842          if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4843 4843                  return (defvalue);
4844 4844  
4845 4845          error = cdev_prop_op(dev, devi, prop_op,
4846 4846              flags, name, (caddr_t)&propvalue, &proplength);
4847 4847          ddi_release_devi(devi);
4848 4848  
4849 4849          if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
4850 4850                  propvalue = 1;
4851 4851  
4852 4852          return (propvalue);
4853 4853  }
4854 4854  
4855 4855  /*
4856 4856   * e_ddi_getprop_int64:
4857 4857   *
4858 4858   * This is a typed interfaces, but predates typed properties. With the
4859 4859   * introduction of typed properties the framework tries to ensure
4860 4860   * consistent use of typed interfaces. This is why TYPE_INT64 is not
4861 4861   * part of TYPE_ANY.  E_ddi_getprop_int64 is a special case where a
4862 4862   * typed interface invokes legacy (non-typed) interfaces:
4863 4863   * cdev_prop_op(), prop_op(9E), ddi_prop_op(9F)).  In this case the
4864 4864   * fact that TYPE_INT64 is not part of TYPE_ANY matters.  To support
4865 4865   * this type of lookup as a single operation we invoke the legacy
4866 4866   * non-typed interfaces with the special CONSUMER_TYPED bit set. The
4867 4867   * framework ddi_prop_op(9F) implementation is expected to check for
4868 4868   * CONSUMER_TYPED and, if set, expand type bits beyond TYPE_ANY
4869 4869   * (currently TYPE_INT64).
4870 4870   */
4871 4871  int64_t
4872 4872  e_ddi_getprop_int64(dev_t dev, vtype_t type, char *name,
4873 4873      int flags, int64_t defvalue)
4874 4874  {
4875 4875          _NOTE(ARGUNUSED(type))
4876 4876          dev_info_t      *devi;
4877 4877          ddi_prop_op_t   prop_op = PROP_LEN_AND_VAL_BUF;
4878 4878          int64_t         propvalue = defvalue;
4879 4879          int             proplength = sizeof (propvalue);
4880 4880          int             error;
4881 4881  
4882 4882          if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4883 4883                  return (defvalue);
4884 4884  
4885 4885          error = cdev_prop_op(dev, devi, prop_op, flags |
4886 4886              DDI_PROP_CONSUMER_TYPED, name, (caddr_t)&propvalue, &proplength);
4887 4887          ddi_release_devi(devi);
4888 4888  
4889 4889          if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
4890 4890                  propvalue = 1;
4891 4891  
4892 4892          return (propvalue);
4893 4893  }
4894 4894  
4895 4895  /*
4896 4896   * e_ddi_getproplen:    See comments for ddi_getproplen.
4897 4897   */
4898 4898  int
4899 4899  e_ddi_getproplen(dev_t dev, vtype_t type, char *name, int flags, int *lengthp)
4900 4900  {
4901 4901          _NOTE(ARGUNUSED(type))
4902 4902          dev_info_t *devi;
4903 4903          ddi_prop_op_t prop_op = PROP_LEN;
4904 4904          int error;
4905 4905  
4906 4906          if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4907 4907                  return (DDI_PROP_NOT_FOUND);
4908 4908  
4909 4909          error = cdev_prop_op(dev, devi, prop_op, flags, name, NULL, lengthp);
4910 4910          ddi_release_devi(devi);
4911 4911          return (error);
4912 4912  }
4913 4913  
4914 4914  /*
4915 4915   * Routines to get at elements of the dev_info structure
4916 4916   */
4917 4917  
4918 4918  /*
4919 4919   * ddi_binding_name: Return the driver binding name of the devinfo node
4920 4920   *              This is the name the OS used to bind the node to a driver.
4921 4921   */
4922 4922  char *
4923 4923  ddi_binding_name(dev_info_t *dip)
4924 4924  {
4925 4925          return (DEVI(dip)->devi_binding_name);
4926 4926  }
4927 4927  
4928 4928  /*
4929 4929   * ddi_driver_major: Return the major number of the driver that
4930 4930   *      the supplied devinfo is bound to.  If not yet bound,
4931 4931   *      DDI_MAJOR_T_NONE.
4932 4932   *
4933 4933   * When used by the driver bound to 'devi', this
4934 4934   * function will reliably return the driver major number.
4935 4935   * Other ways of determining the driver major number, such as
4936 4936   *      major = ddi_name_to_major(ddi_get_name(devi));
4937 4937   *      major = ddi_name_to_major(ddi_binding_name(devi));
4938 4938   * can return a different result as the driver/alias binding
4939 4939   * can change dynamically, and thus should be avoided.
4940 4940   */
4941 4941  major_t
4942 4942  ddi_driver_major(dev_info_t *devi)
4943 4943  {
4944 4944          return (DEVI(devi)->devi_major);
4945 4945  }
4946 4946  
4947 4947  /*
4948 4948   * ddi_driver_name: Return the normalized driver name. this is the
4949 4949   *              actual driver name
4950 4950   */
4951 4951  const char *
4952 4952  ddi_driver_name(dev_info_t *devi)
4953 4953  {
4954 4954          major_t major;
4955 4955  
4956 4956          if ((major = ddi_driver_major(devi)) != DDI_MAJOR_T_NONE)
4957 4957                  return (ddi_major_to_name(major));
4958 4958  
4959 4959          return (ddi_node_name(devi));
4960 4960  }
4961 4961  
4962 4962  /*
4963 4963   * i_ddi_set_binding_name:      Set binding name.
4964 4964   *
4965 4965   *      Set the binding name to the given name.
4966 4966   *      This routine is for use by the ddi implementation, not by drivers.
4967 4967   */
4968 4968  void
4969 4969  i_ddi_set_binding_name(dev_info_t *dip, char *name)
4970 4970  {
4971 4971          DEVI(dip)->devi_binding_name = name;
4972 4972  
4973 4973  }
4974 4974  
4975 4975  /*
4976 4976   * ddi_get_name: A synonym of ddi_binding_name() ... returns a name
4977 4977   * the implementation has used to bind the node to a driver.
4978 4978   */
4979 4979  char *
4980 4980  ddi_get_name(dev_info_t *dip)
4981 4981  {
4982 4982          return (DEVI(dip)->devi_binding_name);
4983 4983  }
4984 4984  
4985 4985  /*
4986 4986   * ddi_node_name: Return the name property of the devinfo node
4987 4987   *              This may differ from ddi_binding_name if the node name
4988 4988   *              does not define a binding to a driver (i.e. generic names).
4989 4989   */
4990 4990  char *
4991 4991  ddi_node_name(dev_info_t *dip)
4992 4992  {
4993 4993          return (DEVI(dip)->devi_node_name);
4994 4994  }
4995 4995  
4996 4996  
4997 4997  /*
4998 4998   * ddi_get_nodeid:      Get nodeid stored in dev_info structure.
4999 4999   */
5000 5000  int
5001 5001  ddi_get_nodeid(dev_info_t *dip)
5002 5002  {
5003 5003          return (DEVI(dip)->devi_nodeid);
5004 5004  }
5005 5005  
5006 5006  int
5007 5007  ddi_get_instance(dev_info_t *dip)
5008 5008  {
5009 5009          return (DEVI(dip)->devi_instance);
5010 5010  }
5011 5011  
5012 5012  struct dev_ops *
5013 5013  ddi_get_driver(dev_info_t *dip)
5014 5014  {
5015 5015          return (DEVI(dip)->devi_ops);
5016 5016  }
5017 5017  
5018 5018  void
5019 5019  ddi_set_driver(dev_info_t *dip, struct dev_ops *devo)
5020 5020  {
5021 5021          DEVI(dip)->devi_ops = devo;
5022 5022  }
5023 5023  
5024 5024  /*
5025 5025   * ddi_set_driver_private/ddi_get_driver_private:
5026 5026   * Get/set device driver private data in devinfo.
5027 5027   */
5028 5028  void
5029 5029  ddi_set_driver_private(dev_info_t *dip, void *data)
5030 5030  {
5031 5031          DEVI(dip)->devi_driver_data = data;
5032 5032  }
5033 5033  
5034 5034  void *
5035 5035  ddi_get_driver_private(dev_info_t *dip)
5036 5036  {
5037 5037          return (DEVI(dip)->devi_driver_data);
5038 5038  }
5039 5039  
5040 5040  /*
5041 5041   * ddi_get_parent, ddi_get_child, ddi_get_next_sibling
5042 5042   */
5043 5043  
5044 5044  dev_info_t *
5045 5045  ddi_get_parent(dev_info_t *dip)
5046 5046  {
5047 5047          return ((dev_info_t *)DEVI(dip)->devi_parent);
5048 5048  }
5049 5049  
5050 5050  dev_info_t *
5051 5051  ddi_get_child(dev_info_t *dip)
5052 5052  {
5053 5053          return ((dev_info_t *)DEVI(dip)->devi_child);
5054 5054  }
5055 5055  
5056 5056  dev_info_t *
5057 5057  ddi_get_next_sibling(dev_info_t *dip)
5058 5058  {
5059 5059          return ((dev_info_t *)DEVI(dip)->devi_sibling);
5060 5060  }
5061 5061  
5062 5062  dev_info_t *
5063 5063  ddi_get_next(dev_info_t *dip)
5064 5064  {
5065 5065          return ((dev_info_t *)DEVI(dip)->devi_next);
5066 5066  }
5067 5067  
5068 5068  void
5069 5069  ddi_set_next(dev_info_t *dip, dev_info_t *nextdip)
5070 5070  {
5071 5071          DEVI(dip)->devi_next = DEVI(nextdip);
5072 5072  }
5073 5073  
5074 5074  /*
5075 5075   * ddi_root_node:               Return root node of devinfo tree
5076 5076   */
5077 5077  
5078 5078  dev_info_t *
5079 5079  ddi_root_node(void)
5080 5080  {
5081 5081          extern dev_info_t *top_devinfo;
5082 5082  
5083 5083          return (top_devinfo);
5084 5084  }
5085 5085  
5086 5086  /*
5087 5087   * Miscellaneous functions:
5088 5088   */
5089 5089  
5090 5090  /*
5091 5091   * Implementation specific hooks
5092 5092   */
5093 5093  
5094 5094  void
5095 5095  ddi_report_dev(dev_info_t *d)
5096 5096  {
5097 5097          char *b;
5098 5098  
5099 5099          (void) ddi_ctlops(d, d, DDI_CTLOPS_REPORTDEV, (void *)0, (void *)0);
5100 5100  
5101 5101          /*
5102 5102           * If this devinfo node has cb_ops, it's implicitly accessible from
5103 5103           * userland, so we print its full name together with the instance
5104 5104           * number 'abbreviation' that the driver may use internally.
5105 5105           */
5106 5106          if (DEVI(d)->devi_ops->devo_cb_ops != (struct cb_ops *)0 &&
5107 5107              (b = kmem_zalloc(MAXPATHLEN, KM_NOSLEEP))) {
5108 5108                  cmn_err(CE_CONT, "?%s%d is %s\n",
5109 5109                      ddi_driver_name(d), ddi_get_instance(d),
5110 5110                      ddi_pathname(d, b));
5111 5111                  kmem_free(b, MAXPATHLEN);
5112 5112          }
5113 5113  }
5114 5114  
5115 5115  /*
5116 5116   * ddi_ctlops() is described in the assembler not to buy a new register
5117 5117   * window when it's called and can reduce cost in climbing the device tree
5118 5118   * without using the tail call optimization.
5119 5119   */
5120 5120  int
5121 5121  ddi_dev_regsize(dev_info_t *dev, uint_t rnumber, off_t *result)
5122 5122  {
5123 5123          int ret;
5124 5124  
5125 5125          ret = ddi_ctlops(dev, dev, DDI_CTLOPS_REGSIZE,
5126 5126              (void *)&rnumber, (void *)result);
5127 5127  
5128 5128          return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5129 5129  }
5130 5130  
5131 5131  int
5132 5132  ddi_dev_nregs(dev_info_t *dev, int *result)
5133 5133  {
5134 5134          return (ddi_ctlops(dev, dev, DDI_CTLOPS_NREGS, 0, (void *)result));
5135 5135  }
5136 5136  
5137 5137  int
5138 5138  ddi_dev_is_sid(dev_info_t *d)
5139 5139  {
5140 5140          return (ddi_ctlops(d, d, DDI_CTLOPS_SIDDEV, (void *)0, (void *)0));
5141 5141  }
5142 5142  
5143 5143  int
5144 5144  ddi_slaveonly(dev_info_t *d)
5145 5145  {
5146 5146          return (ddi_ctlops(d, d, DDI_CTLOPS_SLAVEONLY, (void *)0, (void *)0));
5147 5147  }
5148 5148  
5149 5149  int
5150 5150  ddi_dev_affinity(dev_info_t *a, dev_info_t *b)
5151 5151  {
5152 5152          return (ddi_ctlops(a, a, DDI_CTLOPS_AFFINITY, (void *)b, (void *)0));
5153 5153  }
5154 5154  
5155 5155  int
5156 5156  ddi_streams_driver(dev_info_t *dip)
5157 5157  {
5158 5158          if (i_ddi_devi_attached(dip) &&
5159 5159              (DEVI(dip)->devi_ops->devo_cb_ops != NULL) &&
5160 5160              (DEVI(dip)->devi_ops->devo_cb_ops->cb_str != NULL))
5161 5161                  return (DDI_SUCCESS);
5162 5162          return (DDI_FAILURE);
5163 5163  }
5164 5164  
5165 5165  /*
5166 5166   * callback free list
5167 5167   */
5168 5168  
5169 5169  static int ncallbacks;
5170 5170  static int nc_low = 170;
5171 5171  static int nc_med = 512;
5172 5172  static int nc_high = 2048;
5173 5173  static struct ddi_callback *callbackq;
5174 5174  static struct ddi_callback *callbackqfree;
5175 5175  
5176 5176  /*
5177 5177   * set/run callback lists
5178 5178   */
5179 5179  struct  cbstats {
5180 5180          kstat_named_t   cb_asked;
5181 5181          kstat_named_t   cb_new;
5182 5182          kstat_named_t   cb_run;
5183 5183          kstat_named_t   cb_delete;
5184 5184          kstat_named_t   cb_maxreq;
5185 5185          kstat_named_t   cb_maxlist;
5186 5186          kstat_named_t   cb_alloc;
5187 5187          kstat_named_t   cb_runouts;
5188 5188          kstat_named_t   cb_L2;
5189 5189          kstat_named_t   cb_grow;
5190 5190  } cbstats = {
5191 5191          {"asked",       KSTAT_DATA_UINT32},
5192 5192          {"new",         KSTAT_DATA_UINT32},
5193 5193          {"run",         KSTAT_DATA_UINT32},
5194 5194          {"delete",      KSTAT_DATA_UINT32},
5195 5195          {"maxreq",      KSTAT_DATA_UINT32},
5196 5196          {"maxlist",     KSTAT_DATA_UINT32},
5197 5197          {"alloc",       KSTAT_DATA_UINT32},
5198 5198          {"runouts",     KSTAT_DATA_UINT32},
5199 5199          {"L2",          KSTAT_DATA_UINT32},
5200 5200          {"grow",        KSTAT_DATA_UINT32},
5201 5201  };
5202 5202  
5203 5203  #define nc_asked        cb_asked.value.ui32
5204 5204  #define nc_new          cb_new.value.ui32
5205 5205  #define nc_run          cb_run.value.ui32
5206 5206  #define nc_delete       cb_delete.value.ui32
5207 5207  #define nc_maxreq       cb_maxreq.value.ui32
5208 5208  #define nc_maxlist      cb_maxlist.value.ui32
5209 5209  #define nc_alloc        cb_alloc.value.ui32
5210 5210  #define nc_runouts      cb_runouts.value.ui32
5211 5211  #define nc_L2           cb_L2.value.ui32
5212 5212  #define nc_grow         cb_grow.value.ui32
5213 5213  
5214 5214  static kmutex_t ddi_callback_mutex;
5215 5215  
5216 5216  /*
5217 5217   * callbacks are handled using a L1/L2 cache. The L1 cache
5218 5218   * comes out of kmem_cache_alloc and can expand/shrink dynamically. If
5219 5219   * we can't get callbacks from the L1 cache [because pageout is doing
5220 5220   * I/O at the time freemem is 0], we allocate callbacks out of the
5221 5221   * L2 cache. The L2 cache is static and depends on the memory size.
5222 5222   * [We might also count the number of devices at probe time and
5223 5223   * allocate one structure per device and adjust for deferred attach]
5224 5224   */
5225 5225  void
5226 5226  impl_ddi_callback_init(void)
5227 5227  {
5228 5228          int     i;
5229 5229          uint_t  physmegs;
5230 5230          kstat_t *ksp;
5231 5231  
5232 5232          physmegs = physmem >> (20 - PAGESHIFT);
5233 5233          if (physmegs < 48) {
5234 5234                  ncallbacks = nc_low;
5235 5235          } else if (physmegs < 128) {
5236 5236                  ncallbacks = nc_med;
5237 5237          } else {
5238 5238                  ncallbacks = nc_high;
5239 5239          }
5240 5240  
5241 5241          /*
5242 5242           * init free list
5243 5243           */
5244 5244          callbackq = kmem_zalloc(
5245 5245              ncallbacks * sizeof (struct ddi_callback), KM_SLEEP);
5246 5246          for (i = 0; i < ncallbacks-1; i++)
5247 5247                  callbackq[i].c_nfree = &callbackq[i+1];
5248 5248          callbackqfree = callbackq;
5249 5249  
5250 5250          /* init kstats */
5251 5251          if (ksp = kstat_create("unix", 0, "cbstats", "misc", KSTAT_TYPE_NAMED,
5252 5252              sizeof (cbstats) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL)) {
5253 5253                  ksp->ks_data = (void *) &cbstats;
5254 5254                  kstat_install(ksp);
5255 5255          }
5256 5256  
5257 5257  }
5258 5258  
5259 5259  static void
5260 5260  callback_insert(int (*funcp)(caddr_t), caddr_t arg, uintptr_t *listid,
5261 5261          int count)
5262 5262  {
5263 5263          struct ddi_callback *list, *marker, *new;
5264 5264          size_t size = sizeof (struct ddi_callback);
5265 5265  
5266 5266          list = marker = (struct ddi_callback *)*listid;
5267 5267          while (list != NULL) {
5268 5268                  if (list->c_call == funcp && list->c_arg == arg) {
5269 5269                          list->c_count += count;
5270 5270                          return;
5271 5271                  }
5272 5272                  marker = list;
5273 5273                  list = list->c_nlist;
5274 5274          }
5275 5275          new = kmem_alloc(size, KM_NOSLEEP);
5276 5276          if (new == NULL) {
5277 5277                  new = callbackqfree;
5278 5278                  if (new == NULL) {
5279 5279                          new = kmem_alloc_tryhard(sizeof (struct ddi_callback),
5280 5280                              &size, KM_NOSLEEP | KM_PANIC);
5281 5281                          cbstats.nc_grow++;
5282 5282                  } else {
5283 5283                          callbackqfree = new->c_nfree;
5284 5284                          cbstats.nc_L2++;
5285 5285                  }
5286 5286          }
5287 5287          if (marker != NULL) {
5288 5288                  marker->c_nlist = new;
5289 5289          } else {
5290 5290                  *listid = (uintptr_t)new;
5291 5291          }
5292 5292          new->c_size = size;
5293 5293          new->c_nlist = NULL;
5294 5294          new->c_call = funcp;
5295 5295          new->c_arg = arg;
5296 5296          new->c_count = count;
5297 5297          cbstats.nc_new++;
5298 5298          cbstats.nc_alloc++;
5299 5299          if (cbstats.nc_alloc > cbstats.nc_maxlist)
5300 5300                  cbstats.nc_maxlist = cbstats.nc_alloc;
5301 5301  }
5302 5302  
5303 5303  void
5304 5304  ddi_set_callback(int (*funcp)(caddr_t), caddr_t arg, uintptr_t *listid)
5305 5305  {
5306 5306          mutex_enter(&ddi_callback_mutex);
5307 5307          cbstats.nc_asked++;
5308 5308          if ((cbstats.nc_asked - cbstats.nc_run) > cbstats.nc_maxreq)
5309 5309                  cbstats.nc_maxreq = (cbstats.nc_asked - cbstats.nc_run);
5310 5310          (void) callback_insert(funcp, arg, listid, 1);
5311 5311          mutex_exit(&ddi_callback_mutex);
5312 5312  }
5313 5313  
5314 5314  static void
5315 5315  real_callback_run(void *Queue)
5316 5316  {
5317 5317          int (*funcp)(caddr_t);
5318 5318          caddr_t arg;
5319 5319          int count, rval;
5320 5320          uintptr_t *listid;
5321 5321          struct ddi_callback *list, *marker;
5322 5322          int check_pending = 1;
5323 5323          int pending = 0;
5324 5324  
5325 5325          do {
5326 5326                  mutex_enter(&ddi_callback_mutex);
5327 5327                  listid = Queue;
5328 5328                  list = (struct ddi_callback *)*listid;
5329 5329                  if (list == NULL) {
5330 5330                          mutex_exit(&ddi_callback_mutex);
5331 5331                          return;
5332 5332                  }
5333 5333                  if (check_pending) {
5334 5334                          marker = list;
5335 5335                          while (marker != NULL) {
5336 5336                                  pending += marker->c_count;
5337 5337                                  marker = marker->c_nlist;
5338 5338                          }
5339 5339                          check_pending = 0;
5340 5340                  }
5341 5341                  ASSERT(pending > 0);
5342 5342                  ASSERT(list->c_count > 0);
5343 5343                  funcp = list->c_call;
5344 5344                  arg = list->c_arg;
5345 5345                  count = list->c_count;
5346 5346                  *(uintptr_t *)Queue = (uintptr_t)list->c_nlist;
5347 5347                  if (list >= &callbackq[0] &&
5348 5348                      list <= &callbackq[ncallbacks-1]) {
5349 5349                          list->c_nfree = callbackqfree;
5350 5350                          callbackqfree = list;
5351 5351                  } else
5352 5352                          kmem_free(list, list->c_size);
5353 5353  
5354 5354                  cbstats.nc_delete++;
5355 5355                  cbstats.nc_alloc--;
5356 5356                  mutex_exit(&ddi_callback_mutex);
5357 5357  
5358 5358                  do {
5359 5359                          if ((rval = (*funcp)(arg)) == 0) {
5360 5360                                  pending -= count;
5361 5361                                  mutex_enter(&ddi_callback_mutex);
5362 5362                                  (void) callback_insert(funcp, arg, listid,
5363 5363                                      count);
5364 5364                                  cbstats.nc_runouts++;
5365 5365                          } else {
5366 5366                                  pending--;
5367 5367                                  mutex_enter(&ddi_callback_mutex);
5368 5368                                  cbstats.nc_run++;
5369 5369                          }
5370 5370                          mutex_exit(&ddi_callback_mutex);
5371 5371                  } while (rval != 0 && (--count > 0));
5372 5372          } while (pending > 0);
5373 5373  }
5374 5374  
5375 5375  void
5376 5376  ddi_run_callback(uintptr_t *listid)
5377 5377  {
5378 5378          softcall(real_callback_run, listid);
5379 5379  }
5380 5380  
5381 5381  /*
5382 5382   * ddi_periodic_t
5383 5383   * ddi_periodic_add(void (*func)(void *), void *arg, hrtime_t interval,
5384 5384   *     int level)
5385 5385   *
5386 5386   * INTERFACE LEVEL
5387 5387   *      Solaris DDI specific (Solaris DDI)
5388 5388   *
5389 5389   * PARAMETERS
5390 5390   *      func: the callback function
5391 5391   *
5392 5392   *            The callback function will be invoked. The function is invoked
5393 5393   *            in kernel context if the argument level passed is the zero.
5394 5394   *            Otherwise it's invoked in interrupt context at the specified
5395 5395   *            level.
5396 5396   *
5397 5397   *       arg: the argument passed to the callback function
5398 5398   *
5399 5399   *  interval: interval time
5400 5400   *
5401 5401   *    level : callback interrupt level
5402 5402   *
5403 5403   *            If the value is the zero, the callback function is invoked
5404 5404   *            in kernel context. If the value is more than the zero, but
5405 5405   *            less than or equal to ten, the callback function is invoked in
5406 5406   *            interrupt context at the specified interrupt level, which may
5407 5407   *            be used for real time applications.
5408 5408   *
5409 5409   *            This value must be in range of 0-10, which can be a numeric
5410 5410   *            number or a pre-defined macro (DDI_IPL_0, ... , DDI_IPL_10).
5411 5411   *
5412 5412   * DESCRIPTION
5413 5413   *      ddi_periodic_add(9F) schedules the specified function to be
5414 5414   *      periodically invoked in the interval time.
5415 5415   *
5416 5416   *      As well as timeout(9F), the exact time interval over which the function
5417 5417   *      takes effect cannot be guaranteed, but the value given is a close
5418 5418   *      approximation.
5419 5419   *
5420 5420   *      Drivers waiting on behalf of processes with real-time constraints must
5421 5421   *      pass non-zero value with the level argument to ddi_periodic_add(9F).
5422 5422   *
5423 5423   * RETURN VALUES
5424 5424   *      ddi_periodic_add(9F) returns a non-zero opaque value (ddi_periodic_t),
5425 5425   *      which must be used for ddi_periodic_delete(9F) to specify the request.
5426 5426   *
5427 5427   * CONTEXT
5428 5428   *      ddi_periodic_add(9F) can be called in user or kernel context, but
5429 5429   *      it cannot be called in interrupt context, which is different from
5430 5430   *      timeout(9F).
5431 5431   */
5432 5432  ddi_periodic_t
5433 5433  ddi_periodic_add(void (*func)(void *), void *arg, hrtime_t interval, int level)
5434 5434  {
5435 5435          /*
5436 5436           * Sanity check of the argument level.
5437 5437           */
5438 5438          if (level < DDI_IPL_0 || level > DDI_IPL_10)
5439 5439                  cmn_err(CE_PANIC,
5440 5440                      "ddi_periodic_add: invalid interrupt level (%d).", level);
5441 5441  
5442 5442          /*
5443 5443           * Sanity check of the context. ddi_periodic_add() cannot be
5444 5444           * called in either interrupt context or high interrupt context.
5445 5445           */
5446 5446          if (servicing_interrupt())
5447 5447                  cmn_err(CE_PANIC,
5448 5448                      "ddi_periodic_add: called in (high) interrupt context.");
5449 5449  
5450 5450          return ((ddi_periodic_t)i_timeout(func, arg, interval, level));
5451 5451  }
5452 5452  
5453 5453  /*
5454 5454   * void
5455 5455   * ddi_periodic_delete(ddi_periodic_t req)
5456 5456   *
5457 5457   * INTERFACE LEVEL
5458 5458   *     Solaris DDI specific (Solaris DDI)
5459 5459   *
5460 5460   * PARAMETERS
5461 5461   *     req: ddi_periodic_t opaque value ddi_periodic_add(9F) returned
5462 5462   *     previously.
5463 5463   *
5464 5464   * DESCRIPTION
5465 5465   *     ddi_periodic_delete(9F) cancels the ddi_periodic_add(9F) request
5466 5466   *     previously requested.
5467 5467   *
5468 5468   *     ddi_periodic_delete(9F) will not return until the pending request
5469 5469   *     is canceled or executed.
5470 5470   *
5471 5471   *     As well as untimeout(9F), calling ddi_periodic_delete(9F) for a
5472 5472   *     timeout which is either running on another CPU, or has already
5473 5473   *     completed causes no problems. However, unlike untimeout(9F), there is
5474 5474   *     no restrictions on the lock which might be held across the call to
5475 5475   *     ddi_periodic_delete(9F).
5476 5476   *
5477 5477   *     Drivers should be structured with the understanding that the arrival of
5478 5478   *     both an interrupt and a timeout for that interrupt can occasionally
5479 5479   *     occur, in either order.
5480 5480   *
5481 5481   * CONTEXT
5482 5482   *     ddi_periodic_delete(9F) can be called in user or kernel context, but
5483 5483   *     it cannot be called in interrupt context, which is different from
5484 5484   *     untimeout(9F).
5485 5485   */
5486 5486  void
5487 5487  ddi_periodic_delete(ddi_periodic_t req)
5488 5488  {
5489 5489          /*
5490 5490           * Sanity check of the context. ddi_periodic_delete() cannot be
5491 5491           * called in either interrupt context or high interrupt context.
5492 5492           */
5493 5493          if (servicing_interrupt())
5494 5494                  cmn_err(CE_PANIC,
5495 5495                      "ddi_periodic_delete: called in (high) interrupt context.");
5496 5496  
5497 5497          i_untimeout((timeout_t)req);
5498 5498  }
5499 5499  
5500 5500  dev_info_t *
5501 5501  nodevinfo(dev_t dev, int otyp)
5502 5502  {
5503 5503          _NOTE(ARGUNUSED(dev, otyp))
5504 5504          return ((dev_info_t *)0);
5505 5505  }
5506 5506  
5507 5507  /*
5508 5508   * A driver should support its own getinfo(9E) entry point. This function
5509 5509   * is provided as a convenience for ON drivers that don't expect their
5510 5510   * getinfo(9E) entry point to be called. A driver that uses this must not
5511 5511   * call ddi_create_minor_node.
5512 5512   */
5513 5513  int
5514 5514  ddi_no_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
5515 5515  {
5516 5516          _NOTE(ARGUNUSED(dip, infocmd, arg, result))
5517 5517          return (DDI_FAILURE);
5518 5518  }
5519 5519  
5520 5520  /*
5521 5521   * A driver should support its own getinfo(9E) entry point. This function
5522 5522   * is provided as a convenience for ON drivers that where the minor number
5523 5523   * is the instance. Drivers that do not have 1:1 mapping must implement
5524 5524   * their own getinfo(9E) function.
5525 5525   */
5526 5526  int
5527 5527  ddi_getinfo_1to1(dev_info_t *dip, ddi_info_cmd_t infocmd,
5528 5528      void *arg, void **result)
5529 5529  {
5530 5530          _NOTE(ARGUNUSED(dip))
5531 5531          int     instance;
5532 5532  
5533 5533          if (infocmd != DDI_INFO_DEVT2INSTANCE)
5534 5534                  return (DDI_FAILURE);
5535 5535  
5536 5536          instance = getminor((dev_t)(uintptr_t)arg);
5537 5537          *result = (void *)(uintptr_t)instance;
5538 5538          return (DDI_SUCCESS);
5539 5539  }
5540 5540  
5541 5541  int
5542 5542  ddifail(dev_info_t *devi, ddi_attach_cmd_t cmd)
5543 5543  {
5544 5544          _NOTE(ARGUNUSED(devi, cmd))
5545 5545          return (DDI_FAILURE);
5546 5546  }
5547 5547  
5548 5548  int
5549 5549  ddi_no_dma_map(dev_info_t *dip, dev_info_t *rdip,
5550 5550      struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
5551 5551  {
5552 5552          _NOTE(ARGUNUSED(dip, rdip, dmareqp, handlep))
5553 5553          return (DDI_DMA_NOMAPPING);
5554 5554  }
5555 5555  
5556 5556  int
5557 5557  ddi_no_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
5558 5558      int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
5559 5559  {
5560 5560          _NOTE(ARGUNUSED(dip, rdip, attr, waitfp, arg, handlep))
5561 5561          return (DDI_DMA_BADATTR);
5562 5562  }
5563 5563  
5564 5564  int
5565 5565  ddi_no_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
5566 5566      ddi_dma_handle_t handle)
5567 5567  {
5568 5568          _NOTE(ARGUNUSED(dip, rdip, handle))
5569 5569          return (DDI_FAILURE);
5570 5570  }
5571 5571  
5572 5572  int
5573 5573  ddi_no_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
5574 5574      ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
5575 5575      ddi_dma_cookie_t *cp, uint_t *ccountp)
5576 5576  {
5577 5577          _NOTE(ARGUNUSED(dip, rdip, handle, dmareq, cp, ccountp))
5578 5578          return (DDI_DMA_NOMAPPING);
5579 5579  }
5580 5580  
5581 5581  int
5582 5582  ddi_no_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
5583 5583      ddi_dma_handle_t handle)
5584 5584  {
5585 5585          _NOTE(ARGUNUSED(dip, rdip, handle))
5586 5586          return (DDI_FAILURE);
5587 5587  }
5588 5588  
5589 5589  int
5590 5590  ddi_no_dma_flush(dev_info_t *dip, dev_info_t *rdip,
5591 5591      ddi_dma_handle_t handle, off_t off, size_t len,
5592 5592      uint_t cache_flags)
5593 5593  {
5594 5594          _NOTE(ARGUNUSED(dip, rdip, handle, off, len, cache_flags))
5595 5595          return (DDI_FAILURE);
5596 5596  }
5597 5597  
5598 5598  int
5599 5599  ddi_no_dma_win(dev_info_t *dip, dev_info_t *rdip,
5600 5600      ddi_dma_handle_t handle, uint_t win, off_t *offp,
5601 5601      size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
5602 5602  {
5603 5603          _NOTE(ARGUNUSED(dip, rdip, handle, win, offp, lenp, cookiep, ccountp))
5604 5604          return (DDI_FAILURE);
5605 5605  }
5606 5606  
5607 5607  int
5608 5608  ddi_no_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
5609 5609      ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
5610 5610      off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
5611 5611  {
5612 5612          _NOTE(ARGUNUSED(dip, rdip, handle, request, offp, lenp, objp, flags))
5613 5613          return (DDI_FAILURE);
5614 5614  }
5615 5615  
5616 5616  void
5617 5617  ddivoid(void)
5618 5618  {}
5619 5619  
5620 5620  int
5621 5621  nochpoll(dev_t dev, short events, int anyyet, short *reventsp,
5622 5622      struct pollhead **pollhdrp)
5623 5623  {
5624 5624          _NOTE(ARGUNUSED(dev, events, anyyet, reventsp, pollhdrp))
5625 5625          return (ENXIO);
5626 5626  }
5627 5627  
5628 5628  cred_t *
5629 5629  ddi_get_cred(void)
5630 5630  {
5631 5631          return (CRED());
5632 5632  }
5633 5633  
5634 5634  clock_t
5635 5635  ddi_get_lbolt(void)
5636 5636  {
5637 5637          return ((clock_t)lbolt_hybrid());
5638 5638  }
5639 5639  
5640 5640  int64_t
5641 5641  ddi_get_lbolt64(void)
5642 5642  {
5643 5643          return (lbolt_hybrid());
5644 5644  }
5645 5645  
5646 5646  time_t
5647 5647  ddi_get_time(void)
5648 5648  {
5649 5649          time_t  now;
5650 5650  
5651 5651          if ((now = gethrestime_sec()) == 0) {
5652 5652                  timestruc_t ts;
5653 5653                  mutex_enter(&tod_lock);
5654 5654                  ts = tod_get();
5655 5655                  mutex_exit(&tod_lock);
5656 5656                  return (ts.tv_sec);
5657 5657          } else {
5658 5658                  return (now);
5659 5659          }
5660 5660  }
5661 5661  
5662 5662  pid_t
5663 5663  ddi_get_pid(void)
5664 5664  {
5665 5665          return (ttoproc(curthread)->p_pid);
5666 5666  }
5667 5667  
5668 5668  kt_did_t
5669 5669  ddi_get_kt_did(void)
5670 5670  {
5671 5671          return (curthread->t_did);
5672 5672  }
5673 5673  
5674 5674  /*
5675 5675   * This function returns B_TRUE if the caller can reasonably expect that a call
5676 5676   * to cv_wait_sig(9F), cv_timedwait_sig(9F), or qwait_sig(9F) could be awakened
5677 5677   * by user-level signal.  If it returns B_FALSE, then the caller should use
5678 5678   * other means to make certain that the wait will not hang "forever."
5679 5679   *
5680 5680   * It does not check the signal mask, nor for reception of any particular
5681 5681   * signal.
5682 5682   *
5683 5683   * Currently, a thread can receive a signal if it's not a kernel thread and it
5684 5684   * is not in the middle of exit(2) tear-down.  Threads that are in that
5685 5685   * tear-down effectively convert cv_wait_sig to cv_wait, cv_timedwait_sig to
5686 5686   * cv_timedwait, and qwait_sig to qwait.
5687 5687   */
5688 5688  boolean_t
5689 5689  ddi_can_receive_sig(void)
5690 5690  {
5691 5691          proc_t *pp;
5692 5692  
5693 5693          if (curthread->t_proc_flag & TP_LWPEXIT)
5694 5694                  return (B_FALSE);
5695 5695          if ((pp = ttoproc(curthread)) == NULL)
5696 5696                  return (B_FALSE);
5697 5697          return (pp->p_as != &kas);
5698 5698  }
5699 5699  
5700 5700  /*
5701 5701   * Swap bytes in 16-bit [half-]words
5702 5702   */
5703 5703  void
5704 5704  swab(void *src, void *dst, size_t nbytes)
5705 5705  {
5706 5706          uchar_t *pf = (uchar_t *)src;
5707 5707          uchar_t *pt = (uchar_t *)dst;
5708 5708          uchar_t tmp;
5709 5709          int nshorts;
5710 5710  
5711 5711          nshorts = nbytes >> 1;
5712 5712  
5713 5713          while (--nshorts >= 0) {
5714 5714                  tmp = *pf++;
5715 5715                  *pt++ = *pf++;
5716 5716                  *pt++ = tmp;
5717 5717          }
5718 5718  }
5719 5719  
5720 5720  static void
5721 5721  ddi_append_minor_node(dev_info_t *ddip, struct ddi_minor_data *dmdp)
5722 5722  {
5723 5723          int                     circ;
5724 5724          struct ddi_minor_data   *dp;
5725 5725  
5726 5726          ndi_devi_enter(ddip, &circ);
5727 5727          if ((dp = DEVI(ddip)->devi_minor) == (struct ddi_minor_data *)NULL) {
5728 5728                  DEVI(ddip)->devi_minor = dmdp;
5729 5729          } else {
5730 5730                  while (dp->next != (struct ddi_minor_data *)NULL)
5731 5731                          dp = dp->next;
5732 5732                  dp->next = dmdp;
5733 5733          }
5734 5734          ndi_devi_exit(ddip, circ);
5735 5735  }
5736 5736  
5737 5737  /*
5738 5738   * Part of the obsolete SunCluster DDI Hooks.
5739 5739   * Keep for binary compatibility
5740 5740   */
5741 5741  minor_t
5742 5742  ddi_getiminor(dev_t dev)
5743 5743  {
5744 5744          return (getminor(dev));
5745 5745  }
5746 5746  
5747 5747  static int
5748 5748  i_log_devfs_minor_create(dev_info_t *dip, char *minor_name)
5749 5749  {
5750 5750          int se_flag;
5751 5751          int kmem_flag;
5752 5752          int se_err;
5753 5753          char *pathname, *class_name;
5754 5754          sysevent_t *ev = NULL;
5755 5755          sysevent_id_t eid;
5756 5756          sysevent_value_t se_val;
5757 5757          sysevent_attr_list_t *ev_attr_list = NULL;
5758 5758  
5759 5759          /* determine interrupt context */
5760 5760          se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP;
5761 5761          kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
5762 5762  
5763 5763          i_ddi_di_cache_invalidate();
5764 5764  
5765 5765  #ifdef DEBUG
5766 5766          if ((se_flag == SE_NOSLEEP) && sunddi_debug) {
5767 5767                  cmn_err(CE_CONT, "ddi_create_minor_node: called from "
5768 5768                      "interrupt level by driver %s",
5769 5769                      ddi_driver_name(dip));
5770 5770          }
5771 5771  #endif /* DEBUG */
5772 5772  
5773 5773          ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_MINOR_CREATE, EP_DDI, se_flag);
5774 5774          if (ev == NULL) {
5775 5775                  goto fail;
5776 5776          }
5777 5777  
5778 5778          pathname = kmem_alloc(MAXPATHLEN, kmem_flag);
5779 5779          if (pathname == NULL) {
5780 5780                  sysevent_free(ev);
5781 5781                  goto fail;
5782 5782          }
5783 5783  
5784 5784          (void) ddi_pathname(dip, pathname);
5785 5785          ASSERT(strlen(pathname));
5786 5786          se_val.value_type = SE_DATA_TYPE_STRING;
5787 5787          se_val.value.sv_string = pathname;
5788 5788          if (sysevent_add_attr(&ev_attr_list, DEVFS_PATHNAME,
5789 5789              &se_val, se_flag) != 0) {
5790 5790                  kmem_free(pathname, MAXPATHLEN);
5791 5791                  sysevent_free(ev);
5792 5792                  goto fail;
5793 5793          }
5794 5794          kmem_free(pathname, MAXPATHLEN);
5795 5795  
5796 5796          /* add the device class attribute */
5797 5797          if ((class_name = i_ddi_devi_class(dip)) != NULL) {
5798 5798                  se_val.value_type = SE_DATA_TYPE_STRING;
5799 5799                  se_val.value.sv_string = class_name;
5800 5800                  if (sysevent_add_attr(&ev_attr_list,
5801 5801                      DEVFS_DEVI_CLASS, &se_val, SE_SLEEP) != 0) {
5802 5802                          sysevent_free_attr(ev_attr_list);
5803 5803                          goto fail;
5804 5804                  }
5805 5805          }
5806 5806  
5807 5807          /*
5808 5808           * allow for NULL minor names
5809 5809           */
5810 5810          if (minor_name != NULL) {
5811 5811                  se_val.value.sv_string = minor_name;
5812 5812                  if (sysevent_add_attr(&ev_attr_list, DEVFS_MINOR_NAME,
5813 5813                      &se_val, se_flag) != 0) {
5814 5814                          sysevent_free_attr(ev_attr_list);
5815 5815                          sysevent_free(ev);
5816 5816                          goto fail;
5817 5817                  }
5818 5818          }
5819 5819  
5820 5820          if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
5821 5821                  sysevent_free_attr(ev_attr_list);
5822 5822                  sysevent_free(ev);
5823 5823                  goto fail;
5824 5824          }
5825 5825  
5826 5826          if ((se_err = log_sysevent(ev, se_flag, &eid)) != 0) {
5827 5827                  if (se_err == SE_NO_TRANSPORT) {
5828 5828                          cmn_err(CE_WARN, "/devices or /dev may not be current "
5829 5829                              "for driver %s (%s). Run devfsadm -i %s",
5830 5830                              ddi_driver_name(dip), "syseventd not responding",
5831 5831                              ddi_driver_name(dip));
5832 5832                  } else {
5833 5833                          sysevent_free(ev);
5834 5834                          goto fail;
5835 5835                  }
5836 5836          }
5837 5837  
5838 5838          sysevent_free(ev);
5839 5839          return (DDI_SUCCESS);
5840 5840  fail:
5841 5841          cmn_err(CE_WARN, "/devices or /dev may not be current "
5842 5842              "for driver %s. Run devfsadm -i %s",
5843 5843              ddi_driver_name(dip), ddi_driver_name(dip));
5844 5844          return (DDI_SUCCESS);
5845 5845  }
5846 5846  
5847 5847  /*
5848 5848   * failing to remove a minor node is not of interest
5849 5849   * therefore we do not generate an error message
5850 5850   */
5851 5851  static int
5852 5852  i_log_devfs_minor_remove(dev_info_t *dip, char *minor_name)
5853 5853  {
5854 5854          char *pathname, *class_name;
5855 5855          sysevent_t *ev;
5856 5856          sysevent_id_t eid;
5857 5857          sysevent_value_t se_val;
5858 5858          sysevent_attr_list_t *ev_attr_list = NULL;
5859 5859  
5860 5860          /*
5861 5861           * only log ddi_remove_minor_node() calls outside the scope
5862 5862           * of attach/detach reconfigurations and when the dip is
5863 5863           * still initialized.
5864 5864           */
5865 5865          if (DEVI_IS_ATTACHING(dip) || DEVI_IS_DETACHING(dip) ||
5866 5866              (i_ddi_node_state(dip) < DS_INITIALIZED)) {
5867 5867                  return (DDI_SUCCESS);
5868 5868          }
5869 5869  
5870 5870          i_ddi_di_cache_invalidate();
5871 5871  
5872 5872          ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_MINOR_REMOVE, EP_DDI, SE_SLEEP);
5873 5873          if (ev == NULL) {
5874 5874                  return (DDI_SUCCESS);
5875 5875          }
5876 5876  
5877 5877          pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
5878 5878          if (pathname == NULL) {
5879 5879                  sysevent_free(ev);
5880 5880                  return (DDI_SUCCESS);
5881 5881          }
5882 5882  
5883 5883          (void) ddi_pathname(dip, pathname);
5884 5884          ASSERT(strlen(pathname));
5885 5885          se_val.value_type = SE_DATA_TYPE_STRING;
5886 5886          se_val.value.sv_string = pathname;
5887 5887          if (sysevent_add_attr(&ev_attr_list, DEVFS_PATHNAME,
5888 5888              &se_val, SE_SLEEP) != 0) {
5889 5889                  kmem_free(pathname, MAXPATHLEN);
5890 5890                  sysevent_free(ev);
5891 5891                  return (DDI_SUCCESS);
5892 5892          }
5893 5893  
5894 5894          kmem_free(pathname, MAXPATHLEN);
5895 5895  
5896 5896          /*
5897 5897           * allow for NULL minor names
5898 5898           */
5899 5899          if (minor_name != NULL) {
5900 5900                  se_val.value.sv_string = minor_name;
5901 5901                  if (sysevent_add_attr(&ev_attr_list, DEVFS_MINOR_NAME,
5902 5902                      &se_val, SE_SLEEP) != 0) {
5903 5903                          sysevent_free_attr(ev_attr_list);
5904 5904                          goto fail;
5905 5905                  }
5906 5906          }
5907 5907  
5908 5908          if ((class_name = i_ddi_devi_class(dip)) != NULL) {
5909 5909                  /* add the device class, driver name and instance attributes */
5910 5910  
5911 5911                  se_val.value_type = SE_DATA_TYPE_STRING;
5912 5912                  se_val.value.sv_string = class_name;
5913 5913                  if (sysevent_add_attr(&ev_attr_list,
5914 5914                      DEVFS_DEVI_CLASS, &se_val, SE_SLEEP) != 0) {
5915 5915                          sysevent_free_attr(ev_attr_list);
5916 5916                          goto fail;
5917 5917                  }
5918 5918  
5919 5919                  se_val.value_type = SE_DATA_TYPE_STRING;
5920 5920                  se_val.value.sv_string = (char *)ddi_driver_name(dip);
5921 5921                  if (sysevent_add_attr(&ev_attr_list,
5922 5922                      DEVFS_DRIVER_NAME, &se_val, SE_SLEEP) != 0) {
5923 5923                          sysevent_free_attr(ev_attr_list);
5924 5924                          goto fail;
5925 5925                  }
5926 5926  
5927 5927                  se_val.value_type = SE_DATA_TYPE_INT32;
5928 5928                  se_val.value.sv_int32 = ddi_get_instance(dip);
5929 5929                  if (sysevent_add_attr(&ev_attr_list,
5930 5930                      DEVFS_INSTANCE, &se_val, SE_SLEEP) != 0) {
5931 5931                          sysevent_free_attr(ev_attr_list);
5932 5932                          goto fail;
5933 5933                  }
5934 5934  
5935 5935          }
5936 5936  
5937 5937          if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
5938 5938                  sysevent_free_attr(ev_attr_list);
5939 5939          } else {
5940 5940                  (void) log_sysevent(ev, SE_SLEEP, &eid);
5941 5941          }
5942 5942  fail:
5943 5943          sysevent_free(ev);
5944 5944          return (DDI_SUCCESS);
5945 5945  }
5946 5946  
5947 5947  /*
5948 5948   * Derive the device class of the node.
5949 5949   * Device class names aren't defined yet. Until this is done we use
5950 5950   * devfs event subclass names as device class names.
5951 5951   */
5952 5952  static int
5953 5953  derive_devi_class(dev_info_t *dip, char *node_type, int flag)
5954 5954  {
5955 5955          int rv = DDI_SUCCESS;
5956 5956  
5957 5957          if (i_ddi_devi_class(dip) == NULL) {
5958 5958                  if (strncmp(node_type, DDI_NT_BLOCK,
5959 5959                      sizeof (DDI_NT_BLOCK) - 1) == 0 &&
5960 5960                      (node_type[sizeof (DDI_NT_BLOCK) - 1] == '\0' ||
5961 5961                      node_type[sizeof (DDI_NT_BLOCK) - 1] == ':') &&
5962 5962                      strcmp(node_type, DDI_NT_FD) != 0) {
5963 5963  
5964 5964                          rv = i_ddi_set_devi_class(dip, ESC_DISK, flag);
5965 5965  
5966 5966                  } else if (strncmp(node_type, DDI_NT_NET,
5967 5967                      sizeof (DDI_NT_NET) - 1) == 0 &&
5968 5968                      (node_type[sizeof (DDI_NT_NET) - 1] == '\0' ||
5969 5969                      node_type[sizeof (DDI_NT_NET) - 1] == ':')) {
5970 5970  
5971 5971                          rv = i_ddi_set_devi_class(dip, ESC_NETWORK, flag);
5972 5972  
5973 5973                  } else if (strncmp(node_type, DDI_NT_PRINTER,
5974 5974                      sizeof (DDI_NT_PRINTER) - 1) == 0 &&
5975 5975                      (node_type[sizeof (DDI_NT_PRINTER) - 1] == '\0' ||
5976 5976                      node_type[sizeof (DDI_NT_PRINTER) - 1] == ':')) {
5977 5977  
5978 5978                          rv = i_ddi_set_devi_class(dip, ESC_PRINTER, flag);
5979 5979  
5980 5980                  } else if (strncmp(node_type, DDI_PSEUDO,
5981 5981                      sizeof (DDI_PSEUDO) -1) == 0 &&
5982 5982                      (strncmp(ESC_LOFI, ddi_node_name(dip),
5983 5983                      sizeof (ESC_LOFI) -1) == 0)) {
5984 5984                          rv = i_ddi_set_devi_class(dip, ESC_LOFI, flag);
5985 5985                  }
5986 5986          }
5987 5987  
5988 5988          return (rv);
5989 5989  }
5990 5990  
5991 5991  /*
5992 5992   * Check compliance with PSARC 2003/375:
5993 5993   *
5994 5994   * The name must contain only characters a-z, A-Z, 0-9 or _ and it must not
5995 5995   * exceed IFNAMSIZ (16) characters in length.
5996 5996   */
5997 5997  static boolean_t
5998 5998  verify_name(char *name)
5999 5999  {
6000 6000          size_t  len = strlen(name);
6001 6001          char    *cp;
6002 6002  
6003 6003          if (len == 0 || len > IFNAMSIZ)
6004 6004                  return (B_FALSE);
6005 6005  
6006 6006          for (cp = name; *cp != '\0'; cp++) {
6007 6007                  if (!isalnum(*cp) && *cp != '_')
6008 6008                          return (B_FALSE);
6009 6009          }
6010 6010  
6011 6011          return (B_TRUE);
6012 6012  }
6013 6013  
6014 6014  /*
6015 6015   * ddi_create_minor_common:     Create a  ddi_minor_data structure and
6016 6016   *                              attach it to the given devinfo node.
6017 6017   */
6018 6018  
6019 6019  int
6020 6020  ddi_create_minor_common(dev_info_t *dip, char *name, int spec_type,
6021 6021      minor_t minor_num, char *node_type, int flag, ddi_minor_type mtype,
6022 6022      const char *read_priv, const char *write_priv, mode_t priv_mode)
6023 6023  {
6024 6024          struct ddi_minor_data *dmdp;
6025 6025          major_t major;
6026 6026  
6027 6027          if (spec_type != S_IFCHR && spec_type != S_IFBLK)
6028 6028                  return (DDI_FAILURE);
6029 6029  
6030 6030          if (name == NULL)
6031 6031                  return (DDI_FAILURE);
6032 6032  
6033 6033          /*
6034 6034           * Log a message if the minor number the driver is creating
6035 6035           * is not expressible on the on-disk filesystem (currently
6036 6036           * this is limited to 18 bits both by UFS). The device can
6037 6037           * be opened via devfs, but not by device special files created
6038 6038           * via mknod().
6039 6039           */
6040 6040          if (minor_num > L_MAXMIN32) {
6041 6041                  cmn_err(CE_WARN,
6042 6042                      "%s%d:%s minor 0x%x too big for 32-bit applications",
6043 6043                      ddi_driver_name(dip), ddi_get_instance(dip),
6044 6044                      name, minor_num);
6045 6045                  return (DDI_FAILURE);
6046 6046          }
6047 6047  
6048 6048          /* dip must be bound and attached */
6049 6049          major = ddi_driver_major(dip);
6050 6050          ASSERT(major != DDI_MAJOR_T_NONE);
6051 6051  
6052 6052          /*
6053 6053           * Default node_type to DDI_PSEUDO and issue notice in debug mode
6054 6054           */
6055 6055          if (node_type == NULL) {
6056 6056                  node_type = DDI_PSEUDO;
6057 6057                  NDI_CONFIG_DEBUG((CE_NOTE, "!illegal node_type NULL for %s%d "
6058 6058                      " minor node %s; default to DDI_PSEUDO",
6059 6059                      ddi_driver_name(dip), ddi_get_instance(dip), name));
6060 6060          }
6061 6061  
6062 6062          /*
6063 6063           * If the driver is a network driver, ensure that the name falls within
6064 6064           * the interface naming constraints specified by PSARC/2003/375.
6065 6065           */
6066 6066          if (strcmp(node_type, DDI_NT_NET) == 0) {
6067 6067                  if (!verify_name(name))
6068 6068                          return (DDI_FAILURE);
6069 6069  
6070 6070                  if (mtype == DDM_MINOR) {
6071 6071                          struct devnames *dnp = &devnamesp[major];
6072 6072  
6073 6073                          /* Mark driver as a network driver */
6074 6074                          LOCK_DEV_OPS(&dnp->dn_lock);
6075 6075                          dnp->dn_flags |= DN_NETWORK_DRIVER;
6076 6076  
6077 6077                          /*
6078 6078                           * If this minor node is created during the device
6079 6079                           * attachment, this is a physical network device.
6080 6080                           * Mark the driver as a physical network driver.
6081 6081                           */
6082 6082                          if (DEVI_IS_ATTACHING(dip))
6083 6083                                  dnp->dn_flags |= DN_NETWORK_PHYSDRIVER;
6084 6084                          UNLOCK_DEV_OPS(&dnp->dn_lock);
6085 6085                  }
6086 6086          }
6087 6087  
6088 6088          if (mtype == DDM_MINOR) {
6089 6089                  if (derive_devi_class(dip,  node_type, KM_NOSLEEP) !=
6090 6090                      DDI_SUCCESS)
6091 6091                          return (DDI_FAILURE);
6092 6092          }
6093 6093  
6094 6094          /*
6095 6095           * Take care of minor number information for the node.
6096 6096           */
6097 6097  
6098 6098          if ((dmdp = kmem_zalloc(sizeof (struct ddi_minor_data),
6099 6099              KM_NOSLEEP)) == NULL) {
6100 6100                  return (DDI_FAILURE);
6101 6101          }
6102 6102          if ((dmdp->ddm_name = i_ddi_strdup(name, KM_NOSLEEP)) == NULL) {
6103 6103                  kmem_free(dmdp, sizeof (struct ddi_minor_data));
6104 6104                  return (DDI_FAILURE);
6105 6105          }
6106 6106          dmdp->dip = dip;
6107 6107          dmdp->ddm_dev = makedevice(major, minor_num);
6108 6108          dmdp->ddm_spec_type = spec_type;
6109 6109          dmdp->ddm_node_type = node_type;
6110 6110          dmdp->type = mtype;
6111 6111          if (flag & CLONE_DEV) {
6112 6112                  dmdp->type = DDM_ALIAS;
6113 6113                  dmdp->ddm_dev = makedevice(ddi_driver_major(clone_dip), major);
6114 6114          }
6115 6115          if (flag & PRIVONLY_DEV) {
6116 6116                  dmdp->ddm_flags |= DM_NO_FSPERM;
6117 6117          }
6118 6118          if (read_priv || write_priv) {
6119 6119                  dmdp->ddm_node_priv =
6120 6120                      devpolicy_priv_by_name(read_priv, write_priv);
6121 6121          }
6122 6122          dmdp->ddm_priv_mode = priv_mode;
6123 6123  
6124 6124          ddi_append_minor_node(dip, dmdp);
6125 6125  
6126 6126          /*
6127 6127           * only log ddi_create_minor_node() calls which occur
6128 6128           * outside the scope of attach(9e)/detach(9e) reconfigurations
6129 6129           */
6130 6130          if (!(DEVI_IS_ATTACHING(dip) || DEVI_IS_DETACHING(dip)) &&
6131 6131              mtype != DDM_INTERNAL_PATH) {
6132 6132                  (void) i_log_devfs_minor_create(dip, name);
6133 6133          }
6134 6134  
6135 6135          /*
6136 6136           * Check if any dacf rules match the creation of this minor node
6137 6137           */
6138 6138          dacfc_match_create_minor(name, node_type, dip, dmdp, flag);
6139 6139          return (DDI_SUCCESS);
6140 6140  }
6141 6141  
6142 6142  int
6143 6143  ddi_create_minor_node(dev_info_t *dip, char *name, int spec_type,
6144 6144      minor_t minor_num, char *node_type, int flag)
6145 6145  {
6146 6146          return (ddi_create_minor_common(dip, name, spec_type, minor_num,
6147 6147              node_type, flag, DDM_MINOR, NULL, NULL, 0));
6148 6148  }
6149 6149  
6150 6150  int
6151 6151  ddi_create_priv_minor_node(dev_info_t *dip, char *name, int spec_type,
6152 6152      minor_t minor_num, char *node_type, int flag,
6153 6153      const char *rdpriv, const char *wrpriv, mode_t priv_mode)
6154 6154  {
6155 6155          return (ddi_create_minor_common(dip, name, spec_type, minor_num,
6156 6156              node_type, flag, DDM_MINOR, rdpriv, wrpriv, priv_mode));
6157 6157  }
6158 6158  
6159 6159  int
6160 6160  ddi_create_default_minor_node(dev_info_t *dip, char *name, int spec_type,
6161 6161      minor_t minor_num, char *node_type, int flag)
6162 6162  {
6163 6163          return (ddi_create_minor_common(dip, name, spec_type, minor_num,
6164 6164              node_type, flag, DDM_DEFAULT, NULL, NULL, 0));
6165 6165  }
6166 6166  
6167 6167  /*
6168 6168   * Internal (non-ddi) routine for drivers to export names known
6169 6169   * to the kernel (especially ddi_pathname_to_dev_t and friends)
6170 6170   * but not exported externally to /dev
6171 6171   */
6172 6172  int
6173 6173  ddi_create_internal_pathname(dev_info_t *dip, char *name, int spec_type,
6174 6174      minor_t minor_num)
6175 6175  {
6176 6176          return (ddi_create_minor_common(dip, name, spec_type, minor_num,
6177 6177              "internal", 0, DDM_INTERNAL_PATH, NULL, NULL, 0));
6178 6178  }
6179 6179  
6180 6180  void
6181 6181  ddi_remove_minor_node(dev_info_t *dip, char *name)
6182 6182  {
6183 6183          int                     circ;
6184 6184          struct ddi_minor_data   *dmdp, *dmdp1;
6185 6185          struct ddi_minor_data   **dmdp_prev;
6186 6186  
6187 6187          ndi_devi_enter(dip, &circ);
6188 6188          dmdp_prev = &DEVI(dip)->devi_minor;
6189 6189          dmdp = DEVI(dip)->devi_minor;
6190 6190          while (dmdp != NULL) {
6191 6191                  dmdp1 = dmdp->next;
6192 6192                  if ((name == NULL || (dmdp->ddm_name != NULL &&
6193 6193                      strcmp(name, dmdp->ddm_name) == 0))) {
6194 6194                          if (dmdp->ddm_name != NULL) {
6195 6195                                  if (dmdp->type != DDM_INTERNAL_PATH)
6196 6196                                          (void) i_log_devfs_minor_remove(dip,
6197 6197                                              dmdp->ddm_name);
6198 6198                                  kmem_free(dmdp->ddm_name,
6199 6199                                      strlen(dmdp->ddm_name) + 1);
6200 6200                          }
6201 6201                          /*
6202 6202                           * Release device privilege, if any.
6203 6203                           * Release dacf client data associated with this minor
6204 6204                           * node by storing NULL.
6205 6205                           */
6206 6206                          if (dmdp->ddm_node_priv)
6207 6207                                  dpfree(dmdp->ddm_node_priv);
6208 6208                          dacf_store_info((dacf_infohdl_t)dmdp, NULL);
6209 6209                          kmem_free(dmdp, sizeof (struct ddi_minor_data));
6210 6210                          *dmdp_prev = dmdp1;
6211 6211                          /*
6212 6212                           * OK, we found it, so get out now -- if we drive on,
6213 6213                           * we will strcmp against garbage.  See 1139209.
6214 6214                           */
6215 6215                          if (name != NULL)
6216 6216                                  break;
6217 6217                  } else {
6218 6218                          dmdp_prev = &dmdp->next;
6219 6219                  }
6220 6220                  dmdp = dmdp1;
6221 6221          }
6222 6222          ndi_devi_exit(dip, circ);
6223 6223  }
6224 6224  
6225 6225  
6226 6226  int
6227 6227  ddi_in_panic()
6228 6228  {
6229 6229          return (panicstr != NULL);
6230 6230  }
6231 6231  
6232 6232  
6233 6233  /*
6234 6234   * Find first bit set in a mask (returned counting from 1 up)
6235 6235   */
6236 6236  
6237 6237  int
6238 6238  ddi_ffs(long mask)
6239 6239  {
6240 6240          return (ffs(mask));
6241 6241  }
6242 6242  
6243 6243  /*
6244 6244   * Find last bit set. Take mask and clear
6245 6245   * all but the most significant bit, and
6246 6246   * then let ffs do the rest of the work.
6247 6247   *
6248 6248   * Algorithm courtesy of Steve Chessin.
6249 6249   */
6250 6250  
6251 6251  int
6252 6252  ddi_fls(long mask)
6253 6253  {
6254 6254          while (mask) {
6255 6255                  long nx;
6256 6256  
6257 6257                  if ((nx = (mask & (mask - 1))) == 0)
6258 6258                          break;
6259 6259                  mask = nx;
6260 6260          }
6261 6261          return (ffs(mask));
6262 6262  }
6263 6263  
6264 6264  /*
6265 6265   * The ddi_soft_state_* routines comprise generic storage management utilities
6266 6266   * for driver soft state structures (in "the old days," this was done with
6267 6267   * statically sized array - big systems and dynamic loading and unloading
6268 6268   * make heap allocation more attractive).
6269 6269   */
6270 6270  
6271 6271  /*
6272 6272   * Allocate a set of pointers to 'n_items' objects of size 'size'
6273 6273   * bytes.  Each pointer is initialized to nil.
6274 6274   *
6275 6275   * The 'size' and 'n_items' values are stashed in the opaque
6276 6276   * handle returned to the caller.
6277 6277   *
6278 6278   * This implementation interprets 'set of pointers' to mean 'array
6279 6279   * of pointers' but note that nothing in the interface definition
6280 6280   * precludes an implementation that uses, for example, a linked list.
6281 6281   * However there should be a small efficiency gain from using an array
6282 6282   * at lookup time.
6283 6283   *
6284 6284   * NOTE As an optimization, we make our growable array allocations in
6285 6285   *      powers of two (bytes), since that's how much kmem_alloc (currently)
6286 6286   *      gives us anyway.  It should save us some free/realloc's ..
6287 6287   *
6288 6288   *      As a further optimization, we make the growable array start out
6289 6289   *      with MIN_N_ITEMS in it.
6290 6290   */
6291 6291  
6292 6292  #define MIN_N_ITEMS     8       /* 8 void *'s == 32 bytes */
6293 6293  
6294 6294  int
6295 6295  ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
6296 6296  {
6297 6297          i_ddi_soft_state        *ss;
6298 6298  
6299 6299          if (state_p == NULL || size == 0)
6300 6300                  return (EINVAL);
6301 6301  
6302 6302          ss = kmem_zalloc(sizeof (*ss), KM_SLEEP);
6303 6303          mutex_init(&ss->lock, NULL, MUTEX_DRIVER, NULL);
6304 6304          ss->size = size;
6305 6305  
6306 6306          if (n_items < MIN_N_ITEMS)
6307 6307                  ss->n_items = MIN_N_ITEMS;
6308 6308          else {
6309 6309                  int bitlog;
6310 6310  
6311 6311                  if ((bitlog = ddi_fls(n_items)) == ddi_ffs(n_items))
6312 6312                          bitlog--;
6313 6313                  ss->n_items = 1 << bitlog;
6314 6314          }
6315 6315  
6316 6316          ASSERT(ss->n_items >= n_items);
6317 6317  
6318 6318          ss->array = kmem_zalloc(ss->n_items * sizeof (void *), KM_SLEEP);
6319 6319  
6320 6320          *state_p = ss;
6321 6321          return (0);
6322 6322  }
6323 6323  
6324 6324  /*
6325 6325   * Allocate a state structure of size 'size' to be associated
6326 6326   * with item 'item'.
6327 6327   *
6328 6328   * In this implementation, the array is extended to
6329 6329   * allow the requested offset, if needed.
6330 6330   */
6331 6331  int
6332 6332  ddi_soft_state_zalloc(void *state, int item)
6333 6333  {
6334 6334          i_ddi_soft_state        *ss = (i_ddi_soft_state *)state;
6335 6335          void                    **array;
6336 6336          void                    *new_element;
6337 6337  
6338 6338          if ((state == NULL) || (item < 0))
6339 6339                  return (DDI_FAILURE);
6340 6340  
6341 6341          mutex_enter(&ss->lock);
6342 6342          if (ss->size == 0) {
6343 6343                  mutex_exit(&ss->lock);
6344 6344                  cmn_err(CE_WARN, "ddi_soft_state_zalloc: bad handle: %s",
6345 6345                      mod_containing_pc(caller()));
6346 6346                  return (DDI_FAILURE);
6347 6347          }
6348 6348  
6349 6349          array = ss->array;      /* NULL if ss->n_items == 0 */
6350 6350          ASSERT(ss->n_items != 0 && array != NULL);
6351 6351  
6352 6352          /*
6353 6353           * refuse to tread on an existing element
6354 6354           */
6355 6355          if (item < ss->n_items && array[item] != NULL) {
6356 6356                  mutex_exit(&ss->lock);
6357 6357                  return (DDI_FAILURE);
6358 6358          }
6359 6359  
6360 6360          /*
6361 6361           * Allocate a new element to plug in
6362 6362           */
6363 6363          new_element = kmem_zalloc(ss->size, KM_SLEEP);
6364 6364  
6365 6365          /*
6366 6366           * Check if the array is big enough, if not, grow it.
6367 6367           */
6368 6368          if (item >= ss->n_items) {
6369 6369                  void                    **new_array;
6370 6370                  size_t                  new_n_items;
6371 6371                  struct i_ddi_soft_state *dirty;
6372 6372  
6373 6373                  /*
6374 6374                   * Allocate a new array of the right length, copy
6375 6375                   * all the old pointers to the new array, then
6376 6376                   * if it exists at all, put the old array on the
6377 6377                   * dirty list.
6378 6378                   *
6379 6379                   * Note that we can't kmem_free() the old array.
6380 6380                   *
6381 6381                   * Why -- well the 'get' operation is 'mutex-free', so we
6382 6382                   * can't easily catch a suspended thread that is just about
6383 6383                   * to dereference the array we just grew out of.  So we
6384 6384                   * cons up a header and put it on a list of 'dirty'
6385 6385                   * pointer arrays.  (Dirty in the sense that there may
6386 6386                   * be suspended threads somewhere that are in the middle
6387 6387                   * of referencing them).  Fortunately, we -can- garbage
6388 6388                   * collect it all at ddi_soft_state_fini time.
6389 6389                   */
6390 6390                  new_n_items = ss->n_items;
6391 6391                  while (new_n_items < (1 + item))
6392 6392                          new_n_items <<= 1;      /* double array size .. */
6393 6393  
6394 6394                  ASSERT(new_n_items >= (1 + item));      /* sanity check! */
6395 6395  
6396 6396                  new_array = kmem_zalloc(new_n_items * sizeof (void *),
6397 6397                      KM_SLEEP);
6398 6398                  /*
6399 6399                   * Copy the pointers into the new array
6400 6400                   */
6401 6401                  bcopy(array, new_array, ss->n_items * sizeof (void *));
6402 6402  
6403 6403                  /*
6404 6404                   * Save the old array on the dirty list
6405 6405                   */
6406 6406                  dirty = kmem_zalloc(sizeof (*dirty), KM_SLEEP);
6407 6407                  dirty->array = ss->array;
6408 6408                  dirty->n_items = ss->n_items;
6409 6409                  dirty->next = ss->next;
6410 6410                  ss->next = dirty;
6411 6411  
6412 6412                  ss->array = (array = new_array);
6413 6413                  ss->n_items = new_n_items;
6414 6414          }
6415 6415  
6416 6416          ASSERT(array != NULL && item < ss->n_items && array[item] == NULL);
6417 6417  
6418 6418          array[item] = new_element;
6419 6419  
6420 6420          mutex_exit(&ss->lock);
6421 6421          return (DDI_SUCCESS);
6422 6422  }
6423 6423  
6424 6424  /*
6425 6425   * Fetch a pointer to the allocated soft state structure.
6426 6426   *
6427 6427   * This is designed to be cheap.
6428 6428   *
6429 6429   * There's an argument that there should be more checking for
6430 6430   * nil pointers and out of bounds on the array.. but we do a lot
6431 6431   * of that in the alloc/free routines.
6432 6432   *
6433 6433   * An array has the convenience that we don't need to lock read-access
6434 6434   * to it c.f. a linked list.  However our "expanding array" strategy
6435 6435   * means that we should hold a readers lock on the i_ddi_soft_state
6436 6436   * structure.
6437 6437   *
6438 6438   * However, from a performance viewpoint, we need to do it without
6439 6439   * any locks at all -- this also makes it a leaf routine.  The algorithm
6440 6440   * is 'lock-free' because we only discard the pointer arrays at
6441 6441   * ddi_soft_state_fini() time.
6442 6442   */
6443 6443  void *
6444 6444  ddi_get_soft_state(void *state, int item)
6445 6445  {
6446 6446          i_ddi_soft_state        *ss = (i_ddi_soft_state *)state;
6447 6447  
6448 6448          ASSERT((ss != NULL) && (item >= 0));
6449 6449  
6450 6450          if (item < ss->n_items && ss->array != NULL)
6451 6451                  return (ss->array[item]);
6452 6452          return (NULL);
6453 6453  }
6454 6454  
6455 6455  /*
6456 6456   * Free the state structure corresponding to 'item.'   Freeing an
6457 6457   * element that has either gone or was never allocated is not
6458 6458   * considered an error.  Note that we free the state structure, but
6459 6459   * we don't shrink our pointer array, or discard 'dirty' arrays,
6460 6460   * since even a few pointers don't really waste too much memory.
6461 6461   *
6462 6462   * Passing an item number that is out of bounds, or a null pointer will
6463 6463   * provoke an error message.
6464 6464   */
6465 6465  void
6466 6466  ddi_soft_state_free(void *state, int item)
6467 6467  {
6468 6468          i_ddi_soft_state        *ss = (i_ddi_soft_state *)state;
6469 6469          void                    **array;
6470 6470          void                    *element;
6471 6471          static char             msg[] = "ddi_soft_state_free:";
6472 6472  
6473 6473          if (ss == NULL) {
6474 6474                  cmn_err(CE_WARN, "%s null handle: %s",
6475 6475                      msg, mod_containing_pc(caller()));
6476 6476                  return;
6477 6477          }
6478 6478  
6479 6479          element = NULL;
6480 6480  
6481 6481          mutex_enter(&ss->lock);
6482 6482  
6483 6483          if ((array = ss->array) == NULL || ss->size == 0) {
6484 6484                  cmn_err(CE_WARN, "%s bad handle: %s",
6485 6485                      msg, mod_containing_pc(caller()));
6486 6486          } else if (item < 0 || item >= ss->n_items) {
6487 6487                  cmn_err(CE_WARN, "%s item %d not in range [0..%lu]: %s",
6488 6488                      msg, item, ss->n_items - 1, mod_containing_pc(caller()));
6489 6489          } else if (array[item] != NULL) {
6490 6490                  element = array[item];
6491 6491                  array[item] = NULL;
6492 6492          }
6493 6493  
6494 6494          mutex_exit(&ss->lock);
6495 6495  
6496 6496          if (element)
6497 6497                  kmem_free(element, ss->size);
6498 6498  }
6499 6499  
6500 6500  /*
6501 6501   * Free the entire set of pointers, and any
6502 6502   * soft state structures contained therein.
6503 6503   *
6504 6504   * Note that we don't grab the ss->lock mutex, even though
6505 6505   * we're inspecting the various fields of the data structure.
6506 6506   *
6507 6507   * There is an implicit assumption that this routine will
6508 6508   * never run concurrently with any of the above on this
6509 6509   * particular state structure i.e. by the time the driver
6510 6510   * calls this routine, there should be no other threads
6511 6511   * running in the driver.
6512 6512   */
6513 6513  void
6514 6514  ddi_soft_state_fini(void **state_p)
6515 6515  {
6516 6516          i_ddi_soft_state        *ss, *dirty;
6517 6517          int                     item;
6518 6518          static char             msg[] = "ddi_soft_state_fini:";
6519 6519  
6520 6520          if (state_p == NULL ||
6521 6521              (ss = (i_ddi_soft_state *)(*state_p)) == NULL) {
6522 6522                  cmn_err(CE_WARN, "%s null handle: %s",
6523 6523                      msg, mod_containing_pc(caller()));
6524 6524                  return;
6525 6525          }
6526 6526  
6527 6527          if (ss->size == 0) {
6528 6528                  cmn_err(CE_WARN, "%s bad handle: %s",
6529 6529                      msg, mod_containing_pc(caller()));
6530 6530                  return;
6531 6531          }
6532 6532  
6533 6533          if (ss->n_items > 0) {
6534 6534                  for (item = 0; item < ss->n_items; item++)
6535 6535                          ddi_soft_state_free(ss, item);
6536 6536                  kmem_free(ss->array, ss->n_items * sizeof (void *));
6537 6537          }
6538 6538  
6539 6539          /*
6540 6540           * Now delete any dirty arrays from previous 'grow' operations
6541 6541           */
6542 6542          for (dirty = ss->next; dirty; dirty = ss->next) {
6543 6543                  ss->next = dirty->next;
6544 6544                  kmem_free(dirty->array, dirty->n_items * sizeof (void *));
6545 6545                  kmem_free(dirty, sizeof (*dirty));
6546 6546          }
6547 6547  
6548 6548          mutex_destroy(&ss->lock);
6549 6549          kmem_free(ss, sizeof (*ss));
6550 6550  
6551 6551          *state_p = NULL;
6552 6552  }
6553 6553  
6554 6554  #define SS_N_ITEMS_PER_HASH     16
6555 6555  #define SS_MIN_HASH_SZ          16
6556 6556  #define SS_MAX_HASH_SZ          4096
6557 6557  
6558 6558  int
6559 6559  ddi_soft_state_bystr_init(ddi_soft_state_bystr **state_p, size_t size,
6560 6560      int n_items)
6561 6561  {
6562 6562          i_ddi_soft_state_bystr  *sss;
6563 6563          int                     hash_sz;
6564 6564  
6565 6565          ASSERT(state_p && size && n_items);
6566 6566          if ((state_p == NULL) || (size == 0) || (n_items == 0))
6567 6567                  return (EINVAL);
6568 6568  
6569 6569          /* current implementation is based on hash, convert n_items to hash */
6570 6570          hash_sz = n_items / SS_N_ITEMS_PER_HASH;
6571 6571          if (hash_sz < SS_MIN_HASH_SZ)
6572 6572                  hash_sz = SS_MIN_HASH_SZ;
6573 6573          else if (hash_sz > SS_MAX_HASH_SZ)
6574 6574                  hash_sz = SS_MAX_HASH_SZ;
6575 6575  
6576 6576          /* allocate soft_state pool */
6577 6577          sss = kmem_zalloc(sizeof (*sss), KM_SLEEP);
6578 6578          sss->ss_size = size;
6579 6579          sss->ss_mod_hash = mod_hash_create_strhash("soft_state_bystr",
6580 6580              hash_sz, mod_hash_null_valdtor);
6581 6581          *state_p = (ddi_soft_state_bystr *)sss;
6582 6582          return (0);
6583 6583  }
6584 6584  
6585 6585  int
6586 6586  ddi_soft_state_bystr_zalloc(ddi_soft_state_bystr *state, const char *str)
6587 6587  {
6588 6588          i_ddi_soft_state_bystr  *sss = (i_ddi_soft_state_bystr *)state;
6589 6589          void                    *sso;
6590 6590          char                    *dup_str;
6591 6591  
6592 6592          ASSERT(sss && str && sss->ss_mod_hash);
6593 6593          if ((sss == NULL) || (str == NULL) || (sss->ss_mod_hash == NULL))
6594 6594                  return (DDI_FAILURE);
6595 6595          sso = kmem_zalloc(sss->ss_size, KM_SLEEP);
6596 6596          dup_str = i_ddi_strdup((char *)str, KM_SLEEP);
6597 6597          if (mod_hash_insert(sss->ss_mod_hash,
6598 6598              (mod_hash_key_t)dup_str, (mod_hash_val_t)sso) == 0)
6599 6599                  return (DDI_SUCCESS);
6600 6600  
6601 6601          /*
6602 6602           * The only error from an strhash insert is caused by a duplicate key.
6603 6603           * We refuse to tread on an existing elements, so free and fail.
6604 6604           */
6605 6605          kmem_free(dup_str, strlen(dup_str) + 1);
6606 6606          kmem_free(sso, sss->ss_size);
6607 6607          return (DDI_FAILURE);
6608 6608  }
6609 6609  
6610 6610  void *
6611 6611  ddi_soft_state_bystr_get(ddi_soft_state_bystr *state, const char *str)
6612 6612  {
6613 6613          i_ddi_soft_state_bystr  *sss = (i_ddi_soft_state_bystr *)state;
6614 6614          void                    *sso;
6615 6615  
6616 6616          ASSERT(sss && str && sss->ss_mod_hash);
6617 6617          if ((sss == NULL) || (str == NULL) || (sss->ss_mod_hash == NULL))
6618 6618                  return (NULL);
6619 6619  
6620 6620          if (mod_hash_find(sss->ss_mod_hash,
6621 6621              (mod_hash_key_t)str, (mod_hash_val_t *)&sso) == 0)
6622 6622                  return (sso);
6623 6623          return (NULL);
6624 6624  }
6625 6625  
6626 6626  void
6627 6627  ddi_soft_state_bystr_free(ddi_soft_state_bystr *state, const char *str)
6628 6628  {
6629 6629          i_ddi_soft_state_bystr  *sss = (i_ddi_soft_state_bystr *)state;
6630 6630          void                    *sso;
6631 6631  
6632 6632          ASSERT(sss && str && sss->ss_mod_hash);
6633 6633          if ((sss == NULL) || (str == NULL) || (sss->ss_mod_hash == NULL))
6634 6634                  return;
6635 6635  
6636 6636          (void) mod_hash_remove(sss->ss_mod_hash,
6637 6637              (mod_hash_key_t)str, (mod_hash_val_t *)&sso);
6638 6638          kmem_free(sso, sss->ss_size);
6639 6639  }
6640 6640  
6641 6641  void
6642 6642  ddi_soft_state_bystr_fini(ddi_soft_state_bystr **state_p)
6643 6643  {
6644 6644          i_ddi_soft_state_bystr  *sss;
6645 6645  
6646 6646          ASSERT(state_p);
6647 6647          if (state_p == NULL)
6648 6648                  return;
6649 6649  
6650 6650          sss = (i_ddi_soft_state_bystr *)(*state_p);
6651 6651          if (sss == NULL)
6652 6652                  return;
6653 6653  
6654 6654          ASSERT(sss->ss_mod_hash);
6655 6655          if (sss->ss_mod_hash) {
6656 6656                  mod_hash_destroy_strhash(sss->ss_mod_hash);
6657 6657                  sss->ss_mod_hash = NULL;
6658 6658          }
6659 6659  
6660 6660          kmem_free(sss, sizeof (*sss));
6661 6661          *state_p = NULL;
6662 6662  }
6663 6663  
6664 6664  /*
6665 6665   * The ddi_strid_* routines provide string-to-index management utilities.
6666 6666   */
6667 6667  /* allocate and initialize an strid set */
6668 6668  int
6669 6669  ddi_strid_init(ddi_strid **strid_p, int n_items)
6670 6670  {
6671 6671          i_ddi_strid     *ss;
6672 6672          int             hash_sz;
6673 6673  
6674 6674          if (strid_p == NULL)
6675 6675                  return (DDI_FAILURE);
6676 6676  
6677 6677          /* current implementation is based on hash, convert n_items to hash */
6678 6678          hash_sz = n_items / SS_N_ITEMS_PER_HASH;
6679 6679          if (hash_sz < SS_MIN_HASH_SZ)
6680 6680                  hash_sz = SS_MIN_HASH_SZ;
6681 6681          else if (hash_sz > SS_MAX_HASH_SZ)
6682 6682                  hash_sz = SS_MAX_HASH_SZ;
6683 6683  
6684 6684          ss = kmem_alloc(sizeof (*ss), KM_SLEEP);
6685 6685          ss->strid_chunksz = n_items;
6686 6686          ss->strid_spacesz = n_items;
6687 6687          ss->strid_space = id_space_create("strid", 1, n_items);
6688 6688          ss->strid_bystr = mod_hash_create_strhash("strid_bystr", hash_sz,
6689 6689              mod_hash_null_valdtor);
6690 6690          ss->strid_byid = mod_hash_create_idhash("strid_byid", hash_sz,
6691 6691              mod_hash_null_valdtor);
6692 6692          *strid_p = (ddi_strid *)ss;
6693 6693          return (DDI_SUCCESS);
6694 6694  }
6695 6695  
6696 6696  /* allocate an id mapping within the specified set for str, return id */
6697 6697  static id_t
6698 6698  i_ddi_strid_alloc(ddi_strid *strid, char *str)
6699 6699  {
6700 6700          i_ddi_strid     *ss = (i_ddi_strid *)strid;
6701 6701          id_t            id;
6702 6702          char            *s;
6703 6703  
6704 6704          ASSERT(ss && str);
6705 6705          if ((ss == NULL) || (str == NULL))
6706 6706                  return (0);
6707 6707  
6708 6708          /*
6709 6709           * Allocate an id using VM_FIRSTFIT in order to keep allocated id
6710 6710           * range as compressed as possible.  This is important to minimize
6711 6711           * the amount of space used when the id is used as a ddi_soft_state
6712 6712           * index by the caller.
6713 6713           *
6714 6714           * If the id list is exhausted, increase the size of the list
6715 6715           * by the chuck size specified in ddi_strid_init and reattempt
6716 6716           * the allocation
6717 6717           */
6718 6718          if ((id = id_allocff_nosleep(ss->strid_space)) == (id_t)-1) {
6719 6719                  id_space_extend(ss->strid_space, ss->strid_spacesz,
6720 6720                      ss->strid_spacesz + ss->strid_chunksz);
6721 6721                  ss->strid_spacesz += ss->strid_chunksz;
6722 6722                  if ((id = id_allocff_nosleep(ss->strid_space)) == (id_t)-1)
6723 6723                          return (0);
6724 6724          }
6725 6725  
6726 6726          /*
6727 6727           * NOTE: since we create and destroy in unison we can save space by
6728 6728           * using bystr key as the byid value.  This means destroy must occur
6729 6729           * in (byid, bystr) order.
6730 6730           */
6731 6731          s = i_ddi_strdup(str, KM_SLEEP);
6732 6732          if (mod_hash_insert(ss->strid_bystr, (mod_hash_key_t)s,
6733 6733              (mod_hash_val_t)(intptr_t)id) != 0) {
6734 6734                  ddi_strid_free(strid, id);
6735 6735                  return (0);
6736 6736          }
6737 6737          if (mod_hash_insert(ss->strid_byid, (mod_hash_key_t)(intptr_t)id,
6738 6738              (mod_hash_val_t)s) != 0) {
6739 6739                  ddi_strid_free(strid, id);
6740 6740                  return (0);
6741 6741          }
6742 6742  
6743 6743          /* NOTE: s if freed on mod_hash_destroy by mod_hash_strval_dtor */
6744 6744          return (id);
6745 6745  }
6746 6746  
6747 6747  /* allocate an id mapping within the specified set for str, return id */
6748 6748  id_t
6749 6749  ddi_strid_alloc(ddi_strid *strid, char *str)
6750 6750  {
6751 6751          return (i_ddi_strid_alloc(strid, str));
6752 6752  }
6753 6753  
6754 6754  /* return the id within the specified strid given the str */
6755 6755  id_t
6756 6756  ddi_strid_str2id(ddi_strid *strid, char *str)
6757 6757  {
6758 6758          i_ddi_strid     *ss = (i_ddi_strid *)strid;
6759 6759          id_t            id = 0;
6760 6760          mod_hash_val_t  hv;
6761 6761  
6762 6762          ASSERT(ss && str);
6763 6763          if (ss && str && (mod_hash_find(ss->strid_bystr,
6764 6764              (mod_hash_key_t)str, &hv) == 0))
6765 6765                  id = (int)(intptr_t)hv;
6766 6766          return (id);
6767 6767  }
6768 6768  
6769 6769  /* return str within the specified strid given the id */
6770 6770  char *
6771 6771  ddi_strid_id2str(ddi_strid *strid, id_t id)
6772 6772  {
6773 6773          i_ddi_strid     *ss = (i_ddi_strid *)strid;
6774 6774          char            *str = NULL;
6775 6775          mod_hash_val_t  hv;
6776 6776  
6777 6777          ASSERT(ss && id > 0);
6778 6778          if (ss && (id > 0) && (mod_hash_find(ss->strid_byid,
6779 6779              (mod_hash_key_t)(uintptr_t)id, &hv) == 0))
6780 6780                  str = (char *)hv;
6781 6781          return (str);
6782 6782  }
6783 6783  
6784 6784  /* free the id mapping within the specified strid */
6785 6785  void
6786 6786  ddi_strid_free(ddi_strid *strid, id_t id)
6787 6787  {
6788 6788          i_ddi_strid     *ss = (i_ddi_strid *)strid;
6789 6789          char            *str;
6790 6790  
6791 6791          ASSERT(ss && id > 0);
6792 6792          if ((ss == NULL) || (id <= 0))
6793 6793                  return;
6794 6794  
6795 6795          /* bystr key is byid value: destroy order must be (byid, bystr) */
6796 6796          str = ddi_strid_id2str(strid, id);
6797 6797          (void) mod_hash_destroy(ss->strid_byid, (mod_hash_key_t)(uintptr_t)id);
6798 6798          id_free(ss->strid_space, id);
6799 6799  
6800 6800          if (str)
6801 6801                  (void) mod_hash_destroy(ss->strid_bystr, (mod_hash_key_t)str);
6802 6802  }
6803 6803  
6804 6804  /* destroy the strid set */
6805 6805  void
6806 6806  ddi_strid_fini(ddi_strid **strid_p)
6807 6807  {
6808 6808          i_ddi_strid     *ss;
6809 6809  
6810 6810          ASSERT(strid_p);
6811 6811          if (strid_p == NULL)
6812 6812                  return;
6813 6813  
6814 6814          ss = (i_ddi_strid *)(*strid_p);
6815 6815          if (ss == NULL)
6816 6816                  return;
6817 6817  
6818 6818          /* bystr key is byid value: destroy order must be (byid, bystr) */
6819 6819          if (ss->strid_byid)
6820 6820                  mod_hash_destroy_hash(ss->strid_byid);
6821 6821          if (ss->strid_byid)
6822 6822                  mod_hash_destroy_hash(ss->strid_bystr);
6823 6823          if (ss->strid_space)
6824 6824                  id_space_destroy(ss->strid_space);
6825 6825          kmem_free(ss, sizeof (*ss));
6826 6826          *strid_p = NULL;
6827 6827  }
6828 6828  
6829 6829  /*
6830 6830   * This sets the devi_addr entry in the dev_info structure 'dip' to 'name'.
6831 6831   * Storage is double buffered to prevent updates during devi_addr use -
6832 6832   * double buffering is adaquate for reliable ddi_deviname() consumption.
6833 6833   * The double buffer is not freed until dev_info structure destruction
6834 6834   * (by i_ddi_free_node).
6835 6835   */
6836 6836  void
6837 6837  ddi_set_name_addr(dev_info_t *dip, char *name)
6838 6838  {
6839 6839          char    *buf = DEVI(dip)->devi_addr_buf;
6840 6840          char    *newaddr;
6841 6841  
6842 6842          if (buf == NULL) {
6843 6843                  buf = kmem_zalloc(2 * MAXNAMELEN, KM_SLEEP);
6844 6844                  DEVI(dip)->devi_addr_buf = buf;
6845 6845          }
6846 6846  
6847 6847          if (name) {
6848 6848                  ASSERT(strlen(name) < MAXNAMELEN);
6849 6849                  newaddr = (DEVI(dip)->devi_addr == buf) ?
6850 6850                      (buf + MAXNAMELEN) : buf;
6851 6851                  (void) strlcpy(newaddr, name, MAXNAMELEN);
6852 6852          } else
6853 6853                  newaddr = NULL;
6854 6854  
6855 6855          DEVI(dip)->devi_addr = newaddr;
6856 6856  }
6857 6857  
6858 6858  char *
6859 6859  ddi_get_name_addr(dev_info_t *dip)
6860 6860  {
6861 6861          return (DEVI(dip)->devi_addr);
6862 6862  }
6863 6863  
6864 6864  void
6865 6865  ddi_set_parent_data(dev_info_t *dip, void *pd)
6866 6866  {
6867 6867          DEVI(dip)->devi_parent_data = pd;
6868 6868  }
6869 6869  
6870 6870  void *
6871 6871  ddi_get_parent_data(dev_info_t *dip)
6872 6872  {
6873 6873          return (DEVI(dip)->devi_parent_data);
6874 6874  }
6875 6875  
6876 6876  /*
6877 6877   * ddi_name_to_major: returns the major number of a named module,
6878 6878   * derived from the current driver alias binding.
6879 6879   *
6880 6880   * Caveat: drivers should avoid the use of this function, in particular
6881 6881   * together with ddi_get_name/ddi_binding name, as per
6882 6882   *      major = ddi_name_to_major(ddi_get_name(devi));
6883 6883   * ddi_name_to_major() relies on the state of the device/alias binding,
6884 6884   * which can and does change dynamically as aliases are administered
6885 6885   * over time.  An attached device instance cannot rely on the major
6886 6886   * number returned by ddi_name_to_major() to match its own major number.
6887 6887   *
6888 6888   * For driver use, ddi_driver_major() reliably returns the major number
6889 6889   * for the module to which the device was bound at attach time over
6890 6890   * the life of the instance.
6891 6891   *      major = ddi_driver_major(dev_info_t *)
6892 6892   */
6893 6893  major_t
6894 6894  ddi_name_to_major(char *name)
6895 6895  {
6896 6896          return (mod_name_to_major(name));
6897 6897  }
6898 6898  
6899 6899  /*
6900 6900   * ddi_major_to_name: Returns the module name bound to a major number.
6901 6901   */
6902 6902  char *
6903 6903  ddi_major_to_name(major_t major)
6904 6904  {
6905 6905          return (mod_major_to_name(major));
6906 6906  }
6907 6907  
6908 6908  /*
6909 6909   * Return the name of the devinfo node pointed at by 'dip' in the buffer
6910 6910   * pointed at by 'name.'  A devinfo node is named as a result of calling
6911 6911   * ddi_initchild().
6912 6912   *
6913 6913   * Note: the driver must be held before calling this function!
6914 6914   */
6915 6915  char *
6916 6916  ddi_deviname(dev_info_t *dip, char *name)
6917 6917  {
6918 6918          char *addrname;
6919 6919          char none = '\0';
6920 6920  
6921 6921          if (dip == ddi_root_node()) {
6922 6922                  *name = '\0';
6923 6923                  return (name);
6924 6924          }
6925 6925  
6926 6926          if (i_ddi_node_state(dip) < DS_BOUND) {
6927 6927                  addrname = &none;
6928 6928          } else {
6929 6929                  /*
6930 6930                   * Use ddi_get_name_addr() without checking state so we get
6931 6931                   * a unit-address if we are called after ddi_set_name_addr()
6932 6932                   * by nexus DDI_CTL_INITCHILD code, but before completing
6933 6933                   * node promotion to DS_INITIALIZED.  We currently have
6934 6934                   * two situations where we are called in this state:
6935 6935                   *   o  For framework processing of a path-oriented alias.
6936 6936                   *   o  If a SCSA nexus driver calls ddi_devid_register()
6937 6937                   *      from it's tran_tgt_init(9E) implementation.
6938 6938                   */
6939 6939                  addrname = ddi_get_name_addr(dip);
6940 6940                  if (addrname == NULL)
6941 6941                          addrname = &none;
6942 6942          }
6943 6943  
6944 6944          if (*addrname == '\0') {
6945 6945                  (void) sprintf(name, "/%s", ddi_node_name(dip));
6946 6946          } else {
6947 6947                  (void) sprintf(name, "/%s@%s", ddi_node_name(dip), addrname);
6948 6948          }
6949 6949  
6950 6950          return (name);
6951 6951  }
6952 6952  
6953 6953  /*
6954 6954   * Spits out the name of device node, typically name@addr, for a given node,
6955 6955   * using the driver name, not the nodename.
6956 6956   *
6957 6957   * Used by match_parent. Not to be used elsewhere.
6958 6958   */
6959 6959  char *
6960 6960  i_ddi_parname(dev_info_t *dip, char *name)
6961 6961  {
6962 6962          char *addrname;
6963 6963  
6964 6964          if (dip == ddi_root_node()) {
6965 6965                  *name = '\0';
6966 6966                  return (name);
6967 6967          }
6968 6968  
6969 6969          ASSERT(i_ddi_node_state(dip) >= DS_INITIALIZED);
6970 6970  
6971 6971          if (*(addrname = ddi_get_name_addr(dip)) == '\0')
6972 6972                  (void) sprintf(name, "%s", ddi_binding_name(dip));
6973 6973          else
6974 6974                  (void) sprintf(name, "%s@%s", ddi_binding_name(dip), addrname);
6975 6975          return (name);
6976 6976  }
6977 6977  
6978 6978  static char *
6979 6979  pathname_work(dev_info_t *dip, char *path)
6980 6980  {
6981 6981          char *bp;
6982 6982  
6983 6983          if (dip == ddi_root_node()) {
6984 6984                  *path = '\0';
6985 6985                  return (path);
6986 6986          }
6987 6987          (void) pathname_work(ddi_get_parent(dip), path);
6988 6988          bp = path + strlen(path);
6989 6989          (void) ddi_deviname(dip, bp);
6990 6990          return (path);
6991 6991  }
6992 6992  
6993 6993  char *
6994 6994  ddi_pathname(dev_info_t *dip, char *path)
6995 6995  {
6996 6996          return (pathname_work(dip, path));
6997 6997  }
6998 6998  
6999 6999  char *
7000 7000  ddi_pathname_minor(struct ddi_minor_data *dmdp, char *path)
7001 7001  {
7002 7002          if (dmdp->dip == NULL)
7003 7003                  *path = '\0';
7004 7004          else {
7005 7005                  (void) ddi_pathname(dmdp->dip, path);
7006 7006                  if (dmdp->ddm_name) {
7007 7007                          (void) strcat(path, ":");
7008 7008                          (void) strcat(path, dmdp->ddm_name);
7009 7009                  }
7010 7010          }
7011 7011          return (path);
7012 7012  }
7013 7013  
7014 7014  static char *
7015 7015  pathname_work_obp(dev_info_t *dip, char *path)
7016 7016  {
7017 7017          char *bp;
7018 7018          char *obp_path;
7019 7019  
7020 7020          /*
7021 7021           * look up the "obp-path" property, return the path if it exists
7022 7022           */
7023 7023          if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
7024 7024              "obp-path", &obp_path) == DDI_PROP_SUCCESS) {
7025 7025                  (void) strcpy(path, obp_path);
7026 7026                  ddi_prop_free(obp_path);
7027 7027                  return (path);
7028 7028          }
7029 7029  
7030 7030          /*
7031 7031           * stop at root, no obp path
7032 7032           */
7033 7033          if (dip == ddi_root_node()) {
7034 7034                  return (NULL);
7035 7035          }
7036 7036  
7037 7037          obp_path = pathname_work_obp(ddi_get_parent(dip), path);
7038 7038          if (obp_path == NULL)
7039 7039                  return (NULL);
7040 7040  
7041 7041          /*
7042 7042           * append our component to parent's obp path
7043 7043           */
7044 7044          bp = path + strlen(path);
7045 7045          if (*(bp - 1) != '/')
7046 7046                  (void) strcat(bp++, "/");
7047 7047          (void) ddi_deviname(dip, bp);
7048 7048          return (path);
7049 7049  }
7050 7050  
7051 7051  /*
7052 7052   * return the 'obp-path' based path for the given node, or NULL if the node
7053 7053   * does not have a different obp path. NOTE: Unlike ddi_pathname, this
7054 7054   * function can't be called from interrupt context (since we need to
7055 7055   * lookup a string property).
7056 7056   */
7057 7057  char *
7058 7058  ddi_pathname_obp(dev_info_t *dip, char *path)
7059 7059  {
7060 7060          ASSERT(!servicing_interrupt());
7061 7061          if (dip == NULL || path == NULL)
7062 7062                  return (NULL);
7063 7063  
7064 7064          /* split work into a separate function to aid debugging */
7065 7065          return (pathname_work_obp(dip, path));
7066 7066  }
7067 7067  
7068 7068  int
7069 7069  ddi_pathname_obp_set(dev_info_t *dip, char *component)
7070 7070  {
7071 7071          dev_info_t *pdip;
7072 7072          char *obp_path = NULL;
7073 7073          int rc = DDI_FAILURE;
7074 7074  
7075 7075          if (dip == NULL)
7076 7076                  return (DDI_FAILURE);
7077 7077  
7078 7078          obp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
7079 7079  
7080 7080          pdip = ddi_get_parent(dip);
7081 7081  
7082 7082          if (ddi_pathname_obp(pdip, obp_path) == NULL) {
7083 7083                  (void) ddi_pathname(pdip, obp_path);
7084 7084          }
7085 7085  
7086 7086          if (component) {
7087 7087                  (void) strncat(obp_path, "/", MAXPATHLEN);
7088 7088                  (void) strncat(obp_path, component, MAXPATHLEN);
7089 7089          }
7090 7090          rc = ndi_prop_update_string(DDI_DEV_T_NONE, dip, "obp-path",
7091 7091              obp_path);
7092 7092  
7093 7093          if (obp_path)
7094 7094                  kmem_free(obp_path, MAXPATHLEN);
7095 7095  
7096 7096          return (rc);
7097 7097  }
7098 7098  
7099 7099  /*
7100 7100   * Given a dev_t, return the pathname of the corresponding device in the
7101 7101   * buffer pointed at by "path."  The buffer is assumed to be large enough
7102 7102   * to hold the pathname of the device (MAXPATHLEN).
7103 7103   *
7104 7104   * The pathname of a device is the pathname of the devinfo node to which
7105 7105   * the device "belongs," concatenated with the character ':' and the name
7106 7106   * of the minor node corresponding to the dev_t.  If spec_type is 0 then
7107 7107   * just the pathname of the devinfo node is returned without driving attach
7108 7108   * of that node.  For a non-zero spec_type, an attach is performed and a
7109 7109   * search of the minor list occurs.
7110 7110   *
7111 7111   * It is possible that the path associated with the dev_t is not
7112 7112   * currently available in the devinfo tree.  In order to have a
7113 7113   * dev_t, a device must have been discovered before, which means
7114 7114   * that the path is always in the instance tree.  The one exception
7115 7115   * to this is if the dev_t is associated with a pseudo driver, in
7116 7116   * which case the device must exist on the pseudo branch of the
7117 7117   * devinfo tree as a result of parsing .conf files.
7118 7118   */
7119 7119  int
7120 7120  ddi_dev_pathname(dev_t devt, int spec_type, char *path)
7121 7121  {
7122 7122          int             circ;
7123 7123          major_t         major = getmajor(devt);
7124 7124          int             instance;
7125 7125          dev_info_t      *dip;
7126 7126          char            *minorname;
7127 7127          char            *drvname;
7128 7128  
7129 7129          if (major >= devcnt)
7130 7130                  goto fail;
7131 7131          if (major == clone_major) {
7132 7132                  /* clone has no minor nodes, manufacture the path here */
7133 7133                  if ((drvname = ddi_major_to_name(getminor(devt))) == NULL)
7134 7134                          goto fail;
7135 7135  
7136 7136                  (void) snprintf(path, MAXPATHLEN, "%s:%s", CLONE_PATH, drvname);
7137 7137                  return (DDI_SUCCESS);
7138 7138          }
7139 7139  
7140 7140          /* extract instance from devt (getinfo(9E) DDI_INFO_DEVT2INSTANCE). */
7141 7141          if ((instance = dev_to_instance(devt)) == -1)
7142 7142                  goto fail;
7143 7143  
7144 7144          /* reconstruct the path given the major/instance */
7145 7145          if (e_ddi_majorinstance_to_path(major, instance, path) != DDI_SUCCESS)
7146 7146                  goto fail;
7147 7147  
7148 7148          /* if spec_type given we must drive attach and search minor nodes */
7149 7149          if ((spec_type == S_IFCHR) || (spec_type == S_IFBLK)) {
7150 7150                  /* attach the path so we can search minors */
7151 7151                  if ((dip = e_ddi_hold_devi_by_path(path, 0)) == NULL)
7152 7152                          goto fail;
7153 7153  
7154 7154                  /* Add minorname to path. */
7155 7155                  ndi_devi_enter(dip, &circ);
7156 7156                  minorname = i_ddi_devtspectype_to_minorname(dip,
7157 7157                      devt, spec_type);
7158 7158                  if (minorname) {
7159 7159                          (void) strcat(path, ":");
7160 7160                          (void) strcat(path, minorname);
7161 7161                  }
7162 7162                  ndi_devi_exit(dip, circ);
7163 7163                  ddi_release_devi(dip);
7164 7164                  if (minorname == NULL)
7165 7165                          goto fail;
7166 7166          }
7167 7167          ASSERT(strlen(path) < MAXPATHLEN);
7168 7168          return (DDI_SUCCESS);
7169 7169  
7170 7170  fail:   *path = 0;
7171 7171          return (DDI_FAILURE);
7172 7172  }
7173 7173  
7174 7174  /*
7175 7175   * Given a major number and an instance, return the path.
7176 7176   * This interface does NOT drive attach.
7177 7177   */
7178 7178  int
7179 7179  e_ddi_majorinstance_to_path(major_t major, int instance, char *path)
7180 7180  {
7181 7181          struct devnames *dnp;
7182 7182          dev_info_t      *dip;
7183 7183  
7184 7184          if ((major >= devcnt) || (instance == -1)) {
7185 7185                  *path = 0;
7186 7186                  return (DDI_FAILURE);
7187 7187          }
7188 7188  
7189 7189          /* look for the major/instance in the instance tree */
7190 7190          if (e_ddi_instance_majorinstance_to_path(major, instance,
7191 7191              path) == DDI_SUCCESS) {
7192 7192                  ASSERT(strlen(path) < MAXPATHLEN);
7193 7193                  return (DDI_SUCCESS);
7194 7194          }
7195 7195  
7196 7196          /*
7197 7197           * Not in instance tree, find the instance on the per driver list and
7198 7198           * construct path to instance via ddi_pathname(). This is how paths
7199 7199           * down the 'pseudo' branch are constructed.
7200 7200           */
7201 7201          dnp = &(devnamesp[major]);
7202 7202          LOCK_DEV_OPS(&(dnp->dn_lock));
7203 7203          for (dip = dnp->dn_head; dip;
7204 7204              dip = (dev_info_t *)DEVI(dip)->devi_next) {
7205 7205                  /* Skip if instance does not match. */
7206 7206                  if (DEVI(dip)->devi_instance != instance)
7207 7207                          continue;
7208 7208  
7209 7209                  /*
7210 7210                   * An ndi_hold_devi() does not prevent DS_INITIALIZED->DS_BOUND
7211 7211                   * node demotion, so it is not an effective way of ensuring
7212 7212                   * that the ddi_pathname result has a unit-address.  Instead,
7213 7213                   * we reverify the node state after calling ddi_pathname().
7214 7214                   */
7215 7215                  if (i_ddi_node_state(dip) >= DS_INITIALIZED) {
7216 7216                          (void) ddi_pathname(dip, path);
7217 7217                          if (i_ddi_node_state(dip) < DS_INITIALIZED)
7218 7218                                  continue;
7219 7219                          UNLOCK_DEV_OPS(&(dnp->dn_lock));
7220 7220                          ASSERT(strlen(path) < MAXPATHLEN);
7221 7221                          return (DDI_SUCCESS);
7222 7222                  }
7223 7223          }
7224 7224          UNLOCK_DEV_OPS(&(dnp->dn_lock));
7225 7225  
7226 7226          /* can't reconstruct the path */
7227 7227          *path = 0;
7228 7228          return (DDI_FAILURE);
7229 7229  }
7230 7230  
7231 7231  #define GLD_DRIVER_PPA "SUNW,gld_v0_ppa"
7232 7232  
7233 7233  /*
7234 7234   * Given the dip for a network interface return the ppa for that interface.
7235 7235   *
7236 7236   * In all cases except GLD v0 drivers, the ppa == instance.
7237 7237   * In the case of GLD v0 drivers, the ppa is equal to the attach order.
7238 7238   * So for these drivers when the attach routine calls gld_register(),
7239 7239   * the GLD framework creates an integer property called "gld_driver_ppa"
7240 7240   * that can be queried here.
7241 7241   *
7242 7242   * The only time this function is used is when a system is booting over nfs.
7243 7243   * In this case the system has to resolve the pathname of the boot device
7244 7244   * to it's ppa.
7245 7245   */
7246 7246  int
7247 7247  i_ddi_devi_get_ppa(dev_info_t *dip)
7248 7248  {
7249 7249          return (ddi_prop_get_int(DDI_DEV_T_ANY, dip,
7250 7250              DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
7251 7251              GLD_DRIVER_PPA, ddi_get_instance(dip)));
7252 7252  }
7253 7253  
7254 7254  /*
7255 7255   * i_ddi_devi_set_ppa() should only be called from gld_register()
7256 7256   * and only for GLD v0 drivers
7257 7257   */
7258 7258  void
7259 7259  i_ddi_devi_set_ppa(dev_info_t *dip, int ppa)
7260 7260  {
7261 7261          (void) e_ddi_prop_update_int(DDI_DEV_T_NONE, dip, GLD_DRIVER_PPA, ppa);
7262 7262  }
7263 7263  
7264 7264  
7265 7265  /*
7266 7266   * Private DDI Console bell functions.
7267 7267   */
7268 7268  void
7269 7269  ddi_ring_console_bell(clock_t duration)
7270 7270  {
7271 7271          if (ddi_console_bell_func != NULL)
7272 7272                  (*ddi_console_bell_func)(duration);
7273 7273  }
7274 7274  
7275 7275  void
7276 7276  ddi_set_console_bell(void (*bellfunc)(clock_t duration))
7277 7277  {
7278 7278          ddi_console_bell_func = bellfunc;
7279 7279  }
7280 7280  
7281 7281  int
7282 7282  ddi_dma_alloc_handle(dev_info_t *dip, ddi_dma_attr_t *attr,
7283 7283          int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
7284 7284  {
7285 7285          int (*funcp)() = ddi_dma_allochdl;
7286 7286          ddi_dma_attr_t dma_attr;
7287 7287          struct bus_ops *bop;
7288 7288  
7289 7289          if (attr == (ddi_dma_attr_t *)0)
7290 7290                  return (DDI_DMA_BADATTR);
7291 7291  
7292 7292          dma_attr = *attr;
7293 7293  
7294 7294          bop = DEVI(dip)->devi_ops->devo_bus_ops;
7295 7295          if (bop && bop->bus_dma_allochdl)
7296 7296                  funcp = bop->bus_dma_allochdl;
7297 7297  
7298 7298          return ((*funcp)(dip, dip, &dma_attr, waitfp, arg, handlep));
7299 7299  }
7300 7300  
7301 7301  void
7302 7302  ddi_dma_free_handle(ddi_dma_handle_t *handlep)
7303 7303  {
7304 7304          ddi_dma_handle_t h = *handlep;
7305 7305          (void) ddi_dma_freehdl(HD, HD, h);
7306 7306  }
7307 7307  
7308 7308  static uintptr_t dma_mem_list_id = 0;
7309 7309  
7310 7310  
7311 7311  int
7312 7312  ddi_dma_mem_alloc(ddi_dma_handle_t handle, size_t length,
7313 7313          ddi_device_acc_attr_t *accattrp, uint_t flags,
7314 7314          int (*waitfp)(caddr_t), caddr_t arg, caddr_t *kaddrp,
7315 7315          size_t *real_length, ddi_acc_handle_t *handlep)
7316 7316  {
7317 7317          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7318 7318          dev_info_t *dip = hp->dmai_rdip;
7319 7319          ddi_acc_hdl_t *ap;
7320 7320          ddi_dma_attr_t *attrp = &hp->dmai_attr;
7321 7321          uint_t sleepflag, xfermodes;
7322 7322          int (*fp)(caddr_t);
7323 7323          int rval;
7324 7324  
  
    | 
      ↓ open down ↓ | 
    7324 lines elided | 
    
      ↑ open up ↑ | 
  
7325 7325          if (waitfp == DDI_DMA_SLEEP)
7326 7326                  fp = (int (*)())KM_SLEEP;
7327 7327          else if (waitfp == DDI_DMA_DONTWAIT)
7328 7328                  fp = (int (*)())KM_NOSLEEP;
7329 7329          else
7330 7330                  fp = waitfp;
7331 7331          *handlep = impl_acc_hdl_alloc(fp, arg);
7332 7332          if (*handlep == NULL)
7333 7333                  return (DDI_FAILURE);
7334 7334  
7335      -/* SPARC mappings are always cacheable, as SPARC guarantees cache coherency. */
7336      -#ifndef __sparc
7337      -        /* Transform attributes into correct cache flags. */
7338      -        if ((flags & IOMEM_DATA_MASK) == 0) {
7339      -                switch (accattrp->devacc_attr_dataorder) {
7340      -                case DDI_STRICTORDER_ACC:
7341      -                        flags |= IOMEM_DATA_UNCACHED;
7342      -                        break;
7343      -                case DDI_MERGING_OK_ACC:
7344      -                        flags |= IOMEM_DATA_UC_WR_COMBINE;
7345      -                        break;
7346      -                default:
7347      -                        flags |= IOMEM_DATA_CACHED;
7348      -                        break;
7349      -                }
7350      -        }
7351      -#endif
7352      -
7353 7335          /* check if the cache attributes are supported */
7354 7336          if (i_ddi_check_cache_attr(flags) == B_FALSE)
7355 7337                  return (DDI_FAILURE);
7356 7338  
7357 7339          /*
7358 7340           * Transfer the meaningful bits to xfermodes.
7359 7341           * Double-check if the 3rd party driver correctly sets the bits.
7360 7342           * If not, set DDI_DMA_STREAMING to keep compatibility.
7361 7343           */
7362 7344          xfermodes = flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING);
7363 7345          if (xfermodes == 0) {
7364 7346                  xfermodes = DDI_DMA_STREAMING;
7365 7347          }
7366 7348  
7367 7349          /*
7368 7350           * initialize the common elements of data access handle
7369 7351           */
7370 7352          ap = impl_acc_hdl_get(*handlep);
7371 7353          ap->ah_vers = VERS_ACCHDL;
7372 7354          ap->ah_dip = dip;
7373 7355          ap->ah_offset = 0;
7374 7356          ap->ah_len = 0;
7375 7357          ap->ah_xfermodes = flags;
7376 7358          ap->ah_acc = *accattrp;
7377 7359  
7378 7360          sleepflag = ((waitfp == DDI_DMA_SLEEP) ? 1 : 0);
7379 7361          if (xfermodes == DDI_DMA_CONSISTENT) {
7380 7362                  rval = i_ddi_mem_alloc(dip, attrp, length, sleepflag,
7381 7363                      flags, accattrp, kaddrp, NULL, ap);
7382 7364                  *real_length = length;
7383 7365          } else {
7384 7366                  rval = i_ddi_mem_alloc(dip, attrp, length, sleepflag,
7385 7367                      flags, accattrp, kaddrp, real_length, ap);
7386 7368          }
7387 7369          if (rval == DDI_SUCCESS) {
7388 7370                  ap->ah_len = (off_t)(*real_length);
7389 7371                  ap->ah_addr = *kaddrp;
7390 7372          } else {
7391 7373                  impl_acc_hdl_free(*handlep);
7392 7374                  *handlep = (ddi_acc_handle_t)NULL;
7393 7375                  if (waitfp != DDI_DMA_SLEEP && waitfp != DDI_DMA_DONTWAIT) {
7394 7376                          ddi_set_callback(waitfp, arg, &dma_mem_list_id);
7395 7377                  }
7396 7378                  rval = DDI_FAILURE;
7397 7379          }
7398 7380          return (rval);
7399 7381  }
7400 7382  
7401 7383  void
7402 7384  ddi_dma_mem_free(ddi_acc_handle_t *handlep)
7403 7385  {
7404 7386          ddi_acc_hdl_t *ap;
7405 7387  
7406 7388          ap = impl_acc_hdl_get(*handlep);
7407 7389          ASSERT(ap);
7408 7390  
7409 7391          i_ddi_mem_free((caddr_t)ap->ah_addr, ap);
7410 7392  
7411 7393          /*
7412 7394           * free the handle
7413 7395           */
7414 7396          impl_acc_hdl_free(*handlep);
7415 7397          *handlep = (ddi_acc_handle_t)NULL;
7416 7398  
7417 7399          if (dma_mem_list_id != 0) {
7418 7400                  ddi_run_callback(&dma_mem_list_id);
7419 7401          }
7420 7402  }
7421 7403  
7422 7404  int
7423 7405  ddi_dma_buf_bind_handle(ddi_dma_handle_t handle, struct buf *bp,
7424 7406          uint_t flags, int (*waitfp)(caddr_t), caddr_t arg,
7425 7407          ddi_dma_cookie_t *cookiep, uint_t *ccountp)
7426 7408  {
7427 7409          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7428 7410          dev_info_t *dip, *rdip;
7429 7411          struct ddi_dma_req dmareq;
7430 7412          int (*funcp)();
7431 7413  
7432 7414          dmareq.dmar_flags = flags;
7433 7415          dmareq.dmar_fp = waitfp;
7434 7416          dmareq.dmar_arg = arg;
7435 7417          dmareq.dmar_object.dmao_size = (uint_t)bp->b_bcount;
7436 7418  
7437 7419          if (bp->b_flags & B_PAGEIO) {
7438 7420                  dmareq.dmar_object.dmao_type = DMA_OTYP_PAGES;
7439 7421                  dmareq.dmar_object.dmao_obj.pp_obj.pp_pp = bp->b_pages;
7440 7422                  dmareq.dmar_object.dmao_obj.pp_obj.pp_offset =
7441 7423                      (uint_t)(((uintptr_t)bp->b_un.b_addr) & MMU_PAGEOFFSET);
7442 7424          } else {
7443 7425                  dmareq.dmar_object.dmao_obj.virt_obj.v_addr = bp->b_un.b_addr;
7444 7426                  if (bp->b_flags & B_SHADOW) {
7445 7427                          dmareq.dmar_object.dmao_obj.virt_obj.v_priv =
7446 7428                              bp->b_shadow;
7447 7429                          dmareq.dmar_object.dmao_type = DMA_OTYP_BUFVADDR;
7448 7430                  } else {
7449 7431                          dmareq.dmar_object.dmao_type =
7450 7432                              (bp->b_flags & (B_PHYS | B_REMAPPED)) ?
7451 7433                              DMA_OTYP_BUFVADDR : DMA_OTYP_VADDR;
7452 7434                          dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
7453 7435                  }
7454 7436  
7455 7437                  /*
7456 7438                   * If the buffer has no proc pointer, or the proc
7457 7439                   * struct has the kernel address space, or the buffer has
7458 7440                   * been marked B_REMAPPED (meaning that it is now
7459 7441                   * mapped into the kernel's address space), then
7460 7442                   * the address space is kas (kernel address space).
7461 7443                   */
7462 7444                  if ((bp->b_proc == NULL) || (bp->b_proc->p_as == &kas) ||
7463 7445                      (bp->b_flags & B_REMAPPED)) {
7464 7446                          dmareq.dmar_object.dmao_obj.virt_obj.v_as = 0;
7465 7447                  } else {
7466 7448                          dmareq.dmar_object.dmao_obj.virt_obj.v_as =
7467 7449                              bp->b_proc->p_as;
7468 7450                  }
7469 7451          }
7470 7452  
7471 7453          dip = rdip = hp->dmai_rdip;
7472 7454          if (dip != ddi_root_node())
7473 7455                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
7474 7456          funcp = DEVI(rdip)->devi_bus_dma_bindfunc;
7475 7457          return ((*funcp)(dip, rdip, handle, &dmareq, cookiep, ccountp));
7476 7458  }
7477 7459  
7478 7460  int
7479 7461  ddi_dma_addr_bind_handle(ddi_dma_handle_t handle, struct as *as,
7480 7462          caddr_t addr, size_t len, uint_t flags, int (*waitfp)(caddr_t),
7481 7463          caddr_t arg, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
7482 7464  {
7483 7465          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7484 7466          dev_info_t *dip, *rdip;
7485 7467          struct ddi_dma_req dmareq;
7486 7468          int (*funcp)();
7487 7469  
7488 7470          if (len == (uint_t)0) {
7489 7471                  return (DDI_DMA_NOMAPPING);
7490 7472          }
7491 7473          dmareq.dmar_flags = flags;
7492 7474          dmareq.dmar_fp = waitfp;
7493 7475          dmareq.dmar_arg = arg;
7494 7476          dmareq.dmar_object.dmao_size = len;
7495 7477          dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR;
7496 7478          dmareq.dmar_object.dmao_obj.virt_obj.v_as = as;
7497 7479          dmareq.dmar_object.dmao_obj.virt_obj.v_addr = addr;
7498 7480          dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
7499 7481  
7500 7482          dip = rdip = hp->dmai_rdip;
7501 7483          if (dip != ddi_root_node())
7502 7484                  dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
7503 7485          funcp = DEVI(rdip)->devi_bus_dma_bindfunc;
7504 7486          return ((*funcp)(dip, rdip, handle, &dmareq, cookiep, ccountp));
7505 7487  }
7506 7488  
7507 7489  void
7508 7490  ddi_dma_nextcookie(ddi_dma_handle_t handle, ddi_dma_cookie_t *cookiep)
7509 7491  {
7510 7492          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7511 7493          ddi_dma_cookie_t *cp;
7512 7494  
7513 7495          cp = hp->dmai_cookie;
7514 7496          ASSERT(cp);
7515 7497  
7516 7498          cookiep->dmac_notused = cp->dmac_notused;
7517 7499          cookiep->dmac_type = cp->dmac_type;
7518 7500          cookiep->dmac_address = cp->dmac_address;
7519 7501          cookiep->dmac_size = cp->dmac_size;
7520 7502          hp->dmai_cookie++;
7521 7503  }
7522 7504  
7523 7505  int
7524 7506  ddi_dma_numwin(ddi_dma_handle_t handle, uint_t *nwinp)
7525 7507  {
7526 7508          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7527 7509          if ((hp->dmai_rflags & DDI_DMA_PARTIAL) == 0) {
7528 7510                  return (DDI_FAILURE);
7529 7511          } else {
7530 7512                  *nwinp = hp->dmai_nwin;
7531 7513                  return (DDI_SUCCESS);
7532 7514          }
7533 7515  }
7534 7516  
7535 7517  int
7536 7518  ddi_dma_getwin(ddi_dma_handle_t h, uint_t win, off_t *offp,
7537 7519          size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
7538 7520  {
7539 7521          int (*funcp)() = ddi_dma_win;
7540 7522          struct bus_ops *bop;
7541 7523  
7542 7524          bop = DEVI(HD)->devi_ops->devo_bus_ops;
7543 7525          if (bop && bop->bus_dma_win)
7544 7526                  funcp = bop->bus_dma_win;
7545 7527  
7546 7528          return ((*funcp)(HD, HD, h, win, offp, lenp, cookiep, ccountp));
7547 7529  }
7548 7530  
7549 7531  int
7550 7532  ddi_dma_set_sbus64(ddi_dma_handle_t h, ulong_t burstsizes)
7551 7533  {
7552 7534          return (ddi_dma_mctl(HD, HD, h, DDI_DMA_SET_SBUS64, 0,
7553 7535              &burstsizes, 0, 0));
7554 7536  }
7555 7537  
7556 7538  int
7557 7539  i_ddi_dma_fault_check(ddi_dma_impl_t *hp)
7558 7540  {
7559 7541          return (hp->dmai_fault);
7560 7542  }
7561 7543  
7562 7544  int
7563 7545  ddi_check_dma_handle(ddi_dma_handle_t handle)
7564 7546  {
7565 7547          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7566 7548          int (*check)(ddi_dma_impl_t *);
7567 7549  
7568 7550          if ((check = hp->dmai_fault_check) == NULL)
7569 7551                  check = i_ddi_dma_fault_check;
7570 7552  
7571 7553          return (((*check)(hp) == DDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
7572 7554  }
7573 7555  
7574 7556  void
7575 7557  i_ddi_dma_set_fault(ddi_dma_handle_t handle)
7576 7558  {
7577 7559          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7578 7560          void (*notify)(ddi_dma_impl_t *);
7579 7561  
7580 7562          if (!hp->dmai_fault) {
7581 7563                  hp->dmai_fault = 1;
7582 7564                  if ((notify = hp->dmai_fault_notify) != NULL)
7583 7565                          (*notify)(hp);
7584 7566          }
7585 7567  }
7586 7568  
7587 7569  void
7588 7570  i_ddi_dma_clr_fault(ddi_dma_handle_t handle)
7589 7571  {
7590 7572          ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
7591 7573          void (*notify)(ddi_dma_impl_t *);
7592 7574  
7593 7575          if (hp->dmai_fault) {
7594 7576                  hp->dmai_fault = 0;
7595 7577                  if ((notify = hp->dmai_fault_notify) != NULL)
7596 7578                          (*notify)(hp);
7597 7579          }
7598 7580  }
7599 7581  
7600 7582  /*
7601 7583   * register mapping routines.
7602 7584   */
7603 7585  int
7604 7586  ddi_regs_map_setup(dev_info_t *dip, uint_t rnumber, caddr_t *addrp,
7605 7587          offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp,
7606 7588          ddi_acc_handle_t *handle)
7607 7589  {
7608 7590          ddi_map_req_t mr;
7609 7591          ddi_acc_hdl_t *hp;
7610 7592          int result;
7611 7593  
7612 7594          /*
7613 7595           * Allocate and initialize the common elements of data access handle.
7614 7596           */
7615 7597          *handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
7616 7598          hp = impl_acc_hdl_get(*handle);
7617 7599          hp->ah_vers = VERS_ACCHDL;
7618 7600          hp->ah_dip = dip;
7619 7601          hp->ah_rnumber = rnumber;
7620 7602          hp->ah_offset = offset;
7621 7603          hp->ah_len = len;
7622 7604          hp->ah_acc = *accattrp;
7623 7605  
7624 7606          /*
7625 7607           * Set up the mapping request and call to parent.
7626 7608           */
7627 7609          mr.map_op = DDI_MO_MAP_LOCKED;
7628 7610          mr.map_type = DDI_MT_RNUMBER;
7629 7611          mr.map_obj.rnumber = rnumber;
7630 7612          mr.map_prot = PROT_READ | PROT_WRITE;
7631 7613          mr.map_flags = DDI_MF_KERNEL_MAPPING;
7632 7614          mr.map_handlep = hp;
7633 7615          mr.map_vers = DDI_MAP_VERSION;
7634 7616          result = ddi_map(dip, &mr, offset, len, addrp);
7635 7617  
7636 7618          /*
7637 7619           * check for end result
7638 7620           */
7639 7621          if (result != DDI_SUCCESS) {
7640 7622                  impl_acc_hdl_free(*handle);
7641 7623                  *handle = (ddi_acc_handle_t)NULL;
7642 7624          } else {
7643 7625                  hp->ah_addr = *addrp;
7644 7626          }
7645 7627  
7646 7628          return (result);
7647 7629  }
7648 7630  
7649 7631  void
7650 7632  ddi_regs_map_free(ddi_acc_handle_t *handlep)
7651 7633  {
7652 7634          ddi_map_req_t mr;
7653 7635          ddi_acc_hdl_t *hp;
7654 7636  
7655 7637          hp = impl_acc_hdl_get(*handlep);
7656 7638          ASSERT(hp);
7657 7639  
7658 7640          mr.map_op = DDI_MO_UNMAP;
7659 7641          mr.map_type = DDI_MT_RNUMBER;
7660 7642          mr.map_obj.rnumber = hp->ah_rnumber;
7661 7643          mr.map_prot = PROT_READ | PROT_WRITE;
7662 7644          mr.map_flags = DDI_MF_KERNEL_MAPPING;
7663 7645          mr.map_handlep = hp;
7664 7646          mr.map_vers = DDI_MAP_VERSION;
7665 7647  
7666 7648          /*
7667 7649           * Call my parent to unmap my regs.
7668 7650           */
7669 7651          (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
7670 7652              hp->ah_len, &hp->ah_addr);
7671 7653          /*
7672 7654           * free the handle
7673 7655           */
7674 7656          impl_acc_hdl_free(*handlep);
7675 7657          *handlep = (ddi_acc_handle_t)NULL;
7676 7658  }
7677 7659  
7678 7660  int
7679 7661  ddi_device_zero(ddi_acc_handle_t handle, caddr_t dev_addr, size_t bytecount,
7680 7662          ssize_t dev_advcnt, uint_t dev_datasz)
7681 7663  {
7682 7664          uint8_t *b;
7683 7665          uint16_t *w;
7684 7666          uint32_t *l;
7685 7667          uint64_t *ll;
7686 7668  
7687 7669          /* check for total byte count is multiple of data transfer size */
7688 7670          if (bytecount != ((bytecount / dev_datasz) * dev_datasz))
7689 7671                  return (DDI_FAILURE);
7690 7672  
7691 7673          switch (dev_datasz) {
7692 7674          case DDI_DATA_SZ01_ACC:
7693 7675                  for (b = (uint8_t *)dev_addr;
7694 7676                      bytecount != 0; bytecount -= 1, b += dev_advcnt)
7695 7677                          ddi_put8(handle, b, 0);
7696 7678                  break;
7697 7679          case DDI_DATA_SZ02_ACC:
7698 7680                  for (w = (uint16_t *)dev_addr;
7699 7681                      bytecount != 0; bytecount -= 2, w += dev_advcnt)
7700 7682                          ddi_put16(handle, w, 0);
7701 7683                  break;
7702 7684          case DDI_DATA_SZ04_ACC:
7703 7685                  for (l = (uint32_t *)dev_addr;
7704 7686                      bytecount != 0; bytecount -= 4, l += dev_advcnt)
7705 7687                          ddi_put32(handle, l, 0);
7706 7688                  break;
7707 7689          case DDI_DATA_SZ08_ACC:
7708 7690                  for (ll = (uint64_t *)dev_addr;
7709 7691                      bytecount != 0; bytecount -= 8, ll += dev_advcnt)
7710 7692                          ddi_put64(handle, ll, 0x0ll);
7711 7693                  break;
7712 7694          default:
7713 7695                  return (DDI_FAILURE);
7714 7696          }
7715 7697          return (DDI_SUCCESS);
7716 7698  }
7717 7699  
7718 7700  int
7719 7701  ddi_device_copy(
7720 7702          ddi_acc_handle_t src_handle, caddr_t src_addr, ssize_t src_advcnt,
7721 7703          ddi_acc_handle_t dest_handle, caddr_t dest_addr, ssize_t dest_advcnt,
7722 7704          size_t bytecount, uint_t dev_datasz)
7723 7705  {
7724 7706          uint8_t *b_src, *b_dst;
7725 7707          uint16_t *w_src, *w_dst;
7726 7708          uint32_t *l_src, *l_dst;
7727 7709          uint64_t *ll_src, *ll_dst;
7728 7710  
7729 7711          /* check for total byte count is multiple of data transfer size */
7730 7712          if (bytecount != ((bytecount / dev_datasz) * dev_datasz))
7731 7713                  return (DDI_FAILURE);
7732 7714  
7733 7715          switch (dev_datasz) {
7734 7716          case DDI_DATA_SZ01_ACC:
7735 7717                  b_src = (uint8_t *)src_addr;
7736 7718                  b_dst = (uint8_t *)dest_addr;
7737 7719  
7738 7720                  for (; bytecount != 0; bytecount -= 1) {
7739 7721                          ddi_put8(dest_handle, b_dst,
7740 7722                              ddi_get8(src_handle, b_src));
7741 7723                          b_dst += dest_advcnt;
7742 7724                          b_src += src_advcnt;
7743 7725                  }
7744 7726                  break;
7745 7727          case DDI_DATA_SZ02_ACC:
7746 7728                  w_src = (uint16_t *)src_addr;
7747 7729                  w_dst = (uint16_t *)dest_addr;
7748 7730  
7749 7731                  for (; bytecount != 0; bytecount -= 2) {
7750 7732                          ddi_put16(dest_handle, w_dst,
7751 7733                              ddi_get16(src_handle, w_src));
7752 7734                          w_dst += dest_advcnt;
7753 7735                          w_src += src_advcnt;
7754 7736                  }
7755 7737                  break;
7756 7738          case DDI_DATA_SZ04_ACC:
7757 7739                  l_src = (uint32_t *)src_addr;
7758 7740                  l_dst = (uint32_t *)dest_addr;
7759 7741  
7760 7742                  for (; bytecount != 0; bytecount -= 4) {
7761 7743                          ddi_put32(dest_handle, l_dst,
7762 7744                              ddi_get32(src_handle, l_src));
7763 7745                          l_dst += dest_advcnt;
7764 7746                          l_src += src_advcnt;
7765 7747                  }
7766 7748                  break;
7767 7749          case DDI_DATA_SZ08_ACC:
7768 7750                  ll_src = (uint64_t *)src_addr;
7769 7751                  ll_dst = (uint64_t *)dest_addr;
7770 7752  
7771 7753                  for (; bytecount != 0; bytecount -= 8) {
7772 7754                          ddi_put64(dest_handle, ll_dst,
7773 7755                              ddi_get64(src_handle, ll_src));
7774 7756                          ll_dst += dest_advcnt;
7775 7757                          ll_src += src_advcnt;
7776 7758                  }
7777 7759                  break;
7778 7760          default:
7779 7761                  return (DDI_FAILURE);
7780 7762          }
7781 7763          return (DDI_SUCCESS);
7782 7764  }
7783 7765  
7784 7766  #define swap16(value)  \
7785 7767          ((((value) & 0xff) << 8) | ((value) >> 8))
7786 7768  
7787 7769  #define swap32(value)   \
7788 7770          (((uint32_t)swap16((uint16_t)((value) & 0xffff)) << 16) | \
7789 7771          (uint32_t)swap16((uint16_t)((value) >> 16)))
7790 7772  
7791 7773  #define swap64(value)   \
7792 7774          (((uint64_t)swap32((uint32_t)((value) & 0xffffffff)) \
7793 7775              << 32) | \
7794 7776          (uint64_t)swap32((uint32_t)((value) >> 32)))
7795 7777  
7796 7778  uint16_t
7797 7779  ddi_swap16(uint16_t value)
7798 7780  {
7799 7781          return (swap16(value));
7800 7782  }
7801 7783  
7802 7784  uint32_t
7803 7785  ddi_swap32(uint32_t value)
7804 7786  {
7805 7787          return (swap32(value));
7806 7788  }
7807 7789  
7808 7790  uint64_t
7809 7791  ddi_swap64(uint64_t value)
7810 7792  {
7811 7793          return (swap64(value));
7812 7794  }
7813 7795  
7814 7796  /*
7815 7797   * Convert a binding name to a driver name.
7816 7798   * A binding name is the name used to determine the driver for a
7817 7799   * device - it may be either an alias for the driver or the name
7818 7800   * of the driver itself.
7819 7801   */
7820 7802  char *
7821 7803  i_binding_to_drv_name(char *bname)
7822 7804  {
7823 7805          major_t major_no;
7824 7806  
7825 7807          ASSERT(bname != NULL);
7826 7808  
7827 7809          if ((major_no = ddi_name_to_major(bname)) == -1)
7828 7810                  return (NULL);
7829 7811          return (ddi_major_to_name(major_no));
7830 7812  }
7831 7813  
7832 7814  /*
7833 7815   * Search for minor name that has specified dev_t and spec_type.
7834 7816   * If spec_type is zero then any dev_t match works.  Since we
7835 7817   * are returning a pointer to the minor name string, we require the
7836 7818   * caller to do the locking.
7837 7819   */
7838 7820  char *
7839 7821  i_ddi_devtspectype_to_minorname(dev_info_t *dip, dev_t dev, int spec_type)
7840 7822  {
7841 7823          struct ddi_minor_data   *dmdp;
7842 7824  
7843 7825          /*
7844 7826           * The did layered driver currently intentionally returns a
7845 7827           * devinfo ptr for an underlying sd instance based on a did
7846 7828           * dev_t. In this case it is not an error.
7847 7829           *
7848 7830           * The did layered driver is associated with Sun Cluster.
7849 7831           */
7850 7832          ASSERT((ddi_driver_major(dip) == getmajor(dev)) ||
7851 7833              (strcmp(ddi_major_to_name(getmajor(dev)), "did") == 0));
7852 7834  
7853 7835          ASSERT(DEVI_BUSY_OWNED(dip));
7854 7836          for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
7855 7837                  if (((dmdp->type == DDM_MINOR) ||
7856 7838                      (dmdp->type == DDM_INTERNAL_PATH) ||
7857 7839                      (dmdp->type == DDM_DEFAULT)) &&
7858 7840                      (dmdp->ddm_dev == dev) &&
7859 7841                      ((((spec_type & (S_IFCHR|S_IFBLK))) == 0) ||
7860 7842                      (dmdp->ddm_spec_type == spec_type)))
7861 7843                          return (dmdp->ddm_name);
7862 7844          }
7863 7845  
7864 7846          return (NULL);
7865 7847  }
7866 7848  
7867 7849  /*
7868 7850   * Find the devt and spectype of the specified minor_name.
7869 7851   * Return DDI_FAILURE if minor_name not found. Since we are
7870 7852   * returning everything via arguments we can do the locking.
7871 7853   */
7872 7854  int
7873 7855  i_ddi_minorname_to_devtspectype(dev_info_t *dip, char *minor_name,
7874 7856          dev_t *devtp, int *spectypep)
7875 7857  {
7876 7858          int                     circ;
7877 7859          struct ddi_minor_data   *dmdp;
7878 7860  
7879 7861          /* deal with clone minor nodes */
7880 7862          if (dip == clone_dip) {
7881 7863                  major_t major;
7882 7864                  /*
7883 7865                   * Make sure minor_name is a STREAMS driver.
7884 7866                   * We load the driver but don't attach to any instances.
7885 7867                   */
7886 7868  
7887 7869                  major = ddi_name_to_major(minor_name);
7888 7870                  if (major == DDI_MAJOR_T_NONE)
7889 7871                          return (DDI_FAILURE);
7890 7872  
7891 7873                  if (ddi_hold_driver(major) == NULL)
7892 7874                          return (DDI_FAILURE);
7893 7875  
7894 7876                  if (STREAMSTAB(major) == NULL) {
7895 7877                          ddi_rele_driver(major);
7896 7878                          return (DDI_FAILURE);
7897 7879                  }
7898 7880                  ddi_rele_driver(major);
7899 7881  
7900 7882                  if (devtp)
7901 7883                          *devtp = makedevice(clone_major, (minor_t)major);
7902 7884  
7903 7885                  if (spectypep)
7904 7886                          *spectypep = S_IFCHR;
7905 7887  
7906 7888                  return (DDI_SUCCESS);
7907 7889          }
7908 7890  
7909 7891          ndi_devi_enter(dip, &circ);
7910 7892          for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
7911 7893                  if (((dmdp->type != DDM_MINOR) &&
7912 7894                      (dmdp->type != DDM_INTERNAL_PATH) &&
7913 7895                      (dmdp->type != DDM_DEFAULT)) ||
7914 7896                      strcmp(minor_name, dmdp->ddm_name))
7915 7897                          continue;
7916 7898  
7917 7899                  if (devtp)
7918 7900                          *devtp = dmdp->ddm_dev;
7919 7901  
7920 7902                  if (spectypep)
7921 7903                          *spectypep = dmdp->ddm_spec_type;
7922 7904  
7923 7905                  ndi_devi_exit(dip, circ);
7924 7906                  return (DDI_SUCCESS);
7925 7907          }
7926 7908          ndi_devi_exit(dip, circ);
7927 7909  
7928 7910          return (DDI_FAILURE);
7929 7911  }
7930 7912  
7931 7913  static kmutex_t devid_gen_mutex;
7932 7914  static short    devid_gen_number;
7933 7915  
7934 7916  #ifdef DEBUG
7935 7917  
7936 7918  static int      devid_register_corrupt = 0;
7937 7919  static int      devid_register_corrupt_major = 0;
7938 7920  static int      devid_register_corrupt_hint = 0;
7939 7921  static int      devid_register_corrupt_hint_major = 0;
7940 7922  
7941 7923  static int devid_lyr_debug = 0;
7942 7924  
7943 7925  #define DDI_DEBUG_DEVID_DEVTS(msg, ndevs, devs)         \
7944 7926          if (devid_lyr_debug)                                    \
7945 7927                  ddi_debug_devid_devts(msg, ndevs, devs)
7946 7928  
7947 7929  #else
7948 7930  
7949 7931  #define DDI_DEBUG_DEVID_DEVTS(msg, ndevs, devs)
7950 7932  
7951 7933  #endif /* DEBUG */
7952 7934  
7953 7935  
7954 7936  #ifdef  DEBUG
7955 7937  
7956 7938  static void
7957 7939  ddi_debug_devid_devts(char *msg, int ndevs, dev_t *devs)
7958 7940  {
7959 7941          int i;
7960 7942  
7961 7943          cmn_err(CE_CONT, "%s:\n", msg);
7962 7944          for (i = 0; i < ndevs; i++) {
7963 7945                  cmn_err(CE_CONT, "    0x%lx\n", devs[i]);
7964 7946          }
7965 7947  }
7966 7948  
7967 7949  static void
7968 7950  ddi_debug_devid_paths(char *msg, int npaths, char **paths)
7969 7951  {
7970 7952          int i;
7971 7953  
7972 7954          cmn_err(CE_CONT, "%s:\n", msg);
7973 7955          for (i = 0; i < npaths; i++) {
7974 7956                  cmn_err(CE_CONT, "    %s\n", paths[i]);
7975 7957          }
7976 7958  }
7977 7959  
7978 7960  static void
7979 7961  ddi_debug_devid_devts_per_path(char *path, int ndevs, dev_t *devs)
7980 7962  {
7981 7963          int i;
7982 7964  
7983 7965          cmn_err(CE_CONT, "dev_ts per path %s\n", path);
7984 7966          for (i = 0; i < ndevs; i++) {
7985 7967                  cmn_err(CE_CONT, "    0x%lx\n", devs[i]);
7986 7968          }
7987 7969  }
7988 7970  
7989 7971  #endif  /* DEBUG */
7990 7972  
7991 7973  /*
7992 7974   * Register device id into DDI framework.
7993 7975   * Must be called when the driver is bound.
7994 7976   */
7995 7977  static int
7996 7978  i_ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
7997 7979  {
7998 7980          impl_devid_t    *i_devid = (impl_devid_t *)devid;
7999 7981          size_t          driver_len;
8000 7982          const char      *driver_name;
8001 7983          char            *devid_str;
8002 7984          major_t         major;
8003 7985  
8004 7986          if ((dip == NULL) ||
8005 7987              ((major = ddi_driver_major(dip)) == DDI_MAJOR_T_NONE))
8006 7988                  return (DDI_FAILURE);
8007 7989  
8008 7990          /* verify that the devid is valid */
8009 7991          if (ddi_devid_valid(devid) != DDI_SUCCESS)
8010 7992                  return (DDI_FAILURE);
8011 7993  
8012 7994          /* Updating driver name hint in devid */
8013 7995          driver_name = ddi_driver_name(dip);
8014 7996          driver_len = strlen(driver_name);
8015 7997          if (driver_len > DEVID_HINT_SIZE) {
8016 7998                  /* Pick up last four characters of driver name */
8017 7999                  driver_name += driver_len - DEVID_HINT_SIZE;
8018 8000                  driver_len = DEVID_HINT_SIZE;
8019 8001          }
8020 8002          bzero(i_devid->did_driver, DEVID_HINT_SIZE);
8021 8003          bcopy(driver_name, i_devid->did_driver, driver_len);
8022 8004  
8023 8005  #ifdef DEBUG
8024 8006          /* Corrupt the devid for testing. */
8025 8007          if (devid_register_corrupt)
8026 8008                  i_devid->did_id[0] += devid_register_corrupt;
8027 8009          if (devid_register_corrupt_major &&
8028 8010              (major == devid_register_corrupt_major))
8029 8011                  i_devid->did_id[0] += 1;
8030 8012          if (devid_register_corrupt_hint)
8031 8013                  i_devid->did_driver[0] += devid_register_corrupt_hint;
8032 8014          if (devid_register_corrupt_hint_major &&
8033 8015              (major == devid_register_corrupt_hint_major))
8034 8016                  i_devid->did_driver[0] += 1;
8035 8017  #endif /* DEBUG */
8036 8018  
8037 8019          /* encode the devid as a string */
8038 8020          if ((devid_str = ddi_devid_str_encode(devid, NULL)) == NULL)
8039 8021                  return (DDI_FAILURE);
8040 8022  
8041 8023          /* add string as a string property */
8042 8024          if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
8043 8025              DEVID_PROP_NAME, devid_str) != DDI_SUCCESS) {
8044 8026                  cmn_err(CE_WARN, "%s%d: devid property update failed",
8045 8027                      ddi_driver_name(dip), ddi_get_instance(dip));
8046 8028                  ddi_devid_str_free(devid_str);
8047 8029                  return (DDI_FAILURE);
8048 8030          }
8049 8031  
8050 8032          /* keep pointer to devid string for interrupt context fma code */
8051 8033          if (DEVI(dip)->devi_devid_str)
8052 8034                  ddi_devid_str_free(DEVI(dip)->devi_devid_str);
8053 8035          DEVI(dip)->devi_devid_str = devid_str;
8054 8036          return (DDI_SUCCESS);
8055 8037  }
8056 8038  
8057 8039  int
8058 8040  ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
8059 8041  {
8060 8042          int rval;
8061 8043  
8062 8044          rval = i_ddi_devid_register(dip, devid);
8063 8045          if (rval == DDI_SUCCESS) {
8064 8046                  /*
8065 8047                   * Register devid in devid-to-path cache
8066 8048                   */
8067 8049                  if (e_devid_cache_register(dip, devid) == DDI_SUCCESS) {
8068 8050                          mutex_enter(&DEVI(dip)->devi_lock);
8069 8051                          DEVI(dip)->devi_flags |= DEVI_CACHED_DEVID;
8070 8052                          mutex_exit(&DEVI(dip)->devi_lock);
8071 8053                  } else if (ddi_get_name_addr(dip)) {
8072 8054                          /*
8073 8055                           * We only expect cache_register DDI_FAILURE when we
8074 8056                           * can't form the full path because of NULL devi_addr.
8075 8057                           */
8076 8058                          cmn_err(CE_WARN, "%s%d: failed to cache devid",
8077 8059                              ddi_driver_name(dip), ddi_get_instance(dip));
8078 8060                  }
8079 8061          } else {
8080 8062                  cmn_err(CE_WARN, "%s%d: failed to register devid",
8081 8063                      ddi_driver_name(dip), ddi_get_instance(dip));
8082 8064          }
8083 8065          return (rval);
8084 8066  }
8085 8067  
8086 8068  /*
8087 8069   * Remove (unregister) device id from DDI framework.
8088 8070   * Must be called when device is detached.
8089 8071   */
8090 8072  static void
8091 8073  i_ddi_devid_unregister(dev_info_t *dip)
8092 8074  {
8093 8075          if (DEVI(dip)->devi_devid_str) {
8094 8076                  ddi_devid_str_free(DEVI(dip)->devi_devid_str);
8095 8077                  DEVI(dip)->devi_devid_str = NULL;
8096 8078          }
8097 8079  
8098 8080          /* remove the devid property */
8099 8081          (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, DEVID_PROP_NAME);
8100 8082  }
8101 8083  
8102 8084  void
8103 8085  ddi_devid_unregister(dev_info_t *dip)
8104 8086  {
8105 8087          mutex_enter(&DEVI(dip)->devi_lock);
8106 8088          DEVI(dip)->devi_flags &= ~DEVI_CACHED_DEVID;
8107 8089          mutex_exit(&DEVI(dip)->devi_lock);
8108 8090          e_devid_cache_unregister(dip);
8109 8091          i_ddi_devid_unregister(dip);
8110 8092  }
8111 8093  
8112 8094  /*
8113 8095   * Allocate and initialize a device id.
8114 8096   */
8115 8097  int
8116 8098  ddi_devid_init(
8117 8099          dev_info_t      *dip,
8118 8100          ushort_t        devid_type,
8119 8101          ushort_t        nbytes,
8120 8102          void            *id,
8121 8103          ddi_devid_t     *ret_devid)
8122 8104  {
8123 8105          impl_devid_t    *i_devid;
8124 8106          int             sz = sizeof (*i_devid) + nbytes - sizeof (char);
8125 8107          int             driver_len;
8126 8108          const char      *driver_name;
8127 8109  
8128 8110          switch (devid_type) {
8129 8111          case DEVID_SCSI3_WWN:
8130 8112                  /*FALLTHRU*/
8131 8113          case DEVID_SCSI_SERIAL:
8132 8114                  /*FALLTHRU*/
8133 8115          case DEVID_ATA_SERIAL:
8134 8116                  /*FALLTHRU*/
8135 8117          case DEVID_ENCAP:
8136 8118                  if (nbytes == 0)
8137 8119                          return (DDI_FAILURE);
8138 8120                  if (id == NULL)
8139 8121                          return (DDI_FAILURE);
8140 8122                  break;
8141 8123          case DEVID_FAB:
8142 8124                  if (nbytes != 0)
8143 8125                          return (DDI_FAILURE);
8144 8126                  if (id != NULL)
8145 8127                          return (DDI_FAILURE);
8146 8128                  nbytes = sizeof (int) +
8147 8129                      sizeof (struct timeval32) + sizeof (short);
8148 8130                  sz += nbytes;
8149 8131                  break;
8150 8132          default:
8151 8133                  return (DDI_FAILURE);
8152 8134          }
8153 8135  
8154 8136          if ((i_devid = kmem_zalloc(sz, KM_SLEEP)) == NULL)
8155 8137                  return (DDI_FAILURE);
8156 8138  
8157 8139          i_devid->did_magic_hi = DEVID_MAGIC_MSB;
8158 8140          i_devid->did_magic_lo = DEVID_MAGIC_LSB;
8159 8141          i_devid->did_rev_hi = DEVID_REV_MSB;
8160 8142          i_devid->did_rev_lo = DEVID_REV_LSB;
8161 8143          DEVID_FORMTYPE(i_devid, devid_type);
8162 8144          DEVID_FORMLEN(i_devid, nbytes);
8163 8145  
8164 8146          /* Fill in driver name hint */
8165 8147          driver_name = ddi_driver_name(dip);
8166 8148          driver_len = strlen(driver_name);
8167 8149          if (driver_len > DEVID_HINT_SIZE) {
8168 8150                  /* Pick up last four characters of driver name */
8169 8151                  driver_name += driver_len - DEVID_HINT_SIZE;
8170 8152                  driver_len = DEVID_HINT_SIZE;
8171 8153          }
8172 8154  
8173 8155          bcopy(driver_name, i_devid->did_driver, driver_len);
8174 8156  
8175 8157          /* Fill in id field */
8176 8158          if (devid_type == DEVID_FAB) {
8177 8159                  char            *cp;
8178 8160                  uint32_t        hostid;
8179 8161                  struct timeval32 timestamp32;
8180 8162                  int             i;
8181 8163                  int             *ip;
8182 8164                  short           gen;
8183 8165  
8184 8166                  /* increase the generation number */
8185 8167                  mutex_enter(&devid_gen_mutex);
8186 8168                  gen = devid_gen_number++;
8187 8169                  mutex_exit(&devid_gen_mutex);
8188 8170  
8189 8171                  cp = i_devid->did_id;
8190 8172  
8191 8173                  /* Fill in host id (big-endian byte ordering) */
8192 8174                  hostid = zone_get_hostid(NULL);
8193 8175                  *cp++ = hibyte(hiword(hostid));
8194 8176                  *cp++ = lobyte(hiword(hostid));
8195 8177                  *cp++ = hibyte(loword(hostid));
8196 8178                  *cp++ = lobyte(loword(hostid));
8197 8179  
8198 8180                  /*
8199 8181                   * Fill in timestamp (big-endian byte ordering)
8200 8182                   *
8201 8183                   * (Note that the format may have to be changed
8202 8184                   * before 2038 comes around, though it's arguably
8203 8185                   * unique enough as it is..)
8204 8186                   */
8205 8187                  uniqtime32(×tamp32);
8206 8188                  ip = (int *)×tamp32;
8207 8189                  for (i = 0;
8208 8190                      i < sizeof (timestamp32) / sizeof (int); i++, ip++) {
8209 8191                          int     val;
8210 8192                          val = *ip;
8211 8193                          *cp++ = hibyte(hiword(val));
8212 8194                          *cp++ = lobyte(hiword(val));
8213 8195                          *cp++ = hibyte(loword(val));
8214 8196                          *cp++ = lobyte(loword(val));
8215 8197                  }
8216 8198  
8217 8199                  /* fill in the generation number */
8218 8200                  *cp++ = hibyte(gen);
8219 8201                  *cp++ = lobyte(gen);
8220 8202          } else
8221 8203                  bcopy(id, i_devid->did_id, nbytes);
8222 8204  
8223 8205          /* return device id */
8224 8206          *ret_devid = (ddi_devid_t)i_devid;
8225 8207          return (DDI_SUCCESS);
8226 8208  }
8227 8209  
8228 8210  int
8229 8211  ddi_devid_get(dev_info_t *dip, ddi_devid_t *ret_devid)
8230 8212  {
8231 8213          return (i_ddi_devi_get_devid(DDI_DEV_T_ANY, dip, ret_devid));
8232 8214  }
8233 8215  
8234 8216  int
8235 8217  i_ddi_devi_get_devid(dev_t dev, dev_info_t *dip, ddi_devid_t *ret_devid)
8236 8218  {
8237 8219          char            *devidstr;
8238 8220  
8239 8221          ASSERT(dev != DDI_DEV_T_NONE);
8240 8222  
8241 8223          /* look up the property, devt specific first */
8242 8224          if (ddi_prop_lookup_string(dev, dip, DDI_PROP_DONTPASS,
8243 8225              DEVID_PROP_NAME, &devidstr) != DDI_PROP_SUCCESS) {
8244 8226                  if ((dev == DDI_DEV_T_ANY) ||
8245 8227                      (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
8246 8228                      DDI_PROP_DONTPASS, DEVID_PROP_NAME, &devidstr) !=
8247 8229                      DDI_PROP_SUCCESS)) {
8248 8230                          return (DDI_FAILURE);
8249 8231                  }
8250 8232          }
8251 8233  
8252 8234          /* convert to binary form */
8253 8235          if (ddi_devid_str_decode(devidstr, ret_devid, NULL) == -1) {
8254 8236                  ddi_prop_free(devidstr);
8255 8237                  return (DDI_FAILURE);
8256 8238          }
8257 8239          ddi_prop_free(devidstr);
8258 8240          return (DDI_SUCCESS);
8259 8241  }
8260 8242  
8261 8243  /*
8262 8244   * Return a copy of the device id for dev_t
8263 8245   */
8264 8246  int
8265 8247  ddi_lyr_get_devid(dev_t dev, ddi_devid_t *ret_devid)
8266 8248  {
8267 8249          dev_info_t      *dip;
8268 8250          int             rval;
8269 8251  
8270 8252          /* get the dip */
8271 8253          if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
8272 8254                  return (DDI_FAILURE);
8273 8255  
8274 8256          rval = i_ddi_devi_get_devid(dev, dip, ret_devid);
8275 8257  
8276 8258          ddi_release_devi(dip);          /* e_ddi_hold_devi_by_dev() */
8277 8259          return (rval);
8278 8260  }
8279 8261  
8280 8262  /*
8281 8263   * Return a copy of the minor name for dev_t and spec_type
8282 8264   */
8283 8265  int
8284 8266  ddi_lyr_get_minor_name(dev_t dev, int spec_type, char **minor_name)
8285 8267  {
8286 8268          char            *buf;
8287 8269          int             circ;
8288 8270          dev_info_t      *dip;
8289 8271          char            *nm;
8290 8272          int             rval;
8291 8273  
8292 8274          if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL) {
8293 8275                  *minor_name = NULL;
8294 8276                  return (DDI_FAILURE);
8295 8277          }
8296 8278  
8297 8279          /* Find the minor name and copy into max size buf */
8298 8280          buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
8299 8281          ndi_devi_enter(dip, &circ);
8300 8282          nm = i_ddi_devtspectype_to_minorname(dip, dev, spec_type);
8301 8283          if (nm)
8302 8284                  (void) strcpy(buf, nm);
8303 8285          ndi_devi_exit(dip, circ);
8304 8286          ddi_release_devi(dip);  /* e_ddi_hold_devi_by_dev() */
8305 8287  
8306 8288          if (nm) {
8307 8289                  /* duplicate into min size buf for return result */
8308 8290                  *minor_name = i_ddi_strdup(buf, KM_SLEEP);
8309 8291                  rval = DDI_SUCCESS;
8310 8292          } else {
8311 8293                  *minor_name = NULL;
8312 8294                  rval = DDI_FAILURE;
8313 8295          }
8314 8296  
8315 8297          /* free max size buf and return */
8316 8298          kmem_free(buf, MAXNAMELEN);
8317 8299          return (rval);
8318 8300  }
8319 8301  
8320 8302  int
8321 8303  ddi_lyr_devid_to_devlist(
8322 8304          ddi_devid_t     devid,
8323 8305          char            *minor_name,
8324 8306          int             *retndevs,
8325 8307          dev_t           **retdevs)
8326 8308  {
8327 8309          ASSERT(ddi_devid_valid(devid) == DDI_SUCCESS);
8328 8310  
8329 8311          if (e_devid_cache_to_devt_list(devid, minor_name,
8330 8312              retndevs, retdevs) == DDI_SUCCESS) {
8331 8313                  ASSERT(*retndevs > 0);
8332 8314                  DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
8333 8315                      *retndevs, *retdevs);
8334 8316                  return (DDI_SUCCESS);
8335 8317          }
8336 8318  
8337 8319          if (e_ddi_devid_discovery(devid) == DDI_FAILURE) {
8338 8320                  return (DDI_FAILURE);
8339 8321          }
8340 8322  
8341 8323          if (e_devid_cache_to_devt_list(devid, minor_name,
8342 8324              retndevs, retdevs) == DDI_SUCCESS) {
8343 8325                  ASSERT(*retndevs > 0);
8344 8326                  DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
8345 8327                      *retndevs, *retdevs);
8346 8328                  return (DDI_SUCCESS);
8347 8329          }
8348 8330  
8349 8331          return (DDI_FAILURE);
8350 8332  }
8351 8333  
8352 8334  void
8353 8335  ddi_lyr_free_devlist(dev_t *devlist, int ndevs)
8354 8336  {
8355 8337          kmem_free(devlist, sizeof (dev_t) * ndevs);
8356 8338  }
8357 8339  
8358 8340  /*
8359 8341   * Note: This will need to be fixed if we ever allow processes to
8360 8342   * have more than one data model per exec.
8361 8343   */
8362 8344  model_t
8363 8345  ddi_mmap_get_model(void)
8364 8346  {
8365 8347          return (get_udatamodel());
8366 8348  }
8367 8349  
8368 8350  model_t
8369 8351  ddi_model_convert_from(model_t model)
8370 8352  {
8371 8353          return ((model & DDI_MODEL_MASK) & ~DDI_MODEL_NATIVE);
8372 8354  }
8373 8355  
8374 8356  /*
8375 8357   * ddi interfaces managing storage and retrieval of eventcookies.
8376 8358   */
8377 8359  
8378 8360  /*
8379 8361   * Invoke bus nexus driver's implementation of the
8380 8362   * (*bus_remove_eventcall)() interface to remove a registered
8381 8363   * callback handler for "event".
8382 8364   */
8383 8365  int
8384 8366  ddi_remove_event_handler(ddi_callback_id_t id)
8385 8367  {
8386 8368          ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)id;
8387 8369          dev_info_t *ddip;
8388 8370  
8389 8371          ASSERT(cb);
8390 8372          if (!cb) {
8391 8373                  return (DDI_FAILURE);
8392 8374          }
8393 8375  
8394 8376          ddip = NDI_EVENT_DDIP(cb->ndi_evtcb_cookie);
8395 8377          return (ndi_busop_remove_eventcall(ddip, id));
8396 8378  }
8397 8379  
8398 8380  /*
8399 8381   * Invoke bus nexus driver's implementation of the
8400 8382   * (*bus_add_eventcall)() interface to register a callback handler
8401 8383   * for "event".
8402 8384   */
8403 8385  int
8404 8386  ddi_add_event_handler(dev_info_t *dip, ddi_eventcookie_t event,
8405 8387      void (*handler)(dev_info_t *, ddi_eventcookie_t, void *, void *),
8406 8388      void *arg, ddi_callback_id_t *id)
8407 8389  {
8408 8390          return (ndi_busop_add_eventcall(dip, dip, event, handler, arg, id));
8409 8391  }
8410 8392  
8411 8393  
8412 8394  /*
8413 8395   * Return a handle for event "name" by calling up the device tree
8414 8396   * hierarchy via  (*bus_get_eventcookie)() interface until claimed
8415 8397   * by a bus nexus or top of dev_info tree is reached.
8416 8398   */
8417 8399  int
8418 8400  ddi_get_eventcookie(dev_info_t *dip, char *name,
8419 8401      ddi_eventcookie_t *event_cookiep)
8420 8402  {
8421 8403          return (ndi_busop_get_eventcookie(dip, dip,
8422 8404              name, event_cookiep));
8423 8405  }
8424 8406  
8425 8407  /*
8426 8408   * This procedure is provided as the general callback function when
8427 8409   * umem_lockmemory calls as_add_callback for long term memory locking.
8428 8410   * When as_unmap, as_setprot, or as_free encounter segments which have
8429 8411   * locked memory, this callback will be invoked.
8430 8412   */
8431 8413  void
8432 8414  umem_lock_undo(struct as *as, void *arg, uint_t event)
8433 8415  {
8434 8416          _NOTE(ARGUNUSED(as, event))
8435 8417          struct ddi_umem_cookie *cp = (struct ddi_umem_cookie *)arg;
8436 8418  
8437 8419          /*
8438 8420           * Call the cleanup function.  Decrement the cookie reference
8439 8421           * count, if it goes to zero, return the memory for the cookie.
8440 8422           * The i_ddi_umem_unlock for this cookie may or may not have been
8441 8423           * called already.  It is the responsibility of the caller of
8442 8424           * umem_lockmemory to handle the case of the cleanup routine
8443 8425           * being called after a ddi_umem_unlock for the cookie
8444 8426           * was called.
8445 8427           */
8446 8428  
8447 8429          (*cp->callbacks.cbo_umem_lock_cleanup)((ddi_umem_cookie_t)cp);
8448 8430  
8449 8431          /* remove the cookie if reference goes to zero */
8450 8432          if (atomic_add_long_nv((ulong_t *)(&(cp->cook_refcnt)), -1) == 0) {
8451 8433                  kmem_free(cp, sizeof (struct ddi_umem_cookie));
8452 8434          }
8453 8435  }
8454 8436  
8455 8437  /*
8456 8438   * The following two Consolidation Private routines provide generic
8457 8439   * interfaces to increase/decrease the amount of device-locked memory.
8458 8440   *
8459 8441   * To keep project_rele and project_hold consistent, i_ddi_decr_locked_memory()
8460 8442   * must be called every time i_ddi_incr_locked_memory() is called.
8461 8443   */
8462 8444  int
8463 8445  /* ARGSUSED */
8464 8446  i_ddi_incr_locked_memory(proc_t *procp, rctl_qty_t inc)
8465 8447  {
8466 8448          ASSERT(procp != NULL);
8467 8449          mutex_enter(&procp->p_lock);
8468 8450          if (rctl_incr_locked_mem(procp, NULL, inc, 1)) {
8469 8451                  mutex_exit(&procp->p_lock);
8470 8452                  return (ENOMEM);
8471 8453          }
8472 8454          mutex_exit(&procp->p_lock);
8473 8455          return (0);
8474 8456  }
8475 8457  
8476 8458  /*
8477 8459   * To keep project_rele and project_hold consistent, i_ddi_incr_locked_memory()
8478 8460   * must be called every time i_ddi_decr_locked_memory() is called.
8479 8461   */
8480 8462  /* ARGSUSED */
8481 8463  void
8482 8464  i_ddi_decr_locked_memory(proc_t *procp, rctl_qty_t dec)
8483 8465  {
8484 8466          ASSERT(procp != NULL);
8485 8467          mutex_enter(&procp->p_lock);
8486 8468          rctl_decr_locked_mem(procp, NULL, dec, 1);
8487 8469          mutex_exit(&procp->p_lock);
8488 8470  }
8489 8471  
8490 8472  /*
8491 8473   * The cookie->upd_max_lock_rctl flag is used to determine if we should
8492 8474   * charge device locked memory to the max-locked-memory rctl.  Tracking
8493 8475   * device locked memory causes the rctl locks to get hot under high-speed
8494 8476   * I/O such as RDSv3 over IB.  If there is no max-locked-memory rctl limit,
8495 8477   * we bypass charging the locked memory to the rctl altogether.  The cookie's
8496 8478   * flag tells us if the rctl value should be updated when unlocking the memory,
8497 8479   * in case the rctl gets changed after the memory was locked.  Any device
8498 8480   * locked memory in that rare case will not be counted toward the rctl limit.
8499 8481   *
8500 8482   * When tracking the locked memory, the kproject_t parameter is always NULL
8501 8483   * in the code paths:
8502 8484   *      i_ddi_incr_locked_memory -> rctl_incr_locked_mem
8503 8485   *      i_ddi_decr_locked_memory -> rctl_decr_locked_mem
8504 8486   * Thus, we always use the tk_proj member to check the projp setting.
8505 8487   */
8506 8488  static void
8507 8489  init_lockedmem_rctl_flag(struct ddi_umem_cookie *cookie)
8508 8490  {
8509 8491          proc_t          *p;
8510 8492          kproject_t      *projp;
8511 8493          zone_t          *zonep;
8512 8494  
8513 8495          ASSERT(cookie);
8514 8496          p = cookie->procp;
8515 8497          ASSERT(p);
8516 8498  
8517 8499          zonep = p->p_zone;
8518 8500          projp = p->p_task->tk_proj;
8519 8501  
8520 8502          ASSERT(zonep);
8521 8503          ASSERT(projp);
8522 8504  
8523 8505          if (zonep->zone_locked_mem_ctl == UINT64_MAX &&
8524 8506              projp->kpj_data.kpd_locked_mem_ctl == UINT64_MAX)
8525 8507                  cookie->upd_max_lock_rctl = 0;
8526 8508          else
8527 8509                  cookie->upd_max_lock_rctl = 1;
8528 8510  }
8529 8511  
8530 8512  /*
8531 8513   * This routine checks if the max-locked-memory resource ctl is
8532 8514   * exceeded, if not increments it, grabs a hold on the project.
8533 8515   * Returns 0 if successful otherwise returns error code
8534 8516   */
8535 8517  static int
8536 8518  umem_incr_devlockmem(struct ddi_umem_cookie *cookie)
8537 8519  {
8538 8520          proc_t          *procp;
8539 8521          int             ret;
8540 8522  
8541 8523          ASSERT(cookie);
8542 8524          if (cookie->upd_max_lock_rctl == 0)
8543 8525                  return (0);
8544 8526  
8545 8527          procp = cookie->procp;
8546 8528          ASSERT(procp);
8547 8529  
8548 8530          if ((ret = i_ddi_incr_locked_memory(procp,
8549 8531              cookie->size)) != 0) {
8550 8532                  return (ret);
8551 8533          }
8552 8534          return (0);
8553 8535  }
8554 8536  
8555 8537  /*
8556 8538   * Decrements the max-locked-memory resource ctl and releases
8557 8539   * the hold on the project that was acquired during umem_incr_devlockmem
8558 8540   */
8559 8541  static void
8560 8542  umem_decr_devlockmem(struct ddi_umem_cookie *cookie)
8561 8543  {
8562 8544          proc_t          *proc;
8563 8545  
8564 8546          if (cookie->upd_max_lock_rctl == 0)
8565 8547                  return;
8566 8548  
8567 8549          proc = (proc_t *)cookie->procp;
8568 8550          if (!proc)
8569 8551                  return;
8570 8552  
8571 8553          i_ddi_decr_locked_memory(proc, cookie->size);
8572 8554  }
8573 8555  
8574 8556  /*
8575 8557   * A consolidation private function which is essentially equivalent to
8576 8558   * ddi_umem_lock but with the addition of arguments ops_vector and procp.
8577 8559   * A call to as_add_callback is done if DDI_UMEMLOCK_LONGTERM is set, and
8578 8560   * the ops_vector is valid.
8579 8561   *
8580 8562   * Lock the virtual address range in the current process and create a
8581 8563   * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
8582 8564   * ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
8583 8565   * to user space.
8584 8566   *
8585 8567   * Note: The resource control accounting currently uses a full charge model
8586 8568   * in other words attempts to lock the same/overlapping areas of memory
8587 8569   * will deduct the full size of the buffer from the projects running
8588 8570   * counter for the device locked memory.
8589 8571   *
8590 8572   * addr, size should be PAGESIZE aligned
8591 8573   *
8592 8574   * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
8593 8575   *      identifies whether the locked memory will be read or written or both
8594 8576   *      DDI_UMEMLOCK_LONGTERM  must be set when the locking will
8595 8577   * be maintained for an indefinitely long period (essentially permanent),
8596 8578   * rather than for what would be required for a typical I/O completion.
8597 8579   * When DDI_UMEMLOCK_LONGTERM is set, umem_lockmemory will return EFAULT
8598 8580   * if the memory pertains to a regular file which is mapped MAP_SHARED.
8599 8581   * This is to prevent a deadlock if a file truncation is attempted after
8600 8582   * after the locking is done.
8601 8583   *
8602 8584   * Returns 0 on success
8603 8585   *      EINVAL - for invalid parameters
8604 8586   *      EPERM, ENOMEM and other error codes returned by as_pagelock
8605 8587   *      ENOMEM - is returned if the current request to lock memory exceeds
8606 8588   *              *.max-locked-memory resource control value.
8607 8589   *      EFAULT - memory pertains to a regular file mapped shared and
8608 8590   *              and DDI_UMEMLOCK_LONGTERM flag is set
8609 8591   *      EAGAIN - could not start the ddi_umem_unlock list processing thread
8610 8592   */
8611 8593  int
8612 8594  umem_lockmemory(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie,
8613 8595                  struct umem_callback_ops *ops_vector,
8614 8596                  proc_t *procp)
8615 8597  {
8616 8598          int     error;
8617 8599          struct ddi_umem_cookie *p;
8618 8600          void    (*driver_callback)() = NULL;
8619 8601          struct as *as;
8620 8602          struct seg              *seg;
8621 8603          vnode_t                 *vp;
8622 8604  
8623 8605          /* Allow device drivers to not have to reference "curproc" */
8624 8606          if (procp == NULL)
8625 8607                  procp = curproc;
8626 8608          as = procp->p_as;
8627 8609          *cookie = NULL;         /* in case of any error return */
8628 8610  
8629 8611          /* These are the only three valid flags */
8630 8612          if ((flags & ~(DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE |
8631 8613              DDI_UMEMLOCK_LONGTERM)) != 0)
8632 8614                  return (EINVAL);
8633 8615  
8634 8616          /* At least one (can be both) of the two access flags must be set */
8635 8617          if ((flags & (DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) == 0)
8636 8618                  return (EINVAL);
8637 8619  
8638 8620          /* addr and len must be page-aligned */
8639 8621          if (((uintptr_t)addr & PAGEOFFSET) != 0)
8640 8622                  return (EINVAL);
8641 8623  
8642 8624          if ((len & PAGEOFFSET) != 0)
8643 8625                  return (EINVAL);
8644 8626  
8645 8627          /*
8646 8628           * For longterm locking a driver callback must be specified; if
8647 8629           * not longterm then a callback is optional.
8648 8630           */
8649 8631          if (ops_vector != NULL) {
8650 8632                  if (ops_vector->cbo_umem_callback_version !=
8651 8633                      UMEM_CALLBACK_VERSION)
8652 8634                          return (EINVAL);
8653 8635                  else
8654 8636                          driver_callback = ops_vector->cbo_umem_lock_cleanup;
8655 8637          }
8656 8638          if ((driver_callback == NULL) && (flags & DDI_UMEMLOCK_LONGTERM))
8657 8639                  return (EINVAL);
8658 8640  
8659 8641          /*
8660 8642           * Call i_ddi_umem_unlock_thread_start if necessary.  It will
8661 8643           * be called on first ddi_umem_lock or umem_lockmemory call.
8662 8644           */
8663 8645          if (ddi_umem_unlock_thread == NULL)
8664 8646                  i_ddi_umem_unlock_thread_start();
8665 8647  
8666 8648          /* Allocate memory for the cookie */
8667 8649          p = kmem_zalloc(sizeof (struct ddi_umem_cookie), KM_SLEEP);
8668 8650  
8669 8651          /* Convert the flags to seg_rw type */
8670 8652          if (flags & DDI_UMEMLOCK_WRITE) {
8671 8653                  p->s_flags = S_WRITE;
8672 8654          } else {
8673 8655                  p->s_flags = S_READ;
8674 8656          }
8675 8657  
8676 8658          /* Store procp in cookie for later iosetup/unlock */
8677 8659          p->procp = (void *)procp;
8678 8660  
8679 8661          /*
8680 8662           * Store the struct as pointer in cookie for later use by
8681 8663           * ddi_umem_unlock.  The proc->p_as will be stale if ddi_umem_unlock
8682 8664           * is called after relvm is called.
8683 8665           */
8684 8666          p->asp = as;
8685 8667  
8686 8668          /*
8687 8669           * The size field is needed for lockmem accounting.
8688 8670           */
8689 8671          p->size = len;
8690 8672          init_lockedmem_rctl_flag(p);
8691 8673  
8692 8674          if (umem_incr_devlockmem(p) != 0) {
8693 8675                  /*
8694 8676                   * The requested memory cannot be locked
8695 8677                   */
8696 8678                  kmem_free(p, sizeof (struct ddi_umem_cookie));
8697 8679                  *cookie = (ddi_umem_cookie_t)NULL;
8698 8680                  return (ENOMEM);
8699 8681          }
8700 8682  
8701 8683          /* Lock the pages corresponding to addr, len in memory */
8702 8684          error = as_pagelock(as, &(p->pparray), addr, len, p->s_flags);
8703 8685          if (error != 0) {
8704 8686                  umem_decr_devlockmem(p);
8705 8687                  kmem_free(p, sizeof (struct ddi_umem_cookie));
8706 8688                  *cookie = (ddi_umem_cookie_t)NULL;
8707 8689                  return (error);
8708 8690          }
8709 8691  
8710 8692          /*
8711 8693           * For longterm locking the addr must pertain to a seg_vn segment or
8712 8694           * or a seg_spt segment.
8713 8695           * If the segment pertains to a regular file, it cannot be
8714 8696           * mapped MAP_SHARED.
8715 8697           * This is to prevent a deadlock if a file truncation is attempted
8716 8698           * after the locking is done.
8717 8699           * Doing this after as_pagelock guarantees persistence of the as; if
8718 8700           * an unacceptable segment is found, the cleanup includes calling
8719 8701           * as_pageunlock before returning EFAULT.
8720 8702           *
8721 8703           * segdev is allowed here as it is already locked.  This allows
8722 8704           * for memory exported by drivers through mmap() (which is already
8723 8705           * locked) to be allowed for LONGTERM.
8724 8706           */
8725 8707          if (flags & DDI_UMEMLOCK_LONGTERM) {
8726 8708                  extern  struct seg_ops segspt_shmops;
8727 8709                  extern  struct seg_ops segdev_ops;
8728 8710                  AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
8729 8711                  for (seg = as_segat(as, addr); ; seg = AS_SEGNEXT(as, seg)) {
8730 8712                          if (seg == NULL || seg->s_base > addr + len)
8731 8713                                  break;
8732 8714                          if (seg->s_ops == &segdev_ops)
8733 8715                                  continue;
8734 8716                          if (((seg->s_ops != &segvn_ops) &&
8735 8717                              (seg->s_ops != &segspt_shmops)) ||
8736 8718                              ((SEGOP_GETVP(seg, addr, &vp) == 0 &&
8737 8719                              vp != NULL && vp->v_type == VREG) &&
8738 8720                              (SEGOP_GETTYPE(seg, addr) & MAP_SHARED))) {
8739 8721                                  as_pageunlock(as, p->pparray,
8740 8722                                      addr, len, p->s_flags);
8741 8723                                  AS_LOCK_EXIT(as, &as->a_lock);
8742 8724                                  umem_decr_devlockmem(p);
8743 8725                                  kmem_free(p, sizeof (struct ddi_umem_cookie));
8744 8726                                  *cookie = (ddi_umem_cookie_t)NULL;
8745 8727                                  return (EFAULT);
8746 8728                          }
8747 8729                  }
8748 8730                  AS_LOCK_EXIT(as, &as->a_lock);
8749 8731          }
8750 8732  
8751 8733  
8752 8734          /* Initialize the fields in the ddi_umem_cookie */
8753 8735          p->cvaddr = addr;
8754 8736          p->type = UMEM_LOCKED;
8755 8737          if (driver_callback != NULL) {
8756 8738                  /* i_ddi_umem_unlock and umem_lock_undo may need the cookie */
8757 8739                  p->cook_refcnt = 2;
8758 8740                  p->callbacks = *ops_vector;
8759 8741          } else {
8760 8742                  /* only i_ddi_umme_unlock needs the cookie */
8761 8743                  p->cook_refcnt = 1;
8762 8744          }
8763 8745  
8764 8746          *cookie = (ddi_umem_cookie_t)p;
8765 8747  
8766 8748          /*
8767 8749           * If a driver callback was specified, add an entry to the
8768 8750           * as struct callback list. The as_pagelock above guarantees
8769 8751           * the persistence of as.
8770 8752           */
8771 8753          if (driver_callback) {
8772 8754                  error = as_add_callback(as, umem_lock_undo, p, AS_ALL_EVENT,
8773 8755                      addr, len, KM_SLEEP);
8774 8756                  if (error != 0) {
8775 8757                          as_pageunlock(as, p->pparray,
8776 8758                              addr, len, p->s_flags);
8777 8759                          umem_decr_devlockmem(p);
8778 8760                          kmem_free(p, sizeof (struct ddi_umem_cookie));
8779 8761                          *cookie = (ddi_umem_cookie_t)NULL;
8780 8762                  }
8781 8763          }
8782 8764          return (error);
8783 8765  }
8784 8766  
8785 8767  /*
8786 8768   * Unlock the pages locked by ddi_umem_lock or umem_lockmemory and free
8787 8769   * the cookie.  Called from i_ddi_umem_unlock_thread.
8788 8770   */
8789 8771  
8790 8772  static void
8791 8773  i_ddi_umem_unlock(struct ddi_umem_cookie *p)
8792 8774  {
8793 8775          uint_t  rc;
8794 8776  
8795 8777          /*
8796 8778           * There is no way to determine whether a callback to
8797 8779           * umem_lock_undo was registered via as_add_callback.
8798 8780           * (i.e. umem_lockmemory was called with DDI_MEMLOCK_LONGTERM and
8799 8781           * a valid callback function structure.)  as_delete_callback
8800 8782           * is called to delete a possible registered callback.  If the
8801 8783           * return from as_delete_callbacks is AS_CALLBACK_DELETED, it
8802 8784           * indicates that there was a callback registered, and that is was
8803 8785           * successfully deleted.  Thus, the cookie reference count
8804 8786           * will never be decremented by umem_lock_undo.  Just return the
8805 8787           * memory for the cookie, since both users of the cookie are done.
8806 8788           * A return of AS_CALLBACK_NOTFOUND indicates a callback was
8807 8789           * never registered.  A return of AS_CALLBACK_DELETE_DEFERRED
8808 8790           * indicates that callback processing is taking place and, and
8809 8791           * umem_lock_undo is, or will be, executing, and thus decrementing
8810 8792           * the cookie reference count when it is complete.
8811 8793           *
8812 8794           * This needs to be done before as_pageunlock so that the
8813 8795           * persistence of as is guaranteed because of the locked pages.
8814 8796           *
8815 8797           */
8816 8798          rc = as_delete_callback(p->asp, p);
8817 8799  
8818 8800  
8819 8801          /*
8820 8802           * The proc->p_as will be stale if i_ddi_umem_unlock is called
8821 8803           * after relvm is called so use p->asp.
8822 8804           */
8823 8805          as_pageunlock(p->asp, p->pparray, p->cvaddr, p->size, p->s_flags);
8824 8806  
8825 8807          /*
8826 8808           * Now that we have unlocked the memory decrement the
8827 8809           * *.max-locked-memory rctl
8828 8810           */
8829 8811          umem_decr_devlockmem(p);
8830 8812  
8831 8813          if (rc == AS_CALLBACK_DELETED) {
8832 8814                  /* umem_lock_undo will not happen, return the cookie memory */
8833 8815                  ASSERT(p->cook_refcnt == 2);
8834 8816                  kmem_free(p, sizeof (struct ddi_umem_cookie));
8835 8817          } else {
8836 8818                  /*
8837 8819                   * umem_undo_lock may happen if as_delete_callback returned
8838 8820                   * AS_CALLBACK_DELETE_DEFERRED.  In that case, decrement the
8839 8821                   * reference count, atomically, and return the cookie
8840 8822                   * memory if the reference count goes to zero.  The only
8841 8823                   * other value for rc is AS_CALLBACK_NOTFOUND.  In that
8842 8824                   * case, just return the cookie memory.
8843 8825                   */
8844 8826                  if ((rc != AS_CALLBACK_DELETE_DEFERRED) ||
8845 8827                      (atomic_add_long_nv((ulong_t *)(&(p->cook_refcnt)), -1)
8846 8828                      == 0)) {
8847 8829                          kmem_free(p, sizeof (struct ddi_umem_cookie));
8848 8830                  }
8849 8831          }
8850 8832  }
8851 8833  
8852 8834  /*
8853 8835   * i_ddi_umem_unlock_thread - deferred ddi_umem_unlock list handler.
8854 8836   *
8855 8837   * Call i_ddi_umem_unlock for entries in the ddi_umem_unlock list
8856 8838   * until it is empty.  Then, wait for more to be added.  This thread is awoken
8857 8839   * via calls to ddi_umem_unlock.
8858 8840   */
8859 8841  
8860 8842  static void
8861 8843  i_ddi_umem_unlock_thread(void)
8862 8844  {
8863 8845          struct ddi_umem_cookie  *ret_cookie;
8864 8846          callb_cpr_t     cprinfo;
8865 8847  
8866 8848          /* process the ddi_umem_unlock list */
8867 8849          CALLB_CPR_INIT(&cprinfo, &ddi_umem_unlock_mutex,
8868 8850              callb_generic_cpr, "unlock_thread");
8869 8851          for (;;) {
8870 8852                  mutex_enter(&ddi_umem_unlock_mutex);
8871 8853                  if (ddi_umem_unlock_head != NULL) {     /* list not empty */
8872 8854                          ret_cookie = ddi_umem_unlock_head;
8873 8855                          /* take if off the list */
8874 8856                          if ((ddi_umem_unlock_head =
8875 8857                              ddi_umem_unlock_head->unl_forw) == NULL) {
8876 8858                                  ddi_umem_unlock_tail = NULL;
8877 8859                          }
8878 8860                          mutex_exit(&ddi_umem_unlock_mutex);
8879 8861                          /* unlock the pages in this cookie */
8880 8862                          (void) i_ddi_umem_unlock(ret_cookie);
8881 8863                  } else {   /* list is empty, wait for next ddi_umem_unlock */
8882 8864                          CALLB_CPR_SAFE_BEGIN(&cprinfo);
8883 8865                          cv_wait(&ddi_umem_unlock_cv, &ddi_umem_unlock_mutex);
8884 8866                          CALLB_CPR_SAFE_END(&cprinfo, &ddi_umem_unlock_mutex);
8885 8867                          mutex_exit(&ddi_umem_unlock_mutex);
8886 8868                  }
8887 8869          }
8888 8870          /* ddi_umem_unlock_thread does not exit */
8889 8871          /* NOTREACHED */
8890 8872  }
8891 8873  
8892 8874  /*
8893 8875   * Start the thread that will process the ddi_umem_unlock list if it is
8894 8876   * not already started (i_ddi_umem_unlock_thread).
8895 8877   */
8896 8878  static void
8897 8879  i_ddi_umem_unlock_thread_start(void)
8898 8880  {
8899 8881          mutex_enter(&ddi_umem_unlock_mutex);
8900 8882          if (ddi_umem_unlock_thread == NULL) {
8901 8883                  ddi_umem_unlock_thread = thread_create(NULL, 0,
8902 8884                      i_ddi_umem_unlock_thread, NULL, 0, &p0,
8903 8885                      TS_RUN, minclsyspri);
8904 8886          }
8905 8887          mutex_exit(&ddi_umem_unlock_mutex);
8906 8888  }
8907 8889  
8908 8890  /*
8909 8891   * Lock the virtual address range in the current process and create a
8910 8892   * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
8911 8893   * ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
8912 8894   * to user space.
8913 8895   *
8914 8896   * Note: The resource control accounting currently uses a full charge model
8915 8897   * in other words attempts to lock the same/overlapping areas of memory
8916 8898   * will deduct the full size of the buffer from the projects running
8917 8899   * counter for the device locked memory. This applies to umem_lockmemory too.
8918 8900   *
8919 8901   * addr, size should be PAGESIZE aligned
8920 8902   * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
8921 8903   *      identifies whether the locked memory will be read or written or both
8922 8904   *
8923 8905   * Returns 0 on success
8924 8906   *      EINVAL - for invalid parameters
8925 8907   *      EPERM, ENOMEM and other error codes returned by as_pagelock
8926 8908   *      ENOMEM - is returned if the current request to lock memory exceeds
8927 8909   *              *.max-locked-memory resource control value.
8928 8910   *      EAGAIN - could not start the ddi_umem_unlock list processing thread
8929 8911   */
8930 8912  int
8931 8913  ddi_umem_lock(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie)
8932 8914  {
8933 8915          int     error;
8934 8916          struct ddi_umem_cookie *p;
8935 8917  
8936 8918          *cookie = NULL;         /* in case of any error return */
8937 8919  
8938 8920          /* These are the only two valid flags */
8939 8921          if ((flags & ~(DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) != 0) {
8940 8922                  return (EINVAL);
8941 8923          }
8942 8924  
8943 8925          /* At least one of the two flags (or both) must be set */
8944 8926          if ((flags & (DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) == 0) {
8945 8927                  return (EINVAL);
8946 8928          }
8947 8929  
8948 8930          /* addr and len must be page-aligned */
8949 8931          if (((uintptr_t)addr & PAGEOFFSET) != 0) {
8950 8932                  return (EINVAL);
8951 8933          }
8952 8934  
8953 8935          if ((len & PAGEOFFSET) != 0) {
8954 8936                  return (EINVAL);
8955 8937          }
8956 8938  
8957 8939          /*
8958 8940           * Call i_ddi_umem_unlock_thread_start if necessary.  It will
8959 8941           * be called on first ddi_umem_lock or umem_lockmemory call.
8960 8942           */
8961 8943          if (ddi_umem_unlock_thread == NULL)
8962 8944                  i_ddi_umem_unlock_thread_start();
8963 8945  
8964 8946          /* Allocate memory for the cookie */
8965 8947          p = kmem_zalloc(sizeof (struct ddi_umem_cookie), KM_SLEEP);
8966 8948  
8967 8949          /* Convert the flags to seg_rw type */
8968 8950          if (flags & DDI_UMEMLOCK_WRITE) {
8969 8951                  p->s_flags = S_WRITE;
8970 8952          } else {
8971 8953                  p->s_flags = S_READ;
8972 8954          }
8973 8955  
8974 8956          /* Store curproc in cookie for later iosetup/unlock */
8975 8957          p->procp = (void *)curproc;
8976 8958  
8977 8959          /*
8978 8960           * Store the struct as pointer in cookie for later use by
8979 8961           * ddi_umem_unlock.  The proc->p_as will be stale if ddi_umem_unlock
8980 8962           * is called after relvm is called.
8981 8963           */
8982 8964          p->asp = curproc->p_as;
8983 8965          /*
8984 8966           * The size field is needed for lockmem accounting.
8985 8967           */
8986 8968          p->size = len;
8987 8969          init_lockedmem_rctl_flag(p);
8988 8970  
8989 8971          if (umem_incr_devlockmem(p) != 0) {
8990 8972                  /*
8991 8973                   * The requested memory cannot be locked
8992 8974                   */
8993 8975                  kmem_free(p, sizeof (struct ddi_umem_cookie));
8994 8976                  *cookie = (ddi_umem_cookie_t)NULL;
8995 8977                  return (ENOMEM);
8996 8978          }
8997 8979  
8998 8980          /* Lock the pages corresponding to addr, len in memory */
8999 8981          error = as_pagelock(((proc_t *)p->procp)->p_as, &(p->pparray),
9000 8982              addr, len, p->s_flags);
9001 8983          if (error != 0) {
9002 8984                  umem_decr_devlockmem(p);
9003 8985                  kmem_free(p, sizeof (struct ddi_umem_cookie));
9004 8986                  *cookie = (ddi_umem_cookie_t)NULL;
9005 8987                  return (error);
9006 8988          }
9007 8989  
9008 8990          /* Initialize the fields in the ddi_umem_cookie */
9009 8991          p->cvaddr = addr;
9010 8992          p->type = UMEM_LOCKED;
9011 8993          p->cook_refcnt = 1;
9012 8994  
9013 8995          *cookie = (ddi_umem_cookie_t)p;
9014 8996          return (error);
9015 8997  }
9016 8998  
9017 8999  /*
9018 9000   * Add the cookie to the ddi_umem_unlock list.  Pages will be
9019 9001   * unlocked by i_ddi_umem_unlock_thread.
9020 9002   */
9021 9003  
9022 9004  void
9023 9005  ddi_umem_unlock(ddi_umem_cookie_t cookie)
9024 9006  {
9025 9007          struct ddi_umem_cookie  *p = (struct ddi_umem_cookie *)cookie;
9026 9008  
9027 9009          ASSERT(p->type == UMEM_LOCKED);
9028 9010          ASSERT(CPU_ON_INTR(CPU) == 0); /* cannot be high level */
9029 9011          ASSERT(ddi_umem_unlock_thread != NULL);
9030 9012  
9031 9013          p->unl_forw = (struct ddi_umem_cookie *)NULL;   /* end of list */
9032 9014          /*
9033 9015           * Queue the unlock request and notify i_ddi_umem_unlock thread
9034 9016           * if it's called in the interrupt context. Otherwise, unlock pages
9035 9017           * immediately.
9036 9018           */
9037 9019          if (servicing_interrupt()) {
9038 9020                  /* queue the unlock request and notify the thread */
9039 9021                  mutex_enter(&ddi_umem_unlock_mutex);
9040 9022                  if (ddi_umem_unlock_head == NULL) {
9041 9023                          ddi_umem_unlock_head = ddi_umem_unlock_tail = p;
9042 9024                          cv_broadcast(&ddi_umem_unlock_cv);
9043 9025                  } else {
9044 9026                          ddi_umem_unlock_tail->unl_forw = p;
9045 9027                          ddi_umem_unlock_tail = p;
9046 9028                  }
9047 9029                  mutex_exit(&ddi_umem_unlock_mutex);
9048 9030          } else {
9049 9031                  /* unlock the pages right away */
9050 9032                  (void) i_ddi_umem_unlock(p);
9051 9033          }
9052 9034  }
9053 9035  
9054 9036  /*
9055 9037   * Create a buf structure from a ddi_umem_cookie
9056 9038   * cookie - is a ddi_umem_cookie for from ddi_umem_lock and ddi_umem_alloc
9057 9039   *              (only UMEM_LOCKED & KMEM_NON_PAGEABLE types supported)
9058 9040   * off, len - identifies the portion of the memory represented by the cookie
9059 9041   *              that the buf points to.
9060 9042   *      NOTE: off, len need to follow the alignment/size restrictions of the
9061 9043   *              device (dev) that this buf will be passed to. Some devices
9062 9044   *              will accept unrestricted alignment/size, whereas others (such as
9063 9045   *              st) require some block-size alignment/size. It is the caller's
9064 9046   *              responsibility to ensure that the alignment/size restrictions
9065 9047   *              are met (we cannot assert as we do not know the restrictions)
9066 9048   *
9067 9049   * direction - is one of B_READ or B_WRITE and needs to be compatible with
9068 9050   *              the flags used in ddi_umem_lock
9069 9051   *
9070 9052   * The following three arguments are used to initialize fields in the
9071 9053   * buf structure and are uninterpreted by this routine.
9072 9054   *
9073 9055   * dev
9074 9056   * blkno
9075 9057   * iodone
9076 9058   *
9077 9059   * sleepflag - is one of DDI_UMEM_SLEEP or DDI_UMEM_NOSLEEP
9078 9060   *
9079 9061   * Returns a buf structure pointer on success (to be freed by freerbuf)
9080 9062   *      NULL on any parameter error or memory alloc failure
9081 9063   *
9082 9064   */
9083 9065  struct buf *
9084 9066  ddi_umem_iosetup(ddi_umem_cookie_t cookie, off_t off, size_t len,
9085 9067          int direction, dev_t dev, daddr_t blkno,
9086 9068          int (*iodone)(struct buf *), int sleepflag)
9087 9069  {
9088 9070          struct ddi_umem_cookie *p = (struct ddi_umem_cookie *)cookie;
9089 9071          struct buf *bp;
9090 9072  
9091 9073          /*
9092 9074           * check for valid cookie offset, len
9093 9075           */
9094 9076          if ((off + len) > p->size) {
9095 9077                  return (NULL);
9096 9078          }
9097 9079  
9098 9080          if (len > p->size) {
9099 9081                  return (NULL);
9100 9082          }
9101 9083  
9102 9084          /* direction has to be one of B_READ or B_WRITE */
9103 9085          if ((direction != B_READ) && (direction != B_WRITE)) {
9104 9086                  return (NULL);
9105 9087          }
9106 9088  
9107 9089          /* These are the only two valid sleepflags */
9108 9090          if ((sleepflag != DDI_UMEM_SLEEP) && (sleepflag != DDI_UMEM_NOSLEEP)) {
9109 9091                  return (NULL);
9110 9092          }
9111 9093  
9112 9094          /*
9113 9095           * Only cookies of type UMEM_LOCKED and KMEM_NON_PAGEABLE are supported
9114 9096           */
9115 9097          if ((p->type != UMEM_LOCKED) && (p->type != KMEM_NON_PAGEABLE)) {
9116 9098                  return (NULL);
9117 9099          }
9118 9100  
9119 9101          /* If type is KMEM_NON_PAGEABLE procp is NULL */
9120 9102          ASSERT((p->type == KMEM_NON_PAGEABLE) ?
9121 9103              (p->procp == NULL) : (p->procp != NULL));
9122 9104  
9123 9105          bp = kmem_alloc(sizeof (struct buf), sleepflag);
9124 9106          if (bp == NULL) {
9125 9107                  return (NULL);
9126 9108          }
9127 9109          bioinit(bp);
9128 9110  
9129 9111          bp->b_flags = B_BUSY | B_PHYS | direction;
9130 9112          bp->b_edev = dev;
9131 9113          bp->b_lblkno = blkno;
9132 9114          bp->b_iodone = iodone;
9133 9115          bp->b_bcount = len;
9134 9116          bp->b_proc = (proc_t *)p->procp;
9135 9117          ASSERT(((uintptr_t)(p->cvaddr) & PAGEOFFSET) == 0);
9136 9118          bp->b_un.b_addr = (caddr_t)((uintptr_t)(p->cvaddr) + off);
9137 9119          if (p->pparray != NULL) {
9138 9120                  bp->b_flags |= B_SHADOW;
9139 9121                  ASSERT(((uintptr_t)(p->cvaddr) & PAGEOFFSET) == 0);
9140 9122                  bp->b_shadow = p->pparray + btop(off);
9141 9123          }
9142 9124          return (bp);
9143 9125  }
9144 9126  
9145 9127  /*
9146 9128   * Fault-handling and related routines
9147 9129   */
9148 9130  
9149 9131  ddi_devstate_t
9150 9132  ddi_get_devstate(dev_info_t *dip)
9151 9133  {
9152 9134          if (DEVI_IS_DEVICE_OFFLINE(dip))
9153 9135                  return (DDI_DEVSTATE_OFFLINE);
9154 9136          else if (DEVI_IS_DEVICE_DOWN(dip) || DEVI_IS_BUS_DOWN(dip))
9155 9137                  return (DDI_DEVSTATE_DOWN);
9156 9138          else if (DEVI_IS_BUS_QUIESCED(dip))
9157 9139                  return (DDI_DEVSTATE_QUIESCED);
9158 9140          else if (DEVI_IS_DEVICE_DEGRADED(dip))
9159 9141                  return (DDI_DEVSTATE_DEGRADED);
9160 9142          else
9161 9143                  return (DDI_DEVSTATE_UP);
9162 9144  }
9163 9145  
9164 9146  void
9165 9147  ddi_dev_report_fault(dev_info_t *dip, ddi_fault_impact_t impact,
9166 9148          ddi_fault_location_t location, const char *message)
9167 9149  {
9168 9150          struct ddi_fault_event_data fd;
9169 9151          ddi_eventcookie_t ec;
9170 9152  
9171 9153          /*
9172 9154           * Assemble all the information into a fault-event-data structure
9173 9155           */
9174 9156          fd.f_dip = dip;
9175 9157          fd.f_impact = impact;
9176 9158          fd.f_location = location;
9177 9159          fd.f_message = message;
9178 9160          fd.f_oldstate = ddi_get_devstate(dip);
9179 9161  
9180 9162          /*
9181 9163           * Get eventcookie from defining parent.
9182 9164           */
9183 9165          if (ddi_get_eventcookie(dip, DDI_DEVI_FAULT_EVENT, &ec) !=
9184 9166              DDI_SUCCESS)
9185 9167                  return;
9186 9168  
9187 9169          (void) ndi_post_event(dip, dip, ec, &fd);
9188 9170  }
9189 9171  
9190 9172  char *
9191 9173  i_ddi_devi_class(dev_info_t *dip)
9192 9174  {
9193 9175          return (DEVI(dip)->devi_device_class);
9194 9176  }
9195 9177  
9196 9178  int
9197 9179  i_ddi_set_devi_class(dev_info_t *dip, char *devi_class, int flag)
9198 9180  {
9199 9181          struct dev_info *devi = DEVI(dip);
9200 9182  
9201 9183          mutex_enter(&devi->devi_lock);
9202 9184  
9203 9185          if (devi->devi_device_class)
9204 9186                  kmem_free(devi->devi_device_class,
9205 9187                      strlen(devi->devi_device_class) + 1);
9206 9188  
9207 9189          if ((devi->devi_device_class = i_ddi_strdup(devi_class, flag))
9208 9190              != NULL) {
9209 9191                  mutex_exit(&devi->devi_lock);
9210 9192                  return (DDI_SUCCESS);
9211 9193          }
9212 9194  
9213 9195          mutex_exit(&devi->devi_lock);
9214 9196  
9215 9197          return (DDI_FAILURE);
9216 9198  }
9217 9199  
9218 9200  
9219 9201  /*
9220 9202   * Task Queues DDI interfaces.
9221 9203   */
9222 9204  
9223 9205  /* ARGSUSED */
9224 9206  ddi_taskq_t *
9225 9207  ddi_taskq_create(dev_info_t *dip, const char *name, int nthreads,
9226 9208      pri_t pri, uint_t cflags)
9227 9209  {
9228 9210          char full_name[TASKQ_NAMELEN];
9229 9211          const char *tq_name;
9230 9212          int nodeid = 0;
9231 9213  
9232 9214          if (dip == NULL)
9233 9215                  tq_name = name;
9234 9216          else {
9235 9217                  nodeid = ddi_get_instance(dip);
9236 9218  
9237 9219                  if (name == NULL)
9238 9220                          name = "tq";
9239 9221  
9240 9222                  (void) snprintf(full_name, sizeof (full_name), "%s_%s",
9241 9223                      ddi_driver_name(dip), name);
9242 9224  
9243 9225                  tq_name = full_name;
9244 9226          }
9245 9227  
9246 9228          return ((ddi_taskq_t *)taskq_create_instance(tq_name, nodeid, nthreads,
9247 9229              pri == TASKQ_DEFAULTPRI ? minclsyspri : pri,
9248 9230              nthreads, INT_MAX, TASKQ_PREPOPULATE));
9249 9231  }
9250 9232  
9251 9233  void
9252 9234  ddi_taskq_destroy(ddi_taskq_t *tq)
9253 9235  {
9254 9236          taskq_destroy((taskq_t *)tq);
9255 9237  }
9256 9238  
9257 9239  int
9258 9240  ddi_taskq_dispatch(ddi_taskq_t *tq, void (* func)(void *),
9259 9241      void *arg, uint_t dflags)
9260 9242  {
9261 9243          taskqid_t id = taskq_dispatch((taskq_t *)tq, func, arg,
9262 9244              dflags == DDI_SLEEP ? TQ_SLEEP : TQ_NOSLEEP);
9263 9245  
9264 9246          return (id != 0 ? DDI_SUCCESS : DDI_FAILURE);
9265 9247  }
9266 9248  
9267 9249  void
9268 9250  ddi_taskq_wait(ddi_taskq_t *tq)
9269 9251  {
9270 9252          taskq_wait((taskq_t *)tq);
9271 9253  }
9272 9254  
9273 9255  void
9274 9256  ddi_taskq_suspend(ddi_taskq_t *tq)
9275 9257  {
9276 9258          taskq_suspend((taskq_t *)tq);
9277 9259  }
9278 9260  
9279 9261  boolean_t
9280 9262  ddi_taskq_suspended(ddi_taskq_t *tq)
9281 9263  {
9282 9264          return (taskq_suspended((taskq_t *)tq));
9283 9265  }
9284 9266  
9285 9267  void
9286 9268  ddi_taskq_resume(ddi_taskq_t *tq)
9287 9269  {
9288 9270          taskq_resume((taskq_t *)tq);
9289 9271  }
9290 9272  
9291 9273  int
9292 9274  ddi_parse(
9293 9275          const char      *ifname,
9294 9276          char            *alnum,
9295 9277          uint_t          *nump)
9296 9278  {
9297 9279          const char      *p;
9298 9280          int             l;
9299 9281          ulong_t         num;
9300 9282          boolean_t       nonum = B_TRUE;
9301 9283          char            c;
9302 9284  
9303 9285          l = strlen(ifname);
9304 9286          for (p = ifname + l; p != ifname; l--) {
9305 9287                  c = *--p;
9306 9288                  if (!isdigit(c)) {
9307 9289                          (void) strlcpy(alnum, ifname, l + 1);
9308 9290                          if (ddi_strtoul(p + 1, NULL, 10, &num) != 0)
9309 9291                                  return (DDI_FAILURE);
9310 9292                          break;
9311 9293                  }
9312 9294                  nonum = B_FALSE;
9313 9295          }
9314 9296          if (l == 0 || nonum)
9315 9297                  return (DDI_FAILURE);
9316 9298  
9317 9299          *nump = num;
9318 9300          return (DDI_SUCCESS);
9319 9301  }
9320 9302  
9321 9303  /*
9322 9304   * Default initialization function for drivers that don't need to quiesce.
9323 9305   */
9324 9306  /* ARGSUSED */
9325 9307  int
9326 9308  ddi_quiesce_not_needed(dev_info_t *dip)
9327 9309  {
9328 9310          return (DDI_SUCCESS);
9329 9311  }
9330 9312  
9331 9313  /*
9332 9314   * Initialization function for drivers that should implement quiesce()
9333 9315   * but haven't yet.
9334 9316   */
9335 9317  /* ARGSUSED */
9336 9318  int
9337 9319  ddi_quiesce_not_supported(dev_info_t *dip)
9338 9320  {
9339 9321          return (DDI_FAILURE);
9340 9322  }
9341 9323  
9342 9324  char *
9343 9325  ddi_strdup(const char *str, int flag)
9344 9326  {
9345 9327          int     n;
9346 9328          char    *ptr;
9347 9329  
9348 9330          ASSERT(str != NULL);
9349 9331          ASSERT((flag == KM_SLEEP) || (flag == KM_NOSLEEP));
9350 9332  
9351 9333          n = strlen(str);
9352 9334          if ((ptr = kmem_alloc(n + 1, flag)) == NULL)
9353 9335                  return (NULL);
9354 9336          bcopy(str, ptr, n + 1);
9355 9337          return (ptr);
9356 9338  }
9357 9339  
9358 9340  char *
9359 9341  strdup(const char *str)
9360 9342  {
9361 9343          return (ddi_strdup(str, KM_SLEEP));
9362 9344  }
9363 9345  
9364 9346  void
9365 9347  strfree(char *str)
9366 9348  {
9367 9349          ASSERT(str != NULL);
9368 9350          kmem_free(str, strlen(str) + 1);
9369 9351  }
9370 9352  
9371 9353  /*
9372 9354   * Generic DDI callback interfaces.
9373 9355   */
9374 9356  
9375 9357  int
9376 9358  ddi_cb_register(dev_info_t *dip, ddi_cb_flags_t flags, ddi_cb_func_t cbfunc,
9377 9359      void *arg1, void *arg2, ddi_cb_handle_t *ret_hdlp)
9378 9360  {
9379 9361          ddi_cb_t        *cbp;
9380 9362  
9381 9363          ASSERT(dip != NULL);
9382 9364          ASSERT(DDI_CB_FLAG_VALID(flags));
9383 9365          ASSERT(cbfunc != NULL);
9384 9366          ASSERT(ret_hdlp != NULL);
9385 9367  
9386 9368          /* Sanity check the context */
9387 9369          ASSERT(!servicing_interrupt());
9388 9370          if (servicing_interrupt())
9389 9371                  return (DDI_FAILURE);
9390 9372  
9391 9373          /* Validate parameters */
9392 9374          if ((dip == NULL) || !DDI_CB_FLAG_VALID(flags) ||
9393 9375              (cbfunc == NULL) || (ret_hdlp == NULL))
9394 9376                  return (DDI_EINVAL);
9395 9377  
9396 9378          /* Check for previous registration */
9397 9379          if (DEVI(dip)->devi_cb_p != NULL)
9398 9380                  return (DDI_EALREADY);
9399 9381  
9400 9382          /* Allocate and initialize callback */
9401 9383          cbp = kmem_zalloc(sizeof (ddi_cb_t), KM_SLEEP);
9402 9384          cbp->cb_dip = dip;
9403 9385          cbp->cb_func = cbfunc;
9404 9386          cbp->cb_arg1 = arg1;
9405 9387          cbp->cb_arg2 = arg2;
9406 9388          cbp->cb_flags = flags;
9407 9389          DEVI(dip)->devi_cb_p = cbp;
9408 9390  
9409 9391          /* If adding an IRM callback, notify IRM */
9410 9392          if (flags & DDI_CB_FLAG_INTR)
9411 9393                  i_ddi_irm_set_cb(dip, B_TRUE);
9412 9394  
9413 9395          *ret_hdlp = (ddi_cb_handle_t)&(DEVI(dip)->devi_cb_p);
9414 9396          return (DDI_SUCCESS);
9415 9397  }
9416 9398  
9417 9399  int
9418 9400  ddi_cb_unregister(ddi_cb_handle_t hdl)
9419 9401  {
9420 9402          ddi_cb_t        *cbp;
9421 9403          dev_info_t      *dip;
9422 9404  
9423 9405          ASSERT(hdl != NULL);
9424 9406  
9425 9407          /* Sanity check the context */
9426 9408          ASSERT(!servicing_interrupt());
9427 9409          if (servicing_interrupt())
9428 9410                  return (DDI_FAILURE);
9429 9411  
9430 9412          /* Validate parameters */
9431 9413          if ((hdl == NULL) || ((cbp = *(ddi_cb_t **)hdl) == NULL) ||
9432 9414              ((dip = cbp->cb_dip) == NULL))
9433 9415                  return (DDI_EINVAL);
9434 9416  
9435 9417          /* If removing an IRM callback, notify IRM */
9436 9418          if (cbp->cb_flags & DDI_CB_FLAG_INTR)
9437 9419                  i_ddi_irm_set_cb(dip, B_FALSE);
9438 9420  
9439 9421          /* Destroy the callback */
9440 9422          kmem_free(cbp, sizeof (ddi_cb_t));
9441 9423          DEVI(dip)->devi_cb_p = NULL;
9442 9424  
9443 9425          return (DDI_SUCCESS);
9444 9426  }
9445 9427  
9446 9428  /*
9447 9429   * Platform independent DR routines
9448 9430   */
9449 9431  
9450 9432  static int
9451 9433  ndi2errno(int n)
9452 9434  {
9453 9435          int err = 0;
9454 9436  
9455 9437          switch (n) {
9456 9438                  case NDI_NOMEM:
9457 9439                          err = ENOMEM;
9458 9440                          break;
9459 9441                  case NDI_BUSY:
9460 9442                          err = EBUSY;
9461 9443                          break;
9462 9444                  case NDI_FAULT:
9463 9445                          err = EFAULT;
9464 9446                          break;
9465 9447                  case NDI_FAILURE:
9466 9448                          err = EIO;
9467 9449                          break;
9468 9450                  case NDI_SUCCESS:
9469 9451                          break;
9470 9452                  case NDI_BADHANDLE:
9471 9453                  default:
9472 9454                          err = EINVAL;
9473 9455                          break;
9474 9456          }
9475 9457          return (err);
9476 9458  }
9477 9459  
9478 9460  /*
9479 9461   * Prom tree node list
9480 9462   */
9481 9463  struct ptnode {
9482 9464          pnode_t         nodeid;
9483 9465          struct ptnode   *next;
9484 9466  };
9485 9467  
9486 9468  /*
9487 9469   * Prom tree walk arg
9488 9470   */
9489 9471  struct pta {
9490 9472          dev_info_t      *pdip;
9491 9473          devi_branch_t   *bp;
9492 9474          uint_t          flags;
9493 9475          dev_info_t      *fdip;
9494 9476          struct ptnode   *head;
9495 9477  };
9496 9478  
9497 9479  static void
9498 9480  visit_node(pnode_t nodeid, struct pta *ap)
9499 9481  {
9500 9482          struct ptnode   **nextp;
9501 9483          int             (*select)(pnode_t, void *, uint_t);
9502 9484  
9503 9485          ASSERT(nodeid != OBP_NONODE && nodeid != OBP_BADNODE);
9504 9486  
9505 9487          select = ap->bp->create.prom_branch_select;
9506 9488  
9507 9489          ASSERT(select);
9508 9490  
9509 9491          if (select(nodeid, ap->bp->arg, 0) == DDI_SUCCESS) {
9510 9492  
9511 9493                  for (nextp = &ap->head; *nextp; nextp = &(*nextp)->next)
9512 9494                          ;
9513 9495  
9514 9496                  *nextp = kmem_zalloc(sizeof (struct ptnode), KM_SLEEP);
9515 9497  
9516 9498                  (*nextp)->nodeid = nodeid;
9517 9499          }
9518 9500  
9519 9501          if ((ap->flags & DEVI_BRANCH_CHILD) == DEVI_BRANCH_CHILD)
9520 9502                  return;
9521 9503  
9522 9504          nodeid = prom_childnode(nodeid);
9523 9505          while (nodeid != OBP_NONODE && nodeid != OBP_BADNODE) {
9524 9506                  visit_node(nodeid, ap);
9525 9507                  nodeid = prom_nextnode(nodeid);
9526 9508          }
9527 9509  }
9528 9510  
9529 9511  /*
9530 9512   * NOTE: The caller of this function must check for device contracts
9531 9513   * or LDI callbacks against this dip before setting the dip offline.
9532 9514   */
9533 9515  static int
9534 9516  set_infant_dip_offline(dev_info_t *dip, void *arg)
9535 9517  {
9536 9518          char    *path = (char *)arg;
9537 9519  
9538 9520          ASSERT(dip);
9539 9521          ASSERT(arg);
9540 9522  
9541 9523          if (i_ddi_node_state(dip) >= DS_ATTACHED) {
9542 9524                  (void) ddi_pathname(dip, path);
9543 9525                  cmn_err(CE_WARN, "Attempt to set offline flag on attached "
9544 9526                      "node: %s", path);
9545 9527                  return (DDI_FAILURE);
9546 9528          }
9547 9529  
9548 9530          mutex_enter(&(DEVI(dip)->devi_lock));
9549 9531          if (!DEVI_IS_DEVICE_OFFLINE(dip))
9550 9532                  DEVI_SET_DEVICE_OFFLINE(dip);
9551 9533          mutex_exit(&(DEVI(dip)->devi_lock));
9552 9534  
9553 9535          return (DDI_SUCCESS);
9554 9536  }
9555 9537  
9556 9538  typedef struct result {
9557 9539          char    *path;
9558 9540          int     result;
9559 9541  } result_t;
9560 9542  
9561 9543  static int
9562 9544  dip_set_offline(dev_info_t *dip, void *arg)
9563 9545  {
9564 9546          int end;
9565 9547          result_t *resp = (result_t *)arg;
9566 9548  
9567 9549          ASSERT(dip);
9568 9550          ASSERT(resp);
9569 9551  
9570 9552          /*
9571 9553           * We stop the walk if e_ddi_offline_notify() returns
9572 9554           * failure, because this implies that one or more consumers
9573 9555           * (either LDI or contract based) has blocked the offline.
9574 9556           * So there is no point in conitnuing the walk
9575 9557           */
9576 9558          if (e_ddi_offline_notify(dip) == DDI_FAILURE) {
9577 9559                  resp->result = DDI_FAILURE;
9578 9560                  return (DDI_WALK_TERMINATE);
9579 9561          }
9580 9562  
9581 9563          /*
9582 9564           * If set_infant_dip_offline() returns failure, it implies
9583 9565           * that we failed to set a particular dip offline. This
9584 9566           * does not imply that the offline as a whole should fail.
9585 9567           * We want to do the best we can, so we continue the walk.
9586 9568           */
9587 9569          if (set_infant_dip_offline(dip, resp->path) == DDI_SUCCESS)
9588 9570                  end = DDI_SUCCESS;
9589 9571          else
9590 9572                  end = DDI_FAILURE;
9591 9573  
9592 9574          e_ddi_offline_finalize(dip, end);
9593 9575  
9594 9576          return (DDI_WALK_CONTINUE);
9595 9577  }
9596 9578  
9597 9579  /*
9598 9580   * The call to e_ddi_offline_notify() exists for the
9599 9581   * unlikely error case that a branch we are trying to
9600 9582   * create already exists and has device contracts or LDI
9601 9583   * event callbacks against it.
9602 9584   *
9603 9585   * We allow create to succeed for such branches only if
9604 9586   * no constraints block the offline.
9605 9587   */
9606 9588  static int
9607 9589  branch_set_offline(dev_info_t *dip, char *path)
9608 9590  {
9609 9591          int             circ;
9610 9592          int             end;
9611 9593          result_t        res;
9612 9594  
9613 9595  
9614 9596          if (e_ddi_offline_notify(dip) == DDI_FAILURE) {
9615 9597                  return (DDI_FAILURE);
9616 9598          }
9617 9599  
9618 9600          if (set_infant_dip_offline(dip, path) == DDI_SUCCESS)
9619 9601                  end = DDI_SUCCESS;
9620 9602          else
9621 9603                  end = DDI_FAILURE;
9622 9604  
9623 9605          e_ddi_offline_finalize(dip, end);
9624 9606  
9625 9607          if (end == DDI_FAILURE)
9626 9608                  return (DDI_FAILURE);
9627 9609  
9628 9610          res.result = DDI_SUCCESS;
9629 9611          res.path = path;
9630 9612  
9631 9613          ndi_devi_enter(dip, &circ);
9632 9614          ddi_walk_devs(ddi_get_child(dip), dip_set_offline, &res);
9633 9615          ndi_devi_exit(dip, circ);
9634 9616  
9635 9617          return (res.result);
9636 9618  }
9637 9619  
9638 9620  /*ARGSUSED*/
9639 9621  static int
9640 9622  create_prom_branch(void *arg, int has_changed)
9641 9623  {
9642 9624          int             circ;
9643 9625          int             exists, rv;
9644 9626          pnode_t         nodeid;
9645 9627          struct ptnode   *tnp;
9646 9628          dev_info_t      *dip;
9647 9629          struct pta      *ap = arg;
9648 9630          devi_branch_t   *bp;
9649 9631          char            *path;
9650 9632  
9651 9633          ASSERT(ap);
9652 9634          ASSERT(ap->fdip == NULL);
9653 9635          ASSERT(ap->pdip && ndi_dev_is_prom_node(ap->pdip));
9654 9636  
9655 9637          bp = ap->bp;
9656 9638  
9657 9639          nodeid = ddi_get_nodeid(ap->pdip);
9658 9640          if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) {
9659 9641                  cmn_err(CE_WARN, "create_prom_branch: invalid "
9660 9642                      "nodeid: 0x%x", nodeid);
9661 9643                  return (EINVAL);
9662 9644          }
9663 9645  
9664 9646          ap->head = NULL;
9665 9647  
9666 9648          nodeid = prom_childnode(nodeid);
9667 9649          while (nodeid != OBP_NONODE && nodeid != OBP_BADNODE) {
9668 9650                  visit_node(nodeid, ap);
9669 9651                  nodeid = prom_nextnode(nodeid);
9670 9652          }
9671 9653  
9672 9654          if (ap->head == NULL)
9673 9655                  return (ENODEV);
9674 9656  
9675 9657          path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
9676 9658          rv = 0;
9677 9659          while ((tnp = ap->head) != NULL) {
9678 9660                  ap->head = tnp->next;
9679 9661  
9680 9662                  ndi_devi_enter(ap->pdip, &circ);
9681 9663  
9682 9664                  /*
9683 9665                   * Check if the branch already exists.
9684 9666                   */
9685 9667                  exists = 0;
9686 9668                  dip = e_ddi_nodeid_to_dip(tnp->nodeid);
9687 9669                  if (dip != NULL) {
9688 9670                          exists = 1;
9689 9671  
9690 9672                          /* Parent is held busy, so release hold */
9691 9673                          ndi_rele_devi(dip);
9692 9674  #ifdef  DEBUG
9693 9675                          cmn_err(CE_WARN, "create_prom_branch: dip(%p) exists"
9694 9676                              " for nodeid 0x%x", (void *)dip, tnp->nodeid);
9695 9677  #endif
9696 9678                  } else {
9697 9679                          dip = i_ddi_create_branch(ap->pdip, tnp->nodeid);
9698 9680                  }
9699 9681  
9700 9682                  kmem_free(tnp, sizeof (struct ptnode));
9701 9683  
9702 9684                  /*
9703 9685                   * Hold the branch if it is not already held
9704 9686                   */
9705 9687                  if (dip && !exists) {
9706 9688                          e_ddi_branch_hold(dip);
9707 9689                  }
9708 9690  
9709 9691                  ASSERT(dip == NULL || e_ddi_branch_held(dip));
9710 9692  
9711 9693                  /*
9712 9694                   * Set all dips in the newly created branch offline so that
9713 9695                   * only a "configure" operation can attach
9714 9696                   * the branch
9715 9697                   */
9716 9698                  if (dip == NULL || branch_set_offline(dip, path)
9717 9699                      == DDI_FAILURE) {
9718 9700                          ndi_devi_exit(ap->pdip, circ);
9719 9701                          rv = EIO;
9720 9702                          continue;
9721 9703                  }
9722 9704  
9723 9705                  ASSERT(ddi_get_parent(dip) == ap->pdip);
9724 9706  
9725 9707                  ndi_devi_exit(ap->pdip, circ);
9726 9708  
9727 9709                  if (ap->flags & DEVI_BRANCH_CONFIGURE) {
9728 9710                          int error = e_ddi_branch_configure(dip, &ap->fdip, 0);
9729 9711                          if (error && rv == 0)
9730 9712                                  rv = error;
9731 9713                  }
9732 9714  
9733 9715                  /*
9734 9716                   * Invoke devi_branch_callback() (if it exists) only for
9735 9717                   * newly created branches
9736 9718                   */
9737 9719                  if (bp->devi_branch_callback && !exists)
9738 9720                          bp->devi_branch_callback(dip, bp->arg, 0);
9739 9721          }
9740 9722  
9741 9723          kmem_free(path, MAXPATHLEN);
9742 9724  
9743 9725          return (rv);
9744 9726  }
9745 9727  
9746 9728  static int
9747 9729  sid_node_create(dev_info_t *pdip, devi_branch_t *bp, dev_info_t **rdipp)
9748 9730  {
9749 9731          int                     rv, circ, len;
9750 9732          int                     i, flags, ret;
9751 9733          dev_info_t              *dip;
9752 9734          char                    *nbuf;
9753 9735          char                    *path;
9754 9736          static const char       *noname = "<none>";
9755 9737  
9756 9738          ASSERT(pdip);
9757 9739          ASSERT(DEVI_BUSY_OWNED(pdip));
9758 9740  
9759 9741          flags = 0;
9760 9742  
9761 9743          /*
9762 9744           * Creating the root of a branch ?
9763 9745           */
9764 9746          if (rdipp) {
9765 9747                  *rdipp = NULL;
9766 9748                  flags = DEVI_BRANCH_ROOT;
9767 9749          }
9768 9750  
9769 9751          ndi_devi_alloc_sleep(pdip, (char *)noname, DEVI_SID_NODEID, &dip);
9770 9752          rv = bp->create.sid_branch_create(dip, bp->arg, flags);
9771 9753  
9772 9754          nbuf = kmem_alloc(OBP_MAXDRVNAME, KM_SLEEP);
9773 9755  
9774 9756          if (rv == DDI_WALK_ERROR) {
9775 9757                  cmn_err(CE_WARN, "e_ddi_branch_create: Error setting"
9776 9758                      " properties on devinfo node %p",  (void *)dip);
9777 9759                  goto fail;
9778 9760          }
9779 9761  
9780 9762          len = OBP_MAXDRVNAME;
9781 9763          if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
9782 9764              DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "name", nbuf, &len)
9783 9765              != DDI_PROP_SUCCESS) {
9784 9766                  cmn_err(CE_WARN, "e_ddi_branch_create: devinfo node %p has"
9785 9767                      "no name property", (void *)dip);
9786 9768                  goto fail;
9787 9769          }
9788 9770  
9789 9771          ASSERT(i_ddi_node_state(dip) == DS_PROTO);
9790 9772          if (ndi_devi_set_nodename(dip, nbuf, 0) != NDI_SUCCESS) {
9791 9773                  cmn_err(CE_WARN, "e_ddi_branch_create: cannot set name (%s)"
9792 9774                      " for devinfo node %p", nbuf, (void *)dip);
9793 9775                  goto fail;
9794 9776          }
9795 9777  
9796 9778          kmem_free(nbuf, OBP_MAXDRVNAME);
9797 9779  
9798 9780          /*
9799 9781           * Ignore bind failures just like boot does
9800 9782           */
9801 9783          (void) ndi_devi_bind_driver(dip, 0);
9802 9784  
9803 9785          switch (rv) {
9804 9786          case DDI_WALK_CONTINUE:
9805 9787          case DDI_WALK_PRUNESIB:
9806 9788                  ndi_devi_enter(dip, &circ);
9807 9789  
9808 9790                  i = DDI_WALK_CONTINUE;
9809 9791                  for (; i == DDI_WALK_CONTINUE; ) {
9810 9792                          i = sid_node_create(dip, bp, NULL);
9811 9793                  }
9812 9794  
9813 9795                  ASSERT(i == DDI_WALK_ERROR || i == DDI_WALK_PRUNESIB);
9814 9796                  if (i == DDI_WALK_ERROR)
9815 9797                          rv = i;
9816 9798                  /*
9817 9799                   * If PRUNESIB stop creating siblings
9818 9800                   * of dip's child. Subsequent walk behavior
9819 9801                   * is determined by rv returned by dip.
9820 9802                   */
9821 9803  
9822 9804                  ndi_devi_exit(dip, circ);
9823 9805                  break;
9824 9806          case DDI_WALK_TERMINATE:
9825 9807                  /*
9826 9808                   * Don't create children and ask our parent
9827 9809                   * to not create siblings either.
9828 9810                   */
9829 9811                  rv = DDI_WALK_PRUNESIB;
9830 9812                  break;
9831 9813          case DDI_WALK_PRUNECHILD:
9832 9814                  /*
9833 9815                   * Don't create children, but ask parent to continue
9834 9816                   * with siblings.
9835 9817                   */
9836 9818                  rv = DDI_WALK_CONTINUE;
9837 9819                  break;
9838 9820          default:
9839 9821                  ASSERT(0);
9840 9822                  break;
9841 9823          }
9842 9824  
9843 9825          if (rdipp)
9844 9826                  *rdipp = dip;
9845 9827  
9846 9828          /*
9847 9829           * Set device offline - only the "configure" op should cause an attach.
9848 9830           * Note that it is safe to set the dip offline without checking
9849 9831           * for either device contract or layered driver (LDI) based constraints
9850 9832           * since there cannot be any contracts or LDI opens of this device.
9851 9833           * This is because this node is a newly created dip with the parent busy
9852 9834           * held, so no other thread can come in and attach this dip. A dip that
9853 9835           * has never been attached cannot have contracts since by definition
9854 9836           * a device contract (an agreement between a process and a device minor
9855 9837           * node) can only be created against a device that has minor nodes
9856 9838           * i.e is attached. Similarly an LDI open will only succeed if the
9857 9839           * dip is attached. We assert below that the dip is not attached.
9858 9840           */
9859 9841          ASSERT(i_ddi_node_state(dip) < DS_ATTACHED);
9860 9842          path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
9861 9843          ret = set_infant_dip_offline(dip, path);
9862 9844          ASSERT(ret == DDI_SUCCESS);
9863 9845          kmem_free(path, MAXPATHLEN);
9864 9846  
9865 9847          return (rv);
9866 9848  fail:
9867 9849          (void) ndi_devi_free(dip);
9868 9850          kmem_free(nbuf, OBP_MAXDRVNAME);
9869 9851          return (DDI_WALK_ERROR);
9870 9852  }
9871 9853  
9872 9854  static int
9873 9855  create_sid_branch(
9874 9856          dev_info_t      *pdip,
9875 9857          devi_branch_t   *bp,
9876 9858          dev_info_t      **dipp,
9877 9859          uint_t          flags)
9878 9860  {
9879 9861          int             rv = 0, state = DDI_WALK_CONTINUE;
9880 9862          dev_info_t      *rdip;
9881 9863  
9882 9864          while (state == DDI_WALK_CONTINUE) {
9883 9865                  int     circ;
9884 9866  
9885 9867                  ndi_devi_enter(pdip, &circ);
9886 9868  
9887 9869                  state = sid_node_create(pdip, bp, &rdip);
9888 9870                  if (rdip == NULL) {
9889 9871                          ndi_devi_exit(pdip, circ);
9890 9872                          ASSERT(state == DDI_WALK_ERROR);
9891 9873                          break;
9892 9874                  }
9893 9875  
9894 9876                  e_ddi_branch_hold(rdip);
9895 9877  
9896 9878                  ndi_devi_exit(pdip, circ);
9897 9879  
9898 9880                  if (flags & DEVI_BRANCH_CONFIGURE) {
9899 9881                          int error = e_ddi_branch_configure(rdip, dipp, 0);
9900 9882                          if (error && rv == 0)
9901 9883                                  rv = error;
9902 9884                  }
9903 9885  
9904 9886                  /*
9905 9887                   * devi_branch_callback() is optional
9906 9888                   */
9907 9889                  if (bp->devi_branch_callback)
9908 9890                          bp->devi_branch_callback(rdip, bp->arg, 0);
9909 9891          }
9910 9892  
9911 9893          ASSERT(state == DDI_WALK_ERROR || state == DDI_WALK_PRUNESIB);
9912 9894  
9913 9895          return (state == DDI_WALK_ERROR ? EIO : rv);
9914 9896  }
9915 9897  
9916 9898  int
9917 9899  e_ddi_branch_create(
9918 9900          dev_info_t      *pdip,
9919 9901          devi_branch_t   *bp,
9920 9902          dev_info_t      **dipp,
9921 9903          uint_t          flags)
9922 9904  {
9923 9905          int prom_devi, sid_devi, error;
9924 9906  
9925 9907          if (pdip == NULL || bp == NULL || bp->type == 0)
9926 9908                  return (EINVAL);
9927 9909  
9928 9910          prom_devi = (bp->type == DEVI_BRANCH_PROM) ? 1 : 0;
9929 9911          sid_devi = (bp->type == DEVI_BRANCH_SID) ? 1 : 0;
9930 9912  
9931 9913          if (prom_devi && bp->create.prom_branch_select == NULL)
9932 9914                  return (EINVAL);
9933 9915          else if (sid_devi && bp->create.sid_branch_create == NULL)
9934 9916                  return (EINVAL);
9935 9917          else if (!prom_devi && !sid_devi)
9936 9918                  return (EINVAL);
9937 9919  
9938 9920          if (flags & DEVI_BRANCH_EVENT)
9939 9921                  return (EINVAL);
9940 9922  
9941 9923          if (prom_devi) {
9942 9924                  struct pta pta = {0};
9943 9925  
9944 9926                  pta.pdip = pdip;
9945 9927                  pta.bp = bp;
9946 9928                  pta.flags = flags;
9947 9929  
9948 9930                  error = prom_tree_access(create_prom_branch, &pta, NULL);
9949 9931  
9950 9932                  if (dipp)
9951 9933                          *dipp = pta.fdip;
9952 9934                  else if (pta.fdip)
9953 9935                          ndi_rele_devi(pta.fdip);
9954 9936          } else {
9955 9937                  error = create_sid_branch(pdip, bp, dipp, flags);
9956 9938          }
9957 9939  
9958 9940          return (error);
9959 9941  }
9960 9942  
9961 9943  int
9962 9944  e_ddi_branch_configure(dev_info_t *rdip, dev_info_t **dipp, uint_t flags)
9963 9945  {
9964 9946          int             rv;
9965 9947          char            *devnm;
9966 9948          dev_info_t      *pdip;
9967 9949  
9968 9950          if (dipp)
9969 9951                  *dipp = NULL;
9970 9952  
9971 9953          if (rdip == NULL || flags != 0 || (flags & DEVI_BRANCH_EVENT))
9972 9954                  return (EINVAL);
9973 9955  
9974 9956          pdip = ddi_get_parent(rdip);
9975 9957  
9976 9958          ndi_hold_devi(pdip);
9977 9959  
9978 9960          if (!e_ddi_branch_held(rdip)) {
9979 9961                  ndi_rele_devi(pdip);
9980 9962                  cmn_err(CE_WARN, "e_ddi_branch_configure: "
9981 9963                      "dip(%p) not held", (void *)rdip);
9982 9964                  return (EINVAL);
9983 9965          }
9984 9966  
9985 9967          if (i_ddi_node_state(rdip) < DS_INITIALIZED) {
9986 9968                  /*
9987 9969                   * First attempt to bind a driver. If we fail, return
9988 9970                   * success (On some platforms, dips for some device
9989 9971                   * types (CPUs) may not have a driver)
9990 9972                   */
9991 9973                  if (ndi_devi_bind_driver(rdip, 0) != NDI_SUCCESS) {
9992 9974                          ndi_rele_devi(pdip);
9993 9975                          return (0);
9994 9976                  }
9995 9977  
9996 9978                  if (ddi_initchild(pdip, rdip) != DDI_SUCCESS) {
9997 9979                          rv = NDI_FAILURE;
9998 9980                          goto out;
9999 9981                  }
10000 9982          }
10001 9983  
10002 9984          ASSERT(i_ddi_node_state(rdip) >= DS_INITIALIZED);
10003 9985  
10004 9986          devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
10005 9987  
10006 9988          (void) ddi_deviname(rdip, devnm);
10007 9989  
10008 9990          if ((rv = ndi_devi_config_one(pdip, devnm+1, &rdip,
10009 9991              NDI_DEVI_ONLINE | NDI_CONFIG)) == NDI_SUCCESS) {
10010 9992                  /* release hold from ndi_devi_config_one() */
10011 9993                  ndi_rele_devi(rdip);
10012 9994          }
10013 9995  
10014 9996          kmem_free(devnm, MAXNAMELEN + 1);
10015 9997  out:
10016 9998          if (rv != NDI_SUCCESS && dipp && rdip) {
10017 9999                  ndi_hold_devi(rdip);
10018 10000                  *dipp = rdip;
10019 10001          }
10020 10002          ndi_rele_devi(pdip);
10021 10003          return (ndi2errno(rv));
10022 10004  }
10023 10005  
10024 10006  void
10025 10007  e_ddi_branch_hold(dev_info_t *rdip)
10026 10008  {
10027 10009          if (e_ddi_branch_held(rdip)) {
10028 10010                  cmn_err(CE_WARN, "e_ddi_branch_hold: branch already held");
10029 10011                  return;
10030 10012          }
10031 10013  
10032 10014          mutex_enter(&DEVI(rdip)->devi_lock);
10033 10015          if ((DEVI(rdip)->devi_flags & DEVI_BRANCH_HELD) == 0) {
10034 10016                  DEVI(rdip)->devi_flags |= DEVI_BRANCH_HELD;
10035 10017                  DEVI(rdip)->devi_ref++;
10036 10018          }
10037 10019          ASSERT(DEVI(rdip)->devi_ref > 0);
10038 10020          mutex_exit(&DEVI(rdip)->devi_lock);
10039 10021  }
10040 10022  
10041 10023  int
10042 10024  e_ddi_branch_held(dev_info_t *rdip)
10043 10025  {
10044 10026          int rv = 0;
10045 10027  
10046 10028          mutex_enter(&DEVI(rdip)->devi_lock);
10047 10029          if ((DEVI(rdip)->devi_flags & DEVI_BRANCH_HELD) &&
10048 10030              DEVI(rdip)->devi_ref > 0) {
10049 10031                  rv = 1;
10050 10032          }
10051 10033          mutex_exit(&DEVI(rdip)->devi_lock);
10052 10034  
10053 10035          return (rv);
10054 10036  }
10055 10037  
10056 10038  void
10057 10039  e_ddi_branch_rele(dev_info_t *rdip)
10058 10040  {
10059 10041          mutex_enter(&DEVI(rdip)->devi_lock);
10060 10042          DEVI(rdip)->devi_flags &= ~DEVI_BRANCH_HELD;
10061 10043          DEVI(rdip)->devi_ref--;
10062 10044          mutex_exit(&DEVI(rdip)->devi_lock);
10063 10045  }
10064 10046  
10065 10047  int
10066 10048  e_ddi_branch_unconfigure(
10067 10049          dev_info_t *rdip,
10068 10050          dev_info_t **dipp,
10069 10051          uint_t flags)
10070 10052  {
10071 10053          int     circ, rv;
10072 10054          int     destroy;
10073 10055          char    *devnm;
10074 10056          uint_t  nflags;
10075 10057          dev_info_t *pdip;
10076 10058  
10077 10059          if (dipp)
10078 10060                  *dipp = NULL;
10079 10061  
10080 10062          if (rdip == NULL)
10081 10063                  return (EINVAL);
10082 10064  
10083 10065          pdip = ddi_get_parent(rdip);
10084 10066  
10085 10067          ASSERT(pdip);
10086 10068  
10087 10069          /*
10088 10070           * Check if caller holds pdip busy - can cause deadlocks during
10089 10071           * devfs_clean()
10090 10072           */
10091 10073          if (DEVI_BUSY_OWNED(pdip)) {
10092 10074                  cmn_err(CE_WARN, "e_ddi_branch_unconfigure: failed: parent"
10093 10075                      " devinfo node(%p) is busy held", (void *)pdip);
10094 10076                  return (EINVAL);
10095 10077          }
10096 10078  
10097 10079          destroy = (flags & DEVI_BRANCH_DESTROY) ? 1 : 0;
10098 10080  
10099 10081          devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
10100 10082  
10101 10083          ndi_devi_enter(pdip, &circ);
10102 10084          (void) ddi_deviname(rdip, devnm);
10103 10085          ndi_devi_exit(pdip, circ);
10104 10086  
10105 10087          /*
10106 10088           * ddi_deviname() returns a component name with / prepended.
10107 10089           */
10108 10090          (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
10109 10091  
10110 10092          ndi_devi_enter(pdip, &circ);
10111 10093  
10112 10094          /*
10113 10095           * Recreate device name as it may have changed state (init/uninit)
10114 10096           * when parent busy lock was dropped for devfs_clean()
10115 10097           */
10116 10098          (void) ddi_deviname(rdip, devnm);
10117 10099  
10118 10100          if (!e_ddi_branch_held(rdip)) {
10119 10101                  kmem_free(devnm, MAXNAMELEN + 1);
10120 10102                  ndi_devi_exit(pdip, circ);
10121 10103                  cmn_err(CE_WARN, "e_ddi_%s_branch: dip(%p) not held",
10122 10104                      destroy ? "destroy" : "unconfigure", (void *)rdip);
10123 10105                  return (EINVAL);
10124 10106          }
10125 10107  
10126 10108          /*
10127 10109           * Release hold on the branch. This is ok since we are holding the
10128 10110           * parent busy. If rdip is not removed, we must do a hold on the
10129 10111           * branch before returning.
10130 10112           */
10131 10113          e_ddi_branch_rele(rdip);
10132 10114  
10133 10115          nflags = NDI_DEVI_OFFLINE;
10134 10116          if (destroy || (flags & DEVI_BRANCH_DESTROY)) {
10135 10117                  nflags |= NDI_DEVI_REMOVE;
10136 10118                  destroy = 1;
10137 10119          } else {
10138 10120                  nflags |= NDI_UNCONFIG;         /* uninit but don't remove */
10139 10121          }
10140 10122  
10141 10123          if (flags & DEVI_BRANCH_EVENT)
10142 10124                  nflags |= NDI_POST_EVENT;
10143 10125  
10144 10126          if (i_ddi_devi_attached(pdip) &&
10145 10127              (i_ddi_node_state(rdip) >= DS_INITIALIZED)) {
10146 10128                  rv = ndi_devi_unconfig_one(pdip, devnm+1, dipp, nflags);
10147 10129          } else {
10148 10130                  rv = e_ddi_devi_unconfig(rdip, dipp, nflags);
10149 10131                  if (rv == NDI_SUCCESS) {
10150 10132                          ASSERT(!destroy || ddi_get_child(rdip) == NULL);
10151 10133                          rv = ndi_devi_offline(rdip, nflags);
10152 10134                  }
10153 10135          }
10154 10136  
10155 10137          if (!destroy || rv != NDI_SUCCESS) {
10156 10138                  /* The dip still exists, so do a hold */
10157 10139                  e_ddi_branch_hold(rdip);
10158 10140          }
10159 10141  out:
10160 10142          kmem_free(devnm, MAXNAMELEN + 1);
10161 10143          ndi_devi_exit(pdip, circ);
10162 10144          return (ndi2errno(rv));
10163 10145  }
10164 10146  
10165 10147  int
10166 10148  e_ddi_branch_destroy(dev_info_t *rdip, dev_info_t **dipp, uint_t flag)
10167 10149  {
10168 10150          return (e_ddi_branch_unconfigure(rdip, dipp,
10169 10151              flag|DEVI_BRANCH_DESTROY));
10170 10152  }
10171 10153  
10172 10154  /*
10173 10155   * Number of chains for hash table
10174 10156   */
10175 10157  #define NUMCHAINS       17
10176 10158  
10177 10159  /*
10178 10160   * Devinfo busy arg
10179 10161   */
10180 10162  struct devi_busy {
10181 10163          int dv_total;
10182 10164          int s_total;
10183 10165          mod_hash_t *dv_hash;
10184 10166          mod_hash_t *s_hash;
10185 10167          int (*callback)(dev_info_t *, void *, uint_t);
10186 10168          void *arg;
10187 10169  };
10188 10170  
10189 10171  static int
10190 10172  visit_dip(dev_info_t *dip, void *arg)
10191 10173  {
10192 10174          uintptr_t sbusy, dvbusy, ref;
10193 10175          struct devi_busy *bsp = arg;
10194 10176  
10195 10177          ASSERT(bsp->callback);
10196 10178  
10197 10179          /*
10198 10180           * A dip cannot be busy if its reference count is 0
10199 10181           */
10200 10182          if ((ref = e_ddi_devi_holdcnt(dip)) == 0) {
10201 10183                  return (bsp->callback(dip, bsp->arg, 0));
10202 10184          }
10203 10185  
10204 10186          if (mod_hash_find(bsp->dv_hash, dip, (mod_hash_val_t *)&dvbusy))
10205 10187                  dvbusy = 0;
10206 10188  
10207 10189          /*
10208 10190           * To catch device opens currently maintained on specfs common snodes.
10209 10191           */
10210 10192          if (mod_hash_find(bsp->s_hash, dip, (mod_hash_val_t *)&sbusy))
10211 10193                  sbusy = 0;
10212 10194  
10213 10195  #ifdef  DEBUG
10214 10196          if (ref < sbusy || ref < dvbusy) {
10215 10197                  cmn_err(CE_WARN, "dip(%p): sopen = %lu, dvopen = %lu "
10216 10198                      "dip ref = %lu\n", (void *)dip, sbusy, dvbusy, ref);
10217 10199          }
10218 10200  #endif
10219 10201  
10220 10202          dvbusy = (sbusy > dvbusy) ? sbusy : dvbusy;
10221 10203  
10222 10204          return (bsp->callback(dip, bsp->arg, dvbusy));
10223 10205  }
10224 10206  
10225 10207  static int
10226 10208  visit_snode(struct snode *sp, void *arg)
10227 10209  {
10228 10210          uintptr_t sbusy;
10229 10211          dev_info_t *dip;
10230 10212          int count;
10231 10213          struct devi_busy *bsp = arg;
10232 10214  
10233 10215          ASSERT(sp);
10234 10216  
10235 10217          /*
10236 10218           * The stable lock is held. This prevents
10237 10219           * the snode and its associated dip from
10238 10220           * going away.
10239 10221           */
10240 10222          dip = NULL;
10241 10223          count = spec_devi_open_count(sp, &dip);
10242 10224  
10243 10225          if (count <= 0)
10244 10226                  return (DDI_WALK_CONTINUE);
10245 10227  
10246 10228          ASSERT(dip);
10247 10229  
10248 10230          if (mod_hash_remove(bsp->s_hash, dip, (mod_hash_val_t *)&sbusy))
10249 10231                  sbusy = count;
10250 10232          else
10251 10233                  sbusy += count;
10252 10234  
10253 10235          if (mod_hash_insert(bsp->s_hash, dip, (mod_hash_val_t)sbusy)) {
10254 10236                  cmn_err(CE_WARN, "%s: s_hash insert failed: dip=0x%p, "
10255 10237                      "sbusy = %lu", "e_ddi_branch_referenced",
10256 10238                      (void *)dip, sbusy);
10257 10239          }
10258 10240  
10259 10241          bsp->s_total += count;
10260 10242  
10261 10243          return (DDI_WALK_CONTINUE);
10262 10244  }
10263 10245  
10264 10246  static void
10265 10247  visit_dvnode(struct dv_node *dv, void *arg)
10266 10248  {
10267 10249          uintptr_t dvbusy;
10268 10250          uint_t count;
10269 10251          struct vnode *vp;
10270 10252          struct devi_busy *bsp = arg;
10271 10253  
10272 10254          ASSERT(dv && dv->dv_devi);
10273 10255  
10274 10256          vp = DVTOV(dv);
10275 10257  
10276 10258          mutex_enter(&vp->v_lock);
10277 10259          count = vp->v_count;
10278 10260          mutex_exit(&vp->v_lock);
10279 10261  
10280 10262          if (!count)
10281 10263                  return;
10282 10264  
10283 10265          if (mod_hash_remove(bsp->dv_hash, dv->dv_devi,
10284 10266              (mod_hash_val_t *)&dvbusy))
10285 10267                  dvbusy = count;
10286 10268          else
10287 10269                  dvbusy += count;
10288 10270  
10289 10271          if (mod_hash_insert(bsp->dv_hash, dv->dv_devi,
10290 10272              (mod_hash_val_t)dvbusy)) {
10291 10273                  cmn_err(CE_WARN, "%s: dv_hash insert failed: dip=0x%p, "
10292 10274                      "dvbusy=%lu", "e_ddi_branch_referenced",
10293 10275                      (void *)dv->dv_devi, dvbusy);
10294 10276          }
10295 10277  
10296 10278          bsp->dv_total += count;
10297 10279  }
10298 10280  
10299 10281  /*
10300 10282   * Returns reference count on success or -1 on failure.
10301 10283   */
10302 10284  int
10303 10285  e_ddi_branch_referenced(
10304 10286          dev_info_t *rdip,
10305 10287          int (*callback)(dev_info_t *dip, void *arg, uint_t ref),
10306 10288          void *arg)
10307 10289  {
10308 10290          int circ;
10309 10291          char *path;
10310 10292          dev_info_t *pdip;
10311 10293          struct devi_busy bsa = {0};
10312 10294  
10313 10295          ASSERT(rdip);
10314 10296  
10315 10297          path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
10316 10298  
10317 10299          ndi_hold_devi(rdip);
10318 10300  
10319 10301          pdip = ddi_get_parent(rdip);
10320 10302  
10321 10303          ASSERT(pdip);
10322 10304  
10323 10305          /*
10324 10306           * Check if caller holds pdip busy - can cause deadlocks during
10325 10307           * devfs_walk()
10326 10308           */
10327 10309          if (!e_ddi_branch_held(rdip) || DEVI_BUSY_OWNED(pdip)) {
10328 10310                  cmn_err(CE_WARN, "e_ddi_branch_referenced: failed: "
10329 10311                      "devinfo branch(%p) not held or parent busy held",
10330 10312                      (void *)rdip);
10331 10313                  ndi_rele_devi(rdip);
10332 10314                  kmem_free(path, MAXPATHLEN);
10333 10315                  return (-1);
10334 10316          }
10335 10317  
10336 10318          ndi_devi_enter(pdip, &circ);
10337 10319          (void) ddi_pathname(rdip, path);
10338 10320          ndi_devi_exit(pdip, circ);
10339 10321  
10340 10322          bsa.dv_hash = mod_hash_create_ptrhash("dv_node busy hash", NUMCHAINS,
10341 10323              mod_hash_null_valdtor, sizeof (struct dev_info));
10342 10324  
10343 10325          bsa.s_hash = mod_hash_create_ptrhash("snode busy hash", NUMCHAINS,
10344 10326              mod_hash_null_valdtor, sizeof (struct snode));
10345 10327  
10346 10328          if (devfs_walk(path, visit_dvnode, &bsa)) {
10347 10329                  cmn_err(CE_WARN, "e_ddi_branch_referenced: "
10348 10330                      "devfs walk failed for: %s", path);
10349 10331                  kmem_free(path, MAXPATHLEN);
10350 10332                  bsa.s_total = bsa.dv_total = -1;
10351 10333                  goto out;
10352 10334          }
10353 10335  
10354 10336          kmem_free(path, MAXPATHLEN);
10355 10337  
10356 10338          /*
10357 10339           * Walk the snode table to detect device opens, which are currently
10358 10340           * maintained on specfs common snodes.
10359 10341           */
10360 10342          spec_snode_walk(visit_snode, &bsa);
10361 10343  
10362 10344          if (callback == NULL)
10363 10345                  goto out;
10364 10346  
10365 10347          bsa.callback = callback;
10366 10348          bsa.arg = arg;
10367 10349  
10368 10350          if (visit_dip(rdip, &bsa) == DDI_WALK_CONTINUE) {
10369 10351                  ndi_devi_enter(rdip, &circ);
10370 10352                  ddi_walk_devs(ddi_get_child(rdip), visit_dip, &bsa);
10371 10353                  ndi_devi_exit(rdip, circ);
10372 10354          }
10373 10355  
10374 10356  out:
10375 10357          ndi_rele_devi(rdip);
10376 10358          mod_hash_destroy_ptrhash(bsa.s_hash);
10377 10359          mod_hash_destroy_ptrhash(bsa.dv_hash);
10378 10360          return (bsa.s_total > bsa.dv_total ? bsa.s_total : bsa.dv_total);
10379 10361  }
  
    | 
      ↓ open down ↓ | 
    3017 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX