xref: /titanic_44/usr/src/cmd/devfsadm/i386/misc_link_i386.c (revision db8b037b5616a366b7dfdc01ef9552f02f9adfdd)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2012 Joyent, Inc.  All rights reserved.
25  */
26 
27 #include <regex.h>
28 #include <devfsadm.h>
29 #include <stdio.h>
30 #include <strings.h>
31 #include <stdlib.h>
32 #include <limits.h>
33 #include <ctype.h>
34 #include <sys/mc_amd.h>
35 #include <bsm/devalloc.h>
36 
37 extern int system_labeled;
38 
39 static int lp(di_minor_t minor, di_node_t node);
40 static int serial_dialout(di_minor_t minor, di_node_t node);
41 static int serial(di_minor_t minor, di_node_t node);
42 static int diskette(di_minor_t minor, di_node_t node);
43 static int vt00(di_minor_t minor, di_node_t node);
44 static int kdmouse(di_minor_t minor, di_node_t node);
45 static int ipmi(di_minor_t minor, di_node_t node);
46 static int smbios(di_minor_t minor, di_node_t node);
47 static int agp_process(di_minor_t minor, di_node_t node);
48 static int drm_node(di_minor_t minor, di_node_t node);
49 static int mc_node(di_minor_t minor, di_node_t node);
50 static int xsvc(di_minor_t minor, di_node_t node);
51 static int srn(di_minor_t minor, di_node_t node);
52 static int ucode(di_minor_t minor, di_node_t node);
53 
54 
55 static devfsadm_create_t misc_cbt[] = {
56 	{ "vt00", "ddi_display", NULL,
57 	    TYPE_EXACT, ILEVEL_0,	vt00
58 	},
59 	{ "drm", "ddi_display:drm", NULL,
60 	    TYPE_EXACT, ILEVEL_0,	drm_node
61 	},
62 	{ "mouse", "ddi_mouse", "mouse8042",
63 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, kdmouse
64 	},
65 	{ "pseudo", "ddi_pseudo", "ipmi",
66 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, ipmi,
67 	},
68 	{ "pseudo", "ddi_pseudo", "smbios",
69 	    TYPE_EXACT | DRV_EXACT, ILEVEL_1, smbios,
70 	},
71 	/* floppies share the same class, but not link regex, as hard disks */
72 	{ "disk",  "ddi_block:diskette", NULL,
73 	    TYPE_EXACT, ILEVEL_1, diskette
74 	},
75 	{ "parallel",  "ddi_printer", NULL,
76 	    TYPE_EXACT, ILEVEL_1, lp
77 	},
78 	{ "serial", "ddi_serial:mb", NULL,
79 	    TYPE_EXACT, ILEVEL_1, serial
80 	},
81 	{ "serial",  "ddi_serial:dialout,mb", NULL,
82 	    TYPE_EXACT, ILEVEL_1, serial_dialout
83 	},
84 	{ "agp", "ddi_agp:pseudo", NULL,
85 	    TYPE_EXACT, ILEVEL_0, agp_process
86 	},
87 	{ "agp", "ddi_agp:target", NULL,
88 	    TYPE_EXACT, ILEVEL_0, agp_process
89 	},
90 	{ "agp", "ddi_agp:cpugart", NULL,
91 	    TYPE_EXACT, ILEVEL_0, agp_process
92 	},
93 	{ "agp", "ddi_agp:master", NULL,
94 	    TYPE_EXACT, ILEVEL_0, agp_process
95 	},
96 	{ "pseudo", "ddi_pseudo", NULL,
97 	    TYPE_EXACT, ILEVEL_0, xsvc
98 	},
99 	{ "pseudo", "ddi_pseudo", NULL,
100 	    TYPE_EXACT, ILEVEL_0, srn
101 	},
102 	{ "memory-controller", "ddi_mem_ctrl", NULL,
103 	    TYPE_EXACT, ILEVEL_0, mc_node
104 	},
105 	{ "pseudo", "ddi_pseudo", "ucode",
106 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, ucode,
107 	},
108 };
109 
110 DEVFSADM_CREATE_INIT_V0(misc_cbt);
111 
112 static char *debug_mid = "misc_mid";
113 
114 typedef enum {
115 	DRIVER_AGPPSEUDO = 0,
116 	DRIVER_AGPTARGET,
117 	DRIVER_CPUGART,
118 	DRIVER_AGPMASTER_DRM_I915,
119 	DRIVER_AGPMASTER_DRM_RADEON,
120 	DRIVER_AGPMASTER_VGATEXT,
121 	DRIVER_UNKNOWN
122 } driver_defs_t;
123 
124 typedef struct {
125 	char	*driver_name;
126 	int	index;
127 } driver_name_table_entry_t;
128 
129 static driver_name_table_entry_t driver_name_table[] = {
130 	{ "agpgart",		DRIVER_AGPPSEUDO },
131 	{ "agptarget",		DRIVER_AGPTARGET },
132 	{ "amd64_gart",		DRIVER_CPUGART },
133 	/* AGP master device managed by drm driver */
134 	{ "i915",		DRIVER_AGPMASTER_DRM_I915 },
135 	{ "radeon",		DRIVER_AGPMASTER_DRM_RADEON },
136 	{ "vgatext",		DRIVER_AGPMASTER_VGATEXT },
137 	{ NULL,			DRIVER_UNKNOWN }
138 };
139 
140 static devfsadm_enumerate_t agptarget_rules[1] =
141 	{ "^agp$/^agptarget([0-9]+)$", 1, MATCH_ALL };
142 static devfsadm_enumerate_t cpugart_rules[1] =
143 	{ "^agp$/^cpugart([0-9]+)$", 1, MATCH_ALL };
144 static devfsadm_enumerate_t agpmaster_rules[1] =
145 	{  "^agp$/^agpmaster([0-9]+)$", 1, MATCH_ALL };
146 
147 static devfsadm_remove_t misc_remove_cbt[] = {
148 	{ "vt", "vt[0-9][0-9]", RM_PRE|RM_ALWAYS,
149 		ILEVEL_0, devfsadm_rm_all
150 	},
151 	{ "pseudo", "^ucode$", RM_ALWAYS | RM_PRE | RM_HOT,
152 		ILEVEL_0, devfsadm_rm_all
153 	},
154 	{ "mouse", "^kdmouse$", RM_ALWAYS | RM_PRE,
155 		ILEVEL_0, devfsadm_rm_all
156 	},
157 	{ "disk", "^(diskette|rdiskette)([0-9]*)$",
158 		RM_ALWAYS | RM_PRE, ILEVEL_1, devfsadm_rm_all
159 	},
160 	{ "parallel", "^(lp|ecpp)([0-9]+)$", RM_ALWAYS | RM_PRE,
161 		ILEVEL_1, devfsadm_rm_all
162 	},
163 	{ "serial", "^(tty|ttyd)([0-9]+)$", RM_ALWAYS | RM_PRE,
164 		ILEVEL_1, devfsadm_rm_all
165 	},
166 	{ "serial", "^tty[a-z]$", RM_ALWAYS | RM_PRE,
167 		ILEVEL_1, devfsadm_rm_all
168 	}
169 };
170 
171 DEVFSADM_REMOVE_INIT_V0(misc_remove_cbt);
172 
173 /*
174  * Handles minor node type "ddi_display", in addition to generic processing
175  * done by display().
176  *
177  * This creates a /dev/vt00 link to /dev/fb, for backwards compatibility.
178  */
179 /* ARGSUSED */
180 int
181 vt00(di_minor_t minor, di_node_t node)
182 {
183 	(void) devfsadm_secondary_link("vt00", "fb", 0);
184 	return (DEVFSADM_CONTINUE);
185 }
186 
187 /*
188  * type=ddi_block:diskette;addr=0,0;minor=c        diskette
189  * type=ddi_block:diskette;addr=0,0;minor=c,raw    rdiskette
190  * type=ddi_block:diskette;addr1=0;minor=c diskette\A2
191  * type=ddi_block:diskette;addr1=0;minor=c,raw     rdiskette\A2
192  */
193 static int
194 diskette(di_minor_t minor, di_node_t node)
195 {
196 	int flags = 0;
197 	char *a2;
198 	char link[PATH_MAX];
199 	char *addr = di_bus_addr(node);
200 	char *mn = di_minor_name(minor);
201 
202 	if (system_labeled)
203 		flags = DA_ADD|DA_FLOPPY;
204 
205 	if (strcmp(addr, "0,0") == 0) {
206 		if (strcmp(mn, "c") == 0) {
207 			(void) devfsadm_mklink("diskette", node, minor, flags);
208 		} else if (strcmp(mn, "c,raw") == 0) {
209 			(void) devfsadm_mklink("rdiskette", node, minor, flags);
210 		}
211 
212 	}
213 
214 	if (addr[0] == '0') {
215 		if ((a2 = strchr(addr, ',')) != NULL) {
216 			a2++;
217 			if (strcmp(mn, "c") == 0) {
218 				(void) strcpy(link, "diskette");
219 				(void) strcat(link, a2);
220 				(void) devfsadm_mklink(link, node, minor,
221 				    flags);
222 			} else if (strcmp(mn, "c,raw") == 0) {
223 				(void) strcpy(link, "rdiskette");
224 				(void) strcat(link, a2);
225 				(void) devfsadm_mklink(link, node, minor,
226 				    flags);
227 			}
228 		}
229 	}
230 
231 	return (DEVFSADM_CONTINUE);
232 }
233 
234 /*
235  * type=ddi_printer;name=lp;addr=1,3bc      lp0
236  * type=ddi_printer;name=lp;addr=1,378      lp1
237  * type=ddi_printer;name=lp;addr=1,278      lp2
238  */
239 static int
240 lp(di_minor_t minor, di_node_t node)
241 {
242 	char *addr = di_bus_addr(node);
243 	char *buf;
244 	char path[PATH_MAX + 1];
245 	devfsadm_enumerate_t rules[1] = {"^ecpp([0-9]+)$", 1, MATCH_ALL};
246 
247 	if (strcmp(addr, "1,3bc") == 0) {
248 		(void) devfsadm_mklink("lp0", node, minor, 0);
249 
250 	} else if (strcmp(addr, "1,378") == 0) {
251 		(void) devfsadm_mklink("lp1", node, minor, 0);
252 
253 	} else if (strcmp(addr, "1,278") == 0) {
254 		(void) devfsadm_mklink("lp2", node, minor, 0);
255 	}
256 
257 	if (strcmp(di_driver_name(node), "ecpp") != 0) {
258 		return (DEVFSADM_CONTINUE);
259 	}
260 
261 	if ((buf = di_devfs_path(node)) == NULL) {
262 		return (DEVFSADM_CONTINUE);
263 	}
264 
265 	(void) snprintf(path, sizeof (path), "%s:%s",
266 	    buf, di_minor_name(minor));
267 
268 	di_devfs_path_free(buf);
269 
270 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) {
271 		return (DEVFSADM_CONTINUE);
272 	}
273 
274 	(void) snprintf(path, sizeof (path), "ecpp%s", buf);
275 	free(buf);
276 	(void) devfsadm_mklink(path, node, minor, 0);
277 	return (DEVFSADM_CONTINUE);
278 }
279 
280 /*
281  * type=ddi_serial:mb;minor=a      tty00
282  * type=ddi_serial:mb;minor=b      tty01
283  * type=ddi_serial:mb;minor=c      tty02
284  * type=ddi_serial:mb;minor=d      tty03
285  */
286 static int
287 serial(di_minor_t minor, di_node_t node)
288 {
289 
290 	char *mn = di_minor_name(minor);
291 	char link[PATH_MAX];
292 
293 	(void) strcpy(link, "tty");
294 	(void) strcat(link, mn);
295 	(void) devfsadm_mklink(link, node, minor, 0);
296 
297 	if (strcmp(mn, "a") == 0) {
298 		(void) devfsadm_mklink("tty00", node, minor, 0);
299 
300 	} else if (strcmp(mn, "b") == 0) {
301 		(void) devfsadm_mklink("tty01", node, minor, 0);
302 
303 	} else if (strcmp(mn, "c") == 0) {
304 		(void) devfsadm_mklink("tty02", node, minor, 0);
305 
306 	} else if (strcmp(mn, "d") == 0) {
307 		(void) devfsadm_mklink("tty03", node, minor, 0);
308 	}
309 	return (DEVFSADM_CONTINUE);
310 }
311 
312 /*
313  * type=ddi_serial:dialout,mb;minor=a,cu   ttyd0
314  * type=ddi_serial:dialout,mb;minor=b,cu   ttyd1
315  * type=ddi_serial:dialout,mb;minor=c,cu   ttyd2
316  * type=ddi_serial:dialout,mb;minor=d,cu   ttyd3
317  */
318 static int
319 serial_dialout(di_minor_t minor, di_node_t node)
320 {
321 	char *mn = di_minor_name(minor);
322 
323 	if (strcmp(mn, "a,cu") == 0) {
324 		(void) devfsadm_mklink("ttyd0", node, minor, 0);
325 		(void) devfsadm_mklink("cua0", node, minor, 0);
326 
327 	} else if (strcmp(mn, "b,cu") == 0) {
328 		(void) devfsadm_mklink("ttyd1", node, minor, 0);
329 		(void) devfsadm_mklink("cua1", node, minor, 0);
330 
331 	} else if (strcmp(mn, "c,cu") == 0) {
332 		(void) devfsadm_mklink("ttyd2", node, minor, 0);
333 		(void) devfsadm_mklink("cua2", node, minor, 0);
334 
335 	} else if (strcmp(mn, "d,cu") == 0) {
336 		(void) devfsadm_mklink("ttyd3", node, minor, 0);
337 		(void) devfsadm_mklink("cua3", node, minor, 0);
338 	}
339 	return (DEVFSADM_CONTINUE);
340 }
341 
342 static int
343 kdmouse(di_minor_t minor, di_node_t node)
344 {
345 	(void) devfsadm_mklink("kdmouse", node, minor, 0);
346 	return (DEVFSADM_CONTINUE);
347 }
348 
349 static int
350 ipmi(di_minor_t minor, di_node_t node)
351 {
352 	/*
353 	 * Follow convention from other systems, and include an instance#,
354 	 * even though there will only be one.
355 	 */
356 	(void) devfsadm_mklink("ipmi0", node, minor, 0);
357 	return (DEVFSADM_CONTINUE);
358 }
359 
360 static int
361 smbios(di_minor_t minor, di_node_t node)
362 {
363 	(void) devfsadm_mklink("smbios", node, minor, 0);
364 	return (DEVFSADM_CONTINUE);
365 }
366 
367 static int
368 agp_process(di_minor_t minor, di_node_t node)
369 {
370 	char *minor_nm, *drv_nm;
371 	char *devfspath;
372 	char *I_path, *p_path, *buf;
373 	char *name = (char *)NULL;
374 	int i, index;
375 	devfsadm_enumerate_t rules[1];
376 
377 	minor_nm = di_minor_name(minor);
378 	drv_nm = di_driver_name(node);
379 
380 	if ((minor_nm == NULL) || (drv_nm == NULL)) {
381 		return (DEVFSADM_CONTINUE);
382 	}
383 
384 	devfsadm_print(debug_mid, "agp_process: minor=%s node=%s\n",
385 	    minor_nm, di_node_name(node));
386 
387 	devfspath = di_devfs_path(node);
388 	if (devfspath == NULL) {
389 		devfsadm_print(debug_mid, "agp_process: devfspath is NULL\n");
390 		return (DEVFSADM_CONTINUE);
391 	}
392 
393 	I_path = (char *)malloc(PATH_MAX);
394 
395 	if (I_path == NULL) {
396 		di_devfs_path_free(devfspath);
397 		devfsadm_print(debug_mid,  "agp_process: malloc failed\n");
398 		return (DEVFSADM_CONTINUE);
399 	}
400 
401 	p_path = (char *)malloc(PATH_MAX);
402 
403 	if (p_path == NULL) {
404 		devfsadm_print(debug_mid,  "agp_process: malloc failed\n");
405 		di_devfs_path_free(devfspath);
406 		free(I_path);
407 		return (DEVFSADM_CONTINUE);
408 	}
409 
410 	(void) strlcpy(p_path, devfspath, PATH_MAX);
411 	(void) strlcat(p_path, ":", PATH_MAX);
412 	(void) strlcat(p_path, minor_nm, PATH_MAX);
413 	di_devfs_path_free(devfspath);
414 
415 	devfsadm_print(debug_mid, "agp_process: path %s\n", p_path);
416 
417 	for (i = 0; ; i++) {
418 		if ((driver_name_table[i].driver_name == NULL) ||
419 		    (strcmp(drv_nm, driver_name_table[i].driver_name) == 0)) {
420 			index = driver_name_table[i].index;
421 			break;
422 		}
423 	}
424 	switch (index) {
425 	case DRIVER_AGPPSEUDO:
426 		devfsadm_print(debug_mid,
427 		    "agp_process: psdeudo driver name\n");
428 		name = "agpgart";
429 		(void) snprintf(I_path, PATH_MAX, "%s", name);
430 		devfsadm_print(debug_mid,
431 		    "mklink %s -> %s\n", I_path, p_path);
432 
433 		(void) devfsadm_mklink(I_path, node, minor, 0);
434 
435 		free(I_path);
436 		free(p_path);
437 		return (DEVFSADM_CONTINUE);
438 	case DRIVER_AGPTARGET:
439 		devfsadm_print(debug_mid,
440 		    "agp_process: target driver name\n");
441 		rules[0] = agptarget_rules[0];
442 		name = "agptarget";
443 		break;
444 	case DRIVER_CPUGART:
445 		devfsadm_print(debug_mid,
446 		    "agp_process: cpugart driver name\n");
447 		rules[0] = cpugart_rules[0];
448 		name = "cpugart";
449 		break;
450 	case DRIVER_AGPMASTER_DRM_I915:
451 	case DRIVER_AGPMASTER_DRM_RADEON:
452 	case DRIVER_AGPMASTER_VGATEXT:
453 		devfsadm_print(debug_mid,
454 		    "agp_process: agpmaster driver name\n");
455 		rules[0] = agpmaster_rules[0];
456 		name = "agpmaster";
457 		break;
458 	case DRIVER_UNKNOWN:
459 		devfsadm_print(debug_mid,
460 		    "agp_process: unknown driver name=%s\n", drv_nm);
461 		free(I_path);
462 		free(p_path);
463 		return (DEVFSADM_CONTINUE);
464 	}
465 
466 	if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) {
467 		devfsadm_print(debug_mid, "agp_process: exit/coninue\n");
468 		free(I_path);
469 		free(p_path);
470 		return (DEVFSADM_CONTINUE);
471 	}
472 
473 
474 	(void) snprintf(I_path, PATH_MAX, "agp/%s%s", name, buf);
475 
476 	devfsadm_print(debug_mid, "agp_process: p_path=%s buf=%s\n",
477 	    p_path, buf);
478 
479 	free(buf);
480 
481 	devfsadm_print(debug_mid, "mklink %s -> %s\n", I_path, p_path);
482 
483 	(void) devfsadm_mklink(I_path, node, minor, 0);
484 
485 	free(p_path);
486 	free(I_path);
487 
488 	return (DEVFSADM_CONTINUE);
489 }
490 
491 static int
492 drm_node(di_minor_t minor, di_node_t node)
493 {
494 	char *minor_nm, *drv_nm;
495 	char *devfspath;
496 	char *I_path, *p_path, *buf;
497 	char *name = "card";
498 
499 	devfsadm_enumerate_t drm_rules[1] = {"^dri$/^card([0-9]+)$", 1,
500 		MATCH_ALL };
501 
502 
503 	minor_nm = di_minor_name(minor);
504 	drv_nm = di_driver_name(node);
505 	if ((minor_nm == NULL) || (drv_nm == NULL)) {
506 		return (DEVFSADM_CONTINUE);
507 	}
508 
509 	devfsadm_print(debug_mid, "drm_node: minor=%s node=%s type=%s\n",
510 	    minor_nm, di_node_name(node), di_minor_nodetype(minor));
511 
512 	devfspath = di_devfs_path(node);
513 	if (devfspath == NULL) {
514 		devfsadm_print(debug_mid, "drm_node: devfspath is NULL\n");
515 		return (DEVFSADM_CONTINUE);
516 	}
517 
518 	I_path = (char *)malloc(PATH_MAX);
519 
520 	if (I_path == NULL) {
521 		di_devfs_path_free(devfspath);
522 		devfsadm_print(debug_mid,  "drm_node: malloc failed\n");
523 		return (DEVFSADM_CONTINUE);
524 	}
525 
526 	p_path = (char *)malloc(PATH_MAX);
527 
528 	if (p_path == NULL) {
529 		devfsadm_print(debug_mid,  "drm_node: malloc failed\n");
530 		di_devfs_path_free(devfspath);
531 		free(I_path);
532 		return (DEVFSADM_CONTINUE);
533 	}
534 
535 	(void) strlcpy(p_path, devfspath, PATH_MAX);
536 	(void) strlcat(p_path, ":", PATH_MAX);
537 	(void) strlcat(p_path, minor_nm, PATH_MAX);
538 	di_devfs_path_free(devfspath);
539 
540 	devfsadm_print(debug_mid, "drm_node: p_path %s\n", p_path);
541 
542 	if (devfsadm_enumerate_int(p_path, 0, &buf, drm_rules, 1)) {
543 		free(p_path);
544 		devfsadm_print(debug_mid, "drm_node: exit/coninue\n");
545 		return (DEVFSADM_CONTINUE);
546 	}
547 	(void) snprintf(I_path, PATH_MAX, "dri/%s%s", name, buf);
548 
549 	devfsadm_print(debug_mid, "drm_node: p_path=%s buf=%s\n",
550 	    p_path, buf);
551 
552 	free(buf);
553 
554 	devfsadm_print(debug_mid, "mklink %s -> %s\n", I_path, p_path);
555 	(void) devfsadm_mklink(I_path, node, minor, 0);
556 
557 	free(p_path);
558 	free(I_path);
559 
560 	return (0);
561 }
562 
563 /*
564  * /dev/mc/mc<chipid> -> /devices/.../pci1022,1102@<chipid+24>,2:mc-amd
565  */
566 static int
567 mc_node(di_minor_t minor, di_node_t node)
568 {
569 	const char *minorname = di_minor_name(minor);
570 	const char *busaddr = di_bus_addr(node);
571 	char linkpath[PATH_MAX];
572 	int unitaddr;
573 	char *c;
574 
575 	if (minorname == NULL || busaddr == NULL)
576 		return (DEVFSADM_CONTINUE);
577 
578 	errno = 0;
579 	unitaddr = strtol(busaddr, &c, 16);
580 
581 	if (errno != 0)
582 		return (DEVFSADM_CONTINUE);
583 
584 	if (unitaddr == 0) {
585 		(void) snprintf(linkpath, sizeof (linkpath), "mc/mc");
586 	} else if (unitaddr >= MC_AMD_DEV_OFFSET) {
587 		(void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u",
588 		    unitaddr - MC_AMD_DEV_OFFSET);
589 	} else {
590 		(void) snprintf(linkpath, sizeof (linkpath), "mc/mc%u",
591 		    minor->dev_minor);
592 	}
593 	(void) devfsadm_mklink(linkpath, node, minor, 0);
594 	return (DEVFSADM_CONTINUE);
595 }
596 
597 /*
598  * Creates \M0 devlink for xsvc node
599  */
600 static int
601 xsvc(di_minor_t minor, di_node_t node)
602 {
603 	char *mn;
604 
605 	if (strcmp(di_node_name(node), "xsvc") != 0)
606 		return (DEVFSADM_CONTINUE);
607 
608 	mn = di_minor_name(minor);
609 	if (mn == NULL)
610 		return (DEVFSADM_CONTINUE);
611 
612 	(void) devfsadm_mklink(mn, node, minor, 0);
613 	return (DEVFSADM_CONTINUE);
614 }
615 
616 /*
617  * Creates \M0 devlink for srn device
618  */
619 static int
620 srn(di_minor_t minor, di_node_t node)
621 {
622 	char *mn;
623 
624 	if (strcmp(di_node_name(node), "srn") != 0)
625 		return (DEVFSADM_CONTINUE);
626 
627 	mn = di_minor_name(minor);
628 	if (mn == NULL)
629 		return (DEVFSADM_CONTINUE);
630 
631 	(void) devfsadm_mklink(mn, node, minor, 0);
632 	return (DEVFSADM_CONTINUE);
633 }
634 
635 /*
636  *	/dev/ucode	->	/devices/pseudo/ucode@0:ucode
637  */
638 static int
639 ucode(di_minor_t minor, di_node_t node)
640 {
641 	(void) devfsadm_mklink("ucode", node, minor, 0);
642 	return (DEVFSADM_CONTINUE);
643 }
644