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