xref: /titanic_51/usr/src/cmd/devfsadm/cfg_link.c (revision ff0e937b36dcde1a47ff7b00aa76a491c0dc07a8)
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*ff0e937bSRaymond Chen  * Copyright 2009 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);
604bb7efa7SGarrett 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
1194bb7efa7SGarrett D'Amore 	},
1204bb7efa7SGarrett D'Amore 	{ "attachment-point", DDI_NT_SDCARD_ATTACHMENT_POINT, NULL,
1214bb7efa7SGarrett 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
1514bb7efa7SGarrett D'Amore 	},
1524bb7efa7SGarrett D'Amore 	{ "attachment-point", SDCARD_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
1534bb7efa7SGarrett D'Amore 	    ILEVEL_0, devfsadm_rm_all
1544bb7efa7SGarrett 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 
2804bb7efa7SGarrett D'Amore static int
2814bb7efa7SGarrett D'Amore sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node)
2824bb7efa7SGarrett D'Amore {
2834bb7efa7SGarrett D'Amore 	char path[PATH_MAX +1], l_path[PATH_MAX], *buf, *devfspath;
2844bb7efa7SGarrett D'Amore 	char *minor_nm;
2854bb7efa7SGarrett D'Amore 	devfsadm_enumerate_t rules[1] =
2864bb7efa7SGarrett D'Amore 	    {"^cfg$/^sdcard([0-9]+)$", 1, MATCH_ADDR};
2874bb7efa7SGarrett D'Amore 
2884bb7efa7SGarrett D'Amore 	minor_nm = di_minor_name(minor);
2894bb7efa7SGarrett D'Amore 	if (minor_nm == NULL)
2904bb7efa7SGarrett D'Amore 		return (DEVFSADM_CONTINUE);
2914bb7efa7SGarrett D'Amore 
2924bb7efa7SGarrett D'Amore 	devfspath = di_devfs_path(node);
2934bb7efa7SGarrett D'Amore 	if (devfspath == NULL)
2944bb7efa7SGarrett D'Amore 		return (DEVFSADM_CONTINUE);
2954bb7efa7SGarrett D'Amore 
2964bb7efa7SGarrett D'Amore 	(void) snprintf(path, sizeof (path), "%s:%s", devfspath, minor_nm);
2974bb7efa7SGarrett D'Amore 	di_devfs_path_free(devfspath);
2984bb7efa7SGarrett D'Amore 
2994bb7efa7SGarrett D'Amore 	/* build the physical path from the components */
3004bb7efa7SGarrett D'Amore 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) ==
3014bb7efa7SGarrett D'Amore 	    DEVFSADM_FAILURE) {
3024bb7efa7SGarrett D'Amore 		return (DEVFSADM_CONTINUE);
3034bb7efa7SGarrett D'Amore 	}
3044bb7efa7SGarrett D'Amore 
3054bb7efa7SGarrett D'Amore 	(void) snprintf(l_path, sizeof (l_path), "%s/sdcard%s/%s",
3064bb7efa7SGarrett D'Amore 	    CFG_DIRNAME, buf, minor_nm);
3074bb7efa7SGarrett D'Amore 	free(buf);
3084bb7efa7SGarrett D'Amore 
3094bb7efa7SGarrett D'Amore 	(void) devfsadm_mklink(l_path, node, minor, 0);
3104bb7efa7SGarrett D'Amore 
3114bb7efa7SGarrett D'Amore 	return (DEVFSADM_CONTINUE);
3124bb7efa7SGarrett 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 		}
359*ff0e937bSRaymond Chen 		/*
360*ff0e937bSRaymond Chen 		 * Check if there is any usb_mid node in the middle
361*ff0e937bSRaymond Chen 		 * and remove the node as if there is an extra '.'
362*ff0e937bSRaymond Chen 		 */
363*ff0e937bSRaymond Chen 		if (strstr(cp, "miscellaneous") != NULL) {
364*ff0e937bSRaymond Chen 			count++;
365*ff0e937bSRaymond Chen 		}
3667c478bd9Sstevel@tonic-gate 		*cp = '\0';
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
369*ff0e937bSRaymond Chen 	/* Remove the usb_mid node immediately before the trailing path */
370*ff0e937bSRaymond Chen 	if ((cp = strrchr(physpath, '/')) != NULL && (cp != physpath)) {
371*ff0e937bSRaymond Chen 		if (strstr(cp, "miscellaneous") != NULL) {
372*ff0e937bSRaymond Chen 			*cp = '\0';
373*ff0e937bSRaymond Chen 		}
374*ff0e937bSRaymond Chen 	}
375*ff0e937bSRaymond Chen 
3767c478bd9Sstevel@tonic-gate 	return (physpath);
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate /*
3813c4226f9Spjha  * returns an allocted string containing the device path for <node> and
3823c4226f9Spjha  * <minor>
3833c4226f9Spjha  */
3843c4226f9Spjha static char *
3853c4226f9Spjha pci_cfg_devpath(di_node_t node, di_minor_t minor)
3863c4226f9Spjha {
3873c4226f9Spjha 	char *path;
3883c4226f9Spjha 	char *bufp;
3893c4226f9Spjha 	char *minor_nm;
3903c4226f9Spjha 	int buflen;
3913c4226f9Spjha 
3923c4226f9Spjha 	path = di_devfs_path(node);
3933c4226f9Spjha 	minor_nm = di_minor_name(minor);
394ad86e48dSpjha 	buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1;
3953c4226f9Spjha 
3963c4226f9Spjha 	bufp = malloc(sizeof (char) * buflen);
397ad86e48dSpjha 	if (bufp != NULL)
3983c4226f9Spjha 		(void) snprintf(bufp, buflen, "%s:%s", path, minor_nm);
3993c4226f9Spjha 
4003c4226f9Spjha 	di_devfs_path_free(path);
4013c4226f9Spjha 	return (bufp);
4023c4226f9Spjha }
4033c4226f9Spjha 
4043c4226f9Spjha 
4053c4226f9Spjha static int
4063c4226f9Spjha di_propall_lookup_ints(di_prom_handle_t ph, int flags,
4073c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, int **prop_data)
4083c4226f9Spjha {
4093c4226f9Spjha 	int rv;
4103c4226f9Spjha 
4113c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
4123c4226f9Spjha 		rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data);
4133c4226f9Spjha 		if (rv < 0)
4143c4226f9Spjha 			rv = di_prop_lookup_ints(dev, node, prop_name,
4153c4226f9Spjha 			    prop_data);
4163c4226f9Spjha 	} else {
4173c4226f9Spjha 		rv = di_prop_lookup_ints(dev, node, prop_name, prop_data);
4183c4226f9Spjha 		if (rv < 0)
4193c4226f9Spjha 			rv = di_prom_prop_lookup_ints(ph, node, prop_name,
4203c4226f9Spjha 			    prop_data);
4213c4226f9Spjha 	}
4223c4226f9Spjha 	return (rv);
4233c4226f9Spjha }
4243c4226f9Spjha 
4253c4226f9Spjha 
4263c4226f9Spjha static int
4273c4226f9Spjha di_propall_lookup_strings(di_prom_handle_t ph, int flags,
4283c4226f9Spjha     dev_t dev, di_node_t node, const char *prop_name, char **prop_data)
4293c4226f9Spjha {
4303c4226f9Spjha 	int rv;
4313c4226f9Spjha 
4323c4226f9Spjha 	if (flags & DIPROP_PRI_PROM) {
4333c4226f9Spjha 		rv = di_prom_prop_lookup_strings(ph, node, prop_name,
4343c4226f9Spjha 		    prop_data);
4353c4226f9Spjha 		if (rv < 0)
4363c4226f9Spjha 			rv = di_prop_lookup_strings(dev, node, prop_name,
4373c4226f9Spjha 			    prop_data);
4383c4226f9Spjha 	} else {
4393c4226f9Spjha 		rv = di_prop_lookup_strings(dev, node, prop_name, prop_data);
4403c4226f9Spjha 		if (rv < 0)
4413c4226f9Spjha 			rv = di_prom_prop_lookup_strings(ph, node, prop_name,
4423c4226f9Spjha 			    prop_data);
4433c4226f9Spjha 	}
4443c4226f9Spjha 	return (rv);
4453c4226f9Spjha }
4463c4226f9Spjha 
4473c4226f9Spjha 
4483c4226f9Spjha static di_node_t
4493c4226f9Spjha pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph)
4503c4226f9Spjha {
4513c4226f9Spjha 	di_node_t curnode = node;
4523c4226f9Spjha 	int *firstchas;
4533c4226f9Spjha 
4543c4226f9Spjha 	do {
4553c4226f9Spjha 		if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode,
4563ebafc43Sjveta 		    DI_PROP_FIRST_CHAS, &firstchas) >= 0)
4573c4226f9Spjha 			return (curnode);
4583c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
4593c4226f9Spjha 
4603c4226f9Spjha 	return (DI_NODE_NIL);
4613c4226f9Spjha }
4623c4226f9Spjha 
4633c4226f9Spjha 
4643ebafc43Sjveta static int
4653ebafc43Sjveta di_propall_lookup_slot_names(di_prom_handle_t ph, int flags,
4663ebafc43Sjveta     dev_t dev, di_node_t node, di_slot_name_t **prop_data)
4673ebafc43Sjveta {
4683ebafc43Sjveta 	int rv;
4693ebafc43Sjveta 
4703ebafc43Sjveta 	if (flags & DIPROP_PRI_PROM) {
4713ebafc43Sjveta 		rv = di_prom_prop_lookup_slot_names(ph, node, prop_data);
4723ebafc43Sjveta 		if (rv < 0)
4733ebafc43Sjveta 			rv = di_prop_lookup_slot_names(dev, node, prop_data);
4743ebafc43Sjveta 	} else {
4753ebafc43Sjveta 		rv = di_prop_lookup_slot_names(dev, node, prop_data);
4763ebafc43Sjveta 		if (rv < 0)
4773ebafc43Sjveta 			rv = di_prom_prop_lookup_slot_names(ph, node,
4783ebafc43Sjveta 			    prop_data);
4793ebafc43Sjveta 	}
4803ebafc43Sjveta 	return (rv);
4813ebafc43Sjveta }
4823ebafc43Sjveta 
4833c4226f9Spjha /*
4843ebafc43Sjveta  * returns an allocated string containing the slot name for the slot with
4853ebafc43Sjveta  * device number <pci_dev> on bus <node>
4863c4226f9Spjha  */
4873c4226f9Spjha static char *
4883c4226f9Spjha pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev)
4893c4226f9Spjha {
4903c4226f9Spjha #ifdef	DEBUG
4913c4226f9Spjha 	char *fnm = "pci_cfg_slotname";
4923c4226f9Spjha #endif
4933ebafc43Sjveta 	int i, count;
4943ebafc43Sjveta 	char *name = NULL;
4953ebafc43Sjveta 	di_slot_name_t *slot_names = NULL;
4963c4226f9Spjha 
4973ebafc43Sjveta 	count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node,
4983ebafc43Sjveta 	    &slot_names);
4993ebafc43Sjveta 	if (count < 0)
5003c4226f9Spjha 		return (NULL);
5013c4226f9Spjha 
5023ebafc43Sjveta 	for (i = 0; i < count; i++) {
5033ebafc43Sjveta 		if (slot_names[i].num == (int)pci_dev) {
5043ebafc43Sjveta 			name = strdup(slot_names[i].name);
5053c4226f9Spjha 			break;
5063c4226f9Spjha 		}
5073c4226f9Spjha 	}
5083ebafc43Sjveta #ifdef	DEBUG
5093ebafc43Sjveta 	if (name == NULL)
5103ebafc43Sjveta 		dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n",
5113ebafc43Sjveta 		    fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node)));
5123ebafc43Sjveta #endif
5133ebafc43Sjveta 	if (count > 0)
5143ebafc43Sjveta 		di_slot_names_free(count, slot_names);
5153ebafc43Sjveta 	return (name);
5163c4226f9Spjha }
5173c4226f9Spjha 
5183c4226f9Spjha 
5193c4226f9Spjha /*
5203c4226f9Spjha  * returns non-zero if we can return a valid attachment point name for <node>,
5213c4226f9Spjha  * for its slot identified by child pci device number <pci_dev>, through <buf>
5223c4226f9Spjha  *
5233c4226f9Spjha  * prioritized naming scheme:
5243ebafc43Sjveta  *	1) <DI_PROP_SLOT_NAMES property>    (see pci_cfg_slotname())
5253ebafc43Sjveta  *	2) <device-type><DI_PROP_PHYS_SLOT property>
5263c4226f9Spjha  *	3) <drv name><drv inst>.<device-type><pci_dev>
5273c4226f9Spjha  *
5283ebafc43Sjveta  * where <device-type> is derived from the DI_PROP_DEV_TYPE property:
5293c4226f9Spjha  *	if its value is "pciex" then <device-type> is "pcie"
5303c4226f9Spjha  *	else the raw value is used
5313c4226f9Spjha  *
5323c4226f9Spjha  * if <flags> contains APNODE_DEFNAME, then scheme (3) is used
5337c478bd9Sstevel@tonic-gate  */
5347c478bd9Sstevel@tonic-gate static int
5353c4226f9Spjha pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph,
5363c4226f9Spjha     char *buf, int bufsz, int flags)
5377c478bd9Sstevel@tonic-gate {
5383c4226f9Spjha 	int *nump;
5393c4226f9Spjha 	int rv;
5403c4226f9Spjha 	char *str, *devtype;
5413c4226f9Spjha 
5423c4226f9Spjha 	rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node,
5433ebafc43Sjveta 	    DI_PROP_DEV_TYPE, &devtype);
5443c4226f9Spjha 	if (rv < 1)
5453c4226f9Spjha 		return (0);
5463c4226f9Spjha 
5473c4226f9Spjha 	if (strcmp(devtype, PROPVAL_PCIEX) == 0)
5483c4226f9Spjha 		devtype = DEVTYPE_PCIE;
5493c4226f9Spjha 
5503c4226f9Spjha 	if (flags & APNODE_DEFNAME)
5513c4226f9Spjha 		goto DEF;
5523c4226f9Spjha 
5533c4226f9Spjha 	str = pci_cfg_slotname(node, ph, pci_dev);
5543c4226f9Spjha 	if (str != NULL) {
5553c4226f9Spjha 		(void) strlcpy(buf, str, bufsz);
5563ebafc43Sjveta 		free(str);
5573c4226f9Spjha 		return (1);
5583c4226f9Spjha 	}
5593c4226f9Spjha 
5603ebafc43Sjveta 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node,
5613ebafc43Sjveta 	    DI_PROP_PHYS_SLOT, &nump) > 0) {
5623c4226f9Spjha 		if (*nump > 0) {
5633c4226f9Spjha 			(void) snprintf(buf, bufsz, "%s%d", devtype, *nump);
5643c4226f9Spjha 			return (1);
5653c4226f9Spjha 		}
5663c4226f9Spjha 	}
5673c4226f9Spjha DEF:
5683c4226f9Spjha 	(void) snprintf(buf, bufsz, "%s%d.%s%d",
5693c4226f9Spjha 	    di_driver_name(node), di_instance(node), devtype, pci_dev);
5703c4226f9Spjha 
5713c4226f9Spjha 	return (1);
5723c4226f9Spjha }
5733c4226f9Spjha 
5743c4226f9Spjha 
5753c4226f9Spjha /*
5763c4226f9Spjha  * returns non-zero if we can return a valid expansion chassis name for <node>
5773c4226f9Spjha  * through <buf>
5783c4226f9Spjha  *
5793c4226f9Spjha  * prioritized naming scheme:
5803ebafc43Sjveta  *	1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion>
5813ebafc43Sjveta  *	2) <IOB_PRE string><full DI_PROP_SERID property in hex>
5823c4226f9Spjha  *	3) <IOB_PRE string>
5833c4226f9Spjha  *
5843ebafc43Sjveta  * DI_PROP_SERID encoding <64-bit int: msb ... lsb>:
585b6b3bf89Spjha  * <24 bits: IEEE company id><40 bits: serial number>
5863c4226f9Spjha  *
5873c4226f9Spjha  * sun encoding of 40 bit serial number:
588226236b5Spjha  * first byte = device type indicator
5893c4226f9Spjha  * next 4 bytes = 4 ascii characters
590226236b5Spjha  *
591226236b5Spjha  * In the unlikely event that serial id contains non-printable characters
592226236b5Spjha  * the full 64 bit raw hex string will be used for the attachment point.
5933c4226f9Spjha  */
5943c4226f9Spjha /*ARGSUSED*/
5953c4226f9Spjha static int
5963c4226f9Spjha pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
5973c4226f9Spjha     char *buf, int bufsz)
5983c4226f9Spjha {
5993c4226f9Spjha 	int64_t *seridp;
600b6b3bf89Spjha 	uint64_t serid;
601226236b5Spjha 	char *idstr;
6023c4226f9Spjha 
6033ebafc43Sjveta 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID,
6043c4226f9Spjha 	    &seridp) < 1) {
6053c4226f9Spjha 		(void) strlcpy(buf, IOB_PRE, bufsz);
6063c4226f9Spjha 		return (1);
6073c4226f9Spjha 	}
608226236b5Spjha 
609b6b3bf89Spjha 	serid = (uint64_t)*seridp;
6103c4226f9Spjha 
611226236b5Spjha 	if ((serid >> 40) != (uint64_t)IEEE_SUN_ID ||
612226236b5Spjha 	    !serid_printable(&serid)) {
6133c4226f9Spjha 		(void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid);
6143c4226f9Spjha 		return (1);
6153c4226f9Spjha 	}
6163c4226f9Spjha 
617b6b3bf89Spjha 	/*
618226236b5Spjha 	 * the serial id is constructed from lower 40 bits of the serialid
619226236b5Spjha 	 * property and is represented by 5 ascii characters. The first
620226236b5Spjha 	 * character indicates if the IO Box is PCIe or PCI-X.
621b6b3bf89Spjha 	 */
622b6b3bf89Spjha 
623226236b5Spjha 	serid <<= 24;
624226236b5Spjha 	idstr = (char *)&serid;
625226236b5Spjha 	idstr[sizeof (serid) -1] = '\0';
626226236b5Spjha 
627226236b5Spjha 	(void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr);
628b6b3bf89Spjha 
6293c4226f9Spjha 	return (1);
6303c4226f9Spjha }
6313c4226f9Spjha 
6323c4226f9Spjha 
633ad86e48dSpjha /*
634ad86e48dSpjha  * returns the pci device number for <node> if found, else returns PCIDEV_NIL
635ad86e48dSpjha  */
6363c4226f9Spjha static minor_t
6373c4226f9Spjha pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph)
6383c4226f9Spjha {
6393c4226f9Spjha 	int rv;
6403c4226f9Spjha 	int *regp;
6413c4226f9Spjha 
6423ebafc43Sjveta 	rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG,
6433c4226f9Spjha 	    &regp);
6443c4226f9Spjha 
6453c4226f9Spjha 	if (rv < 1) {
6463c4226f9Spjha 		dprint(("pci_cfg_pcidev: property %s not found "
6473ebafc43Sjveta 		    "for %s%d\n", DI_PROP_REG, DRVINST(node)));
6484e0386dfSjveta 		return (PCIDEV_NIL);
6493c4226f9Spjha 	}
6503c4226f9Spjha 
6513c4226f9Spjha 	return (REG_PCIDEV(regp));
6523c4226f9Spjha }
6533c4226f9Spjha 
6543c4226f9Spjha 
6553c4226f9Spjha /*
6563c4226f9Spjha  * returns non-zero when it can successfully return an attachment point
6573c4226f9Spjha  * through <ap_path> whose length is less than <ap_pathsz>; returns the full
6583c4226f9Spjha  * path of the AP through <pathret> which may be larger than <ap_pathsz>.
6593c4226f9Spjha  * Callers need to free <pathret>.  If it cannot return the full path through
6603c4226f9Spjha  * <pathret> it will be set to NULL
6613c4226f9Spjha  *
6623c4226f9Spjha  * The ap path reflects a subset of the device path from an onboard host slot
6633c4226f9Spjha  * up to <node>.  We traverse up the device tree starting from <node>, naming
6643c4226f9Spjha  * each component using pci_cfg_ap_node().  If we detect that a certain
6653c4226f9Spjha  * segment is contained within an expansion chassis, then we skip any bus
6663c4226f9Spjha  * nodes in between our current node and the topmost node of the chassis,
6673ebafc43Sjveta  * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name
6683c4226f9Spjha  * of the expansion chassis as given by pci_cfg_iob_name()
6693c4226f9Spjha  *
6703c4226f9Spjha  * This scheme is always used for <pathret>.  If however, the size of
6713c4226f9Spjha  * <pathret> is greater than <ap_pathsz> then only the default name as given
6723c4226f9Spjha  * by pci_cfg_ap_node() for <node> will be used
6733c4226f9Spjha  */
6743c4226f9Spjha static int
6753c4226f9Spjha pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
6763c4226f9Spjha     char *ap_path, int ap_pathsz, char **pathret)
6773c4226f9Spjha {
6783c4226f9Spjha #ifdef	DEBUG
6793c4226f9Spjha 	char *fnm = "pci_cfg_ap_path";
6803c4226f9Spjha #endif
6813c4226f9Spjha #define	seplen		(sizeof (AP_PATH_SEP) - 1)
6823c4226f9Spjha #define	iob_pre_len	(sizeof (IOB_PRE) - 1)
6833c4226f9Spjha #define	ap_path_iob_sep_len	(sizeof (AP_PATH_IOB_SEP) - 1)
6843c4226f9Spjha 
6853c4226f9Spjha 	char *bufptr;
6863c4226f9Spjha 	char buf[MAXPATHLEN];
6873c4226f9Spjha 	char pathbuf[MAXPATHLEN];
6883c4226f9Spjha 	int bufsz;
6893c4226f9Spjha 	char *pathptr;
6903c4226f9Spjha 	char *pathend = NULL;
6913c4226f9Spjha 	int len;
6923c4226f9Spjha 	int rv = 0;
6933c4226f9Spjha 	int chasflag = 0;
6943c4226f9Spjha 	di_node_t curnode = node;
6953c4226f9Spjha 	di_node_t chasnode = DI_NODE_NIL;
6967c478bd9Sstevel@tonic-gate 	minor_t pci_dev;
6977c478bd9Sstevel@tonic-gate 
6983c4226f9Spjha 	buf[0] = '\0';
6993c4226f9Spjha 	pathbuf[0] = '\0';
7003c4226f9Spjha 	pathptr = &pathbuf[sizeof (pathbuf) - 1];
7013c4226f9Spjha 	*pathptr = '\0';
7027c478bd9Sstevel@tonic-gate 
7033c4226f9Spjha 	/*
7043c4226f9Spjha 	 * as we traverse up the device tree, we prepend components of our
7053c4226f9Spjha 	 * path inside pathbuf, using pathptr and decrementing
7063c4226f9Spjha 	 */
7073c4226f9Spjha 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
7083c4226f9Spjha 	do {
7093c4226f9Spjha 		bufptr = buf;
7103c4226f9Spjha 		bufsz = sizeof (buf);
7113c4226f9Spjha 
7123c4226f9Spjha 		chasnode = pci_cfg_chassis_node(curnode, ph);
7133c4226f9Spjha 		if (chasnode != DI_NODE_NIL) {
7143c4226f9Spjha 			rv = pci_cfg_iob_name(minor, chasnode, ph,
7153c4226f9Spjha 			    bufptr, bufsz);
7163c4226f9Spjha 			if (rv == 0) {
7173c4226f9Spjha 				dprint(("%s: cannot create iob name "
7183c4226f9Spjha 				    "for %s%d\n", fnm, DRVINST(node)));
7193c4226f9Spjha 				*pathptr = '\0';
7203c4226f9Spjha 				goto OUT;
7213c4226f9Spjha 			}
7223c4226f9Spjha 
7233c4226f9Spjha 			(void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz);
7243c4226f9Spjha 			len = strlen(bufptr);
7253c4226f9Spjha 			bufptr += len;
7263c4226f9Spjha 			bufsz -= len - 1;
7273c4226f9Spjha 
7283c4226f9Spjha 			/* set chasflag when the leaf node is within an iob */
7293c4226f9Spjha 			if ((curnode == node) != NULL)
7303c4226f9Spjha 				chasflag = 1;
7313c4226f9Spjha 		}
7323c4226f9Spjha 		rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0);
7333c4226f9Spjha 		if (rv == 0) {
7343c4226f9Spjha 			dprint(("%s: cannot create ap node name "
7353c4226f9Spjha 			    "for %s%d\n", fnm, DRVINST(node)));
7363c4226f9Spjha 			*pathptr = '\0';
7373c4226f9Spjha 			goto OUT;
7383c4226f9Spjha 		}
7393c4226f9Spjha 
7403c4226f9Spjha 		/*
7413c4226f9Spjha 		 * if we can't fit the entire path in our pathbuf, then use
7423c4226f9Spjha 		 * the default short name and nullify pathptr; also, since
7433c4226f9Spjha 		 * we prepend in the buffer, we must avoid adding a null char
7443c4226f9Spjha 		 */
7453c4226f9Spjha 		if (curnode != node) {
7463c4226f9Spjha 			pathptr -= seplen;
7473c4226f9Spjha 			if (pathptr < pathbuf) {
7483c4226f9Spjha 				pathptr = pathbuf;
7493c4226f9Spjha 				*pathptr = '\0';
7503c4226f9Spjha 				goto DEF;
7513c4226f9Spjha 			}
7523c4226f9Spjha 			(void) memcpy(pathptr, AP_PATH_SEP, seplen);
7533c4226f9Spjha 		}
7543c4226f9Spjha 		len = strlen(buf);
7553c4226f9Spjha 		pathptr -= len;
7563c4226f9Spjha 		if (pathptr < pathbuf) {
7573c4226f9Spjha 			pathptr = pathbuf;
7583c4226f9Spjha 			*pathptr = '\0';
7593c4226f9Spjha 			goto DEF;
7603c4226f9Spjha 		}
7613c4226f9Spjha 		(void) memcpy(pathptr, buf, len);
7623c4226f9Spjha 
7633c4226f9Spjha 		/* remember the leaf component */
7643c4226f9Spjha 		if (curnode == node)
7653c4226f9Spjha 			pathend = pathptr;
7663c4226f9Spjha 
7673c4226f9Spjha 		/*
7683c4226f9Spjha 		 * go no further than the hosts' onboard slots
7693c4226f9Spjha 		 */
7703c4226f9Spjha 		if (chasnode == DI_NODE_NIL)
7713c4226f9Spjha 			break;
7723c4226f9Spjha 		curnode = chasnode;
7733c4226f9Spjha 
7743c4226f9Spjha 		/*
7753c4226f9Spjha 		 * the pci device number of the current node is used to
7763c4226f9Spjha 		 * identify which slot of the parent's bus (next iteration)
7773c4226f9Spjha 		 * the current node is on
7783c4226f9Spjha 		 */
7793c4226f9Spjha 		pci_dev = pci_cfg_pcidev(curnode, ph);
780ad86e48dSpjha 		if (pci_dev == PCIDEV_NIL) {
781ad86e48dSpjha 			dprint(("%s: cannot obtain pci device number "
782ad86e48dSpjha 			    "for %s%d\n", fnm, DRVINST(node)));
783ad86e48dSpjha 			*pathptr = '\0';
784ad86e48dSpjha 			goto OUT;
785ad86e48dSpjha 		}
7863c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
7873c4226f9Spjha 
7883c4226f9Spjha 	pathbuf[sizeof (pathbuf) - 1] = '\0';
7893c4226f9Spjha 	if (strlen(pathptr) < ap_pathsz) {
7903c4226f9Spjha 		(void) strlcpy(ap_path, pathptr, ap_pathsz);
7913c4226f9Spjha 		rv = 1;
7923c4226f9Spjha 		goto OUT;
7933c4226f9Spjha 	}
7943c4226f9Spjha 
7953c4226f9Spjha DEF:
7963c4226f9Spjha 	/*
7973c4226f9Spjha 	 * when our name won't fit <ap_pathsz> we use the endpoint/leaf
7983c4226f9Spjha 	 * <node>'s name ONLY IF it has a serialid# which will make the apid
7993c4226f9Spjha 	 * globally unique
8003c4226f9Spjha 	 */
8013c4226f9Spjha 	if (chasflag && pathend != NULL) {
8023c4226f9Spjha 		if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP,
8033c4226f9Spjha 		    ap_path_iob_sep_len) != 0) &&
8043c4226f9Spjha 		    (strlen(pathend) < ap_pathsz)) {
8053c4226f9Spjha 			(void) strlcpy(ap_path, pathend, ap_pathsz);
8063c4226f9Spjha 			rv = 1;
8073c4226f9Spjha 			goto OUT;
8087c478bd9Sstevel@tonic-gate 		}
8097c478bd9Sstevel@tonic-gate 	}
8107c478bd9Sstevel@tonic-gate 
8113c4226f9Spjha 	/*
8123c4226f9Spjha 	 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s
8133c4226f9Spjha 	 * default name
8143c4226f9Spjha 	 */
8153e655c7dSjveta 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
8163c4226f9Spjha 	rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME);
8173c4226f9Spjha 	if (rv == 0) {
8183c4226f9Spjha 		dprint(("%s: cannot create default ap node name for %s%d\n",
8193c4226f9Spjha 		    fnm, DRVINST(node)));
8203c4226f9Spjha 		*pathptr = '\0';
8213c4226f9Spjha 		goto OUT;
8223c4226f9Spjha 	}
8233c4226f9Spjha 	if (strlen(buf) < ap_pathsz) {
8243c4226f9Spjha 		(void) strlcpy(ap_path, buf, ap_pathsz);
8253c4226f9Spjha 		rv = 1;
8263c4226f9Spjha 		goto OUT;
8273c4226f9Spjha 	}
8283c4226f9Spjha 
8293c4226f9Spjha 	/*
8303c4226f9Spjha 	 * in this case, cfgadm goes through an expensive process to generate
8313c4226f9Spjha 	 * a purely dynamic logical apid: the framework will look through
8323c4226f9Spjha 	 * the device tree for attachment point minor nodes and will invoke
8333c4226f9Spjha 	 * each plugin responsible for that attachment point class, and if
8343c4226f9Spjha 	 * the plugin returns a logical apid that matches the queried apid
8353c4226f9Spjha 	 * or matches the default apid generated by the cfgadm framework for
8363c4226f9Spjha 	 * that driver/class (occurs when plugin returns an empty logical apid)
8373c4226f9Spjha 	 * then that is what it will use
8383c4226f9Spjha 	 *
8393c4226f9Spjha 	 * it is doubly expensive because the cfgadm pci plugin itself will
8403c4226f9Spjha 	 * also search the entire device tree in the absence of a link
8413c4226f9Spjha 	 */
8423c4226f9Spjha 	rv = 0;
8433c4226f9Spjha 	dprint(("%s: cannot create apid for %s%d within length of %d\n",
8443c4226f9Spjha 	    fnm, DRVINST(node), ap_pathsz));
8453c4226f9Spjha 
8463c4226f9Spjha OUT:
8473c4226f9Spjha 	ap_path[ap_pathsz - 1] = '\0';
8483c4226f9Spjha 	*pathret = (*pathptr == '\0') ? NULL : strdup(pathptr);
8493c4226f9Spjha 	return (rv);
8503c4226f9Spjha 
8513c4226f9Spjha #undef	seplen
8523c4226f9Spjha #undef	iob_pre_len
8533c4226f9Spjha #undef	ap_path_iob_sep_len
8543c4226f9Spjha }
8553c4226f9Spjha 
8563c4226f9Spjha 
8573c4226f9Spjha /*
8583ebafc43Sjveta  * the DI_PROP_AP_NAMES property contains the first integer section of the
8593c4226f9Spjha  * ieee1275 "slot-names" property and functions as a bitmask; see comment for
8603c4226f9Spjha  * pci_cfg_slotname()
8613c4226f9Spjha  *
8623c4226f9Spjha  * we use the name of the attachment point minor node if its pci device
8633ebafc43Sjveta  * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES
8643c4226f9Spjha  *
8653c4226f9Spjha  * returns non-zero if we return a valid attachment point through <path>
8663c4226f9Spjha  */
8673c4226f9Spjha static int
8683c4226f9Spjha pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
8693c4226f9Spjha     char *ap_path, int ap_pathsz)
8703c4226f9Spjha {
8713c4226f9Spjha 	minor_t pci_dev;
8723c4226f9Spjha 	int *anp;
8733c4226f9Spjha 
8743ebafc43Sjveta 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES,
8753c4226f9Spjha 	    &anp) < 1)
8763c4226f9Spjha 		return (0);
8773c4226f9Spjha 
8783c4226f9Spjha 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
8793c4226f9Spjha 	if ((*anp & (1 << pci_dev)) == 0)
8803c4226f9Spjha 		return (0);
8813c4226f9Spjha 
8823c4226f9Spjha 	(void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz);
8833c4226f9Spjha 	return (1);
8843c4226f9Spjha }
8853c4226f9Spjha 
8863c4226f9Spjha 
8873c4226f9Spjha /*
8883c4226f9Spjha  * determine if <node> qualifies for a path style apid
8893c4226f9Spjha  */
8903c4226f9Spjha static int
8913c4226f9Spjha pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph)
8923c4226f9Spjha {
8933c4226f9Spjha 	char *devtype;
8943c4226f9Spjha 	di_node_t curnode = node;
8953c4226f9Spjha 
8963c4226f9Spjha 	do {
8973c4226f9Spjha 		if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode,
8983ebafc43Sjveta 		    DI_PROP_DEV_TYPE, &devtype) > 0)
8993c4226f9Spjha 			if (strcmp(devtype, PROPVAL_PCIEX) == 0)
9003c4226f9Spjha 				return (1);
9013c4226f9Spjha 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
9023c4226f9Spjha 
9033c4226f9Spjha 	return (0);
9043c4226f9Spjha }
9053c4226f9Spjha 
9063c4226f9Spjha 
9073c4226f9Spjha /*
9083c4226f9Spjha  * takes a full path as returned by <pathret> from pci_cfg_ap_path() and
9093c4226f9Spjha  * returns an allocated string intendend to be stored in a devlink info (dli)
9103c4226f9Spjha  * file
9113c4226f9Spjha  *
9123c4226f9Spjha  * data format: "Location: <transformed path>"
9133c4226f9Spjha  * where <transformed path> is <path> with occurrances of AP_PATH_SEP
9143c4226f9Spjha  * replaced by "/"
9153c4226f9Spjha  */
9163c4226f9Spjha static char *
9173c4226f9Spjha pci_cfg_info_data(char *path)
9183c4226f9Spjha {
9193c4226f9Spjha #define	head	"Location: "
9203c4226f9Spjha #define	headlen	(sizeof (head) - 1)
9213c4226f9Spjha #define	seplen	(sizeof (AP_PATH_SEP) - 1)
9223c4226f9Spjha 
9233c4226f9Spjha 	char *sep, *prev, *np;
9243c4226f9Spjha 	char *newpath;
9253c4226f9Spjha 	int pathlen = strlen(path);
9263c4226f9Spjha 	int len;
9273c4226f9Spjha 
9283c4226f9Spjha 	newpath = malloc(sizeof (char) * (headlen + pathlen + 1));
9293c4226f9Spjha 	np = newpath;
9303c4226f9Spjha 	(void) strcpy(np, head);
9313c4226f9Spjha 	np += headlen;
9323c4226f9Spjha 
9333c4226f9Spjha 	prev = path;
9343c4226f9Spjha 	while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) {
9353c4226f9Spjha 		len = sep - prev;
9363c4226f9Spjha 		(void) memcpy(np, prev, len);
9373c4226f9Spjha 		np += len;
9383c4226f9Spjha 		*np++ = '/';
9393c4226f9Spjha 		prev = sep + seplen;
9403c4226f9Spjha 	}
9413c4226f9Spjha 	(void) strcpy(np, prev);
9423c4226f9Spjha 	return (newpath);
9433c4226f9Spjha 
9443c4226f9Spjha #undef	head
9453c4226f9Spjha #undef	headlen
9463c4226f9Spjha #undef	seplen
9473c4226f9Spjha }
9483c4226f9Spjha 
9493c4226f9Spjha 
9503c4226f9Spjha static void
9513c4226f9Spjha pci_cfg_rm_link(char *file)
9523c4226f9Spjha {
9533c4226f9Spjha 	char *dlipath;
9543c4226f9Spjha 
9553c4226f9Spjha 	dlipath = di_dli_name(file);
9563c4226f9Spjha 	(void) unlink(dlipath);
9573c4226f9Spjha 
9583c4226f9Spjha 	devfsadm_rm_all(file);
9593c4226f9Spjha 	free(dlipath);
9603c4226f9Spjha }
9613c4226f9Spjha 
9623c4226f9Spjha /*
9633c4226f9Spjha  * removes all registered devlinks to physical path <physpath> except for
9643c4226f9Spjha  * the devlink <valid> if not NULL;
9653c4226f9Spjha  * <physpath> must include the minor node
9663c4226f9Spjha  */
9673c4226f9Spjha static void
9683c4226f9Spjha pci_cfg_rm_invalid_links(char *physpath, char *valid)
9693c4226f9Spjha {
9703c4226f9Spjha 	char **dnp;
9713c4226f9Spjha 	char *cp, *vcp;
9723c4226f9Spjha 	int i, dnlen;
9733c4226f9Spjha 
9743c4226f9Spjha 	dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen);
9753c4226f9Spjha 	if (dnp == NULL)
9763c4226f9Spjha 		return;
9773c4226f9Spjha 
9783c4226f9Spjha 	if (valid != NULL) {
9793c4226f9Spjha 		if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0)
9803c4226f9Spjha 			vcp = valid + DEV_LEN + 1;
9813c4226f9Spjha 		else
9823c4226f9Spjha 			vcp = valid;
9833c4226f9Spjha 	}
9843c4226f9Spjha 
9853c4226f9Spjha 	for (i = 0; i < dnlen; i++) {
9863c4226f9Spjha 		if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0)
9873c4226f9Spjha 			cp = dnp[i] + DEV_LEN + 1;
9883c4226f9Spjha 		else
9893c4226f9Spjha 			cp = dnp[i];
9903c4226f9Spjha 
9913c4226f9Spjha 		if (valid != NULL) {
9923c4226f9Spjha 			if (strcmp(vcp, cp) == 0)
9933c4226f9Spjha 				continue;
9943c4226f9Spjha 		}
9953c4226f9Spjha 		pci_cfg_rm_link(cp);
9963c4226f9Spjha 	}
9973c4226f9Spjha 	devfsadm_free_dev_names(dnp, dnlen);
9983c4226f9Spjha }
9993c4226f9Spjha 
10003c4226f9Spjha 
10013c4226f9Spjha /*
10023c4226f9Spjha  * takes a complete devinfo snapshot and returns the root node;
10033c4226f9Spjha  * callers must do a di_fini() on the returned node;
10043c4226f9Spjha  * if the snapshot failed, DI_NODE_NIL is returned instead
10053c4226f9Spjha  *
10063c4226f9Spjha  * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node
10073c4226f9Spjha  * in the new snapshot and return it through <ret_node> if it is found,
10083c4226f9Spjha  * else DI_NODE_NIL is returned instead
10093c4226f9Spjha  *
10103c4226f9Spjha  * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return
10113c4226f9Spjha  * the matching minor in the new snapshot through <ret_minor> if it is found,
10123c4226f9Spjha  * else DI_MINOR_NIL is returned instead
10133c4226f9Spjha  */
10143c4226f9Spjha static di_node_t
10153c4226f9Spjha pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor,
10163c4226f9Spjha     di_node_t *ret_node, di_minor_t *ret_minor)
10173c4226f9Spjha {
10183c4226f9Spjha 	di_node_t root_node;
10193c4226f9Spjha 	di_node_t node;
10203c4226f9Spjha 	di_minor_t minor;
10213c4226f9Spjha 	int pci_inst;
10223c4226f9Spjha 	dev_t pci_devt;
10233c4226f9Spjha 
10243c4226f9Spjha 	*ret_node = DI_NODE_NIL;
10253c4226f9Spjha 	*ret_minor = DI_MINOR_NIL;
10263c4226f9Spjha 
10273c4226f9Spjha 	root_node = di_init("/", DINFOCPYALL);
10283c4226f9Spjha 	if (root_node == DI_NODE_NIL)
10293c4226f9Spjha 		return (DI_NODE_NIL);
10303c4226f9Spjha 
10313c4226f9Spjha 	/*
10323c4226f9Spjha 	 * narrow down search by driver, then instance, then minor
10333c4226f9Spjha 	 */
10343c4226f9Spjha 	if (pci_node == DI_NODE_NIL)
10353c4226f9Spjha 		return (root_node);
10363c4226f9Spjha 
10373c4226f9Spjha 	pci_inst = di_instance(pci_node);
10383c4226f9Spjha 	node = di_drv_first_node(di_driver_name(pci_node), root_node);
10393c4226f9Spjha 	do {
10403c4226f9Spjha 		if (pci_inst == di_instance(node)) {
10413c4226f9Spjha 			*ret_node = node;
10423c4226f9Spjha 			break;
10433c4226f9Spjha 		}
10443c4226f9Spjha 	} while ((node = di_drv_next_node(node)) != DI_NODE_NIL);
10453c4226f9Spjha 
10463c4226f9Spjha 	if (node == DI_NODE_NIL)
10473c4226f9Spjha 		return (root_node);
10483c4226f9Spjha 
10493c4226f9Spjha 	/*
10503c4226f9Spjha 	 * found node, now search minors
10513c4226f9Spjha 	 */
10523c4226f9Spjha 	if (pci_minor == DI_MINOR_NIL)
10533c4226f9Spjha 		return (root_node);
10543c4226f9Spjha 
10553c4226f9Spjha 	pci_devt = di_minor_devt(pci_minor);
10563c4226f9Spjha 	minor = DI_MINOR_NIL;
10573c4226f9Spjha 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
10583c4226f9Spjha 		if (pci_devt == di_minor_devt(minor)) {
10593c4226f9Spjha 			*ret_minor = minor;
10603c4226f9Spjha 			break;
10613c4226f9Spjha 		}
10623c4226f9Spjha 	}
10633c4226f9Spjha 	return (root_node);
10643c4226f9Spjha }
10653c4226f9Spjha 
10663c4226f9Spjha 
10673c4226f9Spjha static int
10683c4226f9Spjha pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node)
10693c4226f9Spjha {
10703c4226f9Spjha #ifdef	DEBUG
10713c4226f9Spjha 	char *fnm = "pci_cfg_creat_cb";
10723c4226f9Spjha #endif
10733c4226f9Spjha #define	ap_pathsz	(sizeof (ap_path))
10743c4226f9Spjha 
10753c4226f9Spjha 	char ap_path[CFGA_LOG_EXT_LEN];
10763c4226f9Spjha 	char linkbuf[MAXPATHLEN];
10773c4226f9Spjha 	char *fullpath = NULL;
10783c4226f9Spjha 	char *pathinfo = NULL;
10793c4226f9Spjha 	char *devpath = NULL;
1080ad86e48dSpjha 	int rv, fd = -1;
10813c4226f9Spjha 	size_t sz;
10823c4226f9Spjha 	di_prom_handle_t ph;
10833c4226f9Spjha 	di_node_t node;
10843c4226f9Spjha 	di_node_t root_node = DI_NODE_NIL;
10853c4226f9Spjha 	di_minor_t minor;
10863c4226f9Spjha 
10873c4226f9Spjha 	ph = di_prom_init();
10883c4226f9Spjha 	if (ph == DI_PROM_HANDLE_NIL) {
10893c4226f9Spjha 		dprint(("%s: di_prom_init() failed for %s%d\n",
10903c4226f9Spjha 		    fnm, DRVINST(pci_node)));
10913c4226f9Spjha 		goto OUT;
10923c4226f9Spjha 	}
10933c4226f9Spjha 
10943c4226f9Spjha 	/*
10953c4226f9Spjha 	 * Since incoming nodes from hotplug events are from snapshots that
10963c4226f9Spjha 	 * do NOT contain parent/ancestor data, we must retake our own
10973c4226f9Spjha 	 * snapshot and search for the target node
10983c4226f9Spjha 	 */
10993c4226f9Spjha 	root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor);
11003c4226f9Spjha 	if (root_node == DI_NODE_NIL || node == DI_NODE_NIL ||
11013c4226f9Spjha 	    minor == DI_MINOR_NIL) {
11023c4226f9Spjha 		dprint(("%s: devinfo snapshot or search failed for %s%d\n",
11033c4226f9Spjha 		    fnm, DRVINST(pci_node)));
11043c4226f9Spjha 		goto OUT;
11053c4226f9Spjha 	}
11063c4226f9Spjha 
11073c4226f9Spjha 	if (pci_cfg_is_ap_path(node, ph)) {
11083c4226f9Spjha 		rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz,
11093c4226f9Spjha 		    &fullpath);
11103c4226f9Spjha 		if (rv == 0)
11113c4226f9Spjha 			goto OUT;
11123c4226f9Spjha 
11133c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
11143c4226f9Spjha 		    CFG_DIRNAME, ap_path);
11153c4226f9Spjha 
11163c4226f9Spjha 		/*
11173c4226f9Spjha 		 * We must remove existing links because we may have invalid
11183c4226f9Spjha 		 * apids that are valid links.  Since these are not dangling,
11193c4226f9Spjha 		 * devfsadm will not invoke the remove callback on them.
11203c4226f9Spjha 		 *
11213c4226f9Spjha 		 * What are "invalid apids with valid links"?  Consider swapping
11223c4226f9Spjha 		 * an attachment point bus with another while the system is
11233c4226f9Spjha 		 * down, on the same device path bound to the same drivers
11243c4226f9Spjha 		 * but with the new AP bus having different properties
11253c4226f9Spjha 		 * (e.g. serialid#).  If the previous apid is not removed,
11263c4226f9Spjha 		 * there will now be two different links pointing to the same
11273c4226f9Spjha 		 * attachment point, but only one reflects the correct
11283c4226f9Spjha 		 * logical apid
11293c4226f9Spjha 		 */
11303c4226f9Spjha 		devpath = pci_cfg_devpath(node, minor);
11313c4226f9Spjha 		if (devpath == NULL)
11323c4226f9Spjha 			goto OUT;
11333c4226f9Spjha 		pci_cfg_rm_invalid_links(devpath, linkbuf);
11343c4226f9Spjha 		free(devpath);
11353c4226f9Spjha 
11363c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
11373c4226f9Spjha 
11383c4226f9Spjha 		/*
11393c4226f9Spjha 		 * we store the full logical path of the attachment point for
11403c4226f9Spjha 		 * cfgadm to display in its info field which is useful when
11413c4226f9Spjha 		 * the full logical path exceeds the size limit for logical
11423c4226f9Spjha 		 * apids (CFGA_LOG_EXT_LEN)
11433c4226f9Spjha 		 *
11443c4226f9Spjha 		 * for the cfgadm pci plugin to do the same would be expensive
11453c4226f9Spjha 		 * (i.e. devinfo snapshot + top down exhaustive minor search +
11463c4226f9Spjha 		 * equivalent of pci_cfg_ap_path() on every invocation)
11473c4226f9Spjha 		 *
11483c4226f9Spjha 		 * note that if we do not create a link (pci_cfg_ap_path() is
11493c4226f9Spjha 		 * not successful), that is what cfgadm will do anyways to
11503c4226f9Spjha 		 * create a purely dynamic apid
11513c4226f9Spjha 		 */
11523c4226f9Spjha 		pathinfo = pci_cfg_info_data(fullpath);
11533c4226f9Spjha 		fd = di_dli_openw(linkbuf);
11543c4226f9Spjha 		if (fd < 0)
11553c4226f9Spjha 			goto OUT;
11563c4226f9Spjha 
11573c4226f9Spjha 		sz = strlen(pathinfo) + 1;
11583c4226f9Spjha 		rv = write(fd, pathinfo, sz);
11593c4226f9Spjha 		if (rv < sz) {
11603c4226f9Spjha 			dprint(("%s: could not write full pathinfo to dli "
11613c4226f9Spjha 			    "file for %s%d\n", fnm, DRVINST(node)));
11623c4226f9Spjha 			goto OUT;
11633c4226f9Spjha 		}
11643c4226f9Spjha 		di_dli_close(fd);
11653c4226f9Spjha 	} else {
11663c4226f9Spjha 		rv = pci_cfg_ap_legacy(minor, node, ph, ap_path,
11673c4226f9Spjha 		    ap_pathsz);
11683c4226f9Spjha 		if (rv == 0)
11693c4226f9Spjha 			goto OUT;
11703c4226f9Spjha 
11713c4226f9Spjha 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
11723c4226f9Spjha 		    CFG_DIRNAME, ap_path);
11733c4226f9Spjha 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
11743c4226f9Spjha 	}
11753c4226f9Spjha 
11763c4226f9Spjha OUT:
1177ad86e48dSpjha 	if (fd >= 0)
1178ad86e48dSpjha 		di_dli_close(fd);
11793c4226f9Spjha 	if (fullpath != NULL)
11803c4226f9Spjha 		free(fullpath);
11813c4226f9Spjha 	if (pathinfo != NULL)
11823c4226f9Spjha 		free(pathinfo);
11833c4226f9Spjha 	if (ph != DI_PROM_HANDLE_NIL)
11843c4226f9Spjha 		di_prom_fini(ph);
11853c4226f9Spjha 	if (root_node != DI_NODE_NIL)
11863c4226f9Spjha 		di_fini(root_node);
11877c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
11883c4226f9Spjha 
11893c4226f9Spjha #undef	ap_pathsz
11903c4226f9Spjha }
11913c4226f9Spjha 
11923c4226f9Spjha 
11933c4226f9Spjha static void
11943c4226f9Spjha pci_cfg_rm_all(char *file)
11953c4226f9Spjha {
11963c4226f9Spjha 	pci_cfg_rm_link(file);
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate /*
12017c478bd9Sstevel@tonic-gate  * ib_cfg_creat_cb() creates two types of links
12027c478bd9Sstevel@tonic-gate  * One for the fabric as /dev/cfg/ib
12037c478bd9Sstevel@tonic-gate  * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
12047c478bd9Sstevel@tonic-gate  */
12057c478bd9Sstevel@tonic-gate static int
12067c478bd9Sstevel@tonic-gate ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
12077c478bd9Sstevel@tonic-gate {
12087c478bd9Sstevel@tonic-gate 	char	*cp;
12097c478bd9Sstevel@tonic-gate 	char	path[PATH_MAX + 1];
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	if ((cp = di_devfs_path(node)) == NULL) {
12127c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
12167c478bd9Sstevel@tonic-gate 	di_devfs_path_free(cp);
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	/* create fabric or hca:GUID and the symlink */
12197c478bd9Sstevel@tonic-gate 	if (strstr(path, "ib:fabric") != NULL) {
12207c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
12217c478bd9Sstevel@tonic-gate 	} else {
12227c478bd9Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
12237c478bd9Sstevel@tonic-gate 		    di_minor_name(minor));
12247c478bd9Sstevel@tonic-gate 	}
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(path, node, minor, 0);
12277c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
12287c478bd9Sstevel@tonic-gate }
1229226236b5Spjha 
1230226236b5Spjha /*
1231226236b5Spjha  * This function verifies if the serial id is printable.
1232226236b5Spjha  */
1233226236b5Spjha 
1234226236b5Spjha static int
1235226236b5Spjha serid_printable(uint64_t *seridp)
1236226236b5Spjha {
1237226236b5Spjha 
1238226236b5Spjha 	char *ptr;
1239226236b5Spjha 	int i = 0;
1240226236b5Spjha 
1241226236b5Spjha 	for (ptr = (char *)seridp+3; i < 5; ptr++, i++)
1242226236b5Spjha 		if (*ptr < 0x21 || *ptr >= 0x7f)
1243226236b5Spjha 			return (0);
1244226236b5Spjha 
1245226236b5Spjha 	return (1);
1246226236b5Spjha 
1247226236b5Spjha }
1248