xref: /titanic_50/usr/src/cmd/devfsadm/cfg_link.c (revision 3ebafc43f8c876353693c0e5a9e759edd91165b6)
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 /*
23b6b3bf89Spjha  * Copyright 2007 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 **);
90226236b5Spjha static int 	serid_printable(uint64_t *seridp);
91*3ebafc43Sjveta static int	di_propall_lookup_slot_names(di_prom_handle_t, int,
92*3ebafc43Sjveta 		    dev_t, di_node_t, di_slot_name_t **);
933c4226f9Spjha 
943c4226f9Spjha 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * NOTE: The CREATE_DEFER flag is private to this module.
977c478bd9Sstevel@tonic-gate  *	 NOT to be used by other modules
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate static devfsadm_create_t cfg_create_cbt[] = {
1003c4226f9Spjha 	{ "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT, NULL,
1017c478bd9Sstevel@tonic-gate 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
1027c478bd9Sstevel@tonic-gate 	},
1033c4226f9Spjha 	{ "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT, NULL,
1047c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb
1057c478bd9Sstevel@tonic-gate 	},
1063c4226f9Spjha 	{ "fc-attachment-point", DDI_NT_FC_ATTACHMENT_POINT, NULL,
1077c478bd9Sstevel@tonic-gate 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
1087c478bd9Sstevel@tonic-gate 	},
1093c4226f9Spjha 	{ "attachment-point", DDI_NT_USB_ATTACHMENT_POINT, NULL,
1107c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb
1117c478bd9Sstevel@tonic-gate 	},
1123c4226f9Spjha 	{ "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT, NULL,
1137c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb
1147c478bd9Sstevel@tonic-gate 	},
1153c4226f9Spjha 	{ "attachment-point", DDI_NT_IB_ATTACHMENT_POINT, NULL,
1167c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb
11766f9d5cbSmlf 	},
1183c4226f9Spjha 	{ "attachment-point", DDI_NT_SATA_ATTACHMENT_POINT, NULL,
11966f9d5cbSmlf 	    TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb
1207c478bd9Sstevel@tonic-gate 	}
1217c478bd9Sstevel@tonic-gate };
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(cfg_create_cbt);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate static devfsadm_remove_t cfg_remove_cbt[] = {
1267c478bd9Sstevel@tonic-gate 	{ "attachment-point", SCSI_CFG_LINK_RE, RM_POST,
1277c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1287c478bd9Sstevel@tonic-gate 	},
1297c478bd9Sstevel@tonic-gate 	{ "attachment-point", SBD_CFG_LINK_RE, RM_POST,
1307c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1317c478bd9Sstevel@tonic-gate 	},
1327c478bd9Sstevel@tonic-gate 	{ "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST,
1337c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1347c478bd9Sstevel@tonic-gate 	},
1357c478bd9Sstevel@tonic-gate 	{ "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
1367c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1377c478bd9Sstevel@tonic-gate 	},
1387c478bd9Sstevel@tonic-gate 	{ "attachment-point", PCI_CFG_LINK_RE, RM_POST,
1397c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1407c478bd9Sstevel@tonic-gate 	},
1413c4226f9Spjha 	{ "attachment-point", PCI_CFG_PATH_LINK_RE, RM_POST|RM_HOT,
1423c4226f9Spjha 	    ILEVEL_0, pci_cfg_rm_all
1433c4226f9Spjha 	},
1447c478bd9Sstevel@tonic-gate 	{ "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
1457c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
14666f9d5cbSmlf 	},
14766f9d5cbSmlf 	{ "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
14866f9d5cbSmlf 	    ILEVEL_0, devfsadm_rm_all
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate };
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static int
1557c478bd9Sstevel@tonic-gate scsi_cfg_creat_cb(di_minor_t minor, di_node_t node)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	char path[PATH_MAX + 1];
1587c478bd9Sstevel@tonic-gate 	char *c_num = NULL, *devfs_path, *mn;
1597c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t rules[3] = {
1607c478bd9Sstevel@tonic-gate 	    {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT},
1617c478bd9Sstevel@tonic-gate 	    {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR},
1627c478bd9Sstevel@tonic-gate 	    {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT}
1637c478bd9Sstevel@tonic-gate 	};
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	mn = di_minor_name(minor);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	if ((devfs_path = di_devfs_path(node)) == NULL) {
1687c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate 	(void) strcpy(path, devfs_path);
1717c478bd9Sstevel@tonic-gate 	(void) strcat(path, ":");
1727c478bd9Sstevel@tonic-gate 	(void) strcat(path, mn);
1737c478bd9Sstevel@tonic-gate 	di_devfs_path_free(devfs_path);
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3)
1767c478bd9Sstevel@tonic-gate 	    == DEVFSADM_FAILURE) {
1777c478bd9Sstevel@tonic-gate 		/*
1787c478bd9Sstevel@tonic-gate 		 * Unlike the disks module we don't retry on failure.
1797c478bd9Sstevel@tonic-gate 		 * If we have multiple "c" numbers for a single physical
1807c478bd9Sstevel@tonic-gate 		 * controller due to bug 4045879, we will not assign a
1817c478bd9Sstevel@tonic-gate 		 * c-number/symlink for the controller.
1827c478bd9Sstevel@tonic-gate 		 */
1837c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	(void) strcpy(path, CFG_DIRNAME);
1877c478bd9Sstevel@tonic-gate 	(void) strcat(path, "/c");
1887c478bd9Sstevel@tonic-gate 	(void) strcat(path, c_num);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	free(c_num);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate static int
1987c478bd9Sstevel@tonic-gate sbd_cfg_creat_cb(di_minor_t minor, di_node_t node)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate 	char path[PATH_MAX + 1];
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	(void) strcpy(path, CFG_DIRNAME);
2037c478bd9Sstevel@tonic-gate 	(void) strcat(path, "/");
2047c478bd9Sstevel@tonic-gate 	(void) strcat(path, di_minor_name(minor));
2057c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
2067c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate static int
2117c478bd9Sstevel@tonic-gate usb_cfg_creat_cb(di_minor_t minor, di_node_t node)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate 	char *cp, path[PATH_MAX + 1];
2147c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t rules[1] =
2157c478bd9Sstevel@tonic-gate 		{"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub};
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	if ((cp = di_devfs_path(node)) == NULL) {
2187c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
2227c478bd9Sstevel@tonic-gate 	di_devfs_path_free(cp);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) {
2257c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	/* create usbN and the symlink */
2297c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp,
2307c478bd9Sstevel@tonic-gate 	    di_minor_name(minor));
2317c478bd9Sstevel@tonic-gate 	free(cp);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 
23966f9d5cbSmlf static int
24066f9d5cbSmlf sata_cfg_creat_cb(di_minor_t minor, di_node_t node)
24166f9d5cbSmlf {
24266f9d5cbSmlf 	char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath;
24366f9d5cbSmlf 	char *minor_nm;
24466f9d5cbSmlf 	devfsadm_enumerate_t rules[1] =
24566f9d5cbSmlf 		{"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR};
24666f9d5cbSmlf 
24766f9d5cbSmlf 	minor_nm = di_minor_name(minor);
24866f9d5cbSmlf 	if (minor_nm == NULL)
24966f9d5cbSmlf 		return (DEVFSADM_CONTINUE);
25066f9d5cbSmlf 
25166f9d5cbSmlf 	devfspath = di_devfs_path(node);
25266f9d5cbSmlf 	if (devfspath == NULL)
25366f9d5cbSmlf 		return (DEVFSADM_CONTINUE);
25466f9d5cbSmlf 
25566f9d5cbSmlf 	(void) strlcpy(path, devfspath, sizeof (path));
25666f9d5cbSmlf 	(void) strlcat(path, ":", sizeof (path));
25766f9d5cbSmlf 	(void) strlcat(path, minor_nm, sizeof (path));
25866f9d5cbSmlf 	di_devfs_path_free(devfspath);
25966f9d5cbSmlf 
26066f9d5cbSmlf 	/* build the physical path from the components */
26166f9d5cbSmlf 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) ==
26266f9d5cbSmlf 	    DEVFSADM_FAILURE) {
26366f9d5cbSmlf 		return (DEVFSADM_CONTINUE);
26466f9d5cbSmlf 	}
26566f9d5cbSmlf 
26666f9d5cbSmlf 	(void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME,
26766f9d5cbSmlf 			buf, minor_nm);
26866f9d5cbSmlf 	free(buf);
26966f9d5cbSmlf 
27066f9d5cbSmlf 	(void) devfsadm_mklink(l_path, node, minor, 0);
27166f9d5cbSmlf 
27266f9d5cbSmlf 	return (DEVFSADM_CONTINUE);
27366f9d5cbSmlf }
27466f9d5cbSmlf 
27566f9d5cbSmlf 
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate  * get_roothub:
2787c478bd9Sstevel@tonic-gate  *	figure out the root hub path to calculate /dev/cfg/usbN
2797c478bd9Sstevel@tonic-gate  */
2807c478bd9Sstevel@tonic-gate /* ARGSUSED */
2817c478bd9Sstevel@tonic-gate static char *
2827c478bd9Sstevel@tonic-gate get_roothub(const char *path, void *cb_arg)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 	int  i, count = 0;
2857c478bd9Sstevel@tonic-gate 	char *physpath, *cp;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	/* make a copy */
2887c478bd9Sstevel@tonic-gate 	if ((physpath = strdup(path)) == NULL) {
2897c478bd9Sstevel@tonic-gate 		return (NULL);
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/*
2937c478bd9Sstevel@tonic-gate 	 * physpath must always have a minor name component
2947c478bd9Sstevel@tonic-gate 	 */
2957c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(physpath, ':')) == NULL) {
2967c478bd9Sstevel@tonic-gate 		free(physpath);
2977c478bd9Sstevel@tonic-gate 		return (NULL);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 	*cp++ = '\0';
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/*
3027c478bd9Sstevel@tonic-gate 	 * No '.' in the minor name indicates a roothub port.
3037c478bd9Sstevel@tonic-gate 	 */
3047c478bd9Sstevel@tonic-gate 	if (strchr(cp, '.') == NULL) {
3057c478bd9Sstevel@tonic-gate 		/* roothub device */
3067c478bd9Sstevel@tonic-gate 		return (physpath);
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	while (*cp) {
3107c478bd9Sstevel@tonic-gate 		if (*cp == '.')
3117c478bd9Sstevel@tonic-gate 			count++;
3127c478bd9Sstevel@tonic-gate 		cp++;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/* Remove as many trailing path components as there are '.'s */
3167c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
3177c478bd9Sstevel@tonic-gate 		if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) {
3187c478bd9Sstevel@tonic-gate 			free(physpath);
3197c478bd9Sstevel@tonic-gate 			return (NULL);
3207c478bd9Sstevel@tonic-gate 		}
3217c478bd9Sstevel@tonic-gate 		*cp = '\0';
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	return (physpath);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate /*
3293c4226f9Spjha  * returns an allocted string containing the device path for <node> and
3303c4226f9Spjha  * <minor>
3313c4226f9Spjha  */
3323c4226f9Spjha static char *
3333c4226f9Spjha pci_cfg_devpath(di_node_t node, di_minor_t minor)
3343c4226f9Spjha {
3353c4226f9Spjha 	char *path;
3363c4226f9Spjha 	char *bufp;
3373c4226f9Spjha 	char *minor_nm;
3383c4226f9Spjha 	int buflen;
3393c4226f9Spjha 
3403c4226f9Spjha 	path = di_devfs_path(node);
3413c4226f9Spjha 	minor_nm = di_minor_name(minor);
342ad86e48dSpjha 	buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1;
3433c4226f9Spjha 
3443c4226f9Spjha 	bufp = malloc(sizeof (char) * buflen);
345ad86e48dSpjha 	if (bufp != NULL)
3463c4226f9Spjha 		(void) snprintf(bufp, buflen, "%s:%s", path, minor_nm);
3473c4226f9Spjha 
3483c4226f9Spjha 	di_devfs_path_free(path);
3493c4226f9Spjha 	return (bufp);
3503c4226f9Spjha }
3513c4226f9Spjha 
3523c4226f9Spjha 
3533c4226f9Spjha static int
3543c4226f9Spjha di_propall_lookup_ints(di_prom_handle_t ph, int flags,
3553c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, int **prop_data)
3563c4226f9Spjha {
3573c4226f9Spjha 	int rv;
3583c4226f9Spjha 
3593c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
3603c4226f9Spjha 		rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data);
3613c4226f9Spjha 		if (rv < 0)
3623c4226f9Spjha 			rv = di_prop_lookup_ints(dev, node, prop_name,
3633c4226f9Spjha 			    prop_data);
3643c4226f9Spjha 	} else {
3653c4226f9Spjha 		rv = di_prop_lookup_ints(dev, node, prop_name, prop_data);
3663c4226f9Spjha 		if (rv < 0)
3673c4226f9Spjha 			rv = di_prom_prop_lookup_ints(ph, node, prop_name,
3683c4226f9Spjha 			    prop_data);
3693c4226f9Spjha 	}
3703c4226f9Spjha 	return (rv);
3713c4226f9Spjha }
3723c4226f9Spjha 
3733c4226f9Spjha 
3743c4226f9Spjha static int
3753c4226f9Spjha di_propall_lookup_strings(di_prom_handle_t ph, int flags,
3763c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, char **prop_data)
3773c4226f9Spjha {
3783c4226f9Spjha 	int rv;
3793c4226f9Spjha 
3803c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
3813c4226f9Spjha 		rv = di_prom_prop_lookup_strings(ph, node, prop_name,
3823c4226f9Spjha 		    prop_data);
3833c4226f9Spjha 		if (rv < 0)
3843c4226f9Spjha 			rv = di_prop_lookup_strings(dev, node, prop_name,
3853c4226f9Spjha 			    prop_data);
3863c4226f9Spjha 	} else {
3873c4226f9Spjha 		rv = di_prop_lookup_strings(dev, node, prop_name, prop_data);
3883c4226f9Spjha 		if (rv < 0)
3893c4226f9Spjha 			rv = di_prom_prop_lookup_strings(ph, node, prop_name,
3903c4226f9Spjha 			    prop_data);
3913c4226f9Spjha 	}
3923c4226f9Spjha 	return (rv);
3933c4226f9Spjha }
3943c4226f9Spjha 
3953c4226f9Spjha 
3963c4226f9Spjha static di_node_t
3973c4226f9Spjha pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph)
3983c4226f9Spjha {
3993c4226f9Spjha 	di_node_t curnode = node;
4003c4226f9Spjha 	int *firstchas;
4013c4226f9Spjha 
4023c4226f9Spjha 	do {
4033c4226f9Spjha 		if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode,
404*3ebafc43Sjveta 		    DI_PROP_FIRST_CHAS, &firstchas) >= 0)
4053c4226f9Spjha 			return (curnode);
4063c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
4073c4226f9Spjha 
4083c4226f9Spjha 	return (DI_NODE_NIL);
4093c4226f9Spjha }
4103c4226f9Spjha 
4113c4226f9Spjha 
412*3ebafc43Sjveta static int
413*3ebafc43Sjveta di_propall_lookup_slot_names(di_prom_handle_t ph, int flags,
414*3ebafc43Sjveta     dev_t dev, di_node_t node, di_slot_name_t **prop_data)
415*3ebafc43Sjveta {
416*3ebafc43Sjveta 	int rv;
417*3ebafc43Sjveta 
418*3ebafc43Sjveta 	if (flags & DIPROP_PRI_PROM) {
419*3ebafc43Sjveta 		rv = di_prom_prop_lookup_slot_names(ph, node, prop_data);
420*3ebafc43Sjveta 		if (rv < 0)
421*3ebafc43Sjveta 			rv = di_prop_lookup_slot_names(dev, node, prop_data);
422*3ebafc43Sjveta 	} else {
423*3ebafc43Sjveta 		rv = di_prop_lookup_slot_names(dev, node, prop_data);
424*3ebafc43Sjveta 		if (rv < 0)
425*3ebafc43Sjveta 			rv = di_prom_prop_lookup_slot_names(ph, node,
426*3ebafc43Sjveta 			    prop_data);
427*3ebafc43Sjveta 	}
428*3ebafc43Sjveta 	return (rv);
429*3ebafc43Sjveta }
430*3ebafc43Sjveta 
4313c4226f9Spjha /*
432*3ebafc43Sjveta  * returns an allocated string containing the slot name for the slot with
433*3ebafc43Sjveta  * device number <pci_dev> on bus <node>
4343c4226f9Spjha  */
4353c4226f9Spjha static char *
4363c4226f9Spjha pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev)
4373c4226f9Spjha {
4383c4226f9Spjha #ifdef	DEBUG
4393c4226f9Spjha 	char *fnm = "pci_cfg_slotname";
4403c4226f9Spjha #endif
441*3ebafc43Sjveta 	int i, count;
442*3ebafc43Sjveta 	char *name = NULL;
443*3ebafc43Sjveta 	di_slot_name_t *slot_names = NULL;
4443c4226f9Spjha 
445*3ebafc43Sjveta 	count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node,
446*3ebafc43Sjveta 	    &slot_names);
447*3ebafc43Sjveta 	if (count < 0)
4483c4226f9Spjha 		return (NULL);
4493c4226f9Spjha 
450*3ebafc43Sjveta 	for (i = 0; i < count; i++) {
451*3ebafc43Sjveta 		if (slot_names[i].num == (int)pci_dev) {
452*3ebafc43Sjveta 			name = strdup(slot_names[i].name);
4533c4226f9Spjha 			break;
4543c4226f9Spjha 		}
4553c4226f9Spjha 	}
456*3ebafc43Sjveta #ifdef	DEBUG
457*3ebafc43Sjveta 	if (name == NULL)
458*3ebafc43Sjveta 		dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n",
459*3ebafc43Sjveta 		    fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node)));
460*3ebafc43Sjveta #endif
461*3ebafc43Sjveta 	if (count > 0)
462*3ebafc43Sjveta 		di_slot_names_free(count, slot_names);
463*3ebafc43Sjveta 	return (name);
4643c4226f9Spjha }
4653c4226f9Spjha 
4663c4226f9Spjha 
4673c4226f9Spjha /*
4683c4226f9Spjha  * returns non-zero if we can return a valid attachment point name for <node>,
4693c4226f9Spjha  * for its slot identified by child pci device number <pci_dev>, through <buf>
4703c4226f9Spjha  *
4713c4226f9Spjha  * prioritized naming scheme:
472*3ebafc43Sjveta  *	1) <DI_PROP_SLOT_NAMES property>    (see pci_cfg_slotname())
473*3ebafc43Sjveta  *	2) <device-type><DI_PROP_PHYS_SLOT property>
4743c4226f9Spjha  *	3) <drv name><drv inst>.<device-type><pci_dev>
4753c4226f9Spjha  *
476*3ebafc43Sjveta  * where <device-type> is derived from the DI_PROP_DEV_TYPE property:
4773c4226f9Spjha  *	if its value is "pciex" then <device-type> is "pcie"
4783c4226f9Spjha  *	else the raw value is used
4793c4226f9Spjha  *
4803c4226f9Spjha  * if <flags> contains APNODE_DEFNAME, then scheme (3) is used
4817c478bd9Sstevel@tonic-gate  */
4827c478bd9Sstevel@tonic-gate static int
4833c4226f9Spjha pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph,
4843c4226f9Spjha     char *buf, int bufsz, int flags)
4857c478bd9Sstevel@tonic-gate {
4863c4226f9Spjha 	int *nump;
4873c4226f9Spjha 	int rv;
4883c4226f9Spjha 	char *str, *devtype;
4893c4226f9Spjha 
4903c4226f9Spjha 	rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node,
491*3ebafc43Sjveta 	    DI_PROP_DEV_TYPE, &devtype);
4923c4226f9Spjha 	if (rv < 1)
4933c4226f9Spjha 		return (0);
4943c4226f9Spjha 
4953c4226f9Spjha 	if (strcmp(devtype, PROPVAL_PCIEX) == 0)
4963c4226f9Spjha 		devtype = DEVTYPE_PCIE;
4973c4226f9Spjha 
4983c4226f9Spjha 	if (flags & APNODE_DEFNAME)
4993c4226f9Spjha 		goto DEF;
5003c4226f9Spjha 
5013c4226f9Spjha 	str = pci_cfg_slotname(node, ph, pci_dev);
5023c4226f9Spjha 	if (str != NULL) {
5033c4226f9Spjha 		(void) strlcpy(buf, str, bufsz);
504*3ebafc43Sjveta 		free(str);
5053c4226f9Spjha 		return (1);
5063c4226f9Spjha 	}
5073c4226f9Spjha 
508*3ebafc43Sjveta 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node,
509*3ebafc43Sjveta 	    DI_PROP_PHYS_SLOT, &nump) > 0) {
5103c4226f9Spjha 		if (*nump > 0) {
5113c4226f9Spjha 			(void) snprintf(buf, bufsz, "%s%d", devtype, *nump);
5123c4226f9Spjha 			return (1);
5133c4226f9Spjha 		}
5143c4226f9Spjha 	}
5153c4226f9Spjha DEF:
5163c4226f9Spjha 	(void) snprintf(buf, bufsz, "%s%d.%s%d",
5173c4226f9Spjha 	    di_driver_name(node), di_instance(node), devtype, pci_dev);
5183c4226f9Spjha 
5193c4226f9Spjha 	return (1);
5203c4226f9Spjha }
5213c4226f9Spjha 
5223c4226f9Spjha 
5233c4226f9Spjha /*
5243c4226f9Spjha  * returns non-zero if we can return a valid expansion chassis name for <node>
5253c4226f9Spjha  * through <buf>
5263c4226f9Spjha  *
5273c4226f9Spjha  * prioritized naming scheme:
528*3ebafc43Sjveta  *	1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion>
529*3ebafc43Sjveta  *	2) <IOB_PRE string><full DI_PROP_SERID property in hex>
5303c4226f9Spjha  *	3) <IOB_PRE string>
5313c4226f9Spjha  *
532*3ebafc43Sjveta  * DI_PROP_SERID encoding <64-bit int: msb ... lsb>:
533b6b3bf89Spjha  * <24 bits: IEEE company id><40 bits: serial number>
5343c4226f9Spjha  *
5353c4226f9Spjha  * sun encoding of 40 bit serial number:
536226236b5Spjha  * first byte = device type indicator
5373c4226f9Spjha  * next 4 bytes = 4 ascii characters
538226236b5Spjha  *
539226236b5Spjha  * In the unlikely event that serial id contains non-printable characters
540226236b5Spjha  * the full 64 bit raw hex string will be used for the attachment point.
5413c4226f9Spjha  */
5423c4226f9Spjha /*ARGSUSED*/
5433c4226f9Spjha static int
5443c4226f9Spjha pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
5453c4226f9Spjha     char *buf, int bufsz)
5463c4226f9Spjha {
5473c4226f9Spjha 	int64_t *seridp;
548b6b3bf89Spjha 	uint64_t serid;
549226236b5Spjha 	char *idstr;
5503c4226f9Spjha 
551*3ebafc43Sjveta 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID,
5523c4226f9Spjha 	    &seridp) < 1) {
5533c4226f9Spjha 		(void) strlcpy(buf, IOB_PRE, bufsz);
5543c4226f9Spjha 		return (1);
5553c4226f9Spjha 	}
556226236b5Spjha 
557b6b3bf89Spjha 	serid = (uint64_t)*seridp;
5583c4226f9Spjha 
559226236b5Spjha 	if ((serid >> 40) != (uint64_t)IEEE_SUN_ID ||
560226236b5Spjha 		!serid_printable(&serid)) {
5613c4226f9Spjha 		(void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid);
5623c4226f9Spjha 		return (1);
5633c4226f9Spjha 	}
5643c4226f9Spjha 
565b6b3bf89Spjha 	/*
566226236b5Spjha 	 * the serial id is constructed from lower 40 bits of the serialid
567226236b5Spjha 	 * property and is represented by 5 ascii characters. The first
568226236b5Spjha 	 * character indicates if the IO Box is PCIe or PCI-X.
569b6b3bf89Spjha 	 */
570b6b3bf89Spjha 
571226236b5Spjha 	serid <<= 24;
572226236b5Spjha 	idstr = (char *)&serid;
573226236b5Spjha 	idstr[sizeof (serid) -1] = '\0';
574226236b5Spjha 
575226236b5Spjha 	(void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr);
576b6b3bf89Spjha 
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 
590*3ebafc43Sjveta 	rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG,
5913c4226f9Spjha 	    &regp);
5923c4226f9Spjha 
5933c4226f9Spjha 	if (rv < 1) {
5943c4226f9Spjha 		dprint(("pci_cfg_pcidev: property %s not found "
595*3ebafc43Sjveta 		    "for %s%d\n", DI_PROP_REG, DRVINST(node)));
5964e0386dfSjveta 		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,
615*3ebafc43Sjveta  * which is identified by the DI_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 	 */
7633e655c7dSjveta 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
7643c4226f9Spjha 	rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME);
7653c4226f9Spjha 	if (rv == 0) {
7663c4226f9Spjha 		dprint(("%s: cannot create default ap node name for %s%d\n",
7673c4226f9Spjha 		    fnm, DRVINST(node)));
7683c4226f9Spjha 		*pathptr = '\0';
7693c4226f9Spjha 		goto OUT;
7703c4226f9Spjha 	}
7713c4226f9Spjha 	if (strlen(buf) < ap_pathsz) {
7723c4226f9Spjha 		(void) strlcpy(ap_path, buf, ap_pathsz);
7733c4226f9Spjha 		rv = 1;
7743c4226f9Spjha 		goto OUT;
7753c4226f9Spjha 	}
7763c4226f9Spjha 
7773c4226f9Spjha 	/*
7783c4226f9Spjha 	 * in this case, cfgadm goes through an expensive process to generate
7793c4226f9Spjha 	 * a purely dynamic logical apid: the framework will look through
7803c4226f9Spjha 	 * the device tree for attachment point minor nodes and will invoke
7813c4226f9Spjha 	 * each plugin responsible for that attachment point class, and if
7823c4226f9Spjha 	 * the plugin returns a logical apid that matches the queried apid
7833c4226f9Spjha 	 * or matches the default apid generated by the cfgadm framework for
7843c4226f9Spjha 	 * that driver/class (occurs when plugin returns an empty logical apid)
7853c4226f9Spjha 	 * then that is what it will use
7863c4226f9Spjha 	 *
7873c4226f9Spjha 	 * it is doubly expensive because the cfgadm pci plugin itself will
7883c4226f9Spjha 	 * also search the entire device tree in the absence of a link
7893c4226f9Spjha 	 */
7903c4226f9Spjha 	rv = 0;
7913c4226f9Spjha 	dprint(("%s: cannot create apid for %s%d within length of %d\n",
7923c4226f9Spjha 	    fnm, DRVINST(node), ap_pathsz));
7933c4226f9Spjha 
7943c4226f9Spjha OUT:
7953c4226f9Spjha 	ap_path[ap_pathsz - 1] = '\0';
7963c4226f9Spjha 	*pathret = (*pathptr == '\0') ? NULL : strdup(pathptr);
7973c4226f9Spjha 	return (rv);
7983c4226f9Spjha 
7993c4226f9Spjha #undef	seplen
8003c4226f9Spjha #undef	iob_pre_len
8013c4226f9Spjha #undef	ap_path_iob_sep_len
8023c4226f9Spjha }
8033c4226f9Spjha 
8043c4226f9Spjha 
8053c4226f9Spjha /*
806*3ebafc43Sjveta  * the DI_PROP_AP_NAMES property contains the first integer section of the
8073c4226f9Spjha  * ieee1275 "slot-names" property and functions as a bitmask; see comment for
8083c4226f9Spjha  * pci_cfg_slotname()
8093c4226f9Spjha  *
8103c4226f9Spjha  * we use the name of the attachment point minor node if its pci device
811*3ebafc43Sjveta  * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES
8123c4226f9Spjha  *
8133c4226f9Spjha  * returns non-zero if we return a valid attachment point through <path>
8143c4226f9Spjha  */
8153c4226f9Spjha static int
8163c4226f9Spjha pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
8173c4226f9Spjha     char *ap_path, int ap_pathsz)
8183c4226f9Spjha {
8193c4226f9Spjha 	minor_t pci_dev;
8203c4226f9Spjha 	int *anp;
8213c4226f9Spjha 
822*3ebafc43Sjveta 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES,
8233c4226f9Spjha 	    &anp) < 1)
8243c4226f9Spjha 		return (0);
8253c4226f9Spjha 
8263c4226f9Spjha 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
8273c4226f9Spjha 	if ((*anp & (1 << pci_dev)) == 0)
8283c4226f9Spjha 		return (0);
8293c4226f9Spjha 
8303c4226f9Spjha 	(void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz);
8313c4226f9Spjha 	return (1);
8323c4226f9Spjha }
8333c4226f9Spjha 
8343c4226f9Spjha 
8353c4226f9Spjha /*
8363c4226f9Spjha  * determine if <node> qualifies for a path style apid
8373c4226f9Spjha  */
8383c4226f9Spjha static int
8393c4226f9Spjha pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph)
8403c4226f9Spjha {
8413c4226f9Spjha 	char *devtype;
8423c4226f9Spjha 	di_node_t curnode = node;
8433c4226f9Spjha 
8443c4226f9Spjha 	do {
8453c4226f9Spjha 		if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode,
846*3ebafc43Sjveta 		    DI_PROP_DEV_TYPE, &devtype) > 0)
8473c4226f9Spjha 			if (strcmp(devtype, PROPVAL_PCIEX) == 0)
8483c4226f9Spjha 				return (1);
8493c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
8503c4226f9Spjha 
8513c4226f9Spjha 	return (0);
8523c4226f9Spjha }
8533c4226f9Spjha 
8543c4226f9Spjha 
8553c4226f9Spjha /*
8563c4226f9Spjha  * takes a full path as returned by <pathret> from pci_cfg_ap_path() and
8573c4226f9Spjha  * returns an allocated string intendend to be stored in a devlink info (dli)
8583c4226f9Spjha  * file
8593c4226f9Spjha  *
8603c4226f9Spjha  * data format: "Location: <transformed path>"
8613c4226f9Spjha  * where <transformed path> is <path> with occurrances of AP_PATH_SEP
8623c4226f9Spjha  * replaced by "/"
8633c4226f9Spjha  */
8643c4226f9Spjha static char *
8653c4226f9Spjha pci_cfg_info_data(char *path)
8663c4226f9Spjha {
8673c4226f9Spjha #define	head	"Location: "
8683c4226f9Spjha #define	headlen	(sizeof (head) - 1)
8693c4226f9Spjha #define	seplen	(sizeof (AP_PATH_SEP) - 1)
8703c4226f9Spjha 
8713c4226f9Spjha 	char *sep, *prev, *np;
8723c4226f9Spjha 	char *newpath;
8733c4226f9Spjha 	int pathlen = strlen(path);
8743c4226f9Spjha 	int len;
8753c4226f9Spjha 
8763c4226f9Spjha 	newpath = malloc(sizeof (char) * (headlen + pathlen + 1));
8773c4226f9Spjha 	np = newpath;
8783c4226f9Spjha 	(void) strcpy(np, head);
8793c4226f9Spjha 	np += headlen;
8803c4226f9Spjha 
8813c4226f9Spjha 	prev = path;
8823c4226f9Spjha 	while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) {
8833c4226f9Spjha 		len = sep - prev;
8843c4226f9Spjha 		(void) memcpy(np, prev, len);
8853c4226f9Spjha 		np += len;
8863c4226f9Spjha 		*np++ = '/';
8873c4226f9Spjha 		prev = sep + seplen;
8883c4226f9Spjha 	}
8893c4226f9Spjha 	(void) strcpy(np, prev);
8903c4226f9Spjha 	return (newpath);
8913c4226f9Spjha 
8923c4226f9Spjha #undef	head
8933c4226f9Spjha #undef	headlen
8943c4226f9Spjha #undef	seplen
8953c4226f9Spjha }
8963c4226f9Spjha 
8973c4226f9Spjha 
8983c4226f9Spjha static void
8993c4226f9Spjha pci_cfg_rm_link(char *file)
9003c4226f9Spjha {
9013c4226f9Spjha 	char *dlipath;
9023c4226f9Spjha 
9033c4226f9Spjha 	dlipath = di_dli_name(file);
9043c4226f9Spjha 	(void) unlink(dlipath);
9053c4226f9Spjha 
9063c4226f9Spjha 	devfsadm_rm_all(file);
9073c4226f9Spjha 	free(dlipath);
9083c4226f9Spjha }
9093c4226f9Spjha 
9103c4226f9Spjha /*
9113c4226f9Spjha  * removes all registered devlinks to physical path <physpath> except for
9123c4226f9Spjha  * the devlink <valid> if not NULL;
9133c4226f9Spjha  * <physpath> must include the minor node
9143c4226f9Spjha  */
9153c4226f9Spjha static void
9163c4226f9Spjha pci_cfg_rm_invalid_links(char *physpath, char *valid)
9173c4226f9Spjha {
9183c4226f9Spjha 	char **dnp;
9193c4226f9Spjha 	char *cp, *vcp;
9203c4226f9Spjha 	int i, dnlen;
9213c4226f9Spjha 
9223c4226f9Spjha 	dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen);
9233c4226f9Spjha 	if (dnp == NULL)
9243c4226f9Spjha 		return;
9253c4226f9Spjha 
9263c4226f9Spjha 	if (valid != NULL) {
9273c4226f9Spjha 		if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0)
9283c4226f9Spjha 			vcp = valid + DEV_LEN + 1;
9293c4226f9Spjha 		else
9303c4226f9Spjha 			vcp = valid;
9313c4226f9Spjha 	}
9323c4226f9Spjha 
9333c4226f9Spjha 	for (i = 0; i < dnlen; i++) {
9343c4226f9Spjha 		if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0)
9353c4226f9Spjha 			cp = dnp[i] + DEV_LEN + 1;
9363c4226f9Spjha 		else
9373c4226f9Spjha 			cp = dnp[i];
9383c4226f9Spjha 
9393c4226f9Spjha 		if (valid != NULL) {
9403c4226f9Spjha 			if (strcmp(vcp, cp) == 0)
9413c4226f9Spjha 				continue;
9423c4226f9Spjha 		}
9433c4226f9Spjha 		pci_cfg_rm_link(cp);
9443c4226f9Spjha 	}
9453c4226f9Spjha 	devfsadm_free_dev_names(dnp, dnlen);
9463c4226f9Spjha }
9473c4226f9Spjha 
9483c4226f9Spjha 
9493c4226f9Spjha /*
9503c4226f9Spjha  * takes a complete devinfo snapshot and returns the root node;
9513c4226f9Spjha  * callers must do a di_fini() on the returned node;
9523c4226f9Spjha  * if the snapshot failed, DI_NODE_NIL is returned instead
9533c4226f9Spjha  *
9543c4226f9Spjha  * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node
9553c4226f9Spjha  * in the new snapshot and return it through <ret_node> if it is found,
9563c4226f9Spjha  * else DI_NODE_NIL is returned instead
9573c4226f9Spjha  *
9583c4226f9Spjha  * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return
9593c4226f9Spjha  * the matching minor in the new snapshot through <ret_minor> if it is found,
9603c4226f9Spjha  * else DI_MINOR_NIL is returned instead
9613c4226f9Spjha  */
9623c4226f9Spjha static di_node_t
9633c4226f9Spjha pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor,
9643c4226f9Spjha     di_node_t *ret_node, di_minor_t *ret_minor)
9653c4226f9Spjha {
9663c4226f9Spjha 	di_node_t root_node;
9673c4226f9Spjha 	di_node_t node;
9683c4226f9Spjha 	di_minor_t minor;
9693c4226f9Spjha 	int pci_inst;
9703c4226f9Spjha 	dev_t pci_devt;
9713c4226f9Spjha 
9723c4226f9Spjha 	*ret_node = DI_NODE_NIL;
9733c4226f9Spjha 	*ret_minor = DI_MINOR_NIL;
9743c4226f9Spjha 
9753c4226f9Spjha 	root_node = di_init("/", DINFOCPYALL);
9763c4226f9Spjha 	if (root_node == DI_NODE_NIL)
9773c4226f9Spjha 		return (DI_NODE_NIL);
9783c4226f9Spjha 
9793c4226f9Spjha 	/*
9803c4226f9Spjha 	 * narrow down search by driver, then instance, then minor
9813c4226f9Spjha 	 */
9823c4226f9Spjha 	if (pci_node == DI_NODE_NIL)
9833c4226f9Spjha 		return (root_node);
9843c4226f9Spjha 
9853c4226f9Spjha 	pci_inst = di_instance(pci_node);
9863c4226f9Spjha 	node = di_drv_first_node(di_driver_name(pci_node), root_node);
9873c4226f9Spjha 	do {
9883c4226f9Spjha 		if (pci_inst == di_instance(node)) {
9893c4226f9Spjha 			*ret_node = node;
9903c4226f9Spjha 			break;
9913c4226f9Spjha 		}
9923c4226f9Spjha 	} while ((node = di_drv_next_node(node)) != DI_NODE_NIL);
9933c4226f9Spjha 
9943c4226f9Spjha 	if (node == DI_NODE_NIL)
9953c4226f9Spjha 		return (root_node);
9963c4226f9Spjha 
9973c4226f9Spjha 	/*
9983c4226f9Spjha 	 * found node, now search minors
9993c4226f9Spjha 	 */
10003c4226f9Spjha 	if (pci_minor == DI_MINOR_NIL)
10013c4226f9Spjha 		return (root_node);
10023c4226f9Spjha 
10033c4226f9Spjha 	pci_devt = di_minor_devt(pci_minor);
10043c4226f9Spjha 	minor = DI_MINOR_NIL;
10053c4226f9Spjha 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
10063c4226f9Spjha 		if (pci_devt == di_minor_devt(minor)) {
10073c4226f9Spjha 			*ret_minor = minor;
10083c4226f9Spjha 			break;
10093c4226f9Spjha 		}
10103c4226f9Spjha 	}
10113c4226f9Spjha 	return (root_node);
10123c4226f9Spjha }
10133c4226f9Spjha 
10143c4226f9Spjha 
10153c4226f9Spjha static int
10163c4226f9Spjha pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node)
10173c4226f9Spjha {
10183c4226f9Spjha #ifdef	DEBUG
10193c4226f9Spjha 	char *fnm = "pci_cfg_creat_cb";
10203c4226f9Spjha #endif
10213c4226f9Spjha #define	ap_pathsz	(sizeof (ap_path))
10223c4226f9Spjha 
10233c4226f9Spjha 	char ap_path[CFGA_LOG_EXT_LEN];
10243c4226f9Spjha 	char linkbuf[MAXPATHLEN];
10253c4226f9Spjha 	char *fullpath = NULL;
10263c4226f9Spjha 	char *pathinfo = NULL;
10273c4226f9Spjha 	char *devpath = NULL;
1028ad86e48dSpjha 	int rv, fd = -1;
10293c4226f9Spjha 	size_t sz;
10303c4226f9Spjha 	di_prom_handle_t ph;
10313c4226f9Spjha 	di_node_t node;
10323c4226f9Spjha 	di_node_t root_node = DI_NODE_NIL;
10333c4226f9Spjha 	di_minor_t minor;
10343c4226f9Spjha 
10353c4226f9Spjha 	ph = di_prom_init();
10363c4226f9Spjha 	if (ph == DI_PROM_HANDLE_NIL) {
10373c4226f9Spjha 		dprint(("%s: di_prom_init() failed for %s%d\n",
10383c4226f9Spjha 		    fnm, DRVINST(pci_node)));
10393c4226f9Spjha 		goto OUT;
10403c4226f9Spjha 	}
10413c4226f9Spjha 
10423c4226f9Spjha 	/*
10433c4226f9Spjha 	 * Since incoming nodes from hotplug events are from snapshots that
10443c4226f9Spjha 	 * do NOT contain parent/ancestor data, we must retake our own
10453c4226f9Spjha 	 * snapshot and search for the target node
10463c4226f9Spjha 	 */
10473c4226f9Spjha 	root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor);
10483c4226f9Spjha 	if (root_node == DI_NODE_NIL || node == DI_NODE_NIL ||
10493c4226f9Spjha 	    minor == DI_MINOR_NIL) {
10503c4226f9Spjha 		dprint(("%s: devinfo snapshot or search failed for %s%d\n",
10513c4226f9Spjha 		    fnm, DRVINST(pci_node)));
10523c4226f9Spjha 		goto OUT;
10533c4226f9Spjha 	}
10543c4226f9Spjha 
10553c4226f9Spjha 	if (pci_cfg_is_ap_path(node, ph)) {
10563c4226f9Spjha 		rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz,
10573c4226f9Spjha 		    &fullpath);
10583c4226f9Spjha 		if (rv == 0)
10593c4226f9Spjha 			goto OUT;
10603c4226f9Spjha 
10613c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
10623c4226f9Spjha 		    CFG_DIRNAME, ap_path);
10633c4226f9Spjha 
10643c4226f9Spjha 		/*
10653c4226f9Spjha 		 * We must remove existing links because we may have invalid
10663c4226f9Spjha 		 * apids that are valid links.  Since these are not dangling,
10673c4226f9Spjha 		 * devfsadm will not invoke the remove callback on them.
10683c4226f9Spjha 		 *
10693c4226f9Spjha 		 * What are "invalid apids with valid links"?  Consider swapping
10703c4226f9Spjha 		 * an attachment point bus with another while the system is
10713c4226f9Spjha 		 * down, on the same device path bound to the same drivers
10723c4226f9Spjha 		 * but with the new AP bus having different properties
10733c4226f9Spjha 		 * (e.g. serialid#).  If the previous apid is not removed,
10743c4226f9Spjha 		 * there will now be two different links pointing to the same
10753c4226f9Spjha 		 * attachment point, but only one reflects the correct
10763c4226f9Spjha 		 * logical apid
10773c4226f9Spjha 		 */
10783c4226f9Spjha 		devpath = pci_cfg_devpath(node, minor);
10793c4226f9Spjha 		if (devpath == NULL)
10803c4226f9Spjha 			goto OUT;
10813c4226f9Spjha 		pci_cfg_rm_invalid_links(devpath, linkbuf);
10823c4226f9Spjha 		free(devpath);
10833c4226f9Spjha 
10843c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
10853c4226f9Spjha 
10863c4226f9Spjha 		/*
10873c4226f9Spjha 		 * we store the full logical path of the attachment point for
10883c4226f9Spjha 		 * cfgadm to display in its info field which is useful when
10893c4226f9Spjha 		 * the full logical path exceeds the size limit for logical
10903c4226f9Spjha 		 * apids (CFGA_LOG_EXT_LEN)
10913c4226f9Spjha 		 *
10923c4226f9Spjha 		 * for the cfgadm pci plugin to do the same would be expensive
10933c4226f9Spjha 		 * (i.e. devinfo snapshot + top down exhaustive minor search +
10943c4226f9Spjha 		 * equivalent of pci_cfg_ap_path() on every invocation)
10953c4226f9Spjha 		 *
10963c4226f9Spjha 		 * note that if we do not create a link (pci_cfg_ap_path() is
10973c4226f9Spjha 		 * not successful), that is what cfgadm will do anyways to
10983c4226f9Spjha 		 * create a purely dynamic apid
10993c4226f9Spjha 		 */
11003c4226f9Spjha 		pathinfo = pci_cfg_info_data(fullpath);
11013c4226f9Spjha 		fd = di_dli_openw(linkbuf);
11023c4226f9Spjha 		if (fd < 0)
11033c4226f9Spjha 			goto OUT;
11043c4226f9Spjha 
11053c4226f9Spjha 		sz = strlen(pathinfo) + 1;
11063c4226f9Spjha 		rv = write(fd, pathinfo, sz);
11073c4226f9Spjha 		if (rv < sz) {
11083c4226f9Spjha 			dprint(("%s: could not write full pathinfo to dli "
11093c4226f9Spjha 			    "file for %s%d\n", fnm, DRVINST(node)));
11103c4226f9Spjha 			goto OUT;
11113c4226f9Spjha 		}
11123c4226f9Spjha 		di_dli_close(fd);
11133c4226f9Spjha 	} else {
11143c4226f9Spjha 		rv = pci_cfg_ap_legacy(minor, node, ph, ap_path,
11153c4226f9Spjha 		    ap_pathsz);
11163c4226f9Spjha 		if (rv == 0)
11173c4226f9Spjha 			goto OUT;
11183c4226f9Spjha 
11193c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
11203c4226f9Spjha 		    CFG_DIRNAME, ap_path);
11213c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
11223c4226f9Spjha 	}
11233c4226f9Spjha 
11243c4226f9Spjha OUT:
1125ad86e48dSpjha 	if (fd >= 0)
1126ad86e48dSpjha 		di_dli_close(fd);
11273c4226f9Spjha 	if (fullpath != NULL)
11283c4226f9Spjha 		free(fullpath);
11293c4226f9Spjha 	if (pathinfo != NULL)
11303c4226f9Spjha 		free(pathinfo);
11313c4226f9Spjha 	if (ph != DI_PROM_HANDLE_NIL)
11323c4226f9Spjha 		di_prom_fini(ph);
11333c4226f9Spjha 	if (root_node != DI_NODE_NIL)
11343c4226f9Spjha 		di_fini(root_node);
11357c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
11363c4226f9Spjha 
11373c4226f9Spjha #undef	ap_pathsz
11383c4226f9Spjha }
11393c4226f9Spjha 
11403c4226f9Spjha 
11413c4226f9Spjha static void
11423c4226f9Spjha pci_cfg_rm_all(char *file)
11433c4226f9Spjha {
11443c4226f9Spjha 	pci_cfg_rm_link(file);
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate /*
11497c478bd9Sstevel@tonic-gate  * ib_cfg_creat_cb() creates two types of links
11507c478bd9Sstevel@tonic-gate  * One for the fabric as /dev/cfg/ib
11517c478bd9Sstevel@tonic-gate  * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
11527c478bd9Sstevel@tonic-gate  */
11537c478bd9Sstevel@tonic-gate static int
11547c478bd9Sstevel@tonic-gate ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
11557c478bd9Sstevel@tonic-gate {
11567c478bd9Sstevel@tonic-gate 	char	*cp;
11577c478bd9Sstevel@tonic-gate 	char	path[PATH_MAX + 1];
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	if ((cp = di_devfs_path(node)) == NULL) {
11607c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
11617c478bd9Sstevel@tonic-gate 	}
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
11647c478bd9Sstevel@tonic-gate 	di_devfs_path_free(cp);
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	/* create fabric or hca:GUID and the symlink */
11677c478bd9Sstevel@tonic-gate 	if (strstr(path, "ib:fabric") != NULL) {
11687c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
11697c478bd9Sstevel@tonic-gate 	} else {
11707c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
11717c478bd9Sstevel@tonic-gate 		    di_minor_name(minor));
11727c478bd9Sstevel@tonic-gate 	}
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
11757c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
11767c478bd9Sstevel@tonic-gate }
1177226236b5Spjha 
1178226236b5Spjha /*
1179226236b5Spjha  * This function verifies if the serial id is printable.
1180226236b5Spjha  */
1181226236b5Spjha 
1182226236b5Spjha static int
1183226236b5Spjha serid_printable(uint64_t *seridp)
1184226236b5Spjha {
1185226236b5Spjha 
1186226236b5Spjha 	char *ptr;
1187226236b5Spjha 	int i = 0;
1188226236b5Spjha 
1189226236b5Spjha 	for (ptr = (char *)seridp+3; i < 5; ptr++, i++)
1190226236b5Spjha 		if (*ptr < 0x21 || *ptr >= 0x7f)
1191226236b5Spjha 			return (0);
1192226236b5Spjha 
1193226236b5Spjha 	return (1);
1194226236b5Spjha 
1195226236b5Spjha }
1196