xref: /titanic_50/usr/src/cmd/devfsadm/cfg_link.c (revision 4e0386dffa68d848cdca5a6308d652c20d6fc454)
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 /*
233c4226f9Spjha  * 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>
333c4226f9Spjha #include <stdarg.h>
347c478bd9Sstevel@tonic-gate #include <limits.h>
353c4226f9Spjha #include <unistd.h>
363c4226f9Spjha #include <config_admin.h>
373c4226f9Spjha #include <cfg_link.h>
383c4226f9Spjha #include <sys/types.h>
393c4226f9Spjha #include <sys/mkdev.h>
403c4226f9Spjha #include <sys/hotplug/pci/pcihp.h>
417c478bd9Sstevel@tonic-gate 
423c4226f9Spjha #ifdef	DEBUG
433c4226f9Spjha #define	dprint(args)	devfsadm_errprint args
443c4226f9Spjha /*
453c4226f9Spjha  * for use in print routine arg list as a shorthand way to locate node via
463c4226f9Spjha  * "prtconf -D" to avoid messy and cluttered debugging code
473c4226f9Spjha  * don't forget the corresponding "%s%d" format
483c4226f9Spjha  */
493c4226f9Spjha #define	DRVINST(node)	di_driver_name(node), di_instance(node)
503c4226f9Spjha #else
513c4226f9Spjha #define	dprint(args)
523c4226f9Spjha #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 
633c4226f9Spjha static di_node_t	pci_cfg_chassis_node(di_node_t, di_prom_handle_t);
643c4226f9Spjha static char 	*pci_cfg_slotname(di_node_t, di_prom_handle_t, minor_t);
653c4226f9Spjha static int	pci_cfg_ap_node(minor_t, di_node_t, di_prom_handle_t,
663c4226f9Spjha 		    char *, int, int);
673c4226f9Spjha static int	pci_cfg_iob_name(di_minor_t, di_node_t, di_prom_handle_t,
683c4226f9Spjha 		    char *, int);
693c4226f9Spjha static minor_t	pci_cfg_pcidev(di_node_t, di_prom_handle_t);
703c4226f9Spjha static int	pci_cfg_ap_path(di_minor_t, di_node_t, di_prom_handle_t,
713c4226f9Spjha 		    char *, int, char **);
723c4226f9Spjha static char 	*pci_cfg_info_data(char *);
733c4226f9Spjha static int	pci_cfg_is_ap_path(di_node_t, di_prom_handle_t);
743c4226f9Spjha static int	pci_cfg_ap_legacy(di_minor_t, di_node_t, di_prom_handle_t,
753c4226f9Spjha 		    char *, int);
763c4226f9Spjha static void	pci_cfg_rm_invalid_links(char *, char *);
773c4226f9Spjha static void	pci_cfg_rm_link(char *);
783c4226f9Spjha static void	pci_cfg_rm_all(char *);
793c4226f9Spjha static char	*pci_cfg_devpath(di_node_t, di_minor_t);
803c4226f9Spjha static di_node_t	pci_cfg_snapshot(di_node_t, di_minor_t,
813c4226f9Spjha 			    di_node_t *, di_minor_t *);
823c4226f9Spjha 
833c4226f9Spjha /* flag definitions for di_propall_*(); value "0" is always the default flag */
843c4226f9Spjha #define	DIPROP_PRI_NODE		0x0
853c4226f9Spjha #define	DIPROP_PRI_PROM		0x1
863c4226f9Spjha static int	di_propall_lookup_ints(di_prom_handle_t, int,
873c4226f9Spjha 		    dev_t, di_node_t, const char *, int **);
883c4226f9Spjha static int	di_propall_lookup_strings(di_prom_handle_t, int,
893c4226f9Spjha 		    dev_t, di_node_t, const char *, char **);
903c4226f9Spjha 
913c4226f9Spjha 
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[] = {
973c4226f9Spjha 	{ "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT, NULL,
987c478bd9Sstevel@tonic-gate 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
997c478bd9Sstevel@tonic-gate 	},
1003c4226f9Spjha 	{ "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT, NULL,
1017c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb
1027c478bd9Sstevel@tonic-gate 	},
1033c4226f9Spjha 	{ "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 	},
1063c4226f9Spjha 	{ "attachment-point", DDI_NT_USB_ATTACHMENT_POINT, NULL,
1077c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb
1087c478bd9Sstevel@tonic-gate 	},
1093c4226f9Spjha 	{ "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT, NULL,
1107c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb
1117c478bd9Sstevel@tonic-gate 	},
1123c4226f9Spjha 	{ "attachment-point", DDI_NT_IB_ATTACHMENT_POINT, NULL,
1137c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb
11466f9d5cbSmlf 	},
1153c4226f9Spjha 	{ "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 	},
1383c4226f9Spjha 	{ "attachment-point", PCI_CFG_PATH_LINK_RE, RM_POST|RM_HOT,
1393c4226f9Spjha 	    ILEVEL_0, pci_cfg_rm_all
1403c4226f9Spjha 	},
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 /*
3263c4226f9Spjha  * returns an allocted string containing the device path for <node> and
3273c4226f9Spjha  * <minor>
3283c4226f9Spjha  */
3293c4226f9Spjha static char *
3303c4226f9Spjha pci_cfg_devpath(di_node_t node, di_minor_t minor)
3313c4226f9Spjha {
3323c4226f9Spjha 	char *path;
3333c4226f9Spjha 	char *bufp;
3343c4226f9Spjha 	char *minor_nm;
3353c4226f9Spjha 	int buflen;
3363c4226f9Spjha 
3373c4226f9Spjha 	path = di_devfs_path(node);
3383c4226f9Spjha 	minor_nm = di_minor_name(minor);
339ad86e48dSpjha 	buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1;
3403c4226f9Spjha 
3413c4226f9Spjha 	bufp = malloc(sizeof (char) * buflen);
342ad86e48dSpjha 	if (bufp != NULL)
3433c4226f9Spjha 		(void) snprintf(bufp, buflen, "%s:%s", path, minor_nm);
3443c4226f9Spjha 
3453c4226f9Spjha 	di_devfs_path_free(path);
3463c4226f9Spjha 	return (bufp);
3473c4226f9Spjha }
3483c4226f9Spjha 
3493c4226f9Spjha 
3503c4226f9Spjha static int
3513c4226f9Spjha di_propall_lookup_ints(di_prom_handle_t ph, int flags,
3523c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, int **prop_data)
3533c4226f9Spjha {
3543c4226f9Spjha 	int rv;
3553c4226f9Spjha 
3563c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
3573c4226f9Spjha 		rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data);
3583c4226f9Spjha 		if (rv < 0)
3593c4226f9Spjha 			rv = di_prop_lookup_ints(dev, node, prop_name,
3603c4226f9Spjha 			    prop_data);
3613c4226f9Spjha 	} else {
3623c4226f9Spjha 		rv = di_prop_lookup_ints(dev, node, prop_name, prop_data);
3633c4226f9Spjha 		if (rv < 0)
3643c4226f9Spjha 			rv = di_prom_prop_lookup_ints(ph, node, prop_name,
3653c4226f9Spjha 			    prop_data);
3663c4226f9Spjha 	}
3673c4226f9Spjha 	return (rv);
3683c4226f9Spjha }
3693c4226f9Spjha 
3703c4226f9Spjha 
3713c4226f9Spjha static int
3723c4226f9Spjha di_propall_lookup_strings(di_prom_handle_t ph, int flags,
3733c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, char **prop_data)
3743c4226f9Spjha {
3753c4226f9Spjha 	int rv;
3763c4226f9Spjha 
3773c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
3783c4226f9Spjha 		rv = di_prom_prop_lookup_strings(ph, node, prop_name,
3793c4226f9Spjha 		    prop_data);
3803c4226f9Spjha 		if (rv < 0)
3813c4226f9Spjha 			rv = di_prop_lookup_strings(dev, node, prop_name,
3823c4226f9Spjha 			    prop_data);
3833c4226f9Spjha 	} else {
3843c4226f9Spjha 		rv = di_prop_lookup_strings(dev, node, prop_name, prop_data);
3853c4226f9Spjha 		if (rv < 0)
3863c4226f9Spjha 			rv = di_prom_prop_lookup_strings(ph, node, prop_name,
3873c4226f9Spjha 			    prop_data);
3883c4226f9Spjha 	}
3893c4226f9Spjha 	return (rv);
3903c4226f9Spjha }
3913c4226f9Spjha 
3923c4226f9Spjha 
3933c4226f9Spjha static di_node_t
3943c4226f9Spjha pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph)
3953c4226f9Spjha {
3963c4226f9Spjha 	di_node_t curnode = node;
3973c4226f9Spjha 	int *firstchas;
3983c4226f9Spjha 
3993c4226f9Spjha 	do {
4003c4226f9Spjha 		if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode,
4013c4226f9Spjha 		    PROP_FIRST_CHAS, &firstchas) >= 0)
4023c4226f9Spjha 			return (curnode);
4033c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
4043c4226f9Spjha 
4053c4226f9Spjha 	return (DI_NODE_NIL);
4063c4226f9Spjha }
4073c4226f9Spjha 
4083c4226f9Spjha 
4093c4226f9Spjha /*
4103c4226f9Spjha  * yet another redundant common routine to:
4113c4226f9Spjha  * decode the ieee1275 "slot-names" property and returns the string matching
4123c4226f9Spjha  * the pci device number <pci_dev>, if any.
4133c4226f9Spjha  *
4143c4226f9Spjha  * callers must NOT free the returned string
4153c4226f9Spjha  *
4163c4226f9Spjha  * "slot-names" format: [int][string1][string2]...[stringN]
4173c4226f9Spjha  *	- each bit position in [int] represent a pci device number
4183c4226f9Spjha  *	- [string1]...[stringN] are concatenated null-terminated strings
4193c4226f9Spjha  *	- the number of bits set in [int] == the number of strings that follow
4203c4226f9Spjha  *	- each bit that is set corresponds to a string in the following segment
4213c4226f9Spjha  */
4223c4226f9Spjha static char *
4233c4226f9Spjha pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev)
4243c4226f9Spjha {
4253c4226f9Spjha #ifdef	DEBUG
4263c4226f9Spjha 	char *fnm = "pci_cfg_slotname";
4273c4226f9Spjha #endif
4283c4226f9Spjha 	int *snp;
4293c4226f9Spjha 	int snlen;
4303c4226f9Spjha 	int snentlen = sizeof (int);
4313c4226f9Spjha 	int i, max, len, place, curplace;
4323c4226f9Spjha 	char *str;
4333c4226f9Spjha 
4343c4226f9Spjha 	snlen = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node,
4353c4226f9Spjha 	    PROP_SLOT_NAMES, &snp);
4363c4226f9Spjha 	if (snlen < 1)
4373c4226f9Spjha 		return (NULL);
4383c4226f9Spjha 	if ((snp[0] & (1 << pci_dev)) == 0)
4393c4226f9Spjha 		return (NULL);
4403c4226f9Spjha 
4413c4226f9Spjha 	/*
4423c4226f9Spjha 	 * pci device number must be less than the amount of bits in the first
4433c4226f9Spjha 	 * [int] component of slot-names
4443c4226f9Spjha 	 */
4453c4226f9Spjha 	if (pci_dev >= snentlen * 8) {
4463c4226f9Spjha 		dprint(("%s: pci_dev out of range for %s%d\n",
4473c4226f9Spjha 		    fnm, DRVINST(node)));
4483c4226f9Spjha 		return (NULL);
4493c4226f9Spjha 	}
4503c4226f9Spjha 
4513c4226f9Spjha 	place = 0;
4523c4226f9Spjha 	for (i = 0; i < pci_dev; i++) {
4533c4226f9Spjha 		if (snp[0] & (1 << i))
4543c4226f9Spjha 			place++;
4553c4226f9Spjha 	}
4563c4226f9Spjha 
4573c4226f9Spjha 	max = (snlen * snentlen) - snentlen;
4583c4226f9Spjha 	str = (char *)&snp[1];
4593c4226f9Spjha 	i = 0;
4603c4226f9Spjha 	curplace = 0;
4613c4226f9Spjha 	while (i < max && curplace < place) {
4623c4226f9Spjha 		len = strlen(str);
4633c4226f9Spjha 		if (len <= 0)
4643c4226f9Spjha 			break;
4653c4226f9Spjha 		str += len + 1;
4663c4226f9Spjha 		i += len + 1;
4673c4226f9Spjha 		curplace++;
4683c4226f9Spjha 	}
4693c4226f9Spjha 	/* the following condition indicates a badly formed slot-names */
4703c4226f9Spjha 	if (i >= max || *str == '\0') {
4713c4226f9Spjha 		dprint(("%s: badly formed slot-names for %s%d\n",
4723c4226f9Spjha 		    fnm, DRVINST(node)));
4733c4226f9Spjha 		str = NULL;
4743c4226f9Spjha 	}
4753c4226f9Spjha 	return (str);
4763c4226f9Spjha }
4773c4226f9Spjha 
4783c4226f9Spjha 
4793c4226f9Spjha /*
4803c4226f9Spjha  * returns non-zero if we can return a valid attachment point name for <node>,
4813c4226f9Spjha  * for its slot identified by child pci device number <pci_dev>, through <buf>
4823c4226f9Spjha  *
4833c4226f9Spjha  * prioritized naming scheme:
4843c4226f9Spjha  *	1) <PROP_SLOT_NAMES property>    (see pci_cfg_slotname())
4853c4226f9Spjha  *	2) <device-type><PROP_PHYS_SLOT property>
4863c4226f9Spjha  *	3) <drv name><drv inst>.<device-type><pci_dev>
4873c4226f9Spjha  *
4883c4226f9Spjha  * where <device-type> is derived from the PROP_DEV_TYPE property:
4893c4226f9Spjha  *	if its value is "pciex" then <device-type> is "pcie"
4903c4226f9Spjha  *	else the raw value is used
4913c4226f9Spjha  *
4923c4226f9Spjha  * if <flags> contains APNODE_DEFNAME, then scheme (3) is used
4937c478bd9Sstevel@tonic-gate  */
4947c478bd9Sstevel@tonic-gate static int
4953c4226f9Spjha pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph,
4963c4226f9Spjha     char *buf, int bufsz, int flags)
4977c478bd9Sstevel@tonic-gate {
4983c4226f9Spjha 	int *nump;
4993c4226f9Spjha 	int rv;
5003c4226f9Spjha 	char *str, *devtype;
5013c4226f9Spjha 
5023c4226f9Spjha 	rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node,
5033c4226f9Spjha 	    PROP_DEV_TYPE, &devtype);
5043c4226f9Spjha 	if (rv < 1)
5053c4226f9Spjha 		return (0);
5063c4226f9Spjha 
5073c4226f9Spjha 	if (strcmp(devtype, PROPVAL_PCIEX) == 0)
5083c4226f9Spjha 		devtype = DEVTYPE_PCIE;
5093c4226f9Spjha 
5103c4226f9Spjha 	if (flags & APNODE_DEFNAME)
5113c4226f9Spjha 		goto DEF;
5123c4226f9Spjha 
5133c4226f9Spjha 	str = pci_cfg_slotname(node, ph, pci_dev);
5143c4226f9Spjha 	if (str != NULL) {
5153c4226f9Spjha 		(void) strlcpy(buf, str, bufsz);
5163c4226f9Spjha 		return (1);
5173c4226f9Spjha 	}
5183c4226f9Spjha 
5193c4226f9Spjha 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, PROP_PHYS_SLOT,
5203c4226f9Spjha 	    &nump) > 0) {
5213c4226f9Spjha 		if (*nump > 0) {
5223c4226f9Spjha 			(void) snprintf(buf, bufsz, "%s%d", devtype, *nump);
5233c4226f9Spjha 			return (1);
5243c4226f9Spjha 		}
5253c4226f9Spjha 	}
5263c4226f9Spjha DEF:
5273c4226f9Spjha 	(void) snprintf(buf, bufsz, "%s%d.%s%d",
5283c4226f9Spjha 	    di_driver_name(node), di_instance(node), devtype, pci_dev);
5293c4226f9Spjha 
5303c4226f9Spjha 	return (1);
5313c4226f9Spjha }
5323c4226f9Spjha 
5333c4226f9Spjha 
5343c4226f9Spjha /*
5353c4226f9Spjha  * returns non-zero if we can return a valid expansion chassis name for <node>
5363c4226f9Spjha  * through <buf>
5373c4226f9Spjha  *
5383c4226f9Spjha  * prioritized naming scheme:
5393c4226f9Spjha  *	1) <IOB_PRE string><PROP_SERID property: sun specific portion>
5403c4226f9Spjha  *	2) <IOB_PRE string><full PROP_SERID property in hex>
5413c4226f9Spjha  *	3) <IOB_PRE string>
5423c4226f9Spjha  *
5433c4226f9Spjha  * PROP_SERID encoding <64-bit int: msb ... lsb>:
5443c4226f9Spjha  * <24 bits: vendor id><40 bits: serial number>
5453c4226f9Spjha  *
5463c4226f9Spjha  * sun encoding of 40 bit serial number:
5473c4226f9Spjha  * first byte = device type indicator (ignored in naming scheme)
5483c4226f9Spjha  * next 4 bytes = 4 ascii characters
5493c4226f9Spjha  */
5503c4226f9Spjha /*ARGSUSED*/
5513c4226f9Spjha static int
5523c4226f9Spjha pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
5533c4226f9Spjha     char *buf, int bufsz)
5543c4226f9Spjha {
5553c4226f9Spjha 	int64_t *seridp;
5563c4226f9Spjha 	int64_t serid;
5573c4226f9Spjha 	char *idstr;
5583c4226f9Spjha 
5593c4226f9Spjha 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, PROP_SERID,
5603c4226f9Spjha 	    &seridp) < 1) {
5613c4226f9Spjha 		(void) strlcpy(buf, IOB_PRE, bufsz);
5623c4226f9Spjha 		return (1);
5633c4226f9Spjha 	}
5643c4226f9Spjha 	serid = *seridp;
5653c4226f9Spjha 
5663c4226f9Spjha 	if (serid >> 40 != VENDID_SUN) {
5673c4226f9Spjha 		(void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid);
5683c4226f9Spjha 		return (1);
5693c4226f9Spjha 	}
5703c4226f9Spjha 
5713c4226f9Spjha 	serid &= SIZE2MASK64(40);
5723c4226f9Spjha 	idstr = (char *)&serid;
5733c4226f9Spjha 	idstr[sizeof (serid) - 1] = '\0';
5743c4226f9Spjha 	/* skip device type indicator */
5753c4226f9Spjha 	idstr++;
5763c4226f9Spjha 	(void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr);
5773c4226f9Spjha 	return (1);
5783c4226f9Spjha }
5793c4226f9Spjha 
5803c4226f9Spjha 
581ad86e48dSpjha /*
582ad86e48dSpjha  * returns the pci device number for <node> if found, else returns PCIDEV_NIL
583ad86e48dSpjha  */
5843c4226f9Spjha static minor_t
5853c4226f9Spjha pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph)
5863c4226f9Spjha {
5873c4226f9Spjha 	int rv;
5883c4226f9Spjha 	int *regp;
5893c4226f9Spjha 
5903c4226f9Spjha 	rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, PROP_REG,
5913c4226f9Spjha 	    &regp);
5923c4226f9Spjha 
5933c4226f9Spjha 	if (rv < 1) {
5943c4226f9Spjha 		dprint(("pci_cfg_pcidev: property %s not found "
5953c4226f9Spjha 		    "for %s%d\n", PROP_REG, DRVINST(node)));
596*4e0386dfSjveta 		return (PCIDEV_NIL);
5973c4226f9Spjha 	}
5983c4226f9Spjha 
5993c4226f9Spjha 	return (REG_PCIDEV(regp));
6003c4226f9Spjha }
6013c4226f9Spjha 
6023c4226f9Spjha 
6033c4226f9Spjha /*
6043c4226f9Spjha  * returns non-zero when it can successfully return an attachment point
6053c4226f9Spjha  * through <ap_path> whose length is less than <ap_pathsz>; returns the full
6063c4226f9Spjha  * path of the AP through <pathret> which may be larger than <ap_pathsz>.
6073c4226f9Spjha  * Callers need to free <pathret>.  If it cannot return the full path through
6083c4226f9Spjha  * <pathret> it will be set to NULL
6093c4226f9Spjha  *
6103c4226f9Spjha  * The ap path reflects a subset of the device path from an onboard host slot
6113c4226f9Spjha  * up to <node>.  We traverse up the device tree starting from <node>, naming
6123c4226f9Spjha  * each component using pci_cfg_ap_node().  If we detect that a certain
6133c4226f9Spjha  * segment is contained within an expansion chassis, then we skip any bus
6143c4226f9Spjha  * nodes in between our current node and the topmost node of the chassis,
6153c4226f9Spjha  * which is identified by the PROP_FIRST_CHAS property, and prepend the name
6163c4226f9Spjha  * of the expansion chassis as given by pci_cfg_iob_name()
6173c4226f9Spjha  *
6183c4226f9Spjha  * This scheme is always used for <pathret>.  If however, the size of
6193c4226f9Spjha  * <pathret> is greater than <ap_pathsz> then only the default name as given
6203c4226f9Spjha  * by pci_cfg_ap_node() for <node> will be used
6213c4226f9Spjha  */
6223c4226f9Spjha static int
6233c4226f9Spjha pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
6243c4226f9Spjha     char *ap_path, int ap_pathsz, char **pathret)
6253c4226f9Spjha {
6263c4226f9Spjha #ifdef	DEBUG
6273c4226f9Spjha 	char *fnm = "pci_cfg_ap_path";
6283c4226f9Spjha #endif
6293c4226f9Spjha #define	seplen		(sizeof (AP_PATH_SEP) - 1)
6303c4226f9Spjha #define	iob_pre_len	(sizeof (IOB_PRE) - 1)
6313c4226f9Spjha #define	ap_path_iob_sep_len	(sizeof (AP_PATH_IOB_SEP) - 1)
6323c4226f9Spjha 
6333c4226f9Spjha 	char *bufptr;
6343c4226f9Spjha 	char buf[MAXPATHLEN];
6353c4226f9Spjha 	char pathbuf[MAXPATHLEN];
6363c4226f9Spjha 	int bufsz;
6373c4226f9Spjha 	char *pathptr;
6383c4226f9Spjha 	char *pathend = NULL;
6393c4226f9Spjha 	int len;
6403c4226f9Spjha 	int rv = 0;
6413c4226f9Spjha 	int chasflag = 0;
6423c4226f9Spjha 	di_node_t curnode = node;
6433c4226f9Spjha 	di_node_t chasnode = DI_NODE_NIL;
6447c478bd9Sstevel@tonic-gate 	minor_t pci_dev;
6457c478bd9Sstevel@tonic-gate 
6463c4226f9Spjha 	buf[0] = '\0';
6473c4226f9Spjha 	pathbuf[0] = '\0';
6483c4226f9Spjha 	pathptr = &pathbuf[sizeof (pathbuf) - 1];
6493c4226f9Spjha 	*pathptr = '\0';
6507c478bd9Sstevel@tonic-gate 
6513c4226f9Spjha 	/*
6523c4226f9Spjha 	 * as we traverse up the device tree, we prepend components of our
6533c4226f9Spjha 	 * path inside pathbuf, using pathptr and decrementing
6543c4226f9Spjha 	 */
6553c4226f9Spjha 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
6563c4226f9Spjha 	do {
6573c4226f9Spjha 		bufptr = buf;
6583c4226f9Spjha 		bufsz = sizeof (buf);
6593c4226f9Spjha 
6603c4226f9Spjha 		chasnode = pci_cfg_chassis_node(curnode, ph);
6613c4226f9Spjha 		if (chasnode != DI_NODE_NIL) {
6623c4226f9Spjha 			rv = pci_cfg_iob_name(minor, chasnode, ph,
6633c4226f9Spjha 			    bufptr, bufsz);
6643c4226f9Spjha 			if (rv == 0) {
6653c4226f9Spjha 				dprint(("%s: cannot create iob name "
6663c4226f9Spjha 				    "for %s%d\n", fnm, DRVINST(node)));
6673c4226f9Spjha 				*pathptr = '\0';
6683c4226f9Spjha 				goto OUT;
6693c4226f9Spjha 			}
6703c4226f9Spjha 
6713c4226f9Spjha 			(void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz);
6723c4226f9Spjha 			len = strlen(bufptr);
6733c4226f9Spjha 			bufptr += len;
6743c4226f9Spjha 			bufsz -= len - 1;
6753c4226f9Spjha 
6763c4226f9Spjha 			/* set chasflag when the leaf node is within an iob */
6773c4226f9Spjha 			if ((curnode == node) != NULL)
6783c4226f9Spjha 				chasflag = 1;
6793c4226f9Spjha 		}
6803c4226f9Spjha 		rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0);
6813c4226f9Spjha 		if (rv == 0) {
6823c4226f9Spjha 			dprint(("%s: cannot create ap node name "
6833c4226f9Spjha 			    "for %s%d\n", fnm, DRVINST(node)));
6843c4226f9Spjha 			*pathptr = '\0';
6853c4226f9Spjha 			goto OUT;
6863c4226f9Spjha 		}
6873c4226f9Spjha 
6883c4226f9Spjha 		/*
6893c4226f9Spjha 		 * if we can't fit the entire path in our pathbuf, then use
6903c4226f9Spjha 		 * the default short name and nullify pathptr; also, since
6913c4226f9Spjha 		 * we prepend in the buffer, we must avoid adding a null char
6923c4226f9Spjha 		 */
6933c4226f9Spjha 		if (curnode != node) {
6943c4226f9Spjha 			pathptr -= seplen;
6953c4226f9Spjha 			if (pathptr < pathbuf) {
6963c4226f9Spjha 				pathptr = pathbuf;
6973c4226f9Spjha 				*pathptr = '\0';
6983c4226f9Spjha 				goto DEF;
6993c4226f9Spjha 			}
7003c4226f9Spjha 			(void) memcpy(pathptr, AP_PATH_SEP, seplen);
7013c4226f9Spjha 		}
7023c4226f9Spjha 		len = strlen(buf);
7033c4226f9Spjha 		pathptr -= len;
7043c4226f9Spjha 		if (pathptr < pathbuf) {
7053c4226f9Spjha 			pathptr = pathbuf;
7063c4226f9Spjha 			*pathptr = '\0';
7073c4226f9Spjha 			goto DEF;
7083c4226f9Spjha 		}
7093c4226f9Spjha 		(void) memcpy(pathptr, buf, len);
7103c4226f9Spjha 
7113c4226f9Spjha 		/* remember the leaf component */
7123c4226f9Spjha 		if (curnode == node)
7133c4226f9Spjha 			pathend = pathptr;
7143c4226f9Spjha 
7153c4226f9Spjha 		/*
7163c4226f9Spjha 		 * go no further than the hosts' onboard slots
7173c4226f9Spjha 		 */
7183c4226f9Spjha 		if (chasnode == DI_NODE_NIL)
7193c4226f9Spjha 			break;
7203c4226f9Spjha 		curnode = chasnode;
7213c4226f9Spjha 
7223c4226f9Spjha 		/*
7233c4226f9Spjha 		 * the pci device number of the current node is used to
7243c4226f9Spjha 		 * identify which slot of the parent's bus (next iteration)
7253c4226f9Spjha 		 * the current node is on
7263c4226f9Spjha 		 */
7273c4226f9Spjha 		pci_dev = pci_cfg_pcidev(curnode, ph);
728ad86e48dSpjha 		if (pci_dev == PCIDEV_NIL) {
729ad86e48dSpjha 			dprint(("%s: cannot obtain pci device number "
730ad86e48dSpjha 			    "for %s%d\n", fnm, DRVINST(node)));
731ad86e48dSpjha 			*pathptr = '\0';
732ad86e48dSpjha 			goto OUT;
733ad86e48dSpjha 		}
7343c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
7353c4226f9Spjha 
7363c4226f9Spjha 	pathbuf[sizeof (pathbuf) - 1] = '\0';
7373c4226f9Spjha 	if (strlen(pathptr) < ap_pathsz) {
7383c4226f9Spjha 		(void) strlcpy(ap_path, pathptr, ap_pathsz);
7393c4226f9Spjha 		rv = 1;
7403c4226f9Spjha 		goto OUT;
7413c4226f9Spjha 	}
7423c4226f9Spjha 
7433c4226f9Spjha DEF:
7443c4226f9Spjha 	/*
7453c4226f9Spjha 	 * when our name won't fit <ap_pathsz> we use the endpoint/leaf
7463c4226f9Spjha 	 * <node>'s name ONLY IF it has a serialid# which will make the apid
7473c4226f9Spjha 	 * globally unique
7483c4226f9Spjha 	 */
7493c4226f9Spjha 	if (chasflag && pathend != NULL) {
7503c4226f9Spjha 		if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP,
7513c4226f9Spjha 		    ap_path_iob_sep_len) != 0) &&
7523c4226f9Spjha 		    (strlen(pathend) < ap_pathsz)) {
7533c4226f9Spjha 			(void) strlcpy(ap_path, pathend, ap_pathsz);
7543c4226f9Spjha 			rv = 1;
7553c4226f9Spjha 			goto OUT;
7567c478bd9Sstevel@tonic-gate 		}
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7593c4226f9Spjha 	/*
7603c4226f9Spjha 	 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s
7613c4226f9Spjha 	 * default name
7623c4226f9Spjha 	 */
7633c4226f9Spjha 	rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME);
7643c4226f9Spjha 	if (rv == 0) {
7653c4226f9Spjha 		dprint(("%s: cannot create default ap node name for %s%d\n",
7663c4226f9Spjha 		    fnm, DRVINST(node)));
7673c4226f9Spjha 		*pathptr = '\0';
7683c4226f9Spjha 		goto OUT;
7693c4226f9Spjha 	}
7703c4226f9Spjha 	if (strlen(buf) < ap_pathsz) {
7713c4226f9Spjha 		(void) strlcpy(ap_path, buf, ap_pathsz);
7723c4226f9Spjha 		rv = 1;
7733c4226f9Spjha 		goto OUT;
7743c4226f9Spjha 	}
7753c4226f9Spjha 
7763c4226f9Spjha 	/*
7773c4226f9Spjha 	 * in this case, cfgadm goes through an expensive process to generate
7783c4226f9Spjha 	 * a purely dynamic logical apid: the framework will look through
7793c4226f9Spjha 	 * the device tree for attachment point minor nodes and will invoke
7803c4226f9Spjha 	 * each plugin responsible for that attachment point class, and if
7813c4226f9Spjha 	 * the plugin returns a logical apid that matches the queried apid
7823c4226f9Spjha 	 * or matches the default apid generated by the cfgadm framework for
7833c4226f9Spjha 	 * that driver/class (occurs when plugin returns an empty logical apid)
7843c4226f9Spjha 	 * then that is what it will use
7853c4226f9Spjha 	 *
7863c4226f9Spjha 	 * it is doubly expensive because the cfgadm pci plugin itself will
7873c4226f9Spjha 	 * also search the entire device tree in the absence of a link
7883c4226f9Spjha 	 */
7893c4226f9Spjha 	rv = 0;
7903c4226f9Spjha 	dprint(("%s: cannot create apid for %s%d within length of %d\n",
7913c4226f9Spjha 	    fnm, DRVINST(node), ap_pathsz));
7923c4226f9Spjha 
7933c4226f9Spjha OUT:
7943c4226f9Spjha 	ap_path[ap_pathsz - 1] = '\0';
7953c4226f9Spjha 	*pathret = (*pathptr == '\0') ? NULL : strdup(pathptr);
7963c4226f9Spjha 	return (rv);
7973c4226f9Spjha 
7983c4226f9Spjha #undef	seplen
7993c4226f9Spjha #undef	iob_pre_len
8003c4226f9Spjha #undef	ap_path_iob_sep_len
8013c4226f9Spjha }
8023c4226f9Spjha 
8033c4226f9Spjha 
8043c4226f9Spjha /*
8053c4226f9Spjha  * the PROP_AP_NAMES property contains the first integer section of the
8063c4226f9Spjha  * ieee1275 "slot-names" property and functions as a bitmask; see comment for
8073c4226f9Spjha  * pci_cfg_slotname()
8083c4226f9Spjha  *
8093c4226f9Spjha  * we use the name of the attachment point minor node if its pci device
8103c4226f9Spjha  * number (encoded in the minor number) is allowed by PROP_AP_NAMES
8113c4226f9Spjha  *
8123c4226f9Spjha  * returns non-zero if we return a valid attachment point through <path>
8133c4226f9Spjha  */
8143c4226f9Spjha static int
8153c4226f9Spjha pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
8163c4226f9Spjha     char *ap_path, int ap_pathsz)
8173c4226f9Spjha {
8183c4226f9Spjha 	minor_t pci_dev;
8193c4226f9Spjha 	int *anp;
8203c4226f9Spjha 
8213c4226f9Spjha 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, PROP_AP_NAMES,
8223c4226f9Spjha 	    &anp) < 1)
8233c4226f9Spjha 		return (0);
8243c4226f9Spjha 
8253c4226f9Spjha 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
8263c4226f9Spjha 	if ((*anp & (1 << pci_dev)) == 0)
8273c4226f9Spjha 		return (0);
8283c4226f9Spjha 
8293c4226f9Spjha 	(void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz);
8303c4226f9Spjha 	return (1);
8313c4226f9Spjha }
8323c4226f9Spjha 
8333c4226f9Spjha 
8343c4226f9Spjha /*
8353c4226f9Spjha  * determine if <node> qualifies for a path style apid
8363c4226f9Spjha  */
8373c4226f9Spjha static int
8383c4226f9Spjha pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph)
8393c4226f9Spjha {
8403c4226f9Spjha 	char *devtype;
8413c4226f9Spjha 	di_node_t curnode = node;
8423c4226f9Spjha 
8433c4226f9Spjha 	do {
8443c4226f9Spjha 		if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode,
8453c4226f9Spjha 		    PROP_DEV_TYPE, &devtype) > 0)
8463c4226f9Spjha 			if (strcmp(devtype, PROPVAL_PCIEX) == 0)
8473c4226f9Spjha 				return (1);
8483c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
8493c4226f9Spjha 
8503c4226f9Spjha 	return (0);
8513c4226f9Spjha }
8523c4226f9Spjha 
8533c4226f9Spjha 
8543c4226f9Spjha /*
8553c4226f9Spjha  * takes a full path as returned by <pathret> from pci_cfg_ap_path() and
8563c4226f9Spjha  * returns an allocated string intendend to be stored in a devlink info (dli)
8573c4226f9Spjha  * file
8583c4226f9Spjha  *
8593c4226f9Spjha  * data format: "Location: <transformed path>"
8603c4226f9Spjha  * where <transformed path> is <path> with occurrances of AP_PATH_SEP
8613c4226f9Spjha  * replaced by "/"
8623c4226f9Spjha  */
8633c4226f9Spjha static char *
8643c4226f9Spjha pci_cfg_info_data(char *path)
8653c4226f9Spjha {
8663c4226f9Spjha #define	head	"Location: "
8673c4226f9Spjha #define	headlen	(sizeof (head) - 1)
8683c4226f9Spjha #define	seplen	(sizeof (AP_PATH_SEP) - 1)
8693c4226f9Spjha 
8703c4226f9Spjha 	char *sep, *prev, *np;
8713c4226f9Spjha 	char *newpath;
8723c4226f9Spjha 	int pathlen = strlen(path);
8733c4226f9Spjha 	int len;
8743c4226f9Spjha 
8753c4226f9Spjha 	newpath = malloc(sizeof (char) * (headlen + pathlen + 1));
8763c4226f9Spjha 	np = newpath;
8773c4226f9Spjha 	(void) strcpy(np, head);
8783c4226f9Spjha 	np += headlen;
8793c4226f9Spjha 
8803c4226f9Spjha 	prev = path;
8813c4226f9Spjha 	while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) {
8823c4226f9Spjha 		len = sep - prev;
8833c4226f9Spjha 		(void) memcpy(np, prev, len);
8843c4226f9Spjha 		np += len;
8853c4226f9Spjha 		*np++ = '/';
8863c4226f9Spjha 		prev = sep + seplen;
8873c4226f9Spjha 	}
8883c4226f9Spjha 	(void) strcpy(np, prev);
8893c4226f9Spjha 	return (newpath);
8903c4226f9Spjha 
8913c4226f9Spjha #undef	head
8923c4226f9Spjha #undef	headlen
8933c4226f9Spjha #undef	seplen
8943c4226f9Spjha }
8953c4226f9Spjha 
8963c4226f9Spjha 
8973c4226f9Spjha static void
8983c4226f9Spjha pci_cfg_rm_link(char *file)
8993c4226f9Spjha {
9003c4226f9Spjha 	char *dlipath;
9013c4226f9Spjha 
9023c4226f9Spjha 	dlipath = di_dli_name(file);
9033c4226f9Spjha 	(void) unlink(dlipath);
9043c4226f9Spjha 
9053c4226f9Spjha 	devfsadm_rm_all(file);
9063c4226f9Spjha 	free(dlipath);
9073c4226f9Spjha }
9083c4226f9Spjha 
9093c4226f9Spjha /*
9103c4226f9Spjha  * removes all registered devlinks to physical path <physpath> except for
9113c4226f9Spjha  * the devlink <valid> if not NULL;
9123c4226f9Spjha  * <physpath> must include the minor node
9133c4226f9Spjha  */
9143c4226f9Spjha static void
9153c4226f9Spjha pci_cfg_rm_invalid_links(char *physpath, char *valid)
9163c4226f9Spjha {
9173c4226f9Spjha 	char **dnp;
9183c4226f9Spjha 	char *cp, *vcp;
9193c4226f9Spjha 	int i, dnlen;
9203c4226f9Spjha 
9213c4226f9Spjha 	dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen);
9223c4226f9Spjha 	if (dnp == NULL)
9233c4226f9Spjha 		return;
9243c4226f9Spjha 
9253c4226f9Spjha 	if (valid != NULL) {
9263c4226f9Spjha 		if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0)
9273c4226f9Spjha 			vcp = valid + DEV_LEN + 1;
9283c4226f9Spjha 		else
9293c4226f9Spjha 			vcp = valid;
9303c4226f9Spjha 	}
9313c4226f9Spjha 
9323c4226f9Spjha 	for (i = 0; i < dnlen; i++) {
9333c4226f9Spjha 		if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0)
9343c4226f9Spjha 			cp = dnp[i] + DEV_LEN + 1;
9353c4226f9Spjha 		else
9363c4226f9Spjha 			cp = dnp[i];
9373c4226f9Spjha 
9383c4226f9Spjha 		if (valid != NULL) {
9393c4226f9Spjha 			if (strcmp(vcp, cp) == 0)
9403c4226f9Spjha 				continue;
9413c4226f9Spjha 		}
9423c4226f9Spjha 		pci_cfg_rm_link(cp);
9433c4226f9Spjha 	}
9443c4226f9Spjha 	devfsadm_free_dev_names(dnp, dnlen);
9453c4226f9Spjha }
9463c4226f9Spjha 
9473c4226f9Spjha 
9483c4226f9Spjha /*
9493c4226f9Spjha  * takes a complete devinfo snapshot and returns the root node;
9503c4226f9Spjha  * callers must do a di_fini() on the returned node;
9513c4226f9Spjha  * if the snapshot failed, DI_NODE_NIL is returned instead
9523c4226f9Spjha  *
9533c4226f9Spjha  * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node
9543c4226f9Spjha  * in the new snapshot and return it through <ret_node> if it is found,
9553c4226f9Spjha  * else DI_NODE_NIL is returned instead
9563c4226f9Spjha  *
9573c4226f9Spjha  * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return
9583c4226f9Spjha  * the matching minor in the new snapshot through <ret_minor> if it is found,
9593c4226f9Spjha  * else DI_MINOR_NIL is returned instead
9603c4226f9Spjha  */
9613c4226f9Spjha static di_node_t
9623c4226f9Spjha pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor,
9633c4226f9Spjha     di_node_t *ret_node, di_minor_t *ret_minor)
9643c4226f9Spjha {
9653c4226f9Spjha 	di_node_t root_node;
9663c4226f9Spjha 	di_node_t node;
9673c4226f9Spjha 	di_minor_t minor;
9683c4226f9Spjha 	int pci_inst;
9693c4226f9Spjha 	dev_t pci_devt;
9703c4226f9Spjha 
9713c4226f9Spjha 	*ret_node = DI_NODE_NIL;
9723c4226f9Spjha 	*ret_minor = DI_MINOR_NIL;
9733c4226f9Spjha 
9743c4226f9Spjha 	root_node = di_init("/", DINFOCPYALL);
9753c4226f9Spjha 	if (root_node == DI_NODE_NIL)
9763c4226f9Spjha 		return (DI_NODE_NIL);
9773c4226f9Spjha 
9783c4226f9Spjha 	/*
9793c4226f9Spjha 	 * narrow down search by driver, then instance, then minor
9803c4226f9Spjha 	 */
9813c4226f9Spjha 	if (pci_node == DI_NODE_NIL)
9823c4226f9Spjha 		return (root_node);
9833c4226f9Spjha 
9843c4226f9Spjha 	pci_inst = di_instance(pci_node);
9853c4226f9Spjha 	node = di_drv_first_node(di_driver_name(pci_node), root_node);
9863c4226f9Spjha 	do {
9873c4226f9Spjha 		if (pci_inst == di_instance(node)) {
9883c4226f9Spjha 			*ret_node = node;
9893c4226f9Spjha 			break;
9903c4226f9Spjha 		}
9913c4226f9Spjha 	} while ((node = di_drv_next_node(node)) != DI_NODE_NIL);
9923c4226f9Spjha 
9933c4226f9Spjha 	if (node == DI_NODE_NIL)
9943c4226f9Spjha 		return (root_node);
9953c4226f9Spjha 
9963c4226f9Spjha 	/*
9973c4226f9Spjha 	 * found node, now search minors
9983c4226f9Spjha 	 */
9993c4226f9Spjha 	if (pci_minor == DI_MINOR_NIL)
10003c4226f9Spjha 		return (root_node);
10013c4226f9Spjha 
10023c4226f9Spjha 	pci_devt = di_minor_devt(pci_minor);
10033c4226f9Spjha 	minor = DI_MINOR_NIL;
10043c4226f9Spjha 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
10053c4226f9Spjha 		if (pci_devt == di_minor_devt(minor)) {
10063c4226f9Spjha 			*ret_minor = minor;
10073c4226f9Spjha 			break;
10083c4226f9Spjha 		}
10093c4226f9Spjha 	}
10103c4226f9Spjha 	return (root_node);
10113c4226f9Spjha }
10123c4226f9Spjha 
10133c4226f9Spjha 
10143c4226f9Spjha static int
10153c4226f9Spjha pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node)
10163c4226f9Spjha {
10173c4226f9Spjha #ifdef	DEBUG
10183c4226f9Spjha 	char *fnm = "pci_cfg_creat_cb";
10193c4226f9Spjha #endif
10203c4226f9Spjha #define	ap_pathsz	(sizeof (ap_path))
10213c4226f9Spjha 
10223c4226f9Spjha 	char ap_path[CFGA_LOG_EXT_LEN];
10233c4226f9Spjha 	char linkbuf[MAXPATHLEN];
10243c4226f9Spjha 	char *fullpath = NULL;
10253c4226f9Spjha 	char *pathinfo = NULL;
10263c4226f9Spjha 	char *devpath = NULL;
1027ad86e48dSpjha 	int rv, fd = -1;
10283c4226f9Spjha 	size_t sz;
10293c4226f9Spjha 	di_prom_handle_t ph;
10303c4226f9Spjha 	di_node_t node;
10313c4226f9Spjha 	di_node_t root_node = DI_NODE_NIL;
10323c4226f9Spjha 	di_minor_t minor;
10333c4226f9Spjha 
10343c4226f9Spjha 	ph = di_prom_init();
10353c4226f9Spjha 	if (ph == DI_PROM_HANDLE_NIL) {
10363c4226f9Spjha 		dprint(("%s: di_prom_init() failed for %s%d\n",
10373c4226f9Spjha 		    fnm, DRVINST(pci_node)));
10383c4226f9Spjha 		goto OUT;
10393c4226f9Spjha 	}
10403c4226f9Spjha 
10413c4226f9Spjha 	/*
10423c4226f9Spjha 	 * Since incoming nodes from hotplug events are from snapshots that
10433c4226f9Spjha 	 * do NOT contain parent/ancestor data, we must retake our own
10443c4226f9Spjha 	 * snapshot and search for the target node
10453c4226f9Spjha 	 */
10463c4226f9Spjha 	root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor);
10473c4226f9Spjha 	if (root_node == DI_NODE_NIL || node == DI_NODE_NIL ||
10483c4226f9Spjha 	    minor == DI_MINOR_NIL) {
10493c4226f9Spjha 		dprint(("%s: devinfo snapshot or search failed for %s%d\n",
10503c4226f9Spjha 		    fnm, DRVINST(pci_node)));
10513c4226f9Spjha 		goto OUT;
10523c4226f9Spjha 	}
10533c4226f9Spjha 
10543c4226f9Spjha 	if (pci_cfg_is_ap_path(node, ph)) {
10553c4226f9Spjha 		rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz,
10563c4226f9Spjha 		    &fullpath);
10573c4226f9Spjha 		if (rv == 0)
10583c4226f9Spjha 			goto OUT;
10593c4226f9Spjha 
10603c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
10613c4226f9Spjha 		    CFG_DIRNAME, ap_path);
10623c4226f9Spjha 
10633c4226f9Spjha 		/*
10643c4226f9Spjha 		 * We must remove existing links because we may have invalid
10653c4226f9Spjha 		 * apids that are valid links.  Since these are not dangling,
10663c4226f9Spjha 		 * devfsadm will not invoke the remove callback on them.
10673c4226f9Spjha 		 *
10683c4226f9Spjha 		 * What are "invalid apids with valid links"?  Consider swapping
10693c4226f9Spjha 		 * an attachment point bus with another while the system is
10703c4226f9Spjha 		 * down, on the same device path bound to the same drivers
10713c4226f9Spjha 		 * but with the new AP bus having different properties
10723c4226f9Spjha 		 * (e.g. serialid#).  If the previous apid is not removed,
10733c4226f9Spjha 		 * there will now be two different links pointing to the same
10743c4226f9Spjha 		 * attachment point, but only one reflects the correct
10753c4226f9Spjha 		 * logical apid
10763c4226f9Spjha 		 */
10773c4226f9Spjha 		devpath = pci_cfg_devpath(node, minor);
10783c4226f9Spjha 		if (devpath == NULL)
10793c4226f9Spjha 			goto OUT;
10803c4226f9Spjha 		pci_cfg_rm_invalid_links(devpath, linkbuf);
10813c4226f9Spjha 		free(devpath);
10823c4226f9Spjha 
10833c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
10843c4226f9Spjha 
10853c4226f9Spjha 		/*
10863c4226f9Spjha 		 * we store the full logical path of the attachment point for
10873c4226f9Spjha 		 * cfgadm to display in its info field which is useful when
10883c4226f9Spjha 		 * the full logical path exceeds the size limit for logical
10893c4226f9Spjha 		 * apids (CFGA_LOG_EXT_LEN)
10903c4226f9Spjha 		 *
10913c4226f9Spjha 		 * for the cfgadm pci plugin to do the same would be expensive
10923c4226f9Spjha 		 * (i.e. devinfo snapshot + top down exhaustive minor search +
10933c4226f9Spjha 		 * equivalent of pci_cfg_ap_path() on every invocation)
10943c4226f9Spjha 		 *
10953c4226f9Spjha 		 * note that if we do not create a link (pci_cfg_ap_path() is
10963c4226f9Spjha 		 * not successful), that is what cfgadm will do anyways to
10973c4226f9Spjha 		 * create a purely dynamic apid
10983c4226f9Spjha 		 */
10993c4226f9Spjha 		pathinfo = pci_cfg_info_data(fullpath);
11003c4226f9Spjha 		fd = di_dli_openw(linkbuf);
11013c4226f9Spjha 		if (fd < 0)
11023c4226f9Spjha 			goto OUT;
11033c4226f9Spjha 
11043c4226f9Spjha 		sz = strlen(pathinfo) + 1;
11053c4226f9Spjha 		rv = write(fd, pathinfo, sz);
11063c4226f9Spjha 		if (rv < sz) {
11073c4226f9Spjha 			dprint(("%s: could not write full pathinfo to dli "
11083c4226f9Spjha 			    "file for %s%d\n", fnm, DRVINST(node)));
11093c4226f9Spjha 			goto OUT;
11103c4226f9Spjha 		}
11113c4226f9Spjha 		di_dli_close(fd);
11123c4226f9Spjha 	} else {
11133c4226f9Spjha 		rv = pci_cfg_ap_legacy(minor, node, ph, ap_path,
11143c4226f9Spjha 		    ap_pathsz);
11153c4226f9Spjha 		if (rv == 0)
11163c4226f9Spjha 			goto OUT;
11173c4226f9Spjha 
11183c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
11193c4226f9Spjha 		    CFG_DIRNAME, ap_path);
11203c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
11213c4226f9Spjha 	}
11223c4226f9Spjha 
11233c4226f9Spjha OUT:
1124ad86e48dSpjha 	if (fd >= 0)
1125ad86e48dSpjha 		di_dli_close(fd);
11263c4226f9Spjha 	if (fullpath != NULL)
11273c4226f9Spjha 		free(fullpath);
11283c4226f9Spjha 	if (pathinfo != NULL)
11293c4226f9Spjha 		free(pathinfo);
11303c4226f9Spjha 	if (ph != DI_PROM_HANDLE_NIL)
11313c4226f9Spjha 		di_prom_fini(ph);
11323c4226f9Spjha 	if (root_node != DI_NODE_NIL)
11333c4226f9Spjha 		di_fini(root_node);
11347c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
11353c4226f9Spjha 
11363c4226f9Spjha #undef	ap_pathsz
11373c4226f9Spjha }
11383c4226f9Spjha 
11393c4226f9Spjha 
11403c4226f9Spjha static void
11413c4226f9Spjha pci_cfg_rm_all(char *file)
11423c4226f9Spjha {
11433c4226f9Spjha 	pci_cfg_rm_link(file);
11447c478bd9Sstevel@tonic-gate }
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate /*
11487c478bd9Sstevel@tonic-gate  * ib_cfg_creat_cb() creates two types of links
11497c478bd9Sstevel@tonic-gate  * One for the fabric as /dev/cfg/ib
11507c478bd9Sstevel@tonic-gate  * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
11517c478bd9Sstevel@tonic-gate  */
11527c478bd9Sstevel@tonic-gate static int
11537c478bd9Sstevel@tonic-gate ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
11547c478bd9Sstevel@tonic-gate {
11557c478bd9Sstevel@tonic-gate 	char	*cp;
11567c478bd9Sstevel@tonic-gate 	char	path[PATH_MAX + 1];
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	if ((cp = di_devfs_path(node)) == NULL) {
11597c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
11637c478bd9Sstevel@tonic-gate 	di_devfs_path_free(cp);
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	/* create fabric or hca:GUID and the symlink */
11667c478bd9Sstevel@tonic-gate 	if (strstr(path, "ib:fabric") != NULL) {
11677c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
11687c478bd9Sstevel@tonic-gate 	} else {
11697c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
11707c478bd9Sstevel@tonic-gate 		    di_minor_name(minor));
11717c478bd9Sstevel@tonic-gate 	}
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
11747c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
11757c478bd9Sstevel@tonic-gate }
1176