1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 #include <regex.h>
  27 #include <devfsadm.h>
  28 #include <stdio.h>
  29 #include <strings.h>
  30 #include <stdlib.h>
  31 #include <limits.h>
  32 #include <sys/zone.h>
  33 #include <sys/zcons.h>
  34 #include <sys/cpuid_drv.h>
  35 
  36 static int display(di_minor_t minor, di_node_t node);
  37 static int parallel(di_minor_t minor, di_node_t node);
  38 static int node_slash_minor(di_minor_t minor, di_node_t node);
  39 static int driver_minor(di_minor_t minor, di_node_t node);
  40 static int node_name(di_minor_t minor, di_node_t node);
  41 static int minor_name(di_minor_t minor, di_node_t node);
  42 static int wifi_minor_name(di_minor_t minor, di_node_t node);
  43 static int conskbd(di_minor_t minor, di_node_t node);
  44 static int consms(di_minor_t minor, di_node_t node);
  45 static int power_button(di_minor_t minor, di_node_t node);
  46 static int fc_port(di_minor_t minor, di_node_t node);
  47 static int printer_create(di_minor_t minor, di_node_t node);
  48 static int se_hdlc_create(di_minor_t minor, di_node_t node);
  49 static int ppm(di_minor_t minor, di_node_t node);
  50 static int gpio(di_minor_t minor, di_node_t node);
  51 static int av_create(di_minor_t minor, di_node_t node);
  52 static int tsalarm_create(di_minor_t minor, di_node_t node);
  53 static int ntwdt_create(di_minor_t minor, di_node_t node);
  54 static int zcons_create(di_minor_t minor, di_node_t node);
  55 static int cpuid(di_minor_t minor, di_node_t node);
  56 static int glvc(di_minor_t minor, di_node_t node);
  57 static int ses_callback(di_minor_t minor, di_node_t node);
  58 static int kmdrv_create(di_minor_t minor, di_node_t node);
  59 
  60 static devfsadm_create_t misc_cbt[] = {
  61         { "pseudo", "ddi_pseudo", "(^sad$)",
  62             TYPE_EXACT | DRV_RE, ILEVEL_0, node_slash_minor
  63         },
  64         { "pseudo", "ddi_pseudo", "zsh",
  65             TYPE_EXACT | DRV_EXACT, ILEVEL_0, driver_minor
  66         },
  67         { "network", "ddi_network", NULL,
  68             TYPE_EXACT, ILEVEL_0, minor_name
  69         },
  70         { "wifi", "ddi_network:wifi", NULL,
  71             TYPE_EXACT, ILEVEL_0, wifi_minor_name
  72         },
  73         { "display", "ddi_display", NULL,
  74             TYPE_EXACT, ILEVEL_0, display
  75         },
  76         { "parallel", "ddi_parallel", NULL,
  77             TYPE_EXACT, ILEVEL_0, parallel
  78         },
  79         { "enclosure", DDI_NT_SCSI_ENCLOSURE, NULL,
  80             TYPE_EXACT, ILEVEL_0, ses_callback
  81         },
  82         { "pseudo", "ddi_pseudo", "(^winlock$)|(^pm$)",
  83             TYPE_EXACT | DRV_RE, ILEVEL_0, node_name
  84         },
  85         { "pseudo", "ddi_pseudo", "conskbd",
  86             TYPE_EXACT | DRV_EXACT, ILEVEL_0, conskbd
  87         },
  88         { "pseudo", "ddi_pseudo", "consms",
  89             TYPE_EXACT | DRV_EXACT, ILEVEL_0, consms
  90         },
  91         { "pseudo", "ddi_pseudo", "rsm",
  92             TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
  93         },
  94         { "pseudo", "ddi_pseudo",
  95             "(^lockstat$)|(^SUNW,rtvc$)|(^vol$)|(^log$)|(^sy$)|"
  96             "(^ksyms$)|(^clone$)|(^tl$)|(^tnf$)|(^kstat$)|(^mdesc$)|(^eeprom$)|"
  97             "(^ptsl$)|(^mm$)|(^wc$)|(^dump$)|(^cn$)|(^svvslo$)|(^ptm$)|"
  98             "(^ptc$)|(^openeepr$)|(^poll$)|(^sysmsg$)|(^random$)|(^trapstat$)|"
  99             "(^cryptoadm$)|(^crypto$)|(^pool$)|(^poolctl$)|(^bl$)|(^kmdb$)|"
 100             "(^sysevent$)|(^kssl$)|(^physmem$)",
 101             TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name
 102         },
 103         { "pseudo", "ddi_pseudo",
 104             "(^ip$)|(^tcp$)|(^udp$)|(^icmp$)|"
 105             "(^ip6$)|(^tcp6$)|(^udp6$)|(^icmp6$)|"
 106             "(^rts$)|(^arp$)|(^ipsecah$)|(^ipsecesp$)|(^keysock$)|(^spdsock$)|"
 107             "(^nca$)|(^rds$)|(^sdp$)|(^ipnet$)|(^dlpistub$)|(^bpf$)",
 108             TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name
 109         },
 110         { "pseudo", "ddi_pseudo",
 111             "(^ipf$)|(^ipnat$)|(^ipstate$)|(^ipauth$)|"
 112             "(^ipsync$)|(^ipscan$)|(^iplookup$)",
 113             TYPE_EXACT | DRV_RE, ILEVEL_0, minor_name,
 114         },
 115         { "pseudo", "ddi_pseudo", "dld",
 116             TYPE_EXACT | DRV_EXACT, ILEVEL_0, node_name
 117         },
 118         { "pseudo", "ddi_pseudo",
 119             "(^kdmouse$)|(^rootprop$)",
 120             TYPE_EXACT | DRV_RE, ILEVEL_0, node_name
 121         },
 122         { "pseudo", "ddi_pseudo", "tod",
 123             TYPE_EXACT | DRV_EXACT, ILEVEL_0, node_name
 124         },
 125         { "pseudo", "ddi_pseudo", "envctrl(two)?",
 126             TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name,
 127         },
 128         { "pseudo", "ddi_pseudo", "fcode",
 129             TYPE_EXACT | DRV_RE, ILEVEL_0, minor_name,
 130         },
 131         { "power_button", "ddi_power_button", NULL,
 132             TYPE_EXACT, ILEVEL_0, power_button,
 133         },
 134         { "FC port", "ddi_ctl:devctl", "fp",
 135             TYPE_EXACT | DRV_EXACT, ILEVEL_0, fc_port
 136         },
 137         { "printer", "ddi_printer", NULL,
 138             TYPE_EXACT, ILEVEL_0, printer_create
 139         },
 140         { "pseudo", "ddi_pseudo", "se",
 141             TYPE_EXACT | DRV_EXACT, ILEVEL_0, se_hdlc_create
 142         },
 143         { "ppm",  "ddi_ppm", NULL,
 144             TYPE_EXACT, ILEVEL_0, ppm
 145         },
 146         { "pseudo", "ddi_pseudo", "gpio_87317",
 147             TYPE_EXACT | DRV_EXACT, ILEVEL_0, gpio
 148         },
 149         { "pseudo", "ddi_pseudo", "sckmdrv",
 150             TYPE_EXACT | DRV_RE, ILEVEL_0, kmdrv_create,
 151         },
 152         { "pseudo", "ddi_pseudo", "oplkmdrv",
 153             TYPE_EXACT | DRV_RE, ILEVEL_0, kmdrv_create,
 154         },
 155         { "av", "^ddi_av:(isoch|async)$", NULL,
 156             TYPE_RE, ILEVEL_0, av_create,
 157         },
 158         { "pseudo", "ddi_pseudo", "tsalarm",
 159             TYPE_EXACT | DRV_RE, ILEVEL_0, tsalarm_create,
 160         },
 161         { "pseudo", "ddi_pseudo", "ntwdt",
 162             TYPE_EXACT | DRV_RE, ILEVEL_0, ntwdt_create,
 163         },
 164         { "pseudo", "ddi_pseudo", "daplt",
 165             TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
 166         },
 167         { "pseudo", "ddi_pseudo", "zcons",
 168             TYPE_EXACT | DRV_EXACT, ILEVEL_0, zcons_create,
 169         },
 170         { "pseudo", "ddi_pseudo", CPUID_DRIVER_NAME,
 171             TYPE_EXACT | DRV_EXACT, ILEVEL_0, cpuid,
 172         },
 173         { "pseudo", "ddi_pseudo", "glvc",
 174             TYPE_EXACT | DRV_EXACT, ILEVEL_0, glvc,
 175         },
 176         { "pseudo", "ddi_pseudo", "dm2s",
 177             TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name,
 178         },
 179         { "pseudo", "ddi_pseudo", "nsmb",
 180             TYPE_EXACT | DRV_EXACT, ILEVEL_1, minor_name,
 181         },
 182         { "pseudo", "ddi_pseudo", "mem_cache",
 183             TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name,
 184         },
 185         { "pseudo", "ddi_pseudo", "fm",
 186             TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name,
 187         },
 188         { "pseudo", "ddi_pseudo", "smbsrv",
 189             TYPE_EXACT | DRV_EXACT, ILEVEL_1, minor_name,
 190         },
 191         { "pseudo", "ddi_pseudo", "tpm",
 192             TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
 193         },
 194 };
 195 
 196 DEVFSADM_CREATE_INIT_V0(misc_cbt);
 197 
 198 static devfsadm_remove_t misc_remove_cbt[] = {
 199         { "pseudo", "^profile$",
 200             RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
 201         },
 202         { "pseudo", "^rsm$",
 203             RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
 204         },
 205         { "printer", "^printers/[0-9]+$",
 206             RM_PRE | RM_HOT | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
 207         },
 208         { "av", "^av/[0-9]+/(async|isoch)$",
 209             RM_PRE | RM_HOT | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
 210         },
 211         { "pseudo", "^daplt$",
 212             RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
 213         },
 214         { "pseudo", "^zcons/" ZONENAME_REGEXP "/(" ZCONS_MASTER_NAME "|"
 215                 ZCONS_SLAVE_NAME ")$",
 216             RM_PRE | RM_HOT | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
 217         },
 218         { "pseudo", "^" CPUID_SELF_NAME "$", RM_ALWAYS | RM_PRE | RM_HOT,
 219             ILEVEL_0, devfsadm_rm_all
 220         },
 221         { "enclosure", "^es/ses[0-9]+$", RM_POST,
 222                 ILEVEL_0, devfsadm_rm_all
 223         },
 224         { "pseudo", "^pfil$",
 225             RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
 226         },
 227         { "pseudo", "^tpm$",
 228             RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
 229         },
 230         { "pseudo", "^sctp|sctp6$",
 231             RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_link
 232         }
 233 };
 234 
 235 /* Rules for gpio devices */
 236 static devfsadm_enumerate_t gpio_rules[1] =
 237         {"^gpio([0-9]+)$", 1, MATCH_ALL};
 238 
 239 DEVFSADM_REMOVE_INIT_V0(misc_remove_cbt);
 240 
 241 /*
 242  * Handles minor node type "ddi_display".
 243  *
 244  * type=ddi_display fbs/\M0 fb\N0
 245  */
 246 static int
 247 display(di_minor_t minor, di_node_t node)
 248 {
 249         char l_path[PATH_MAX + 1], contents[PATH_MAX + 1], *buf;
 250         devfsadm_enumerate_t rules[1] = {"^fb([0-9]+)$", 1, MATCH_ALL};
 251         char *mn = di_minor_name(minor);
 252 
 253         /* create fbs/\M0 primary link */
 254         (void) strcpy(l_path, "fbs/");
 255         (void) strcat(l_path, mn);
 256         (void) devfsadm_mklink(l_path, node, minor, 0);
 257 
 258         /* create fb\N0 which links to fbs/\M0 */
 259         if (devfsadm_enumerate_int(l_path, 0, &buf, rules, 1)) {
 260                 return (DEVFSADM_CONTINUE);
 261         }
 262         (void) strcpy(contents, l_path);
 263         (void) strcpy(l_path, "fb");
 264         (void) strcat(l_path, buf);
 265         free(buf);
 266         (void) devfsadm_secondary_link(l_path, contents, 0);
 267         return (DEVFSADM_CONTINUE);
 268 }
 269 
 270 /*
 271  * Handles minor node type "ddi_parallel".
 272  * type=ddi_parallel;name=mcpp     mcpp\N0
 273  */
 274 static int
 275 parallel(di_minor_t minor, di_node_t node)
 276 {
 277         char path[PATH_MAX + 1], *buf;
 278         devfsadm_enumerate_t rules[1] = {"mcpp([0-9]+)$", 1, MATCH_ALL};
 279 
 280 
 281         if (strcmp(di_node_name(node), "mcpp") != 0) {
 282                 return (DEVFSADM_CONTINUE);
 283         }
 284 
 285         if (NULL == (buf = di_devfs_path(node))) {
 286                 return (DEVFSADM_CONTINUE);
 287         }
 288 
 289         (void) snprintf(path, sizeof (path), "%s:%s",
 290             buf, di_minor_name(minor));
 291 
 292         di_devfs_path_free(buf);
 293 
 294         if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) {
 295                 return (DEVFSADM_CONTINUE);
 296         }
 297         (void) snprintf(path, sizeof (path), "mcpp%s", buf);
 298         free(buf);
 299 
 300         (void) devfsadm_mklink(path, node, minor, 0);
 301         return (DEVFSADM_CONTINUE);
 302 }
 303 
 304 static int
 305 ses_callback(di_minor_t minor, di_node_t node)
 306 {
 307         char l_path[PATH_MAX];
 308         char *buf;
 309         char *devfspath;
 310         char p_path[PATH_MAX];
 311         devfsadm_enumerate_t re[] = {"^es$/^ses([0-9]+)$", 1, MATCH_ALL};
 312 
 313         /* find devices path -- need to free mem */
 314         if (NULL == (devfspath = di_devfs_path(node))) {
 315                 return (DEVFSADM_CONTINUE);
 316         }
 317 
 318         (void) snprintf(p_path, sizeof (p_path), "%s:%s", devfspath,
 319             di_minor_name(minor));
 320 
 321 
 322         /* find next number to use; buf is an ascii number */
 323         if (devfsadm_enumerate_int(p_path, 0, &buf, re, 1)) {
 324                 /* free memory */
 325                 di_devfs_path_free(devfspath);
 326                 return (DEVFSADM_CONTINUE);
 327         }
 328 
 329         (void) snprintf(l_path, sizeof (l_path), "es/ses%s", buf);
 330 
 331         (void) devfsadm_mklink(l_path, node, minor, 0);
 332         /* free memory */
 333         free(buf);
 334         di_devfs_path_free(devfspath);
 335         return (DEVFSADM_CONTINUE);
 336 
 337 }
 338 
 339 static int
 340 node_slash_minor(di_minor_t minor, di_node_t node)
 341 {
 342 
 343         char path[PATH_MAX + 1];
 344 
 345         (void) strcpy(path, di_node_name(node));
 346         (void) strcat(path, "/");
 347         (void) strcat(path, di_minor_name(minor));
 348         (void) devfsadm_mklink(path, node, minor, 0);
 349         return (DEVFSADM_CONTINUE);
 350 }
 351 
 352 static int
 353 driver_minor(di_minor_t minor, di_node_t node)
 354 {
 355         char path[PATH_MAX + 1];
 356 
 357         (void) strcpy(path, di_driver_name(node));
 358         (void) strcat(path, di_minor_name(minor));
 359         (void) devfsadm_mklink(path, node, minor, 0);
 360         return (DEVFSADM_CONTINUE);
 361 }
 362 
 363 /*
 364  * Handles links of the form:
 365  * type=ddi_pseudo;name=xyz  \D
 366  */
 367 static int
 368 node_name(di_minor_t minor, di_node_t node)
 369 {
 370         (void) devfsadm_mklink(di_node_name(node), node, minor, 0);
 371         return (DEVFSADM_CONTINUE);
 372 }
 373 
 374 /*
 375  * Handles links of the form:
 376  * type=ddi_pseudo;name=xyz  \M0
 377  */
 378 static int
 379 minor_name(di_minor_t minor, di_node_t node)
 380 {
 381         char *mn = di_minor_name(minor);
 382 
 383         (void) devfsadm_mklink(mn, node, minor, 0);
 384         if (strcmp(mn, "icmp") == 0) {
 385                 (void) devfsadm_mklink("rawip", node, minor, 0);
 386         }
 387         if (strcmp(mn, "icmp6") == 0) {
 388                 (void) devfsadm_mklink("rawip6", node, minor, 0);
 389         }
 390         if (strcmp(mn, "ipf") == 0) {
 391                 (void) devfsadm_mklink("ipl", node, minor, 0);
 392         }
 393         return (DEVFSADM_CONTINUE);
 394 }
 395 
 396 /*
 397  * create links at /dev/wifi for wifi minor node
 398  */
 399 static int
 400 wifi_minor_name(di_minor_t minor, di_node_t node)
 401 {
 402         char buf[256];
 403         char *mn = di_minor_name(minor);
 404 
 405         (void) snprintf(buf, sizeof (buf), "%s%s", "wifi/", mn);
 406         (void) devfsadm_mklink(buf, node, minor, 0);
 407 
 408         return (DEVFSADM_CONTINUE);
 409 }
 410 
 411 static int
 412 conskbd(di_minor_t minor, di_node_t node)
 413 {
 414         (void) devfsadm_mklink("kbd", node, minor, 0);
 415         return (DEVFSADM_CONTINUE);
 416 }
 417 
 418 static int
 419 consms(di_minor_t minor, di_node_t node)
 420 {
 421         (void) devfsadm_mklink("mouse", node, minor, 0);
 422         return (DEVFSADM_CONTINUE);
 423 }
 424 
 425 static int
 426 power_button(di_minor_t minor, di_node_t node)
 427 {
 428         (void) devfsadm_mklink("power_button", node, minor, 0);
 429         return (DEVFSADM_CONTINUE);
 430 }
 431 
 432 static int
 433 fc_port(di_minor_t minor, di_node_t node)
 434 {
 435         devfsadm_enumerate_t rules[1] = {"fc/fp([0-9]+)$", 1, MATCH_ALL};
 436         char *buf, path[PATH_MAX + 1];
 437         char *ptr;
 438 
 439         if (NULL == (ptr = di_devfs_path(node))) {
 440                 return (DEVFSADM_CONTINUE);
 441         }
 442 
 443         (void) strcpy(path, ptr);
 444         (void) strcat(path, ":");
 445         (void) strcat(path, di_minor_name(minor));
 446 
 447         di_devfs_path_free(ptr);
 448 
 449         if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) != 0) {
 450                 return (DEVFSADM_CONTINUE);
 451         }
 452 
 453         (void) strcpy(path, "fc/fp");
 454         (void) strcat(path, buf);
 455         free(buf);
 456 
 457         (void) devfsadm_mklink(path, node, minor, 0);
 458         return (DEVFSADM_CONTINUE);
 459 }
 460 
 461 /*
 462  * Handles:
 463  *      minor node type "ddi_printer".
 464  *      rules of the form: type=ddi_printer;name=bpp  \M0
 465  */
 466 static int
 467 printer_create(di_minor_t minor, di_node_t node)
 468 {
 469         char *mn;
 470         char path[PATH_MAX + 1], *buf;
 471         devfsadm_enumerate_t rules[1] = {"^printers$/^([0-9]+)$", 1, MATCH_ALL};
 472 
 473         mn = di_minor_name(minor);
 474 
 475         if (strcmp(di_driver_name(node), "bpp") == 0) {
 476                 (void) devfsadm_mklink(mn, node, minor, 0);
 477         }
 478 
 479         if (NULL == (buf = di_devfs_path(node))) {
 480                 return (DEVFSADM_CONTINUE);
 481         }
 482 
 483         (void) snprintf(path, sizeof (path), "%s:%s", buf, mn);
 484         di_devfs_path_free(buf);
 485 
 486         if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) {
 487                 return (DEVFSADM_CONTINUE);
 488         }
 489 
 490         (void) snprintf(path, sizeof (path), "printers/%s", buf);
 491         free(buf);
 492 
 493         (void) devfsadm_mklink(path, node, minor, 0);
 494 
 495         return (DEVFSADM_CONTINUE);
 496 }
 497 
 498 /*
 499  * Handles links of the form:
 500  * type=ddi_pseudo;name=se;minor2=hdlc  se_hdlc\N0
 501  * type=ddi_pseudo;name=serial;minor2=hdlc      se_hdlc\N0
 502  */
 503 static int
 504 se_hdlc_create(di_minor_t minor, di_node_t node)
 505 {
 506         devfsadm_enumerate_t rules[1] = {"^se_hdlc([0-9]+)$", 1, MATCH_ALL};
 507         char *buf, path[PATH_MAX + 1];
 508         char *ptr;
 509         char *mn;
 510 
 511         mn = di_minor_name(minor);
 512 
 513         /* minor node should be of the form: "?,hdlc" */
 514         if (strcmp(mn + 1, ",hdlc") != 0) {
 515                 return (DEVFSADM_CONTINUE);
 516         }
 517 
 518         if (NULL == (ptr = di_devfs_path(node))) {
 519                 return (DEVFSADM_CONTINUE);
 520         }
 521 
 522         (void) strcpy(path, ptr);
 523         (void) strcat(path, ":");
 524         (void) strcat(path, mn);
 525 
 526         di_devfs_path_free(ptr);
 527 
 528         if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) != 0) {
 529                 return (DEVFSADM_CONTINUE);
 530         }
 531 
 532         (void) strcpy(path, "se_hdlc");
 533         (void) strcat(path, buf);
 534         free(buf);
 535 
 536         (void) devfsadm_mklink(path, node, minor, 0);
 537 
 538         return (DEVFSADM_CONTINUE);
 539 }
 540 
 541 static int
 542 gpio(di_minor_t minor, di_node_t node)
 543 {
 544         char l_path[PATH_MAX], p_path[PATH_MAX], *buf, *devfspath;
 545         char *minor_nm, *drvr_nm;
 546 
 547 
 548         minor_nm = di_minor_name(minor);
 549         drvr_nm = di_driver_name(node);
 550         if ((minor_nm == NULL) || (drvr_nm == NULL)) {
 551                 return (DEVFSADM_CONTINUE);
 552         }
 553 
 554         devfspath = di_devfs_path(node);
 555 
 556         (void) strcpy(p_path, devfspath);
 557         (void) strcat(p_path, ":");
 558         (void) strcat(p_path, minor_nm);
 559         di_devfs_path_free(devfspath);
 560 
 561         /* build the physical path from the components */
 562         if (devfsadm_enumerate_int(p_path, 0, &buf, gpio_rules, 1)) {
 563                 return (DEVFSADM_CONTINUE);
 564         }
 565 
 566         (void) snprintf(l_path, sizeof (l_path), "%s%s", "gpio", buf);
 567 
 568         free(buf);
 569 
 570         (void) devfsadm_mklink(l_path, node, minor, 0);
 571 
 572         return (DEVFSADM_CONTINUE);
 573 }
 574 
 575 /*
 576  * Creates /dev/ppm nodes for Platform Specific PM module
 577  */
 578 static int
 579 ppm(di_minor_t minor, di_node_t node)
 580 {
 581         (void) devfsadm_mklink("ppm", node, minor, 0);
 582         return (DEVFSADM_CONTINUE);
 583 }
 584 
 585 /*
 586  * Handles:
 587  *      /dev/av/[0-9]+/(async|isoch)
 588  */
 589 static int
 590 av_create(di_minor_t minor, di_node_t node)
 591 {
 592         devfsadm_enumerate_t rules[1] = {"^av$/^([0-9]+)$", 1, MATCH_ADDR};
 593         char    *minor_str;
 594         char    path[PATH_MAX + 1];
 595         char    *buf;
 596 
 597         if ((buf = di_devfs_path(node)) == NULL) {
 598                 return (DEVFSADM_CONTINUE);
 599         }
 600 
 601         minor_str = di_minor_name(minor);
 602         (void) snprintf(path, sizeof (path), "%s:%s", buf, minor_str);
 603         di_devfs_path_free(buf);
 604 
 605         if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) {
 606                 return (DEVFSADM_CONTINUE);
 607         }
 608 
 609         (void) snprintf(path, sizeof (path), "av/%s/%s", buf, minor_str);
 610         free(buf);
 611 
 612         (void) devfsadm_mklink(path, node, minor, 0);
 613 
 614         return (DEVFSADM_CONTINUE);
 615 }
 616 
 617 /*
 618  * Creates /dev/lom and /dev/tsalarm:ctl for tsalarm node
 619  */
 620 static int
 621 tsalarm_create(di_minor_t minor, di_node_t node)
 622 {
 623         char buf[PATH_MAX + 1];
 624         char *mn = di_minor_name(minor);
 625 
 626         (void) snprintf(buf, sizeof (buf), "%s%s", di_node_name(node), ":ctl");
 627 
 628         (void) devfsadm_mklink(mn, node, minor, 0);
 629         (void) devfsadm_mklink(buf, node, minor, 0);
 630 
 631         return (DEVFSADM_CONTINUE);
 632 }
 633 
 634 /*
 635  * Creates /dev/ntwdt for ntwdt node
 636  */
 637 static int
 638 ntwdt_create(di_minor_t minor, di_node_t node)
 639 {
 640         (void) devfsadm_mklink("ntwdt", node, minor, 0);
 641         return (DEVFSADM_CONTINUE);
 642 }
 643 
 644 static int
 645 zcons_create(di_minor_t minor, di_node_t node)
 646 {
 647         char    *minor_str;
 648         char    *zonename;
 649         char    path[MAXPATHLEN];
 650 
 651         minor_str = di_minor_name(minor);
 652 
 653         if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
 654             &zonename) == -1) {
 655                 return (DEVFSADM_CONTINUE);
 656         }
 657 
 658         (void) snprintf(path, sizeof (path), "zcons/%s/%s", zonename,
 659             minor_str);
 660         (void) devfsadm_mklink(path, node, minor, 0);
 661 
 662         return (DEVFSADM_CONTINUE);
 663 }
 664 
 665 /*
 666  *      /dev/cpu/self/cpuid     ->   /devices/pseudo/cpuid@0:self
 667  */
 668 static int
 669 cpuid(di_minor_t minor, di_node_t node)
 670 {
 671         (void) devfsadm_mklink(CPUID_SELF_NAME, node, minor, 0);
 672         return (DEVFSADM_CONTINUE);
 673 }
 674 
 675 /*
 676  * For device
 677  *      /dev/spfma -> /devices/virtual-devices/fma@5:glvc
 678  */
 679 static int
 680 glvc(di_minor_t minor, di_node_t node)
 681 {
 682         char node_name[MAXNAMELEN + 1];
 683 
 684         (void) strcpy(node_name, di_node_name(node));
 685 
 686         if (strncmp(node_name, "fma", 3) == 0) {
 687                 /* Only one fma channel */
 688                 (void) devfsadm_mklink("spfma", node, minor, 0);
 689         }
 690         return (DEVFSADM_CONTINUE);
 691 }
 692 
 693 /*
 694  * Handles links of the form:
 695  * type=ddi_pseudo;name=sckmdrv         kmdrv\M0
 696  * type=ddi_pseudo;name=oplkmdrv        kmdrv\M0
 697  */
 698 static int
 699 kmdrv_create(di_minor_t minor, di_node_t node)
 700 {
 701 
 702         (void) devfsadm_mklink("kmdrv", node, minor, 0);
 703         return (DEVFSADM_CONTINUE);
 704 }