xref: /titanic_44/usr/src/cmd/devfsadm/cfg_link.c (revision 3c4226f98775d47a05fa88f9f72479f1a250eaa5)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
566f9d5cbSmlf  * Common Development and Distribution License (the "License").
666f9d5cbSmlf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2166f9d5cbSmlf 
227c478bd9Sstevel@tonic-gate /*
23*3c4226f9Spjha  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <devfsadm.h>
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <strings.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*3c4226f9Spjha #include <stdarg.h>
347c478bd9Sstevel@tonic-gate #include <limits.h>
35*3c4226f9Spjha #include <unistd.h>
36*3c4226f9Spjha #include <config_admin.h>
37*3c4226f9Spjha #include <cfg_link.h>
38*3c4226f9Spjha #include <sys/types.h>
39*3c4226f9Spjha #include <sys/mkdev.h>
40*3c4226f9Spjha #include <sys/hotplug/pci/pcihp.h>
417c478bd9Sstevel@tonic-gate 
42*3c4226f9Spjha #ifdef	DEBUG
43*3c4226f9Spjha #define	dprint(args)	devfsadm_errprint args
44*3c4226f9Spjha /*
45*3c4226f9Spjha  * for use in print routine arg list as a shorthand way to locate node via
46*3c4226f9Spjha  * "prtconf -D" to avoid messy and cluttered debugging code
47*3c4226f9Spjha  * don't forget the corresponding "%s%d" format
48*3c4226f9Spjha  */
49*3c4226f9Spjha #define	DRVINST(node)	di_driver_name(node), di_instance(node)
50*3c4226f9Spjha #else
51*3c4226f9Spjha #define	dprint(args)
52*3c4226f9Spjha #endif
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate static int	scsi_cfg_creat_cb(di_minor_t minor, di_node_t node);
567c478bd9Sstevel@tonic-gate static int	sbd_cfg_creat_cb(di_minor_t minor, di_node_t node);
577c478bd9Sstevel@tonic-gate static int	usb_cfg_creat_cb(di_minor_t minor, di_node_t node);
587c478bd9Sstevel@tonic-gate static char	*get_roothub(const char *path, void *cb_arg);
597c478bd9Sstevel@tonic-gate static int	pci_cfg_creat_cb(di_minor_t minor, di_node_t node);
607c478bd9Sstevel@tonic-gate static int	ib_cfg_creat_cb(di_minor_t minor, di_node_t node);
6166f9d5cbSmlf static int	sata_cfg_creat_cb(di_minor_t minor, di_node_t node);
627c478bd9Sstevel@tonic-gate 
63*3c4226f9Spjha static di_node_t	pci_cfg_chassis_node(di_node_t, di_prom_handle_t);
64*3c4226f9Spjha static char 	*pci_cfg_slotname(di_node_t, di_prom_handle_t, minor_t);
65*3c4226f9Spjha static int	pci_cfg_ap_node(minor_t, di_node_t, di_prom_handle_t,
66*3c4226f9Spjha 		    char *, int, int);
67*3c4226f9Spjha static int	pci_cfg_iob_name(di_minor_t, di_node_t, di_prom_handle_t,
68*3c4226f9Spjha 		    char *, int);
69*3c4226f9Spjha static minor_t	pci_cfg_pcidev(di_node_t, di_prom_handle_t);
70*3c4226f9Spjha static int	pci_cfg_ap_path(di_minor_t, di_node_t, di_prom_handle_t,
71*3c4226f9Spjha 		    char *, int, char **);
72*3c4226f9Spjha static char 	*pci_cfg_info_data(char *);
73*3c4226f9Spjha static int	pci_cfg_is_ap_path(di_node_t, di_prom_handle_t);
74*3c4226f9Spjha static int	pci_cfg_ap_legacy(di_minor_t, di_node_t, di_prom_handle_t,
75*3c4226f9Spjha 		    char *, int);
76*3c4226f9Spjha static void	pci_cfg_rm_invalid_links(char *, char *);
77*3c4226f9Spjha static void	pci_cfg_rm_link(char *);
78*3c4226f9Spjha static void	pci_cfg_rm_all(char *);
79*3c4226f9Spjha static char	*pci_cfg_devpath(di_node_t, di_minor_t);
80*3c4226f9Spjha static di_node_t	pci_cfg_snapshot(di_node_t, di_minor_t,
81*3c4226f9Spjha 			    di_node_t *, di_minor_t *);
82*3c4226f9Spjha 
83*3c4226f9Spjha /* flag definitions for di_propall_*(); value "0" is always the default flag */
84*3c4226f9Spjha #define	DIPROP_PRI_NODE		0x0
85*3c4226f9Spjha #define	DIPROP_PRI_PROM		0x1
86*3c4226f9Spjha static int	di_propall_lookup_ints(di_prom_handle_t, int,
87*3c4226f9Spjha 		    dev_t, di_node_t, const char *, int **);
88*3c4226f9Spjha static int	di_propall_lookup_strings(di_prom_handle_t, int,
89*3c4226f9Spjha 		    dev_t, di_node_t, const char *, char **);
90*3c4226f9Spjha 
91*3c4226f9Spjha 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * NOTE: The CREATE_DEFER flag is private to this module.
947c478bd9Sstevel@tonic-gate  *	 NOT to be used by other modules
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate static devfsadm_create_t cfg_create_cbt[] = {
97*3c4226f9Spjha 	{ "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT, NULL,
987c478bd9Sstevel@tonic-gate 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
997c478bd9Sstevel@tonic-gate 	},
100*3c4226f9Spjha 	{ "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT, NULL,
1017c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb
1027c478bd9Sstevel@tonic-gate 	},
103*3c4226f9Spjha 	{ "fc-attachment-point", DDI_NT_FC_ATTACHMENT_POINT, NULL,
1047c478bd9Sstevel@tonic-gate 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
1057c478bd9Sstevel@tonic-gate 	},
106*3c4226f9Spjha 	{ "attachment-point", DDI_NT_USB_ATTACHMENT_POINT, NULL,
1077c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb
1087c478bd9Sstevel@tonic-gate 	},
109*3c4226f9Spjha 	{ "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT, NULL,
1107c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb
1117c478bd9Sstevel@tonic-gate 	},
112*3c4226f9Spjha 	{ "attachment-point", DDI_NT_IB_ATTACHMENT_POINT, NULL,
1137c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb
11466f9d5cbSmlf 	},
115*3c4226f9Spjha 	{ "attachment-point", DDI_NT_SATA_ATTACHMENT_POINT, NULL,
11666f9d5cbSmlf 	    TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb
1177c478bd9Sstevel@tonic-gate 	}
1187c478bd9Sstevel@tonic-gate };
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(cfg_create_cbt);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate static devfsadm_remove_t cfg_remove_cbt[] = {
1237c478bd9Sstevel@tonic-gate 	{ "attachment-point", SCSI_CFG_LINK_RE, RM_POST,
1247c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1257c478bd9Sstevel@tonic-gate 	},
1267c478bd9Sstevel@tonic-gate 	{ "attachment-point", SBD_CFG_LINK_RE, RM_POST,
1277c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1287c478bd9Sstevel@tonic-gate 	},
1297c478bd9Sstevel@tonic-gate 	{ "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST,
1307c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1317c478bd9Sstevel@tonic-gate 	},
1327c478bd9Sstevel@tonic-gate 	{ "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
1337c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1347c478bd9Sstevel@tonic-gate 	},
1357c478bd9Sstevel@tonic-gate 	{ "attachment-point", PCI_CFG_LINK_RE, RM_POST,
1367c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1377c478bd9Sstevel@tonic-gate 	},
138*3c4226f9Spjha 	{ "attachment-point", PCI_CFG_PATH_LINK_RE, RM_POST|RM_HOT,
139*3c4226f9Spjha 	    ILEVEL_0, pci_cfg_rm_all
140*3c4226f9Spjha 	},
1417c478bd9Sstevel@tonic-gate 	{ "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
1427c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
14366f9d5cbSmlf 	},
14466f9d5cbSmlf 	{ "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
14566f9d5cbSmlf 	    ILEVEL_0, devfsadm_rm_all
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate };
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate static int
1527c478bd9Sstevel@tonic-gate scsi_cfg_creat_cb(di_minor_t minor, di_node_t node)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	char path[PATH_MAX + 1];
1557c478bd9Sstevel@tonic-gate 	char *c_num = NULL, *devfs_path, *mn;
1567c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t rules[3] = {
1577c478bd9Sstevel@tonic-gate 	    {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT},
1587c478bd9Sstevel@tonic-gate 	    {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR},
1597c478bd9Sstevel@tonic-gate 	    {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT}
1607c478bd9Sstevel@tonic-gate 	};
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	mn = di_minor_name(minor);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if ((devfs_path = di_devfs_path(node)) == NULL) {
1657c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 	(void) strcpy(path, devfs_path);
1687c478bd9Sstevel@tonic-gate 	(void) strcat(path, ":");
1697c478bd9Sstevel@tonic-gate 	(void) strcat(path, mn);
1707c478bd9Sstevel@tonic-gate 	di_devfs_path_free(devfs_path);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3)
1737c478bd9Sstevel@tonic-gate 	    == DEVFSADM_FAILURE) {
1747c478bd9Sstevel@tonic-gate 		/*
1757c478bd9Sstevel@tonic-gate 		 * Unlike the disks module we don't retry on failure.
1767c478bd9Sstevel@tonic-gate 		 * If we have multiple "c" numbers for a single physical
1777c478bd9Sstevel@tonic-gate 		 * controller due to bug 4045879, we will not assign a
1787c478bd9Sstevel@tonic-gate 		 * c-number/symlink for the controller.
1797c478bd9Sstevel@tonic-gate 		 */
1807c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	(void) strcpy(path, CFG_DIRNAME);
1847c478bd9Sstevel@tonic-gate 	(void) strcat(path, "/c");
1857c478bd9Sstevel@tonic-gate 	(void) strcat(path, c_num);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	free(c_num);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate static int
1957c478bd9Sstevel@tonic-gate sbd_cfg_creat_cb(di_minor_t minor, di_node_t node)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	char path[PATH_MAX + 1];
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	(void) strcpy(path, CFG_DIRNAME);
2007c478bd9Sstevel@tonic-gate 	(void) strcat(path, "/");
2017c478bd9Sstevel@tonic-gate 	(void) strcat(path, di_minor_name(minor));
2027c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
2037c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate static int
2087c478bd9Sstevel@tonic-gate usb_cfg_creat_cb(di_minor_t minor, di_node_t node)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	char *cp, path[PATH_MAX + 1];
2117c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t rules[1] =
2127c478bd9Sstevel@tonic-gate 		{"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub};
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	if ((cp = di_devfs_path(node)) == NULL) {
2157c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
2197c478bd9Sstevel@tonic-gate 	di_devfs_path_free(cp);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) {
2227c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	/* create usbN and the symlink */
2267c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp,
2277c478bd9Sstevel@tonic-gate 	    di_minor_name(minor));
2287c478bd9Sstevel@tonic-gate 	free(cp);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 
23666f9d5cbSmlf static int
23766f9d5cbSmlf sata_cfg_creat_cb(di_minor_t minor, di_node_t node)
23866f9d5cbSmlf {
23966f9d5cbSmlf 	char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath;
24066f9d5cbSmlf 	char *minor_nm;
24166f9d5cbSmlf 	devfsadm_enumerate_t rules[1] =
24266f9d5cbSmlf 		{"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR};
24366f9d5cbSmlf 
24466f9d5cbSmlf 	minor_nm = di_minor_name(minor);
24566f9d5cbSmlf 	if (minor_nm == NULL)
24666f9d5cbSmlf 		return (DEVFSADM_CONTINUE);
24766f9d5cbSmlf 
24866f9d5cbSmlf 	devfspath = di_devfs_path(node);
24966f9d5cbSmlf 	if (devfspath == NULL)
25066f9d5cbSmlf 		return (DEVFSADM_CONTINUE);
25166f9d5cbSmlf 
25266f9d5cbSmlf 	(void) strlcpy(path, devfspath, sizeof (path));
25366f9d5cbSmlf 	(void) strlcat(path, ":", sizeof (path));
25466f9d5cbSmlf 	(void) strlcat(path, minor_nm, sizeof (path));
25566f9d5cbSmlf 	di_devfs_path_free(devfspath);
25666f9d5cbSmlf 
25766f9d5cbSmlf 	/* build the physical path from the components */
25866f9d5cbSmlf 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) ==
25966f9d5cbSmlf 	    DEVFSADM_FAILURE) {
26066f9d5cbSmlf 		return (DEVFSADM_CONTINUE);
26166f9d5cbSmlf 	}
26266f9d5cbSmlf 
26366f9d5cbSmlf 	(void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME,
26466f9d5cbSmlf 			buf, minor_nm);
26566f9d5cbSmlf 	free(buf);
26666f9d5cbSmlf 
26766f9d5cbSmlf 	(void) devfsadm_mklink(l_path, node, minor, 0);
26866f9d5cbSmlf 
26966f9d5cbSmlf 	return (DEVFSADM_CONTINUE);
27066f9d5cbSmlf }
27166f9d5cbSmlf 
27266f9d5cbSmlf 
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate  * get_roothub:
2757c478bd9Sstevel@tonic-gate  *	figure out the root hub path to calculate /dev/cfg/usbN
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate /* ARGSUSED */
2787c478bd9Sstevel@tonic-gate static char *
2797c478bd9Sstevel@tonic-gate get_roothub(const char *path, void *cb_arg)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	int  i, count = 0;
2827c478bd9Sstevel@tonic-gate 	char *physpath, *cp;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/* make a copy */
2857c478bd9Sstevel@tonic-gate 	if ((physpath = strdup(path)) == NULL) {
2867c478bd9Sstevel@tonic-gate 		return (NULL);
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	/*
2907c478bd9Sstevel@tonic-gate 	 * physpath must always have a minor name component
2917c478bd9Sstevel@tonic-gate 	 */
2927c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(physpath, ':')) == NULL) {
2937c478bd9Sstevel@tonic-gate 		free(physpath);
2947c478bd9Sstevel@tonic-gate 		return (NULL);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 	*cp++ = '\0';
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/*
2997c478bd9Sstevel@tonic-gate 	 * No '.' in the minor name indicates a roothub port.
3007c478bd9Sstevel@tonic-gate 	 */
3017c478bd9Sstevel@tonic-gate 	if (strchr(cp, '.') == NULL) {
3027c478bd9Sstevel@tonic-gate 		/* roothub device */
3037c478bd9Sstevel@tonic-gate 		return (physpath);
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	while (*cp) {
3077c478bd9Sstevel@tonic-gate 		if (*cp == '.')
3087c478bd9Sstevel@tonic-gate 			count++;
3097c478bd9Sstevel@tonic-gate 		cp++;
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	/* Remove as many trailing path components as there are '.'s */
3137c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
3147c478bd9Sstevel@tonic-gate 		if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) {
3157c478bd9Sstevel@tonic-gate 			free(physpath);
3167c478bd9Sstevel@tonic-gate 			return (NULL);
3177c478bd9Sstevel@tonic-gate 		}
3187c478bd9Sstevel@tonic-gate 		*cp = '\0';
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	return (physpath);
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate /*
326*3c4226f9Spjha  * returns an allocted string containing the device path for <node> and
327*3c4226f9Spjha  * <minor>
328*3c4226f9Spjha  */
329*3c4226f9Spjha static char *
330*3c4226f9Spjha pci_cfg_devpath(di_node_t node, di_minor_t minor)
331*3c4226f9Spjha {
332*3c4226f9Spjha 	char *path;
333*3c4226f9Spjha 	char *bufp;
334*3c4226f9Spjha 	char *minor_nm;
335*3c4226f9Spjha 	int buflen;
336*3c4226f9Spjha 
337*3c4226f9Spjha 	path = di_devfs_path(node);
338*3c4226f9Spjha 	minor_nm = di_minor_name(minor);
339*3c4226f9Spjha 	buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm);
340*3c4226f9Spjha 
341*3c4226f9Spjha 	bufp = malloc(sizeof (char) * buflen);
342*3c4226f9Spjha 	if (bufp == NULL)
343*3c4226f9Spjha 		goto OUT;
344*3c4226f9Spjha 	(void) snprintf(bufp, buflen, "%s:%s", path, minor_nm);
345*3c4226f9Spjha 
346*3c4226f9Spjha OUT:
347*3c4226f9Spjha 	di_devfs_path_free(path);
348*3c4226f9Spjha 	return (bufp);
349*3c4226f9Spjha }
350*3c4226f9Spjha 
351*3c4226f9Spjha 
352*3c4226f9Spjha static int
353*3c4226f9Spjha di_propall_lookup_ints(di_prom_handle_t ph, int flags,
354*3c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, int **prop_data)
355*3c4226f9Spjha {
356*3c4226f9Spjha 	int rv;
357*3c4226f9Spjha 
358*3c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
359*3c4226f9Spjha 		rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data);
360*3c4226f9Spjha 		if (rv < 0)
361*3c4226f9Spjha 			rv = di_prop_lookup_ints(dev, node, prop_name,
362*3c4226f9Spjha 			    prop_data);
363*3c4226f9Spjha 	} else {
364*3c4226f9Spjha 		rv = di_prop_lookup_ints(dev, node, prop_name, prop_data);
365*3c4226f9Spjha 		if (rv < 0)
366*3c4226f9Spjha 			rv = di_prom_prop_lookup_ints(ph, node, prop_name,
367*3c4226f9Spjha 			    prop_data);
368*3c4226f9Spjha 	}
369*3c4226f9Spjha 	return (rv);
370*3c4226f9Spjha }
371*3c4226f9Spjha 
372*3c4226f9Spjha 
373*3c4226f9Spjha static int
374*3c4226f9Spjha di_propall_lookup_strings(di_prom_handle_t ph, int flags,
375*3c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, char **prop_data)
376*3c4226f9Spjha {
377*3c4226f9Spjha 	int rv;
378*3c4226f9Spjha 
379*3c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
380*3c4226f9Spjha 		rv = di_prom_prop_lookup_strings(ph, node, prop_name,
381*3c4226f9Spjha 		    prop_data);
382*3c4226f9Spjha 		if (rv < 0)
383*3c4226f9Spjha 			rv = di_prop_lookup_strings(dev, node, prop_name,
384*3c4226f9Spjha 			    prop_data);
385*3c4226f9Spjha 	} else {
386*3c4226f9Spjha 		rv = di_prop_lookup_strings(dev, node, prop_name, prop_data);
387*3c4226f9Spjha 		if (rv < 0)
388*3c4226f9Spjha 			rv = di_prom_prop_lookup_strings(ph, node, prop_name,
389*3c4226f9Spjha 			    prop_data);
390*3c4226f9Spjha 	}
391*3c4226f9Spjha 	return (rv);
392*3c4226f9Spjha }
393*3c4226f9Spjha 
394*3c4226f9Spjha 
395*3c4226f9Spjha static di_node_t
396*3c4226f9Spjha pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph)
397*3c4226f9Spjha {
398*3c4226f9Spjha 	di_node_t curnode = node;
399*3c4226f9Spjha 	int *firstchas;
400*3c4226f9Spjha 
401*3c4226f9Spjha 	do {
402*3c4226f9Spjha 		if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode,
403*3c4226f9Spjha 		    PROP_FIRST_CHAS, &firstchas) >= 0)
404*3c4226f9Spjha 			return (curnode);
405*3c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
406*3c4226f9Spjha 
407*3c4226f9Spjha 	return (DI_NODE_NIL);
408*3c4226f9Spjha }
409*3c4226f9Spjha 
410*3c4226f9Spjha 
411*3c4226f9Spjha /*
412*3c4226f9Spjha  * yet another redundant common routine to:
413*3c4226f9Spjha  * decode the ieee1275 "slot-names" property and returns the string matching
414*3c4226f9Spjha  * the pci device number <pci_dev>, if any.
415*3c4226f9Spjha  *
416*3c4226f9Spjha  * callers must NOT free the returned string
417*3c4226f9Spjha  *
418*3c4226f9Spjha  * "slot-names" format: [int][string1][string2]...[stringN]
419*3c4226f9Spjha  *	- each bit position in [int] represent a pci device number
420*3c4226f9Spjha  *	- [string1]...[stringN] are concatenated null-terminated strings
421*3c4226f9Spjha  *	- the number of bits set in [int] == the number of strings that follow
422*3c4226f9Spjha  *	- each bit that is set corresponds to a string in the following segment
423*3c4226f9Spjha  */
424*3c4226f9Spjha static char *
425*3c4226f9Spjha pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev)
426*3c4226f9Spjha {
427*3c4226f9Spjha #ifdef	DEBUG
428*3c4226f9Spjha 	char *fnm = "pci_cfg_slotname";
429*3c4226f9Spjha #endif
430*3c4226f9Spjha 	int *snp;
431*3c4226f9Spjha 	int snlen;
432*3c4226f9Spjha 	int snentlen = sizeof (int);
433*3c4226f9Spjha 	int i, max, len, place, curplace;
434*3c4226f9Spjha 	char *str;
435*3c4226f9Spjha 
436*3c4226f9Spjha 	snlen = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node,
437*3c4226f9Spjha 	    PROP_SLOT_NAMES, &snp);
438*3c4226f9Spjha 	if (snlen < 1)
439*3c4226f9Spjha 		return (NULL);
440*3c4226f9Spjha 	if ((snp[0] & (1 << pci_dev)) == 0)
441*3c4226f9Spjha 		return (NULL);
442*3c4226f9Spjha 
443*3c4226f9Spjha 	/*
444*3c4226f9Spjha 	 * pci device number must be less than the amount of bits in the first
445*3c4226f9Spjha 	 * [int] component of slot-names
446*3c4226f9Spjha 	 */
447*3c4226f9Spjha 	if (pci_dev >= snentlen * 8) {
448*3c4226f9Spjha 		dprint(("%s: pci_dev out of range for %s%d\n",
449*3c4226f9Spjha 		    fnm, DRVINST(node)));
450*3c4226f9Spjha 		return (NULL);
451*3c4226f9Spjha 	}
452*3c4226f9Spjha 
453*3c4226f9Spjha 	place = 0;
454*3c4226f9Spjha 	for (i = 0; i < pci_dev; i++) {
455*3c4226f9Spjha 		if (snp[0] & (1 << i))
456*3c4226f9Spjha 			place++;
457*3c4226f9Spjha 	}
458*3c4226f9Spjha 
459*3c4226f9Spjha 	max = (snlen * snentlen) - snentlen;
460*3c4226f9Spjha 	str = (char *)&snp[1];
461*3c4226f9Spjha 	i = 0;
462*3c4226f9Spjha 	curplace = 0;
463*3c4226f9Spjha 	while (i < max && curplace < place) {
464*3c4226f9Spjha 		len = strlen(str);
465*3c4226f9Spjha 		if (len <= 0)
466*3c4226f9Spjha 			break;
467*3c4226f9Spjha 		str += len + 1;
468*3c4226f9Spjha 		i += len + 1;
469*3c4226f9Spjha 		curplace++;
470*3c4226f9Spjha 	}
471*3c4226f9Spjha 	/* the following condition indicates a badly formed slot-names */
472*3c4226f9Spjha 	if (i >= max || *str == '\0') {
473*3c4226f9Spjha 		dprint(("%s: badly formed slot-names for %s%d\n",
474*3c4226f9Spjha 		    fnm, DRVINST(node)));
475*3c4226f9Spjha 		str = NULL;
476*3c4226f9Spjha 	}
477*3c4226f9Spjha 	return (str);
478*3c4226f9Spjha }
479*3c4226f9Spjha 
480*3c4226f9Spjha 
481*3c4226f9Spjha /*
482*3c4226f9Spjha  * returns non-zero if we can return a valid attachment point name for <node>,
483*3c4226f9Spjha  * for its slot identified by child pci device number <pci_dev>, through <buf>
484*3c4226f9Spjha  *
485*3c4226f9Spjha  * prioritized naming scheme:
486*3c4226f9Spjha  *	1) <PROP_SLOT_NAMES property>    (see pci_cfg_slotname())
487*3c4226f9Spjha  *	2) <device-type><PROP_PHYS_SLOT property>
488*3c4226f9Spjha  *	3) <drv name><drv inst>.<device-type><pci_dev>
489*3c4226f9Spjha  *
490*3c4226f9Spjha  * where <device-type> is derived from the PROP_DEV_TYPE property:
491*3c4226f9Spjha  *	if its value is "pciex" then <device-type> is "pcie"
492*3c4226f9Spjha  *	else the raw value is used
493*3c4226f9Spjha  *
494*3c4226f9Spjha  * if <flags> contains APNODE_DEFNAME, then scheme (3) is used
4957c478bd9Sstevel@tonic-gate  */
4967c478bd9Sstevel@tonic-gate static int
497*3c4226f9Spjha pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph,
498*3c4226f9Spjha     char *buf, int bufsz, int flags)
4997c478bd9Sstevel@tonic-gate {
500*3c4226f9Spjha 	int *nump;
501*3c4226f9Spjha 	int rv;
502*3c4226f9Spjha 	char *str, *devtype;
503*3c4226f9Spjha 
504*3c4226f9Spjha 	rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node,
505*3c4226f9Spjha 	    PROP_DEV_TYPE, &devtype);
506*3c4226f9Spjha 	if (rv < 1)
507*3c4226f9Spjha 		return (0);
508*3c4226f9Spjha 
509*3c4226f9Spjha 	if (strcmp(devtype, PROPVAL_PCIEX) == 0)
510*3c4226f9Spjha 		devtype = DEVTYPE_PCIE;
511*3c4226f9Spjha 
512*3c4226f9Spjha 	if (flags & APNODE_DEFNAME)
513*3c4226f9Spjha 		goto DEF;
514*3c4226f9Spjha 
515*3c4226f9Spjha 	str = pci_cfg_slotname(node, ph, pci_dev);
516*3c4226f9Spjha 	if (str != NULL) {
517*3c4226f9Spjha 		(void) strlcpy(buf, str, bufsz);
518*3c4226f9Spjha 		return (1);
519*3c4226f9Spjha 	}
520*3c4226f9Spjha 
521*3c4226f9Spjha 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, PROP_PHYS_SLOT,
522*3c4226f9Spjha 	    &nump) > 0) {
523*3c4226f9Spjha 		if (*nump > 0) {
524*3c4226f9Spjha 			(void) snprintf(buf, bufsz, "%s%d", devtype, *nump);
525*3c4226f9Spjha 			return (1);
526*3c4226f9Spjha 		}
527*3c4226f9Spjha 	}
528*3c4226f9Spjha DEF:
529*3c4226f9Spjha 	(void) snprintf(buf, bufsz, "%s%d.%s%d",
530*3c4226f9Spjha 	    di_driver_name(node), di_instance(node), devtype, pci_dev);
531*3c4226f9Spjha 
532*3c4226f9Spjha 	return (1);
533*3c4226f9Spjha }
534*3c4226f9Spjha 
535*3c4226f9Spjha 
536*3c4226f9Spjha /*
537*3c4226f9Spjha  * returns non-zero if we can return a valid expansion chassis name for <node>
538*3c4226f9Spjha  * through <buf>
539*3c4226f9Spjha  *
540*3c4226f9Spjha  * prioritized naming scheme:
541*3c4226f9Spjha  *	1) <IOB_PRE string><PROP_SERID property: sun specific portion>
542*3c4226f9Spjha  *	2) <IOB_PRE string><full PROP_SERID property in hex>
543*3c4226f9Spjha  *	3) <IOB_PRE string>
544*3c4226f9Spjha  *
545*3c4226f9Spjha  * PROP_SERID encoding <64-bit int: msb ... lsb>:
546*3c4226f9Spjha  * <24 bits: vendor id><40 bits: serial number>
547*3c4226f9Spjha  *
548*3c4226f9Spjha  * sun encoding of 40 bit serial number:
549*3c4226f9Spjha  * first byte = device type indicator (ignored in naming scheme)
550*3c4226f9Spjha  * next 4 bytes = 4 ascii characters
551*3c4226f9Spjha  */
552*3c4226f9Spjha /*ARGSUSED*/
553*3c4226f9Spjha static int
554*3c4226f9Spjha pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
555*3c4226f9Spjha     char *buf, int bufsz)
556*3c4226f9Spjha {
557*3c4226f9Spjha 	int64_t *seridp;
558*3c4226f9Spjha 	int64_t serid;
559*3c4226f9Spjha 	char *idstr;
560*3c4226f9Spjha 
561*3c4226f9Spjha 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, PROP_SERID,
562*3c4226f9Spjha 	    &seridp) < 1) {
563*3c4226f9Spjha 		(void) strlcpy(buf, IOB_PRE, bufsz);
564*3c4226f9Spjha 		return (1);
565*3c4226f9Spjha 	}
566*3c4226f9Spjha 	serid = *seridp;
567*3c4226f9Spjha 
568*3c4226f9Spjha 	if (serid >> 40 != VENDID_SUN) {
569*3c4226f9Spjha 		(void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid);
570*3c4226f9Spjha 		return (1);
571*3c4226f9Spjha 	}
572*3c4226f9Spjha 
573*3c4226f9Spjha 	serid &= SIZE2MASK64(40);
574*3c4226f9Spjha 	idstr = (char *)&serid;
575*3c4226f9Spjha 	idstr[sizeof (serid) - 1] = '\0';
576*3c4226f9Spjha 	/* skip device type indicator */
577*3c4226f9Spjha 	idstr++;
578*3c4226f9Spjha 	(void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr);
579*3c4226f9Spjha 	return (1);
580*3c4226f9Spjha }
581*3c4226f9Spjha 
582*3c4226f9Spjha 
583*3c4226f9Spjha static minor_t
584*3c4226f9Spjha pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph)
585*3c4226f9Spjha {
586*3c4226f9Spjha 	int rv;
587*3c4226f9Spjha 	int *regp;
588*3c4226f9Spjha 
589*3c4226f9Spjha 	rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, PROP_REG,
590*3c4226f9Spjha 	    &regp);
591*3c4226f9Spjha 
592*3c4226f9Spjha 	if (rv < 1) {
593*3c4226f9Spjha 		dprint(("pci_cfg_pcidev: property %s not found "
594*3c4226f9Spjha 		    "for %s%d\n", PROP_REG, DRVINST(node)));
595*3c4226f9Spjha 		return (rv);
596*3c4226f9Spjha 	}
597*3c4226f9Spjha 
598*3c4226f9Spjha 	return (REG_PCIDEV(regp));
599*3c4226f9Spjha }
600*3c4226f9Spjha 
601*3c4226f9Spjha 
602*3c4226f9Spjha /*
603*3c4226f9Spjha  * returns non-zero when it can successfully return an attachment point
604*3c4226f9Spjha  * through <ap_path> whose length is less than <ap_pathsz>; returns the full
605*3c4226f9Spjha  * path of the AP through <pathret> which may be larger than <ap_pathsz>.
606*3c4226f9Spjha  * Callers need to free <pathret>.  If it cannot return the full path through
607*3c4226f9Spjha  * <pathret> it will be set to NULL
608*3c4226f9Spjha  *
609*3c4226f9Spjha  * The ap path reflects a subset of the device path from an onboard host slot
610*3c4226f9Spjha  * up to <node>.  We traverse up the device tree starting from <node>, naming
611*3c4226f9Spjha  * each component using pci_cfg_ap_node().  If we detect that a certain
612*3c4226f9Spjha  * segment is contained within an expansion chassis, then we skip any bus
613*3c4226f9Spjha  * nodes in between our current node and the topmost node of the chassis,
614*3c4226f9Spjha  * which is identified by the PROP_FIRST_CHAS property, and prepend the name
615*3c4226f9Spjha  * of the expansion chassis as given by pci_cfg_iob_name()
616*3c4226f9Spjha  *
617*3c4226f9Spjha  * This scheme is always used for <pathret>.  If however, the size of
618*3c4226f9Spjha  * <pathret> is greater than <ap_pathsz> then only the default name as given
619*3c4226f9Spjha  * by pci_cfg_ap_node() for <node> will be used
620*3c4226f9Spjha  */
621*3c4226f9Spjha static int
622*3c4226f9Spjha pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
623*3c4226f9Spjha     char *ap_path, int ap_pathsz, char **pathret)
624*3c4226f9Spjha {
625*3c4226f9Spjha #ifdef	DEBUG
626*3c4226f9Spjha 	char *fnm = "pci_cfg_ap_path";
627*3c4226f9Spjha #endif
628*3c4226f9Spjha #define	seplen		(sizeof (AP_PATH_SEP) - 1)
629*3c4226f9Spjha #define	iob_pre_len	(sizeof (IOB_PRE) - 1)
630*3c4226f9Spjha #define	ap_path_iob_sep_len	(sizeof (AP_PATH_IOB_SEP) - 1)
631*3c4226f9Spjha 
632*3c4226f9Spjha 	char *bufptr;
633*3c4226f9Spjha 	char buf[MAXPATHLEN];
634*3c4226f9Spjha 	char pathbuf[MAXPATHLEN];
635*3c4226f9Spjha 	int bufsz;
636*3c4226f9Spjha 	char *pathptr;
637*3c4226f9Spjha 	char *pathend = NULL;
638*3c4226f9Spjha 	int len;
639*3c4226f9Spjha 	int rv = 0;
640*3c4226f9Spjha 	int chasflag = 0;
641*3c4226f9Spjha 	di_node_t curnode = node;
642*3c4226f9Spjha 	di_node_t chasnode = DI_NODE_NIL;
6437c478bd9Sstevel@tonic-gate 	minor_t pci_dev;
6447c478bd9Sstevel@tonic-gate 
645*3c4226f9Spjha 	buf[0] = '\0';
646*3c4226f9Spjha 	pathbuf[0] = '\0';
647*3c4226f9Spjha 	pathptr = &pathbuf[sizeof (pathbuf) - 1];
648*3c4226f9Spjha 	*pathptr = '\0';
6497c478bd9Sstevel@tonic-gate 
650*3c4226f9Spjha 	/*
651*3c4226f9Spjha 	 * as we traverse up the device tree, we prepend components of our
652*3c4226f9Spjha 	 * path inside pathbuf, using pathptr and decrementing
653*3c4226f9Spjha 	 */
654*3c4226f9Spjha 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
655*3c4226f9Spjha 	do {
656*3c4226f9Spjha 		bufptr = buf;
657*3c4226f9Spjha 		bufsz = sizeof (buf);
658*3c4226f9Spjha 
659*3c4226f9Spjha 		chasnode = pci_cfg_chassis_node(curnode, ph);
660*3c4226f9Spjha 		if (chasnode != DI_NODE_NIL) {
661*3c4226f9Spjha 			rv = pci_cfg_iob_name(minor, chasnode, ph,
662*3c4226f9Spjha 			    bufptr, bufsz);
663*3c4226f9Spjha 			if (rv == 0) {
664*3c4226f9Spjha 				dprint(("%s: cannot create iob name "
665*3c4226f9Spjha 				    "for %s%d\n", fnm, DRVINST(node)));
666*3c4226f9Spjha 				*pathptr = '\0';
667*3c4226f9Spjha 				goto OUT;
668*3c4226f9Spjha 			}
669*3c4226f9Spjha 
670*3c4226f9Spjha 			(void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz);
671*3c4226f9Spjha 			len = strlen(bufptr);
672*3c4226f9Spjha 			bufptr += len;
673*3c4226f9Spjha 			bufsz -= len - 1;
674*3c4226f9Spjha 
675*3c4226f9Spjha 			/* set chasflag when the leaf node is within an iob */
676*3c4226f9Spjha 			if ((curnode == node) != NULL)
677*3c4226f9Spjha 				chasflag = 1;
678*3c4226f9Spjha 		}
679*3c4226f9Spjha 		rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0);
680*3c4226f9Spjha 		if (rv == 0) {
681*3c4226f9Spjha 			dprint(("%s: cannot create ap node name "
682*3c4226f9Spjha 			    "for %s%d\n", fnm, DRVINST(node)));
683*3c4226f9Spjha 			*pathptr = '\0';
684*3c4226f9Spjha 			goto OUT;
685*3c4226f9Spjha 		}
686*3c4226f9Spjha 
687*3c4226f9Spjha 		/*
688*3c4226f9Spjha 		 * if we can't fit the entire path in our pathbuf, then use
689*3c4226f9Spjha 		 * the default short name and nullify pathptr; also, since
690*3c4226f9Spjha 		 * we prepend in the buffer, we must avoid adding a null char
691*3c4226f9Spjha 		 */
692*3c4226f9Spjha 		if (curnode != node) {
693*3c4226f9Spjha 			pathptr -= seplen;
694*3c4226f9Spjha 			if (pathptr < pathbuf) {
695*3c4226f9Spjha 				pathptr = pathbuf;
696*3c4226f9Spjha 				*pathptr = '\0';
697*3c4226f9Spjha 				goto DEF;
698*3c4226f9Spjha 			}
699*3c4226f9Spjha 			(void) memcpy(pathptr, AP_PATH_SEP, seplen);
700*3c4226f9Spjha 		}
701*3c4226f9Spjha 		len = strlen(buf);
702*3c4226f9Spjha 		pathptr -= len;
703*3c4226f9Spjha 		if (pathptr < pathbuf) {
704*3c4226f9Spjha 			pathptr = pathbuf;
705*3c4226f9Spjha 			*pathptr = '\0';
706*3c4226f9Spjha 			goto DEF;
707*3c4226f9Spjha 		}
708*3c4226f9Spjha 		(void) memcpy(pathptr, buf, len);
709*3c4226f9Spjha 
710*3c4226f9Spjha 		/* remember the leaf component */
711*3c4226f9Spjha 		if (curnode == node)
712*3c4226f9Spjha 			pathend = pathptr;
713*3c4226f9Spjha 
714*3c4226f9Spjha 		/*
715*3c4226f9Spjha 		 * go no further than the hosts' onboard slots
716*3c4226f9Spjha 		 */
717*3c4226f9Spjha 		if (chasnode == DI_NODE_NIL)
718*3c4226f9Spjha 			break;
719*3c4226f9Spjha 		curnode = chasnode;
720*3c4226f9Spjha 
721*3c4226f9Spjha 		/*
722*3c4226f9Spjha 		 * the pci device number of the current node is used to
723*3c4226f9Spjha 		 * identify which slot of the parent's bus (next iteration)
724*3c4226f9Spjha 		 * the current node is on
725*3c4226f9Spjha 		 */
726*3c4226f9Spjha 		pci_dev = pci_cfg_pcidev(curnode, ph);
727*3c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
728*3c4226f9Spjha 
729*3c4226f9Spjha 	pathbuf[sizeof (pathbuf) - 1] = '\0';
730*3c4226f9Spjha 	if (strlen(pathptr) < ap_pathsz) {
731*3c4226f9Spjha 		(void) strlcpy(ap_path, pathptr, ap_pathsz);
732*3c4226f9Spjha 		rv = 1;
733*3c4226f9Spjha 		goto OUT;
734*3c4226f9Spjha 	}
735*3c4226f9Spjha 
736*3c4226f9Spjha DEF:
737*3c4226f9Spjha 	/*
738*3c4226f9Spjha 	 * when our name won't fit <ap_pathsz> we use the endpoint/leaf
739*3c4226f9Spjha 	 * <node>'s name ONLY IF it has a serialid# which will make the apid
740*3c4226f9Spjha 	 * globally unique
741*3c4226f9Spjha 	 */
742*3c4226f9Spjha 	if (chasflag && pathend != NULL) {
743*3c4226f9Spjha 		if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP,
744*3c4226f9Spjha 		    ap_path_iob_sep_len) != 0) &&
745*3c4226f9Spjha 		    (strlen(pathend) < ap_pathsz)) {
746*3c4226f9Spjha 			(void) strlcpy(ap_path, pathend, ap_pathsz);
747*3c4226f9Spjha 			rv = 1;
748*3c4226f9Spjha 			goto OUT;
7497c478bd9Sstevel@tonic-gate 		}
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
752*3c4226f9Spjha 	/*
753*3c4226f9Spjha 	 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s
754*3c4226f9Spjha 	 * default name
755*3c4226f9Spjha 	 */
756*3c4226f9Spjha 	rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME);
757*3c4226f9Spjha 	if (rv == 0) {
758*3c4226f9Spjha 		dprint(("%s: cannot create default ap node name for %s%d\n",
759*3c4226f9Spjha 		    fnm, DRVINST(node)));
760*3c4226f9Spjha 		*pathptr = '\0';
761*3c4226f9Spjha 		goto OUT;
762*3c4226f9Spjha 	}
763*3c4226f9Spjha 	if (strlen(buf) < ap_pathsz) {
764*3c4226f9Spjha 		(void) strlcpy(ap_path, buf, ap_pathsz);
765*3c4226f9Spjha 		rv = 1;
766*3c4226f9Spjha 		goto OUT;
767*3c4226f9Spjha 	}
768*3c4226f9Spjha 
769*3c4226f9Spjha 	/*
770*3c4226f9Spjha 	 * in this case, cfgadm goes through an expensive process to generate
771*3c4226f9Spjha 	 * a purely dynamic logical apid: the framework will look through
772*3c4226f9Spjha 	 * the device tree for attachment point minor nodes and will invoke
773*3c4226f9Spjha 	 * each plugin responsible for that attachment point class, and if
774*3c4226f9Spjha 	 * the plugin returns a logical apid that matches the queried apid
775*3c4226f9Spjha 	 * or matches the default apid generated by the cfgadm framework for
776*3c4226f9Spjha 	 * that driver/class (occurs when plugin returns an empty logical apid)
777*3c4226f9Spjha 	 * then that is what it will use
778*3c4226f9Spjha 	 *
779*3c4226f9Spjha 	 * it is doubly expensive because the cfgadm pci plugin itself will
780*3c4226f9Spjha 	 * also search the entire device tree in the absence of a link
781*3c4226f9Spjha 	 */
782*3c4226f9Spjha 	rv = 0;
783*3c4226f9Spjha 	dprint(("%s: cannot create apid for %s%d within length of %d\n",
784*3c4226f9Spjha 	    fnm, DRVINST(node), ap_pathsz));
785*3c4226f9Spjha 
786*3c4226f9Spjha OUT:
787*3c4226f9Spjha 	ap_path[ap_pathsz - 1] = '\0';
788*3c4226f9Spjha 	*pathret = (*pathptr == '\0') ? NULL : strdup(pathptr);
789*3c4226f9Spjha 	return (rv);
790*3c4226f9Spjha 
791*3c4226f9Spjha #undef	seplen
792*3c4226f9Spjha #undef	iob_pre_len
793*3c4226f9Spjha #undef	ap_path_iob_sep_len
794*3c4226f9Spjha }
795*3c4226f9Spjha 
796*3c4226f9Spjha 
797*3c4226f9Spjha /*
798*3c4226f9Spjha  * the PROP_AP_NAMES property contains the first integer section of the
799*3c4226f9Spjha  * ieee1275 "slot-names" property and functions as a bitmask; see comment for
800*3c4226f9Spjha  * pci_cfg_slotname()
801*3c4226f9Spjha  *
802*3c4226f9Spjha  * we use the name of the attachment point minor node if its pci device
803*3c4226f9Spjha  * number (encoded in the minor number) is allowed by PROP_AP_NAMES
804*3c4226f9Spjha  *
805*3c4226f9Spjha  * returns non-zero if we return a valid attachment point through <path>
806*3c4226f9Spjha  */
807*3c4226f9Spjha static int
808*3c4226f9Spjha pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
809*3c4226f9Spjha     char *ap_path, int ap_pathsz)
810*3c4226f9Spjha {
811*3c4226f9Spjha 	minor_t pci_dev;
812*3c4226f9Spjha 	int *anp;
813*3c4226f9Spjha 
814*3c4226f9Spjha 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, PROP_AP_NAMES,
815*3c4226f9Spjha 	    &anp) < 1)
816*3c4226f9Spjha 		return (0);
817*3c4226f9Spjha 
818*3c4226f9Spjha 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
819*3c4226f9Spjha 	if ((*anp & (1 << pci_dev)) == 0)
820*3c4226f9Spjha 		return (0);
821*3c4226f9Spjha 
822*3c4226f9Spjha 	(void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz);
823*3c4226f9Spjha 	return (1);
824*3c4226f9Spjha }
825*3c4226f9Spjha 
826*3c4226f9Spjha 
827*3c4226f9Spjha /*
828*3c4226f9Spjha  * determine if <node> qualifies for a path style apid
829*3c4226f9Spjha  */
830*3c4226f9Spjha static int
831*3c4226f9Spjha pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph)
832*3c4226f9Spjha {
833*3c4226f9Spjha 	char *devtype;
834*3c4226f9Spjha 	di_node_t curnode = node;
835*3c4226f9Spjha 
836*3c4226f9Spjha 	do {
837*3c4226f9Spjha 		if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode,
838*3c4226f9Spjha 		    PROP_DEV_TYPE, &devtype) > 0)
839*3c4226f9Spjha 			if (strcmp(devtype, PROPVAL_PCIEX) == 0)
840*3c4226f9Spjha 				return (1);
841*3c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
842*3c4226f9Spjha 
843*3c4226f9Spjha 	return (0);
844*3c4226f9Spjha }
845*3c4226f9Spjha 
846*3c4226f9Spjha 
847*3c4226f9Spjha /*
848*3c4226f9Spjha  * takes a full path as returned by <pathret> from pci_cfg_ap_path() and
849*3c4226f9Spjha  * returns an allocated string intendend to be stored in a devlink info (dli)
850*3c4226f9Spjha  * file
851*3c4226f9Spjha  *
852*3c4226f9Spjha  * data format: "Location: <transformed path>"
853*3c4226f9Spjha  * where <transformed path> is <path> with occurrances of AP_PATH_SEP
854*3c4226f9Spjha  * replaced by "/"
855*3c4226f9Spjha  */
856*3c4226f9Spjha static char *
857*3c4226f9Spjha pci_cfg_info_data(char *path)
858*3c4226f9Spjha {
859*3c4226f9Spjha #define	head	"Location: "
860*3c4226f9Spjha #define	headlen	(sizeof (head) - 1)
861*3c4226f9Spjha #define	seplen	(sizeof (AP_PATH_SEP) - 1)
862*3c4226f9Spjha 
863*3c4226f9Spjha 	char *sep, *prev, *np;
864*3c4226f9Spjha 	char *newpath;
865*3c4226f9Spjha 	int pathlen = strlen(path);
866*3c4226f9Spjha 	int len;
867*3c4226f9Spjha 
868*3c4226f9Spjha 	newpath = malloc(sizeof (char) * (headlen + pathlen + 1));
869*3c4226f9Spjha 	np = newpath;
870*3c4226f9Spjha 	(void) strcpy(np, head);
871*3c4226f9Spjha 	np += headlen;
872*3c4226f9Spjha 
873*3c4226f9Spjha 	prev = path;
874*3c4226f9Spjha 	while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) {
875*3c4226f9Spjha 		len = sep - prev;
876*3c4226f9Spjha 		(void) memcpy(np, prev, len);
877*3c4226f9Spjha 		np += len;
878*3c4226f9Spjha 		*np++ = '/';
879*3c4226f9Spjha 		prev = sep + seplen;
880*3c4226f9Spjha 	}
881*3c4226f9Spjha 	(void) strcpy(np, prev);
882*3c4226f9Spjha 	return (newpath);
883*3c4226f9Spjha 
884*3c4226f9Spjha #undef	head
885*3c4226f9Spjha #undef	headlen
886*3c4226f9Spjha #undef	seplen
887*3c4226f9Spjha }
888*3c4226f9Spjha 
889*3c4226f9Spjha 
890*3c4226f9Spjha static void
891*3c4226f9Spjha pci_cfg_rm_link(char *file)
892*3c4226f9Spjha {
893*3c4226f9Spjha 	char *dlipath;
894*3c4226f9Spjha 
895*3c4226f9Spjha 	dlipath = di_dli_name(file);
896*3c4226f9Spjha 	(void) unlink(dlipath);
897*3c4226f9Spjha 
898*3c4226f9Spjha 	devfsadm_rm_all(file);
899*3c4226f9Spjha 	free(dlipath);
900*3c4226f9Spjha }
901*3c4226f9Spjha 
902*3c4226f9Spjha /*
903*3c4226f9Spjha  * removes all registered devlinks to physical path <physpath> except for
904*3c4226f9Spjha  * the devlink <valid> if not NULL;
905*3c4226f9Spjha  * <physpath> must include the minor node
906*3c4226f9Spjha  */
907*3c4226f9Spjha static void
908*3c4226f9Spjha pci_cfg_rm_invalid_links(char *physpath, char *valid)
909*3c4226f9Spjha {
910*3c4226f9Spjha 	char **dnp;
911*3c4226f9Spjha 	char *cp, *vcp;
912*3c4226f9Spjha 	int i, dnlen;
913*3c4226f9Spjha 
914*3c4226f9Spjha 	dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen);
915*3c4226f9Spjha 	if (dnp == NULL)
916*3c4226f9Spjha 		return;
917*3c4226f9Spjha 
918*3c4226f9Spjha 	if (valid != NULL) {
919*3c4226f9Spjha 		if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0)
920*3c4226f9Spjha 			vcp = valid + DEV_LEN + 1;
921*3c4226f9Spjha 		else
922*3c4226f9Spjha 			vcp = valid;
923*3c4226f9Spjha 	}
924*3c4226f9Spjha 
925*3c4226f9Spjha 	for (i = 0; i < dnlen; i++) {
926*3c4226f9Spjha 		if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0)
927*3c4226f9Spjha 			cp = dnp[i] + DEV_LEN + 1;
928*3c4226f9Spjha 		else
929*3c4226f9Spjha 			cp = dnp[i];
930*3c4226f9Spjha 
931*3c4226f9Spjha 		if (valid != NULL) {
932*3c4226f9Spjha 			if (strcmp(vcp, cp) == 0)
933*3c4226f9Spjha 				continue;
934*3c4226f9Spjha 		}
935*3c4226f9Spjha 		pci_cfg_rm_link(cp);
936*3c4226f9Spjha 	}
937*3c4226f9Spjha 	devfsadm_free_dev_names(dnp, dnlen);
938*3c4226f9Spjha }
939*3c4226f9Spjha 
940*3c4226f9Spjha 
941*3c4226f9Spjha /*
942*3c4226f9Spjha  * takes a complete devinfo snapshot and returns the root node;
943*3c4226f9Spjha  * callers must do a di_fini() on the returned node;
944*3c4226f9Spjha  * if the snapshot failed, DI_NODE_NIL is returned instead
945*3c4226f9Spjha  *
946*3c4226f9Spjha  * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node
947*3c4226f9Spjha  * in the new snapshot and return it through <ret_node> if it is found,
948*3c4226f9Spjha  * else DI_NODE_NIL is returned instead
949*3c4226f9Spjha  *
950*3c4226f9Spjha  * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return
951*3c4226f9Spjha  * the matching minor in the new snapshot through <ret_minor> if it is found,
952*3c4226f9Spjha  * else DI_MINOR_NIL is returned instead
953*3c4226f9Spjha  */
954*3c4226f9Spjha static di_node_t
955*3c4226f9Spjha pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor,
956*3c4226f9Spjha     di_node_t *ret_node, di_minor_t *ret_minor)
957*3c4226f9Spjha {
958*3c4226f9Spjha 	di_node_t root_node;
959*3c4226f9Spjha 	di_node_t node;
960*3c4226f9Spjha 	di_minor_t minor;
961*3c4226f9Spjha 	int pci_inst;
962*3c4226f9Spjha 	dev_t pci_devt;
963*3c4226f9Spjha 
964*3c4226f9Spjha 	*ret_node = DI_NODE_NIL;
965*3c4226f9Spjha 	*ret_minor = DI_MINOR_NIL;
966*3c4226f9Spjha 
967*3c4226f9Spjha 	root_node = di_init("/", DINFOCPYALL);
968*3c4226f9Spjha 	if (root_node == DI_NODE_NIL)
969*3c4226f9Spjha 		return (DI_NODE_NIL);
970*3c4226f9Spjha 
971*3c4226f9Spjha 	/*
972*3c4226f9Spjha 	 * narrow down search by driver, then instance, then minor
973*3c4226f9Spjha 	 */
974*3c4226f9Spjha 	if (pci_node == DI_NODE_NIL)
975*3c4226f9Spjha 		return (root_node);
976*3c4226f9Spjha 
977*3c4226f9Spjha 	pci_inst = di_instance(pci_node);
978*3c4226f9Spjha 	node = di_drv_first_node(di_driver_name(pci_node), root_node);
979*3c4226f9Spjha 	do {
980*3c4226f9Spjha 		if (pci_inst == di_instance(node)) {
981*3c4226f9Spjha 			*ret_node = node;
982*3c4226f9Spjha 			break;
983*3c4226f9Spjha 		}
984*3c4226f9Spjha 	} while ((node = di_drv_next_node(node)) != DI_NODE_NIL);
985*3c4226f9Spjha 
986*3c4226f9Spjha 	if (node == DI_NODE_NIL)
987*3c4226f9Spjha 		return (root_node);
988*3c4226f9Spjha 
989*3c4226f9Spjha 	/*
990*3c4226f9Spjha 	 * found node, now search minors
991*3c4226f9Spjha 	 */
992*3c4226f9Spjha 	if (pci_minor == DI_MINOR_NIL)
993*3c4226f9Spjha 		return (root_node);
994*3c4226f9Spjha 
995*3c4226f9Spjha 	pci_devt = di_minor_devt(pci_minor);
996*3c4226f9Spjha 	minor = DI_MINOR_NIL;
997*3c4226f9Spjha 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
998*3c4226f9Spjha 		if (pci_devt == di_minor_devt(minor)) {
999*3c4226f9Spjha 			*ret_minor = minor;
1000*3c4226f9Spjha 			break;
1001*3c4226f9Spjha 		}
1002*3c4226f9Spjha 	}
1003*3c4226f9Spjha 	return (root_node);
1004*3c4226f9Spjha }
1005*3c4226f9Spjha 
1006*3c4226f9Spjha 
1007*3c4226f9Spjha static int
1008*3c4226f9Spjha pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node)
1009*3c4226f9Spjha {
1010*3c4226f9Spjha #ifdef	DEBUG
1011*3c4226f9Spjha 	char *fnm = "pci_cfg_creat_cb";
1012*3c4226f9Spjha #endif
1013*3c4226f9Spjha #define	ap_pathsz	(sizeof (ap_path))
1014*3c4226f9Spjha 
1015*3c4226f9Spjha 	char ap_path[CFGA_LOG_EXT_LEN];
1016*3c4226f9Spjha 	char linkbuf[MAXPATHLEN];
1017*3c4226f9Spjha 	char *fullpath = NULL;
1018*3c4226f9Spjha 	char *pathinfo = NULL;
1019*3c4226f9Spjha 	char *devpath = NULL;
1020*3c4226f9Spjha 	int rv, fd;
1021*3c4226f9Spjha 	size_t sz;
1022*3c4226f9Spjha 	di_prom_handle_t ph;
1023*3c4226f9Spjha 	di_node_t node;
1024*3c4226f9Spjha 	di_node_t root_node = DI_NODE_NIL;
1025*3c4226f9Spjha 	di_minor_t minor;
1026*3c4226f9Spjha 
1027*3c4226f9Spjha 	ph = di_prom_init();
1028*3c4226f9Spjha 	if (ph == DI_PROM_HANDLE_NIL) {
1029*3c4226f9Spjha 		dprint(("%s: di_prom_init() failed for %s%d\n",
1030*3c4226f9Spjha 		    fnm, DRVINST(pci_node)));
1031*3c4226f9Spjha 		goto OUT;
1032*3c4226f9Spjha 	}
1033*3c4226f9Spjha 
1034*3c4226f9Spjha 	/*
1035*3c4226f9Spjha 	 * Since incoming nodes from hotplug events are from snapshots that
1036*3c4226f9Spjha 	 * do NOT contain parent/ancestor data, we must retake our own
1037*3c4226f9Spjha 	 * snapshot and search for the target node
1038*3c4226f9Spjha 	 */
1039*3c4226f9Spjha 	root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor);
1040*3c4226f9Spjha 	if (root_node == DI_NODE_NIL || node == DI_NODE_NIL ||
1041*3c4226f9Spjha 	    minor == DI_MINOR_NIL) {
1042*3c4226f9Spjha 		dprint(("%s: devinfo snapshot or search failed for %s%d\n",
1043*3c4226f9Spjha 		    fnm, DRVINST(pci_node)));
1044*3c4226f9Spjha 		goto OUT;
1045*3c4226f9Spjha 	}
1046*3c4226f9Spjha 
1047*3c4226f9Spjha 	if (pci_cfg_is_ap_path(node, ph)) {
1048*3c4226f9Spjha 		rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz,
1049*3c4226f9Spjha 		    &fullpath);
1050*3c4226f9Spjha 		if (rv == 0)
1051*3c4226f9Spjha 			goto OUT;
1052*3c4226f9Spjha 
1053*3c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
1054*3c4226f9Spjha 		    CFG_DIRNAME, ap_path);
1055*3c4226f9Spjha 
1056*3c4226f9Spjha 		/*
1057*3c4226f9Spjha 		 * We must remove existing links because we may have invalid
1058*3c4226f9Spjha 		 * apids that are valid links.  Since these are not dangling,
1059*3c4226f9Spjha 		 * devfsadm will not invoke the remove callback on them.
1060*3c4226f9Spjha 		 *
1061*3c4226f9Spjha 		 * What are "invalid apids with valid links"?  Consider swapping
1062*3c4226f9Spjha 		 * an attachment point bus with another while the system is
1063*3c4226f9Spjha 		 * down, on the same device path bound to the same drivers
1064*3c4226f9Spjha 		 * but with the new AP bus having different properties
1065*3c4226f9Spjha 		 * (e.g. serialid#).  If the previous apid is not removed,
1066*3c4226f9Spjha 		 * there will now be two different links pointing to the same
1067*3c4226f9Spjha 		 * attachment point, but only one reflects the correct
1068*3c4226f9Spjha 		 * logical apid
1069*3c4226f9Spjha 		 */
1070*3c4226f9Spjha 		devpath = pci_cfg_devpath(node, minor);
1071*3c4226f9Spjha 		if (devpath == NULL)
1072*3c4226f9Spjha 			goto OUT;
1073*3c4226f9Spjha 		pci_cfg_rm_invalid_links(devpath, linkbuf);
1074*3c4226f9Spjha 		free(devpath);
1075*3c4226f9Spjha 
1076*3c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
1077*3c4226f9Spjha 
1078*3c4226f9Spjha 		/*
1079*3c4226f9Spjha 		 * we store the full logical path of the attachment point for
1080*3c4226f9Spjha 		 * cfgadm to display in its info field which is useful when
1081*3c4226f9Spjha 		 * the full logical path exceeds the size limit for logical
1082*3c4226f9Spjha 		 * apids (CFGA_LOG_EXT_LEN)
1083*3c4226f9Spjha 		 *
1084*3c4226f9Spjha 		 * for the cfgadm pci plugin to do the same would be expensive
1085*3c4226f9Spjha 		 * (i.e. devinfo snapshot + top down exhaustive minor search +
1086*3c4226f9Spjha 		 * equivalent of pci_cfg_ap_path() on every invocation)
1087*3c4226f9Spjha 		 *
1088*3c4226f9Spjha 		 * note that if we do not create a link (pci_cfg_ap_path() is
1089*3c4226f9Spjha 		 * not successful), that is what cfgadm will do anyways to
1090*3c4226f9Spjha 		 * create a purely dynamic apid
1091*3c4226f9Spjha 		 */
1092*3c4226f9Spjha 		pathinfo = pci_cfg_info_data(fullpath);
1093*3c4226f9Spjha 		fd = di_dli_openw(linkbuf);
1094*3c4226f9Spjha 		if (fd < 0)
1095*3c4226f9Spjha 			goto OUT;
1096*3c4226f9Spjha 
1097*3c4226f9Spjha 		sz = strlen(pathinfo) + 1;
1098*3c4226f9Spjha 		rv = write(fd, pathinfo, sz);
1099*3c4226f9Spjha 		if (rv < sz) {
1100*3c4226f9Spjha 			dprint(("%s: could not write full pathinfo to dli "
1101*3c4226f9Spjha 			    "file for %s%d\n", fnm, DRVINST(node)));
1102*3c4226f9Spjha 			goto OUT;
1103*3c4226f9Spjha 		}
1104*3c4226f9Spjha 		di_dli_close(fd);
1105*3c4226f9Spjha 	} else {
1106*3c4226f9Spjha 		rv = pci_cfg_ap_legacy(minor, node, ph, ap_path,
1107*3c4226f9Spjha 		    ap_pathsz);
1108*3c4226f9Spjha 		if (rv == 0)
1109*3c4226f9Spjha 			goto OUT;
1110*3c4226f9Spjha 
1111*3c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
1112*3c4226f9Spjha 		    CFG_DIRNAME, ap_path);
1113*3c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
1114*3c4226f9Spjha 	}
1115*3c4226f9Spjha 
1116*3c4226f9Spjha OUT:
1117*3c4226f9Spjha 	if (fullpath != NULL)
1118*3c4226f9Spjha 		free(fullpath);
1119*3c4226f9Spjha 	if (pathinfo != NULL)
1120*3c4226f9Spjha 		free(pathinfo);
1121*3c4226f9Spjha 	if (ph != DI_PROM_HANDLE_NIL)
1122*3c4226f9Spjha 		di_prom_fini(ph);
1123*3c4226f9Spjha 	if (root_node != DI_NODE_NIL)
1124*3c4226f9Spjha 		di_fini(root_node);
11257c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
1126*3c4226f9Spjha 
1127*3c4226f9Spjha #undef	ap_pathsz
1128*3c4226f9Spjha }
1129*3c4226f9Spjha 
1130*3c4226f9Spjha 
1131*3c4226f9Spjha static void
1132*3c4226f9Spjha pci_cfg_rm_all(char *file)
1133*3c4226f9Spjha {
1134*3c4226f9Spjha 	pci_cfg_rm_link(file);
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate /*
11397c478bd9Sstevel@tonic-gate  * ib_cfg_creat_cb() creates two types of links
11407c478bd9Sstevel@tonic-gate  * One for the fabric as /dev/cfg/ib
11417c478bd9Sstevel@tonic-gate  * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
11427c478bd9Sstevel@tonic-gate  */
11437c478bd9Sstevel@tonic-gate static int
11447c478bd9Sstevel@tonic-gate ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
11457c478bd9Sstevel@tonic-gate {
11467c478bd9Sstevel@tonic-gate 	char	*cp;
11477c478bd9Sstevel@tonic-gate 	char	path[PATH_MAX + 1];
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	if ((cp = di_devfs_path(node)) == NULL) {
11507c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
11547c478bd9Sstevel@tonic-gate 	di_devfs_path_free(cp);
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	/* create fabric or hca:GUID and the symlink */
11577c478bd9Sstevel@tonic-gate 	if (strstr(path, "ib:fabric") != NULL) {
11587c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
11597c478bd9Sstevel@tonic-gate 	} else {
11607c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
11617c478bd9Sstevel@tonic-gate 		    di_minor_name(minor));
11627c478bd9Sstevel@tonic-gate 	}
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
11657c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
11667c478bd9Sstevel@tonic-gate }
1167