xref: /titanic_44/usr/src/cmd/devfsadm/cfg_link.c (revision 4bb7efa72ed531c10f097919636e67724ec4c25a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
566f9d5cbSmlf  * Common Development and Distribution License (the "License").
666f9d5cbSmlf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2166f9d5cbSmlf 
227c478bd9Sstevel@tonic-gate /*
23*4bb7efa7SGarrett D'Amore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <devfsadm.h>
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <strings.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
313c4226f9Spjha #include <stdarg.h>
327c478bd9Sstevel@tonic-gate #include <limits.h>
333c4226f9Spjha #include <unistd.h>
343c4226f9Spjha #include <config_admin.h>
353c4226f9Spjha #include <cfg_link.h>
363c4226f9Spjha #include <sys/types.h>
373c4226f9Spjha #include <sys/mkdev.h>
383c4226f9Spjha #include <sys/hotplug/pci/pcihp.h>
397c478bd9Sstevel@tonic-gate 
403c4226f9Spjha #ifdef	DEBUG
413c4226f9Spjha #define	dprint(args)	devfsadm_errprint args
423c4226f9Spjha /*
433c4226f9Spjha  * for use in print routine arg list as a shorthand way to locate node via
443c4226f9Spjha  * "prtconf -D" to avoid messy and cluttered debugging code
453c4226f9Spjha  * don't forget the corresponding "%s%d" format
463c4226f9Spjha  */
473c4226f9Spjha #define	DRVINST(node)	di_driver_name(node), di_instance(node)
483c4226f9Spjha #else
493c4226f9Spjha #define	dprint(args)
503c4226f9Spjha #endif
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static int	scsi_cfg_creat_cb(di_minor_t minor, di_node_t node);
547c478bd9Sstevel@tonic-gate static int	sbd_cfg_creat_cb(di_minor_t minor, di_node_t node);
557c478bd9Sstevel@tonic-gate static int	usb_cfg_creat_cb(di_minor_t minor, di_node_t node);
567c478bd9Sstevel@tonic-gate static char	*get_roothub(const char *path, void *cb_arg);
577c478bd9Sstevel@tonic-gate static int	pci_cfg_creat_cb(di_minor_t minor, di_node_t node);
587c478bd9Sstevel@tonic-gate static int	ib_cfg_creat_cb(di_minor_t minor, di_node_t node);
5966f9d5cbSmlf static int	sata_cfg_creat_cb(di_minor_t minor, di_node_t node);
60*4bb7efa7SGarrett D'Amore static int	sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node);
617c478bd9Sstevel@tonic-gate 
623c4226f9Spjha static di_node_t	pci_cfg_chassis_node(di_node_t, di_prom_handle_t);
633c4226f9Spjha static char 	*pci_cfg_slotname(di_node_t, di_prom_handle_t, minor_t);
643c4226f9Spjha static int	pci_cfg_ap_node(minor_t, di_node_t, di_prom_handle_t,
653c4226f9Spjha 		    char *, int, int);
663c4226f9Spjha static int	pci_cfg_iob_name(di_minor_t, di_node_t, di_prom_handle_t,
673c4226f9Spjha 		    char *, int);
683c4226f9Spjha static minor_t	pci_cfg_pcidev(di_node_t, di_prom_handle_t);
693c4226f9Spjha static int	pci_cfg_ap_path(di_minor_t, di_node_t, di_prom_handle_t,
703c4226f9Spjha 		    char *, int, char **);
713c4226f9Spjha static char 	*pci_cfg_info_data(char *);
723c4226f9Spjha static int	pci_cfg_is_ap_path(di_node_t, di_prom_handle_t);
733c4226f9Spjha static int	pci_cfg_ap_legacy(di_minor_t, di_node_t, di_prom_handle_t,
743c4226f9Spjha 		    char *, int);
753c4226f9Spjha static void	pci_cfg_rm_invalid_links(char *, char *);
763c4226f9Spjha static void	pci_cfg_rm_link(char *);
773c4226f9Spjha static void	pci_cfg_rm_all(char *);
783c4226f9Spjha static char	*pci_cfg_devpath(di_node_t, di_minor_t);
793c4226f9Spjha static di_node_t	pci_cfg_snapshot(di_node_t, di_minor_t,
803c4226f9Spjha 			    di_node_t *, di_minor_t *);
813c4226f9Spjha 
823c4226f9Spjha /* flag definitions for di_propall_*(); value "0" is always the default flag */
833c4226f9Spjha #define	DIPROP_PRI_NODE		0x0
843c4226f9Spjha #define	DIPROP_PRI_PROM		0x1
853c4226f9Spjha static int	di_propall_lookup_ints(di_prom_handle_t, int,
863c4226f9Spjha 		    dev_t, di_node_t, const char *, int **);
873c4226f9Spjha static int	di_propall_lookup_strings(di_prom_handle_t, int,
883c4226f9Spjha 		    dev_t, di_node_t, const char *, char **);
89226236b5Spjha static int 	serid_printable(uint64_t *seridp);
903ebafc43Sjveta static int	di_propall_lookup_slot_names(di_prom_handle_t, int,
913ebafc43Sjveta 		    dev_t, di_node_t, di_slot_name_t **);
923c4226f9Spjha 
933c4226f9Spjha 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * NOTE: The CREATE_DEFER flag is private to this module.
967c478bd9Sstevel@tonic-gate  *	 NOT to be used by other modules
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate static devfsadm_create_t cfg_create_cbt[] = {
993c4226f9Spjha 	{ "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT, NULL,
1007c478bd9Sstevel@tonic-gate 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
1017c478bd9Sstevel@tonic-gate 	},
1023c4226f9Spjha 	{ "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT, NULL,
1037c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb
1047c478bd9Sstevel@tonic-gate 	},
1053c4226f9Spjha 	{ "fc-attachment-point", DDI_NT_FC_ATTACHMENT_POINT, NULL,
1067c478bd9Sstevel@tonic-gate 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
1077c478bd9Sstevel@tonic-gate 	},
1083c4226f9Spjha 	{ "attachment-point", DDI_NT_USB_ATTACHMENT_POINT, NULL,
1097c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb
1107c478bd9Sstevel@tonic-gate 	},
1113c4226f9Spjha 	{ "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT, NULL,
1127c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb
1137c478bd9Sstevel@tonic-gate 	},
1143c4226f9Spjha 	{ "attachment-point", DDI_NT_IB_ATTACHMENT_POINT, NULL,
1157c478bd9Sstevel@tonic-gate 	    TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb
11666f9d5cbSmlf 	},
1173c4226f9Spjha 	{ "attachment-point", DDI_NT_SATA_ATTACHMENT_POINT, NULL,
11866f9d5cbSmlf 	    TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb
119*4bb7efa7SGarrett D'Amore 	},
120*4bb7efa7SGarrett D'Amore 	{ "attachment-point", DDI_NT_SDCARD_ATTACHMENT_POINT, NULL,
121*4bb7efa7SGarrett D'Amore 	    TYPE_EXACT, ILEVEL_0, sdcard_cfg_creat_cb
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate };
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(cfg_create_cbt);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate static devfsadm_remove_t cfg_remove_cbt[] = {
1287c478bd9Sstevel@tonic-gate 	{ "attachment-point", SCSI_CFG_LINK_RE, RM_POST,
1297c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1307c478bd9Sstevel@tonic-gate 	},
1317c478bd9Sstevel@tonic-gate 	{ "attachment-point", SBD_CFG_LINK_RE, RM_POST,
1327c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1337c478bd9Sstevel@tonic-gate 	},
1347c478bd9Sstevel@tonic-gate 	{ "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST,
1357c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1367c478bd9Sstevel@tonic-gate 	},
1377c478bd9Sstevel@tonic-gate 	{ "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
1387c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1397c478bd9Sstevel@tonic-gate 	},
1407c478bd9Sstevel@tonic-gate 	{ "attachment-point", PCI_CFG_LINK_RE, RM_POST,
1417c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
1427c478bd9Sstevel@tonic-gate 	},
1433c4226f9Spjha 	{ "attachment-point", PCI_CFG_PATH_LINK_RE, RM_POST|RM_HOT,
1443c4226f9Spjha 	    ILEVEL_0, pci_cfg_rm_all
1453c4226f9Spjha 	},
1467c478bd9Sstevel@tonic-gate 	{ "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
1477c478bd9Sstevel@tonic-gate 	    ILEVEL_0, devfsadm_rm_all
14866f9d5cbSmlf 	},
14966f9d5cbSmlf 	{ "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
15066f9d5cbSmlf 	    ILEVEL_0, devfsadm_rm_all
151*4bb7efa7SGarrett D'Amore 	},
152*4bb7efa7SGarrett D'Amore 	{ "attachment-point", SDCARD_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
153*4bb7efa7SGarrett D'Amore 	    ILEVEL_0, devfsadm_rm_all
154*4bb7efa7SGarrett D'Amore 	},
1557c478bd9Sstevel@tonic-gate };
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate static int
1607c478bd9Sstevel@tonic-gate scsi_cfg_creat_cb(di_minor_t minor, di_node_t node)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	char path[PATH_MAX + 1];
1637c478bd9Sstevel@tonic-gate 	char *c_num = NULL, *devfs_path, *mn;
1647c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t rules[3] = {
1657c478bd9Sstevel@tonic-gate 	    {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT},
1667c478bd9Sstevel@tonic-gate 	    {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR},
1677c478bd9Sstevel@tonic-gate 	    {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT}
1687c478bd9Sstevel@tonic-gate 	};
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	mn = di_minor_name(minor);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if ((devfs_path = di_devfs_path(node)) == NULL) {
1737c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 	(void) strcpy(path, devfs_path);
1767c478bd9Sstevel@tonic-gate 	(void) strcat(path, ":");
1777c478bd9Sstevel@tonic-gate 	(void) strcat(path, mn);
1787c478bd9Sstevel@tonic-gate 	di_devfs_path_free(devfs_path);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3)
1817c478bd9Sstevel@tonic-gate 	    == DEVFSADM_FAILURE) {
1827c478bd9Sstevel@tonic-gate 		/*
1837c478bd9Sstevel@tonic-gate 		 * Unlike the disks module we don't retry on failure.
1847c478bd9Sstevel@tonic-gate 		 * If we have multiple "c" numbers for a single physical
1857c478bd9Sstevel@tonic-gate 		 * controller due to bug 4045879, we will not assign a
1867c478bd9Sstevel@tonic-gate 		 * c-number/symlink for the controller.
1877c478bd9Sstevel@tonic-gate 		 */
1887c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	(void) strcpy(path, CFG_DIRNAME);
1927c478bd9Sstevel@tonic-gate 	(void) strcat(path, "/c");
1937c478bd9Sstevel@tonic-gate 	(void) strcat(path, c_num);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	free(c_num);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static int
2037c478bd9Sstevel@tonic-gate sbd_cfg_creat_cb(di_minor_t minor, di_node_t node)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	char path[PATH_MAX + 1];
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	(void) strcpy(path, CFG_DIRNAME);
2087c478bd9Sstevel@tonic-gate 	(void) strcat(path, "/");
2097c478bd9Sstevel@tonic-gate 	(void) strcat(path, di_minor_name(minor));
2107c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
2117c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate static int
2167c478bd9Sstevel@tonic-gate usb_cfg_creat_cb(di_minor_t minor, di_node_t node)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	char *cp, path[PATH_MAX + 1];
2197c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t rules[1] =
2207c478bd9Sstevel@tonic-gate 		{"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub};
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	if ((cp = di_devfs_path(node)) == NULL) {
2237c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
2277c478bd9Sstevel@tonic-gate 	di_devfs_path_free(cp);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) {
2307c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/* create usbN and the symlink */
2347c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp,
2357c478bd9Sstevel@tonic-gate 	    di_minor_name(minor));
2367c478bd9Sstevel@tonic-gate 	free(cp);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 
24466f9d5cbSmlf static int
24566f9d5cbSmlf sata_cfg_creat_cb(di_minor_t minor, di_node_t node)
24666f9d5cbSmlf {
24766f9d5cbSmlf 	char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath;
24866f9d5cbSmlf 	char *minor_nm;
24966f9d5cbSmlf 	devfsadm_enumerate_t rules[1] =
25066f9d5cbSmlf 		{"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR};
25166f9d5cbSmlf 
25266f9d5cbSmlf 	minor_nm = di_minor_name(minor);
25366f9d5cbSmlf 	if (minor_nm == NULL)
25466f9d5cbSmlf 		return (DEVFSADM_CONTINUE);
25566f9d5cbSmlf 
25666f9d5cbSmlf 	devfspath = di_devfs_path(node);
25766f9d5cbSmlf 	if (devfspath == NULL)
25866f9d5cbSmlf 		return (DEVFSADM_CONTINUE);
25966f9d5cbSmlf 
26066f9d5cbSmlf 	(void) strlcpy(path, devfspath, sizeof (path));
26166f9d5cbSmlf 	(void) strlcat(path, ":", sizeof (path));
26266f9d5cbSmlf 	(void) strlcat(path, minor_nm, sizeof (path));
26366f9d5cbSmlf 	di_devfs_path_free(devfspath);
26466f9d5cbSmlf 
26566f9d5cbSmlf 	/* build the physical path from the components */
26666f9d5cbSmlf 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) ==
26766f9d5cbSmlf 	    DEVFSADM_FAILURE) {
26866f9d5cbSmlf 		return (DEVFSADM_CONTINUE);
26966f9d5cbSmlf 	}
27066f9d5cbSmlf 
27166f9d5cbSmlf 	(void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME,
27266f9d5cbSmlf 	    buf, minor_nm);
27366f9d5cbSmlf 	free(buf);
27466f9d5cbSmlf 
27566f9d5cbSmlf 	(void) devfsadm_mklink(l_path, node, minor, 0);
27666f9d5cbSmlf 
27766f9d5cbSmlf 	return (DEVFSADM_CONTINUE);
27866f9d5cbSmlf }
27966f9d5cbSmlf 
280*4bb7efa7SGarrett D'Amore static int
281*4bb7efa7SGarrett D'Amore sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node)
282*4bb7efa7SGarrett D'Amore {
283*4bb7efa7SGarrett D'Amore 	char path[PATH_MAX +1], l_path[PATH_MAX], *buf, *devfspath;
284*4bb7efa7SGarrett D'Amore 	char *minor_nm;
285*4bb7efa7SGarrett D'Amore 	devfsadm_enumerate_t rules[1] =
286*4bb7efa7SGarrett D'Amore 	    {"^cfg$/^sdcard([0-9]+)$", 1, MATCH_ADDR};
287*4bb7efa7SGarrett D'Amore 
288*4bb7efa7SGarrett D'Amore 	minor_nm = di_minor_name(minor);
289*4bb7efa7SGarrett D'Amore 	if (minor_nm == NULL)
290*4bb7efa7SGarrett D'Amore 		return (DEVFSADM_CONTINUE);
291*4bb7efa7SGarrett D'Amore 
292*4bb7efa7SGarrett D'Amore 	devfspath = di_devfs_path(node);
293*4bb7efa7SGarrett D'Amore 	if (devfspath == NULL)
294*4bb7efa7SGarrett D'Amore 		return (DEVFSADM_CONTINUE);
295*4bb7efa7SGarrett D'Amore 
296*4bb7efa7SGarrett D'Amore 	(void) snprintf(path, sizeof (path), "%s:%s", devfspath, minor_nm);
297*4bb7efa7SGarrett D'Amore 	di_devfs_path_free(devfspath);
298*4bb7efa7SGarrett D'Amore 
299*4bb7efa7SGarrett D'Amore 	/* build the physical path from the components */
300*4bb7efa7SGarrett D'Amore 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) ==
301*4bb7efa7SGarrett D'Amore 	    DEVFSADM_FAILURE) {
302*4bb7efa7SGarrett D'Amore 		return (DEVFSADM_CONTINUE);
303*4bb7efa7SGarrett D'Amore 	}
304*4bb7efa7SGarrett D'Amore 
305*4bb7efa7SGarrett D'Amore 	(void) snprintf(l_path, sizeof (l_path), "%s/sdcard%s/%s",
306*4bb7efa7SGarrett D'Amore 	    CFG_DIRNAME, buf, minor_nm);
307*4bb7efa7SGarrett D'Amore 	free(buf);
308*4bb7efa7SGarrett D'Amore 
309*4bb7efa7SGarrett D'Amore 	(void) devfsadm_mklink(l_path, node, minor, 0);
310*4bb7efa7SGarrett D'Amore 
311*4bb7efa7SGarrett D'Amore 	return (DEVFSADM_CONTINUE);
312*4bb7efa7SGarrett D'Amore }
31366f9d5cbSmlf 
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate  * get_roothub:
3167c478bd9Sstevel@tonic-gate  *	figure out the root hub path to calculate /dev/cfg/usbN
3177c478bd9Sstevel@tonic-gate  */
3187c478bd9Sstevel@tonic-gate /* ARGSUSED */
3197c478bd9Sstevel@tonic-gate static char *
3207c478bd9Sstevel@tonic-gate get_roothub(const char *path, void *cb_arg)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	int  i, count = 0;
3237c478bd9Sstevel@tonic-gate 	char *physpath, *cp;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/* make a copy */
3267c478bd9Sstevel@tonic-gate 	if ((physpath = strdup(path)) == NULL) {
3277c478bd9Sstevel@tonic-gate 		return (NULL);
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/*
3317c478bd9Sstevel@tonic-gate 	 * physpath must always have a minor name component
3327c478bd9Sstevel@tonic-gate 	 */
3337c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(physpath, ':')) == NULL) {
3347c478bd9Sstevel@tonic-gate 		free(physpath);
3357c478bd9Sstevel@tonic-gate 		return (NULL);
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 	*cp++ = '\0';
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * No '.' in the minor name indicates a roothub port.
3417c478bd9Sstevel@tonic-gate 	 */
3427c478bd9Sstevel@tonic-gate 	if (strchr(cp, '.') == NULL) {
3437c478bd9Sstevel@tonic-gate 		/* roothub device */
3447c478bd9Sstevel@tonic-gate 		return (physpath);
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	while (*cp) {
3487c478bd9Sstevel@tonic-gate 		if (*cp == '.')
3497c478bd9Sstevel@tonic-gate 			count++;
3507c478bd9Sstevel@tonic-gate 		cp++;
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/* Remove as many trailing path components as there are '.'s */
3547c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
3557c478bd9Sstevel@tonic-gate 		if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) {
3567c478bd9Sstevel@tonic-gate 			free(physpath);
3577c478bd9Sstevel@tonic-gate 			return (NULL);
3587c478bd9Sstevel@tonic-gate 		}
3597c478bd9Sstevel@tonic-gate 		*cp = '\0';
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	return (physpath);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3673c4226f9Spjha  * returns an allocted string containing the device path for <node> and
3683c4226f9Spjha  * <minor>
3693c4226f9Spjha  */
3703c4226f9Spjha static char *
3713c4226f9Spjha pci_cfg_devpath(di_node_t node, di_minor_t minor)
3723c4226f9Spjha {
3733c4226f9Spjha 	char *path;
3743c4226f9Spjha 	char *bufp;
3753c4226f9Spjha 	char *minor_nm;
3763c4226f9Spjha 	int buflen;
3773c4226f9Spjha 
3783c4226f9Spjha 	path = di_devfs_path(node);
3793c4226f9Spjha 	minor_nm = di_minor_name(minor);
380ad86e48dSpjha 	buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1;
3813c4226f9Spjha 
3823c4226f9Spjha 	bufp = malloc(sizeof (char) * buflen);
383ad86e48dSpjha 	if (bufp != NULL)
3843c4226f9Spjha 		(void) snprintf(bufp, buflen, "%s:%s", path, minor_nm);
3853c4226f9Spjha 
3863c4226f9Spjha 	di_devfs_path_free(path);
3873c4226f9Spjha 	return (bufp);
3883c4226f9Spjha }
3893c4226f9Spjha 
3903c4226f9Spjha 
3913c4226f9Spjha static int
3923c4226f9Spjha di_propall_lookup_ints(di_prom_handle_t ph, int flags,
3933c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, int **prop_data)
3943c4226f9Spjha {
3953c4226f9Spjha 	int rv;
3963c4226f9Spjha 
3973c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
3983c4226f9Spjha 		rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data);
3993c4226f9Spjha 		if (rv < 0)
4003c4226f9Spjha 			rv = di_prop_lookup_ints(dev, node, prop_name,
4013c4226f9Spjha 			    prop_data);
4023c4226f9Spjha 	} else {
4033c4226f9Spjha 		rv = di_prop_lookup_ints(dev, node, prop_name, prop_data);
4043c4226f9Spjha 		if (rv < 0)
4053c4226f9Spjha 			rv = di_prom_prop_lookup_ints(ph, node, prop_name,
4063c4226f9Spjha 			    prop_data);
4073c4226f9Spjha 	}
4083c4226f9Spjha 	return (rv);
4093c4226f9Spjha }
4103c4226f9Spjha 
4113c4226f9Spjha 
4123c4226f9Spjha static int
4133c4226f9Spjha di_propall_lookup_strings(di_prom_handle_t ph, int flags,
4143c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, char **prop_data)
4153c4226f9Spjha {
4163c4226f9Spjha 	int rv;
4173c4226f9Spjha 
4183c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
4193c4226f9Spjha 		rv = di_prom_prop_lookup_strings(ph, node, prop_name,
4203c4226f9Spjha 		    prop_data);
4213c4226f9Spjha 		if (rv < 0)
4223c4226f9Spjha 			rv = di_prop_lookup_strings(dev, node, prop_name,
4233c4226f9Spjha 			    prop_data);
4243c4226f9Spjha 	} else {
4253c4226f9Spjha 		rv = di_prop_lookup_strings(dev, node, prop_name, prop_data);
4263c4226f9Spjha 		if (rv < 0)
4273c4226f9Spjha 			rv = di_prom_prop_lookup_strings(ph, node, prop_name,
4283c4226f9Spjha 			    prop_data);
4293c4226f9Spjha 	}
4303c4226f9Spjha 	return (rv);
4313c4226f9Spjha }
4323c4226f9Spjha 
4333c4226f9Spjha 
4343c4226f9Spjha static di_node_t
4353c4226f9Spjha pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph)
4363c4226f9Spjha {
4373c4226f9Spjha 	di_node_t curnode = node;
4383c4226f9Spjha 	int *firstchas;
4393c4226f9Spjha 
4403c4226f9Spjha 	do {
4413c4226f9Spjha 		if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode,
4423ebafc43Sjveta 		    DI_PROP_FIRST_CHAS, &firstchas) >= 0)
4433c4226f9Spjha 			return (curnode);
4443c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
4453c4226f9Spjha 
4463c4226f9Spjha 	return (DI_NODE_NIL);
4473c4226f9Spjha }
4483c4226f9Spjha 
4493c4226f9Spjha 
4503ebafc43Sjveta static int
4513ebafc43Sjveta di_propall_lookup_slot_names(di_prom_handle_t ph, int flags,
4523ebafc43Sjveta     dev_t dev, di_node_t node, di_slot_name_t **prop_data)
4533ebafc43Sjveta {
4543ebafc43Sjveta 	int rv;
4553ebafc43Sjveta 
4563ebafc43Sjveta 	if (flags & DIPROP_PRI_PROM) {
4573ebafc43Sjveta 		rv = di_prom_prop_lookup_slot_names(ph, node, prop_data);
4583ebafc43Sjveta 		if (rv < 0)
4593ebafc43Sjveta 			rv = di_prop_lookup_slot_names(dev, node, prop_data);
4603ebafc43Sjveta 	} else {
4613ebafc43Sjveta 		rv = di_prop_lookup_slot_names(dev, node, prop_data);
4623ebafc43Sjveta 		if (rv < 0)
4633ebafc43Sjveta 			rv = di_prom_prop_lookup_slot_names(ph, node,
4643ebafc43Sjveta 			    prop_data);
4653ebafc43Sjveta 	}
4663ebafc43Sjveta 	return (rv);
4673ebafc43Sjveta }
4683ebafc43Sjveta 
4693c4226f9Spjha /*
4703ebafc43Sjveta  * returns an allocated string containing the slot name for the slot with
4713ebafc43Sjveta  * device number <pci_dev> on bus <node>
4723c4226f9Spjha  */
4733c4226f9Spjha static char *
4743c4226f9Spjha pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev)
4753c4226f9Spjha {
4763c4226f9Spjha #ifdef	DEBUG
4773c4226f9Spjha 	char *fnm = "pci_cfg_slotname";
4783c4226f9Spjha #endif
4793ebafc43Sjveta 	int i, count;
4803ebafc43Sjveta 	char *name = NULL;
4813ebafc43Sjveta 	di_slot_name_t *slot_names = NULL;
4823c4226f9Spjha 
4833ebafc43Sjveta 	count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node,
4843ebafc43Sjveta 	    &slot_names);
4853ebafc43Sjveta 	if (count < 0)
4863c4226f9Spjha 		return (NULL);
4873c4226f9Spjha 
4883ebafc43Sjveta 	for (i = 0; i < count; i++) {
4893ebafc43Sjveta 		if (slot_names[i].num == (int)pci_dev) {
4903ebafc43Sjveta 			name = strdup(slot_names[i].name);
4913c4226f9Spjha 			break;
4923c4226f9Spjha 		}
4933c4226f9Spjha 	}
4943ebafc43Sjveta #ifdef	DEBUG
4953ebafc43Sjveta 	if (name == NULL)
4963ebafc43Sjveta 		dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n",
4973ebafc43Sjveta 		    fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node)));
4983ebafc43Sjveta #endif
4993ebafc43Sjveta 	if (count > 0)
5003ebafc43Sjveta 		di_slot_names_free(count, slot_names);
5013ebafc43Sjveta 	return (name);
5023c4226f9Spjha }
5033c4226f9Spjha 
5043c4226f9Spjha 
5053c4226f9Spjha /*
5063c4226f9Spjha  * returns non-zero if we can return a valid attachment point name for <node>,
5073c4226f9Spjha  * for its slot identified by child pci device number <pci_dev>, through <buf>
5083c4226f9Spjha  *
5093c4226f9Spjha  * prioritized naming scheme:
5103ebafc43Sjveta  *	1) <DI_PROP_SLOT_NAMES property>    (see pci_cfg_slotname())
5113ebafc43Sjveta  *	2) <device-type><DI_PROP_PHYS_SLOT property>
5123c4226f9Spjha  *	3) <drv name><drv inst>.<device-type><pci_dev>
5133c4226f9Spjha  *
5143ebafc43Sjveta  * where <device-type> is derived from the DI_PROP_DEV_TYPE property:
5153c4226f9Spjha  *	if its value is "pciex" then <device-type> is "pcie"
5163c4226f9Spjha  *	else the raw value is used
5173c4226f9Spjha  *
5183c4226f9Spjha  * if <flags> contains APNODE_DEFNAME, then scheme (3) is used
5197c478bd9Sstevel@tonic-gate  */
5207c478bd9Sstevel@tonic-gate static int
5213c4226f9Spjha pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph,
5223c4226f9Spjha     char *buf, int bufsz, int flags)
5237c478bd9Sstevel@tonic-gate {
5243c4226f9Spjha 	int *nump;
5253c4226f9Spjha 	int rv;
5263c4226f9Spjha 	char *str, *devtype;
5273c4226f9Spjha 
5283c4226f9Spjha 	rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node,
5293ebafc43Sjveta 	    DI_PROP_DEV_TYPE, &devtype);
5303c4226f9Spjha 	if (rv < 1)
5313c4226f9Spjha 		return (0);
5323c4226f9Spjha 
5333c4226f9Spjha 	if (strcmp(devtype, PROPVAL_PCIEX) == 0)
5343c4226f9Spjha 		devtype = DEVTYPE_PCIE;
5353c4226f9Spjha 
5363c4226f9Spjha 	if (flags & APNODE_DEFNAME)
5373c4226f9Spjha 		goto DEF;
5383c4226f9Spjha 
5393c4226f9Spjha 	str = pci_cfg_slotname(node, ph, pci_dev);
5403c4226f9Spjha 	if (str != NULL) {
5413c4226f9Spjha 		(void) strlcpy(buf, str, bufsz);
5423ebafc43Sjveta 		free(str);
5433c4226f9Spjha 		return (1);
5443c4226f9Spjha 	}
5453c4226f9Spjha 
5463ebafc43Sjveta 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node,
5473ebafc43Sjveta 	    DI_PROP_PHYS_SLOT, &nump) > 0) {
5483c4226f9Spjha 		if (*nump > 0) {
5493c4226f9Spjha 			(void) snprintf(buf, bufsz, "%s%d", devtype, *nump);
5503c4226f9Spjha 			return (1);
5513c4226f9Spjha 		}
5523c4226f9Spjha 	}
5533c4226f9Spjha DEF:
5543c4226f9Spjha 	(void) snprintf(buf, bufsz, "%s%d.%s%d",
5553c4226f9Spjha 	    di_driver_name(node), di_instance(node), devtype, pci_dev);
5563c4226f9Spjha 
5573c4226f9Spjha 	return (1);
5583c4226f9Spjha }
5593c4226f9Spjha 
5603c4226f9Spjha 
5613c4226f9Spjha /*
5623c4226f9Spjha  * returns non-zero if we can return a valid expansion chassis name for <node>
5633c4226f9Spjha  * through <buf>
5643c4226f9Spjha  *
5653c4226f9Spjha  * prioritized naming scheme:
5663ebafc43Sjveta  *	1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion>
5673ebafc43Sjveta  *	2) <IOB_PRE string><full DI_PROP_SERID property in hex>
5683c4226f9Spjha  *	3) <IOB_PRE string>
5693c4226f9Spjha  *
5703ebafc43Sjveta  * DI_PROP_SERID encoding <64-bit int: msb ... lsb>:
571b6b3bf89Spjha  * <24 bits: IEEE company id><40 bits: serial number>
5723c4226f9Spjha  *
5733c4226f9Spjha  * sun encoding of 40 bit serial number:
574226236b5Spjha  * first byte = device type indicator
5753c4226f9Spjha  * next 4 bytes = 4 ascii characters
576226236b5Spjha  *
577226236b5Spjha  * In the unlikely event that serial id contains non-printable characters
578226236b5Spjha  * the full 64 bit raw hex string will be used for the attachment point.
5793c4226f9Spjha  */
5803c4226f9Spjha /*ARGSUSED*/
5813c4226f9Spjha static int
5823c4226f9Spjha pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
5833c4226f9Spjha     char *buf, int bufsz)
5843c4226f9Spjha {
5853c4226f9Spjha 	int64_t *seridp;
586b6b3bf89Spjha 	uint64_t serid;
587226236b5Spjha 	char *idstr;
5883c4226f9Spjha 
5893ebafc43Sjveta 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID,
5903c4226f9Spjha 	    &seridp) < 1) {
5913c4226f9Spjha 		(void) strlcpy(buf, IOB_PRE, bufsz);
5923c4226f9Spjha 		return (1);
5933c4226f9Spjha 	}
594226236b5Spjha 
595b6b3bf89Spjha 	serid = (uint64_t)*seridp;
5963c4226f9Spjha 
597226236b5Spjha 	if ((serid >> 40) != (uint64_t)IEEE_SUN_ID ||
598226236b5Spjha 	    !serid_printable(&serid)) {
5993c4226f9Spjha 		(void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid);
6003c4226f9Spjha 		return (1);
6013c4226f9Spjha 	}
6023c4226f9Spjha 
603b6b3bf89Spjha 	/*
604226236b5Spjha 	 * the serial id is constructed from lower 40 bits of the serialid
605226236b5Spjha 	 * property and is represented by 5 ascii characters. The first
606226236b5Spjha 	 * character indicates if the IO Box is PCIe or PCI-X.
607b6b3bf89Spjha 	 */
608b6b3bf89Spjha 
609226236b5Spjha 	serid <<= 24;
610226236b5Spjha 	idstr = (char *)&serid;
611226236b5Spjha 	idstr[sizeof (serid) -1] = '\0';
612226236b5Spjha 
613226236b5Spjha 	(void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr);
614b6b3bf89Spjha 
6153c4226f9Spjha 	return (1);
6163c4226f9Spjha }
6173c4226f9Spjha 
6183c4226f9Spjha 
619ad86e48dSpjha /*
620ad86e48dSpjha  * returns the pci device number for <node> if found, else returns PCIDEV_NIL
621ad86e48dSpjha  */
6223c4226f9Spjha static minor_t
6233c4226f9Spjha pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph)
6243c4226f9Spjha {
6253c4226f9Spjha 	int rv;
6263c4226f9Spjha 	int *regp;
6273c4226f9Spjha 
6283ebafc43Sjveta 	rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG,
6293c4226f9Spjha 	    &regp);
6303c4226f9Spjha 
6313c4226f9Spjha 	if (rv < 1) {
6323c4226f9Spjha 		dprint(("pci_cfg_pcidev: property %s not found "
6333ebafc43Sjveta 		    "for %s%d\n", DI_PROP_REG, DRVINST(node)));
6344e0386dfSjveta 		return (PCIDEV_NIL);
6353c4226f9Spjha 	}
6363c4226f9Spjha 
6373c4226f9Spjha 	return (REG_PCIDEV(regp));
6383c4226f9Spjha }
6393c4226f9Spjha 
6403c4226f9Spjha 
6413c4226f9Spjha /*
6423c4226f9Spjha  * returns non-zero when it can successfully return an attachment point
6433c4226f9Spjha  * through <ap_path> whose length is less than <ap_pathsz>; returns the full
6443c4226f9Spjha  * path of the AP through <pathret> which may be larger than <ap_pathsz>.
6453c4226f9Spjha  * Callers need to free <pathret>.  If it cannot return the full path through
6463c4226f9Spjha  * <pathret> it will be set to NULL
6473c4226f9Spjha  *
6483c4226f9Spjha  * The ap path reflects a subset of the device path from an onboard host slot
6493c4226f9Spjha  * up to <node>.  We traverse up the device tree starting from <node>, naming
6503c4226f9Spjha  * each component using pci_cfg_ap_node().  If we detect that a certain
6513c4226f9Spjha  * segment is contained within an expansion chassis, then we skip any bus
6523c4226f9Spjha  * nodes in between our current node and the topmost node of the chassis,
6533ebafc43Sjveta  * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name
6543c4226f9Spjha  * of the expansion chassis as given by pci_cfg_iob_name()
6553c4226f9Spjha  *
6563c4226f9Spjha  * This scheme is always used for <pathret>.  If however, the size of
6573c4226f9Spjha  * <pathret> is greater than <ap_pathsz> then only the default name as given
6583c4226f9Spjha  * by pci_cfg_ap_node() for <node> will be used
6593c4226f9Spjha  */
6603c4226f9Spjha static int
6613c4226f9Spjha pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
6623c4226f9Spjha     char *ap_path, int ap_pathsz, char **pathret)
6633c4226f9Spjha {
6643c4226f9Spjha #ifdef	DEBUG
6653c4226f9Spjha 	char *fnm = "pci_cfg_ap_path";
6663c4226f9Spjha #endif
6673c4226f9Spjha #define	seplen		(sizeof (AP_PATH_SEP) - 1)
6683c4226f9Spjha #define	iob_pre_len	(sizeof (IOB_PRE) - 1)
6693c4226f9Spjha #define	ap_path_iob_sep_len	(sizeof (AP_PATH_IOB_SEP) - 1)
6703c4226f9Spjha 
6713c4226f9Spjha 	char *bufptr;
6723c4226f9Spjha 	char buf[MAXPATHLEN];
6733c4226f9Spjha 	char pathbuf[MAXPATHLEN];
6743c4226f9Spjha 	int bufsz;
6753c4226f9Spjha 	char *pathptr;
6763c4226f9Spjha 	char *pathend = NULL;
6773c4226f9Spjha 	int len;
6783c4226f9Spjha 	int rv = 0;
6793c4226f9Spjha 	int chasflag = 0;
6803c4226f9Spjha 	di_node_t curnode = node;
6813c4226f9Spjha 	di_node_t chasnode = DI_NODE_NIL;
6827c478bd9Sstevel@tonic-gate 	minor_t pci_dev;
6837c478bd9Sstevel@tonic-gate 
6843c4226f9Spjha 	buf[0] = '\0';
6853c4226f9Spjha 	pathbuf[0] = '\0';
6863c4226f9Spjha 	pathptr = &pathbuf[sizeof (pathbuf) - 1];
6873c4226f9Spjha 	*pathptr = '\0';
6887c478bd9Sstevel@tonic-gate 
6893c4226f9Spjha 	/*
6903c4226f9Spjha 	 * as we traverse up the device tree, we prepend components of our
6913c4226f9Spjha 	 * path inside pathbuf, using pathptr and decrementing
6923c4226f9Spjha 	 */
6933c4226f9Spjha 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
6943c4226f9Spjha 	do {
6953c4226f9Spjha 		bufptr = buf;
6963c4226f9Spjha 		bufsz = sizeof (buf);
6973c4226f9Spjha 
6983c4226f9Spjha 		chasnode = pci_cfg_chassis_node(curnode, ph);
6993c4226f9Spjha 		if (chasnode != DI_NODE_NIL) {
7003c4226f9Spjha 			rv = pci_cfg_iob_name(minor, chasnode, ph,
7013c4226f9Spjha 			    bufptr, bufsz);
7023c4226f9Spjha 			if (rv == 0) {
7033c4226f9Spjha 				dprint(("%s: cannot create iob name "
7043c4226f9Spjha 				    "for %s%d\n", fnm, DRVINST(node)));
7053c4226f9Spjha 				*pathptr = '\0';
7063c4226f9Spjha 				goto OUT;
7073c4226f9Spjha 			}
7083c4226f9Spjha 
7093c4226f9Spjha 			(void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz);
7103c4226f9Spjha 			len = strlen(bufptr);
7113c4226f9Spjha 			bufptr += len;
7123c4226f9Spjha 			bufsz -= len - 1;
7133c4226f9Spjha 
7143c4226f9Spjha 			/* set chasflag when the leaf node is within an iob */
7153c4226f9Spjha 			if ((curnode == node) != NULL)
7163c4226f9Spjha 				chasflag = 1;
7173c4226f9Spjha 		}
7183c4226f9Spjha 		rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0);
7193c4226f9Spjha 		if (rv == 0) {
7203c4226f9Spjha 			dprint(("%s: cannot create ap node name "
7213c4226f9Spjha 			    "for %s%d\n", fnm, DRVINST(node)));
7223c4226f9Spjha 			*pathptr = '\0';
7233c4226f9Spjha 			goto OUT;
7243c4226f9Spjha 		}
7253c4226f9Spjha 
7263c4226f9Spjha 		/*
7273c4226f9Spjha 		 * if we can't fit the entire path in our pathbuf, then use
7283c4226f9Spjha 		 * the default short name and nullify pathptr; also, since
7293c4226f9Spjha 		 * we prepend in the buffer, we must avoid adding a null char
7303c4226f9Spjha 		 */
7313c4226f9Spjha 		if (curnode != node) {
7323c4226f9Spjha 			pathptr -= seplen;
7333c4226f9Spjha 			if (pathptr < pathbuf) {
7343c4226f9Spjha 				pathptr = pathbuf;
7353c4226f9Spjha 				*pathptr = '\0';
7363c4226f9Spjha 				goto DEF;
7373c4226f9Spjha 			}
7383c4226f9Spjha 			(void) memcpy(pathptr, AP_PATH_SEP, seplen);
7393c4226f9Spjha 		}
7403c4226f9Spjha 		len = strlen(buf);
7413c4226f9Spjha 		pathptr -= len;
7423c4226f9Spjha 		if (pathptr < pathbuf) {
7433c4226f9Spjha 			pathptr = pathbuf;
7443c4226f9Spjha 			*pathptr = '\0';
7453c4226f9Spjha 			goto DEF;
7463c4226f9Spjha 		}
7473c4226f9Spjha 		(void) memcpy(pathptr, buf, len);
7483c4226f9Spjha 
7493c4226f9Spjha 		/* remember the leaf component */
7503c4226f9Spjha 		if (curnode == node)
7513c4226f9Spjha 			pathend = pathptr;
7523c4226f9Spjha 
7533c4226f9Spjha 		/*
7543c4226f9Spjha 		 * go no further than the hosts' onboard slots
7553c4226f9Spjha 		 */
7563c4226f9Spjha 		if (chasnode == DI_NODE_NIL)
7573c4226f9Spjha 			break;
7583c4226f9Spjha 		curnode = chasnode;
7593c4226f9Spjha 
7603c4226f9Spjha 		/*
7613c4226f9Spjha 		 * the pci device number of the current node is used to
7623c4226f9Spjha 		 * identify which slot of the parent's bus (next iteration)
7633c4226f9Spjha 		 * the current node is on
7643c4226f9Spjha 		 */
7653c4226f9Spjha 		pci_dev = pci_cfg_pcidev(curnode, ph);
766ad86e48dSpjha 		if (pci_dev == PCIDEV_NIL) {
767ad86e48dSpjha 			dprint(("%s: cannot obtain pci device number "
768ad86e48dSpjha 			    "for %s%d\n", fnm, DRVINST(node)));
769ad86e48dSpjha 			*pathptr = '\0';
770ad86e48dSpjha 			goto OUT;
771ad86e48dSpjha 		}
7723c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
7733c4226f9Spjha 
7743c4226f9Spjha 	pathbuf[sizeof (pathbuf) - 1] = '\0';
7753c4226f9Spjha 	if (strlen(pathptr) < ap_pathsz) {
7763c4226f9Spjha 		(void) strlcpy(ap_path, pathptr, ap_pathsz);
7773c4226f9Spjha 		rv = 1;
7783c4226f9Spjha 		goto OUT;
7793c4226f9Spjha 	}
7803c4226f9Spjha 
7813c4226f9Spjha DEF:
7823c4226f9Spjha 	/*
7833c4226f9Spjha 	 * when our name won't fit <ap_pathsz> we use the endpoint/leaf
7843c4226f9Spjha 	 * <node>'s name ONLY IF it has a serialid# which will make the apid
7853c4226f9Spjha 	 * globally unique
7863c4226f9Spjha 	 */
7873c4226f9Spjha 	if (chasflag && pathend != NULL) {
7883c4226f9Spjha 		if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP,
7893c4226f9Spjha 		    ap_path_iob_sep_len) != 0) &&
7903c4226f9Spjha 		    (strlen(pathend) < ap_pathsz)) {
7913c4226f9Spjha 			(void) strlcpy(ap_path, pathend, ap_pathsz);
7923c4226f9Spjha 			rv = 1;
7933c4226f9Spjha 			goto OUT;
7947c478bd9Sstevel@tonic-gate 		}
7957c478bd9Sstevel@tonic-gate 	}
7967c478bd9Sstevel@tonic-gate 
7973c4226f9Spjha 	/*
7983c4226f9Spjha 	 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s
7993c4226f9Spjha 	 * default name
8003c4226f9Spjha 	 */
8013e655c7dSjveta 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
8023c4226f9Spjha 	rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME);
8033c4226f9Spjha 	if (rv == 0) {
8043c4226f9Spjha 		dprint(("%s: cannot create default ap node name for %s%d\n",
8053c4226f9Spjha 		    fnm, DRVINST(node)));
8063c4226f9Spjha 		*pathptr = '\0';
8073c4226f9Spjha 		goto OUT;
8083c4226f9Spjha 	}
8093c4226f9Spjha 	if (strlen(buf) < ap_pathsz) {
8103c4226f9Spjha 		(void) strlcpy(ap_path, buf, ap_pathsz);
8113c4226f9Spjha 		rv = 1;
8123c4226f9Spjha 		goto OUT;
8133c4226f9Spjha 	}
8143c4226f9Spjha 
8153c4226f9Spjha 	/*
8163c4226f9Spjha 	 * in this case, cfgadm goes through an expensive process to generate
8173c4226f9Spjha 	 * a purely dynamic logical apid: the framework will look through
8183c4226f9Spjha 	 * the device tree for attachment point minor nodes and will invoke
8193c4226f9Spjha 	 * each plugin responsible for that attachment point class, and if
8203c4226f9Spjha 	 * the plugin returns a logical apid that matches the queried apid
8213c4226f9Spjha 	 * or matches the default apid generated by the cfgadm framework for
8223c4226f9Spjha 	 * that driver/class (occurs when plugin returns an empty logical apid)
8233c4226f9Spjha 	 * then that is what it will use
8243c4226f9Spjha 	 *
8253c4226f9Spjha 	 * it is doubly expensive because the cfgadm pci plugin itself will
8263c4226f9Spjha 	 * also search the entire device tree in the absence of a link
8273c4226f9Spjha 	 */
8283c4226f9Spjha 	rv = 0;
8293c4226f9Spjha 	dprint(("%s: cannot create apid for %s%d within length of %d\n",
8303c4226f9Spjha 	    fnm, DRVINST(node), ap_pathsz));
8313c4226f9Spjha 
8323c4226f9Spjha OUT:
8333c4226f9Spjha 	ap_path[ap_pathsz - 1] = '\0';
8343c4226f9Spjha 	*pathret = (*pathptr == '\0') ? NULL : strdup(pathptr);
8353c4226f9Spjha 	return (rv);
8363c4226f9Spjha 
8373c4226f9Spjha #undef	seplen
8383c4226f9Spjha #undef	iob_pre_len
8393c4226f9Spjha #undef	ap_path_iob_sep_len
8403c4226f9Spjha }
8413c4226f9Spjha 
8423c4226f9Spjha 
8433c4226f9Spjha /*
8443ebafc43Sjveta  * the DI_PROP_AP_NAMES property contains the first integer section of the
8453c4226f9Spjha  * ieee1275 "slot-names" property and functions as a bitmask; see comment for
8463c4226f9Spjha  * pci_cfg_slotname()
8473c4226f9Spjha  *
8483c4226f9Spjha  * we use the name of the attachment point minor node if its pci device
8493ebafc43Sjveta  * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES
8503c4226f9Spjha  *
8513c4226f9Spjha  * returns non-zero if we return a valid attachment point through <path>
8523c4226f9Spjha  */
8533c4226f9Spjha static int
8543c4226f9Spjha pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
8553c4226f9Spjha     char *ap_path, int ap_pathsz)
8563c4226f9Spjha {
8573c4226f9Spjha 	minor_t pci_dev;
8583c4226f9Spjha 	int *anp;
8593c4226f9Spjha 
8603ebafc43Sjveta 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES,
8613c4226f9Spjha 	    &anp) < 1)
8623c4226f9Spjha 		return (0);
8633c4226f9Spjha 
8643c4226f9Spjha 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
8653c4226f9Spjha 	if ((*anp & (1 << pci_dev)) == 0)
8663c4226f9Spjha 		return (0);
8673c4226f9Spjha 
8683c4226f9Spjha 	(void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz);
8693c4226f9Spjha 	return (1);
8703c4226f9Spjha }
8713c4226f9Spjha 
8723c4226f9Spjha 
8733c4226f9Spjha /*
8743c4226f9Spjha  * determine if <node> qualifies for a path style apid
8753c4226f9Spjha  */
8763c4226f9Spjha static int
8773c4226f9Spjha pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph)
8783c4226f9Spjha {
8793c4226f9Spjha 	char *devtype;
8803c4226f9Spjha 	di_node_t curnode = node;
8813c4226f9Spjha 
8823c4226f9Spjha 	do {
8833c4226f9Spjha 		if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode,
8843ebafc43Sjveta 		    DI_PROP_DEV_TYPE, &devtype) > 0)
8853c4226f9Spjha 			if (strcmp(devtype, PROPVAL_PCIEX) == 0)
8863c4226f9Spjha 				return (1);
8873c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
8883c4226f9Spjha 
8893c4226f9Spjha 	return (0);
8903c4226f9Spjha }
8913c4226f9Spjha 
8923c4226f9Spjha 
8933c4226f9Spjha /*
8943c4226f9Spjha  * takes a full path as returned by <pathret> from pci_cfg_ap_path() and
8953c4226f9Spjha  * returns an allocated string intendend to be stored in a devlink info (dli)
8963c4226f9Spjha  * file
8973c4226f9Spjha  *
8983c4226f9Spjha  * data format: "Location: <transformed path>"
8993c4226f9Spjha  * where <transformed path> is <path> with occurrances of AP_PATH_SEP
9003c4226f9Spjha  * replaced by "/"
9013c4226f9Spjha  */
9023c4226f9Spjha static char *
9033c4226f9Spjha pci_cfg_info_data(char *path)
9043c4226f9Spjha {
9053c4226f9Spjha #define	head	"Location: "
9063c4226f9Spjha #define	headlen	(sizeof (head) - 1)
9073c4226f9Spjha #define	seplen	(sizeof (AP_PATH_SEP) - 1)
9083c4226f9Spjha 
9093c4226f9Spjha 	char *sep, *prev, *np;
9103c4226f9Spjha 	char *newpath;
9113c4226f9Spjha 	int pathlen = strlen(path);
9123c4226f9Spjha 	int len;
9133c4226f9Spjha 
9143c4226f9Spjha 	newpath = malloc(sizeof (char) * (headlen + pathlen + 1));
9153c4226f9Spjha 	np = newpath;
9163c4226f9Spjha 	(void) strcpy(np, head);
9173c4226f9Spjha 	np += headlen;
9183c4226f9Spjha 
9193c4226f9Spjha 	prev = path;
9203c4226f9Spjha 	while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) {
9213c4226f9Spjha 		len = sep - prev;
9223c4226f9Spjha 		(void) memcpy(np, prev, len);
9233c4226f9Spjha 		np += len;
9243c4226f9Spjha 		*np++ = '/';
9253c4226f9Spjha 		prev = sep + seplen;
9263c4226f9Spjha 	}
9273c4226f9Spjha 	(void) strcpy(np, prev);
9283c4226f9Spjha 	return (newpath);
9293c4226f9Spjha 
9303c4226f9Spjha #undef	head
9313c4226f9Spjha #undef	headlen
9323c4226f9Spjha #undef	seplen
9333c4226f9Spjha }
9343c4226f9Spjha 
9353c4226f9Spjha 
9363c4226f9Spjha static void
9373c4226f9Spjha pci_cfg_rm_link(char *file)
9383c4226f9Spjha {
9393c4226f9Spjha 	char *dlipath;
9403c4226f9Spjha 
9413c4226f9Spjha 	dlipath = di_dli_name(file);
9423c4226f9Spjha 	(void) unlink(dlipath);
9433c4226f9Spjha 
9443c4226f9Spjha 	devfsadm_rm_all(file);
9453c4226f9Spjha 	free(dlipath);
9463c4226f9Spjha }
9473c4226f9Spjha 
9483c4226f9Spjha /*
9493c4226f9Spjha  * removes all registered devlinks to physical path <physpath> except for
9503c4226f9Spjha  * the devlink <valid> if not NULL;
9513c4226f9Spjha  * <physpath> must include the minor node
9523c4226f9Spjha  */
9533c4226f9Spjha static void
9543c4226f9Spjha pci_cfg_rm_invalid_links(char *physpath, char *valid)
9553c4226f9Spjha {
9563c4226f9Spjha 	char **dnp;
9573c4226f9Spjha 	char *cp, *vcp;
9583c4226f9Spjha 	int i, dnlen;
9593c4226f9Spjha 
9603c4226f9Spjha 	dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen);
9613c4226f9Spjha 	if (dnp == NULL)
9623c4226f9Spjha 		return;
9633c4226f9Spjha 
9643c4226f9Spjha 	if (valid != NULL) {
9653c4226f9Spjha 		if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0)
9663c4226f9Spjha 			vcp = valid + DEV_LEN + 1;
9673c4226f9Spjha 		else
9683c4226f9Spjha 			vcp = valid;
9693c4226f9Spjha 	}
9703c4226f9Spjha 
9713c4226f9Spjha 	for (i = 0; i < dnlen; i++) {
9723c4226f9Spjha 		if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0)
9733c4226f9Spjha 			cp = dnp[i] + DEV_LEN + 1;
9743c4226f9Spjha 		else
9753c4226f9Spjha 			cp = dnp[i];
9763c4226f9Spjha 
9773c4226f9Spjha 		if (valid != NULL) {
9783c4226f9Spjha 			if (strcmp(vcp, cp) == 0)
9793c4226f9Spjha 				continue;
9803c4226f9Spjha 		}
9813c4226f9Spjha 		pci_cfg_rm_link(cp);
9823c4226f9Spjha 	}
9833c4226f9Spjha 	devfsadm_free_dev_names(dnp, dnlen);
9843c4226f9Spjha }
9853c4226f9Spjha 
9863c4226f9Spjha 
9873c4226f9Spjha /*
9883c4226f9Spjha  * takes a complete devinfo snapshot and returns the root node;
9893c4226f9Spjha  * callers must do a di_fini() on the returned node;
9903c4226f9Spjha  * if the snapshot failed, DI_NODE_NIL is returned instead
9913c4226f9Spjha  *
9923c4226f9Spjha  * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node
9933c4226f9Spjha  * in the new snapshot and return it through <ret_node> if it is found,
9943c4226f9Spjha  * else DI_NODE_NIL is returned instead
9953c4226f9Spjha  *
9963c4226f9Spjha  * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return
9973c4226f9Spjha  * the matching minor in the new snapshot through <ret_minor> if it is found,
9983c4226f9Spjha  * else DI_MINOR_NIL is returned instead
9993c4226f9Spjha  */
10003c4226f9Spjha static di_node_t
10013c4226f9Spjha pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor,
10023c4226f9Spjha     di_node_t *ret_node, di_minor_t *ret_minor)
10033c4226f9Spjha {
10043c4226f9Spjha 	di_node_t root_node;
10053c4226f9Spjha 	di_node_t node;
10063c4226f9Spjha 	di_minor_t minor;
10073c4226f9Spjha 	int pci_inst;
10083c4226f9Spjha 	dev_t pci_devt;
10093c4226f9Spjha 
10103c4226f9Spjha 	*ret_node = DI_NODE_NIL;
10113c4226f9Spjha 	*ret_minor = DI_MINOR_NIL;
10123c4226f9Spjha 
10133c4226f9Spjha 	root_node = di_init("/", DINFOCPYALL);
10143c4226f9Spjha 	if (root_node == DI_NODE_NIL)
10153c4226f9Spjha 		return (DI_NODE_NIL);
10163c4226f9Spjha 
10173c4226f9Spjha 	/*
10183c4226f9Spjha 	 * narrow down search by driver, then instance, then minor
10193c4226f9Spjha 	 */
10203c4226f9Spjha 	if (pci_node == DI_NODE_NIL)
10213c4226f9Spjha 		return (root_node);
10223c4226f9Spjha 
10233c4226f9Spjha 	pci_inst = di_instance(pci_node);
10243c4226f9Spjha 	node = di_drv_first_node(di_driver_name(pci_node), root_node);
10253c4226f9Spjha 	do {
10263c4226f9Spjha 		if (pci_inst == di_instance(node)) {
10273c4226f9Spjha 			*ret_node = node;
10283c4226f9Spjha 			break;
10293c4226f9Spjha 		}
10303c4226f9Spjha 	} while ((node = di_drv_next_node(node)) != DI_NODE_NIL);
10313c4226f9Spjha 
10323c4226f9Spjha 	if (node == DI_NODE_NIL)
10333c4226f9Spjha 		return (root_node);
10343c4226f9Spjha 
10353c4226f9Spjha 	/*
10363c4226f9Spjha 	 * found node, now search minors
10373c4226f9Spjha 	 */
10383c4226f9Spjha 	if (pci_minor == DI_MINOR_NIL)
10393c4226f9Spjha 		return (root_node);
10403c4226f9Spjha 
10413c4226f9Spjha 	pci_devt = di_minor_devt(pci_minor);
10423c4226f9Spjha 	minor = DI_MINOR_NIL;
10433c4226f9Spjha 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
10443c4226f9Spjha 		if (pci_devt == di_minor_devt(minor)) {
10453c4226f9Spjha 			*ret_minor = minor;
10463c4226f9Spjha 			break;
10473c4226f9Spjha 		}
10483c4226f9Spjha 	}
10493c4226f9Spjha 	return (root_node);
10503c4226f9Spjha }
10513c4226f9Spjha 
10523c4226f9Spjha 
10533c4226f9Spjha static int
10543c4226f9Spjha pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node)
10553c4226f9Spjha {
10563c4226f9Spjha #ifdef	DEBUG
10573c4226f9Spjha 	char *fnm = "pci_cfg_creat_cb";
10583c4226f9Spjha #endif
10593c4226f9Spjha #define	ap_pathsz	(sizeof (ap_path))
10603c4226f9Spjha 
10613c4226f9Spjha 	char ap_path[CFGA_LOG_EXT_LEN];
10623c4226f9Spjha 	char linkbuf[MAXPATHLEN];
10633c4226f9Spjha 	char *fullpath = NULL;
10643c4226f9Spjha 	char *pathinfo = NULL;
10653c4226f9Spjha 	char *devpath = NULL;
1066ad86e48dSpjha 	int rv, fd = -1;
10673c4226f9Spjha 	size_t sz;
10683c4226f9Spjha 	di_prom_handle_t ph;
10693c4226f9Spjha 	di_node_t node;
10703c4226f9Spjha 	di_node_t root_node = DI_NODE_NIL;
10713c4226f9Spjha 	di_minor_t minor;
10723c4226f9Spjha 
10733c4226f9Spjha 	ph = di_prom_init();
10743c4226f9Spjha 	if (ph == DI_PROM_HANDLE_NIL) {
10753c4226f9Spjha 		dprint(("%s: di_prom_init() failed for %s%d\n",
10763c4226f9Spjha 		    fnm, DRVINST(pci_node)));
10773c4226f9Spjha 		goto OUT;
10783c4226f9Spjha 	}
10793c4226f9Spjha 
10803c4226f9Spjha 	/*
10813c4226f9Spjha 	 * Since incoming nodes from hotplug events are from snapshots that
10823c4226f9Spjha 	 * do NOT contain parent/ancestor data, we must retake our own
10833c4226f9Spjha 	 * snapshot and search for the target node
10843c4226f9Spjha 	 */
10853c4226f9Spjha 	root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor);
10863c4226f9Spjha 	if (root_node == DI_NODE_NIL || node == DI_NODE_NIL ||
10873c4226f9Spjha 	    minor == DI_MINOR_NIL) {
10883c4226f9Spjha 		dprint(("%s: devinfo snapshot or search failed for %s%d\n",
10893c4226f9Spjha 		    fnm, DRVINST(pci_node)));
10903c4226f9Spjha 		goto OUT;
10913c4226f9Spjha 	}
10923c4226f9Spjha 
10933c4226f9Spjha 	if (pci_cfg_is_ap_path(node, ph)) {
10943c4226f9Spjha 		rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz,
10953c4226f9Spjha 		    &fullpath);
10963c4226f9Spjha 		if (rv == 0)
10973c4226f9Spjha 			goto OUT;
10983c4226f9Spjha 
10993c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
11003c4226f9Spjha 		    CFG_DIRNAME, ap_path);
11013c4226f9Spjha 
11023c4226f9Spjha 		/*
11033c4226f9Spjha 		 * We must remove existing links because we may have invalid
11043c4226f9Spjha 		 * apids that are valid links.  Since these are not dangling,
11053c4226f9Spjha 		 * devfsadm will not invoke the remove callback on them.
11063c4226f9Spjha 		 *
11073c4226f9Spjha 		 * What are "invalid apids with valid links"?  Consider swapping
11083c4226f9Spjha 		 * an attachment point bus with another while the system is
11093c4226f9Spjha 		 * down, on the same device path bound to the same drivers
11103c4226f9Spjha 		 * but with the new AP bus having different properties
11113c4226f9Spjha 		 * (e.g. serialid#).  If the previous apid is not removed,
11123c4226f9Spjha 		 * there will now be two different links pointing to the same
11133c4226f9Spjha 		 * attachment point, but only one reflects the correct
11143c4226f9Spjha 		 * logical apid
11153c4226f9Spjha 		 */
11163c4226f9Spjha 		devpath = pci_cfg_devpath(node, minor);
11173c4226f9Spjha 		if (devpath == NULL)
11183c4226f9Spjha 			goto OUT;
11193c4226f9Spjha 		pci_cfg_rm_invalid_links(devpath, linkbuf);
11203c4226f9Spjha 		free(devpath);
11213c4226f9Spjha 
11223c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
11233c4226f9Spjha 
11243c4226f9Spjha 		/*
11253c4226f9Spjha 		 * we store the full logical path of the attachment point for
11263c4226f9Spjha 		 * cfgadm to display in its info field which is useful when
11273c4226f9Spjha 		 * the full logical path exceeds the size limit for logical
11283c4226f9Spjha 		 * apids (CFGA_LOG_EXT_LEN)
11293c4226f9Spjha 		 *
11303c4226f9Spjha 		 * for the cfgadm pci plugin to do the same would be expensive
11313c4226f9Spjha 		 * (i.e. devinfo snapshot + top down exhaustive minor search +
11323c4226f9Spjha 		 * equivalent of pci_cfg_ap_path() on every invocation)
11333c4226f9Spjha 		 *
11343c4226f9Spjha 		 * note that if we do not create a link (pci_cfg_ap_path() is
11353c4226f9Spjha 		 * not successful), that is what cfgadm will do anyways to
11363c4226f9Spjha 		 * create a purely dynamic apid
11373c4226f9Spjha 		 */
11383c4226f9Spjha 		pathinfo = pci_cfg_info_data(fullpath);
11393c4226f9Spjha 		fd = di_dli_openw(linkbuf);
11403c4226f9Spjha 		if (fd < 0)
11413c4226f9Spjha 			goto OUT;
11423c4226f9Spjha 
11433c4226f9Spjha 		sz = strlen(pathinfo) + 1;
11443c4226f9Spjha 		rv = write(fd, pathinfo, sz);
11453c4226f9Spjha 		if (rv < sz) {
11463c4226f9Spjha 			dprint(("%s: could not write full pathinfo to dli "
11473c4226f9Spjha 			    "file for %s%d\n", fnm, DRVINST(node)));
11483c4226f9Spjha 			goto OUT;
11493c4226f9Spjha 		}
11503c4226f9Spjha 		di_dli_close(fd);
11513c4226f9Spjha 	} else {
11523c4226f9Spjha 		rv = pci_cfg_ap_legacy(minor, node, ph, ap_path,
11533c4226f9Spjha 		    ap_pathsz);
11543c4226f9Spjha 		if (rv == 0)
11553c4226f9Spjha 			goto OUT;
11563c4226f9Spjha 
11573c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
11583c4226f9Spjha 		    CFG_DIRNAME, ap_path);
11593c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
11603c4226f9Spjha 	}
11613c4226f9Spjha 
11623c4226f9Spjha OUT:
1163ad86e48dSpjha 	if (fd >= 0)
1164ad86e48dSpjha 		di_dli_close(fd);
11653c4226f9Spjha 	if (fullpath != NULL)
11663c4226f9Spjha 		free(fullpath);
11673c4226f9Spjha 	if (pathinfo != NULL)
11683c4226f9Spjha 		free(pathinfo);
11693c4226f9Spjha 	if (ph != DI_PROM_HANDLE_NIL)
11703c4226f9Spjha 		di_prom_fini(ph);
11713c4226f9Spjha 	if (root_node != DI_NODE_NIL)
11723c4226f9Spjha 		di_fini(root_node);
11737c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
11743c4226f9Spjha 
11753c4226f9Spjha #undef	ap_pathsz
11763c4226f9Spjha }
11773c4226f9Spjha 
11783c4226f9Spjha 
11793c4226f9Spjha static void
11803c4226f9Spjha pci_cfg_rm_all(char *file)
11813c4226f9Spjha {
11823c4226f9Spjha 	pci_cfg_rm_link(file);
11837c478bd9Sstevel@tonic-gate }
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate /*
11877c478bd9Sstevel@tonic-gate  * ib_cfg_creat_cb() creates two types of links
11887c478bd9Sstevel@tonic-gate  * One for the fabric as /dev/cfg/ib
11897c478bd9Sstevel@tonic-gate  * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
11907c478bd9Sstevel@tonic-gate  */
11917c478bd9Sstevel@tonic-gate static int
11927c478bd9Sstevel@tonic-gate ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
11937c478bd9Sstevel@tonic-gate {
11947c478bd9Sstevel@tonic-gate 	char	*cp;
11957c478bd9Sstevel@tonic-gate 	char	path[PATH_MAX + 1];
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	if ((cp = di_devfs_path(node)) == NULL) {
11987c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
11997c478bd9Sstevel@tonic-gate 	}
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
12027c478bd9Sstevel@tonic-gate 	di_devfs_path_free(cp);
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	/* create fabric or hca:GUID and the symlink */
12057c478bd9Sstevel@tonic-gate 	if (strstr(path, "ib:fabric") != NULL) {
12067c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
12077c478bd9Sstevel@tonic-gate 	} else {
12087c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
12097c478bd9Sstevel@tonic-gate 		    di_minor_name(minor));
12107c478bd9Sstevel@tonic-gate 	}
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
12137c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
12147c478bd9Sstevel@tonic-gate }
1215226236b5Spjha 
1216226236b5Spjha /*
1217226236b5Spjha  * This function verifies if the serial id is printable.
1218226236b5Spjha  */
1219226236b5Spjha 
1220226236b5Spjha static int
1221226236b5Spjha serid_printable(uint64_t *seridp)
1222226236b5Spjha {
1223226236b5Spjha 
1224226236b5Spjha 	char *ptr;
1225226236b5Spjha 	int i = 0;
1226226236b5Spjha 
1227226236b5Spjha 	for (ptr = (char *)seridp+3; i < 5; ptr++, i++)
1228226236b5Spjha 		if (*ptr < 0x21 || *ptr >= 0x7f)
1229226236b5Spjha 			return (0);
1230226236b5Spjha 
1231226236b5Spjha 	return (1);
1232226236b5Spjha 
1233226236b5Spjha }
1234