xref: /titanic_51/usr/src/uts/sun4u/io/gptwocfg.c (revision 88294e09b5c27cbb12b6735e2fb247a86b76666d)
11c42de6dSgd78059 /*
21c42de6dSgd78059  * CDDL HEADER START
31c42de6dSgd78059  *
41c42de6dSgd78059  * The contents of this file are subject to the terms of the
51c42de6dSgd78059  * Common Development and Distribution License (the "License").
61c42de6dSgd78059  * You may not use this file except in compliance with the License.
71c42de6dSgd78059  *
81c42de6dSgd78059  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91c42de6dSgd78059  * or http://www.opensolaris.org/os/licensing.
101c42de6dSgd78059  * See the License for the specific language governing permissions
111c42de6dSgd78059  * and limitations under the License.
121c42de6dSgd78059  *
131c42de6dSgd78059  * When distributing Covered Code, include this CDDL HEADER in each
141c42de6dSgd78059  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151c42de6dSgd78059  * If applicable, add the following below this CDDL HEADER, with the
161c42de6dSgd78059  * fields enclosed by brackets "[]" replaced with your own identifying
171c42de6dSgd78059  * information: Portions Copyright [yyyy] [name of copyright owner]
181c42de6dSgd78059  *
191c42de6dSgd78059  * CDDL HEADER END
201c42de6dSgd78059  */
211c42de6dSgd78059 /*
22*88294e09SRichard Bean  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
231c42de6dSgd78059  * Use is subject to license terms.
241c42de6dSgd78059  */
251c42de6dSgd78059 
261c42de6dSgd78059 /*
271c42de6dSgd78059  * Safari Configurator  (gptwocfg)
281c42de6dSgd78059  *
291c42de6dSgd78059  */
301c42de6dSgd78059 
311c42de6dSgd78059 #include <sys/types.h>
321c42de6dSgd78059 #include <sys/cred.h>
331c42de6dSgd78059 #include <sys/mman.h>
341c42de6dSgd78059 #include <sys/kmem.h>
351c42de6dSgd78059 #include <sys/conf.h>
361c42de6dSgd78059 #include <sys/cmn_err.h>
371c42de6dSgd78059 #include <sys/ddi.h>
381c42de6dSgd78059 #include <sys/sunddi.h>
391c42de6dSgd78059 #include <sys/sunndi.h>
401c42de6dSgd78059 #include <sys/modctl.h>
411c42de6dSgd78059 #include <sys/stat.h>
421c42de6dSgd78059 #include <sys/param.h>
431c42de6dSgd78059 #include <sys/autoconf.h>
441c42de6dSgd78059 #include <sys/ksynch.h>
451c42de6dSgd78059 #include <sys/promif.h>
461c42de6dSgd78059 #include <sys/ndi_impldefs.h>
471c42de6dSgd78059 #include <sys/ddi_impldefs.h>
481c42de6dSgd78059 #include <sys/gp2cfg.h>
491c42de6dSgd78059 #include <sys/machsystm.h>
501c42de6dSgd78059 #include <sys/platform_module.h>
511c42de6dSgd78059 #pragma weak starcat_dr_name
521c42de6dSgd78059 
531c42de6dSgd78059 #ifdef DEBUG
541c42de6dSgd78059 int gptwocfg_debug = 0;
551c42de6dSgd78059 
561c42de6dSgd78059 static void debug(char *, uintptr_t, uintptr_t,
571c42de6dSgd78059     uintptr_t, uintptr_t, uintptr_t);
581c42de6dSgd78059 
591c42de6dSgd78059 #define	GPTWO_DEBUG0(level, flag, s) if (gptwocfg_debug >= level) \
601c42de6dSgd78059     cmn_err(flag, s)
611c42de6dSgd78059 #define	GPTWO_DEBUG1(level, flag, fmt, a1) if (gptwocfg_debug >= level) \
621c42de6dSgd78059     debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
631c42de6dSgd78059 #define	GPTWO_DEBUG2(level, flag, fmt, a1, a2) if (gptwocfg_debug >= level) \
641c42de6dSgd78059     debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
651c42de6dSgd78059 #define	GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3) \
661c42de6dSgd78059     if (gptwocfg_debug >= level) \
671c42de6dSgd78059     debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
681c42de6dSgd78059 #else
691c42de6dSgd78059 #define	GPTWO_DEBUG0(level, flag, s)
701c42de6dSgd78059 #define	GPTWO_DEBUG1(level, flag, fmt, a1)
711c42de6dSgd78059 #define	GPTWO_DEBUG2(level, flag, fmt, a1, a2)
721c42de6dSgd78059 #define	GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3)
731c42de6dSgd78059 #endif
741c42de6dSgd78059 
751c42de6dSgd78059 kmutex_t gptwo_handle_list_lock;
761c42de6dSgd78059 gptwocfg_handle_list_t *gptwocfg_handle_list;
771c42de6dSgd78059 
781c42de6dSgd78059 static kmutex_t gptwo_config_list_lock;
791c42de6dSgd78059 static gptwocfg_config_t *gptwo_config_list;
801c42de6dSgd78059 
811c42de6dSgd78059 static gptwo_new_nodes_t *
821c42de6dSgd78059     gptwocfg_get_obp_created_nodes(dev_info_t *, uint_t);
831c42de6dSgd78059 
841c42de6dSgd78059 void (*gptwocfg_unclaim_address)(uint_t);
851c42de6dSgd78059 
861c42de6dSgd78059 extern caddr_t efcode_vaddr;
871c42de6dSgd78059 extern int efcode_size;
881c42de6dSgd78059 
891c42de6dSgd78059 #define		GPTWO_NUMBER_OF_DEVICE_TYPES	6
901c42de6dSgd78059 
911c42de6dSgd78059 static kmutex_t gptwocfg_ops_table_lock;
921c42de6dSgd78059 gptwocfg_ops_t *gptwocfg_ops_table[GPTWO_NUMBER_OF_DEVICE_TYPES];
931c42de6dSgd78059 
941c42de6dSgd78059 /*
951c42de6dSgd78059  * Module linkage information for the kernel.
961c42de6dSgd78059  */
971c42de6dSgd78059 
981c42de6dSgd78059 extern struct mod_ops mod_miscops;
991c42de6dSgd78059 
1001c42de6dSgd78059 static struct modlmisc modlmisc = {
1011c42de6dSgd78059 	&mod_miscops, /* Type of module */
102*88294e09SRichard Bean 	"gptwo configurator",
1031c42de6dSgd78059 };
1041c42de6dSgd78059 
1051c42de6dSgd78059 static struct modlinkage modlinkage = {
1061c42de6dSgd78059 	MODREV_1, (void *)&modlmisc, NULL
1071c42de6dSgd78059 };
1081c42de6dSgd78059 
1091c42de6dSgd78059 int
1101c42de6dSgd78059 _init(void)
1111c42de6dSgd78059 {
1121c42de6dSgd78059 	unsigned int i;
1131c42de6dSgd78059 
1141c42de6dSgd78059 	GPTWO_DEBUG0(1, CE_WARN, "gptwocfg (Safari Configurator) "
1151c42de6dSgd78059 	    "has been loaded\n");
1161c42de6dSgd78059 
1171c42de6dSgd78059 	mutex_init(&gptwo_config_list_lock, NULL, MUTEX_DRIVER, NULL);
1181c42de6dSgd78059 	mutex_init(&gptwocfg_ops_table_lock, NULL, MUTEX_DRIVER, NULL);
1191c42de6dSgd78059 	gptwo_config_list = NULL;
1201c42de6dSgd78059 
1211c42de6dSgd78059 	mutex_init(&gptwo_handle_list_lock, NULL, MUTEX_DRIVER, NULL);
1221c42de6dSgd78059 	gptwocfg_handle_list = NULL;
1231c42de6dSgd78059 
1241c42de6dSgd78059 	for (i = 0; i < GPTWO_NUMBER_OF_DEVICE_TYPES; i++)
1251c42de6dSgd78059 		gptwocfg_ops_table[i] = NULL;
1261c42de6dSgd78059 
1271c42de6dSgd78059 	return (mod_install(&modlinkage));
1281c42de6dSgd78059 }
1291c42de6dSgd78059 
1301c42de6dSgd78059 int
1311c42de6dSgd78059 _fini(void)
1321c42de6dSgd78059 {
1331c42de6dSgd78059 	int	error;
1341c42de6dSgd78059 
1351c42de6dSgd78059 	error = mod_remove(&modlinkage);
1361c42de6dSgd78059 	if (error != 0) {
1371c42de6dSgd78059 		return (error);
1381c42de6dSgd78059 	}
1391c42de6dSgd78059 	mutex_destroy(&gptwo_config_list_lock);
1401c42de6dSgd78059 	mutex_destroy(&gptwocfg_ops_table_lock);
1411c42de6dSgd78059 	mutex_destroy(&gptwo_handle_list_lock);
1421c42de6dSgd78059 
1431c42de6dSgd78059 	return (0);
1441c42de6dSgd78059 }
1451c42de6dSgd78059 
1461c42de6dSgd78059 int
1471c42de6dSgd78059 _info(modinfop)
1481c42de6dSgd78059 struct modinfo *modinfop;
1491c42de6dSgd78059 {
1501c42de6dSgd78059 	return (mod_info(&modlinkage, modinfop));
1511c42de6dSgd78059 }
1521c42de6dSgd78059 
1531c42de6dSgd78059 gptwo_new_nodes_t *
1541c42de6dSgd78059 gptwocfg_allocate_node_list(int number_of_nodes)
1551c42de6dSgd78059 {
1561c42de6dSgd78059 	gptwo_new_nodes_t	*gptwo_new_nodes;
1571c42de6dSgd78059 	int size;
1581c42de6dSgd78059 
1591c42de6dSgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_allocate_node_list- %d nodes",
1601c42de6dSgd78059 	    number_of_nodes);
1611c42de6dSgd78059 
1621c42de6dSgd78059 	size = sizeof (gptwo_new_nodes_t) +
1631c42de6dSgd78059 	    ((number_of_nodes -1) * sizeof (dev_info_t *));
1641c42de6dSgd78059 
1651c42de6dSgd78059 	gptwo_new_nodes = kmem_zalloc(size, KM_SLEEP);
1661c42de6dSgd78059 
1671c42de6dSgd78059 	gptwo_new_nodes->gptwo_number_of_nodes = number_of_nodes;
1681c42de6dSgd78059 	gptwo_new_nodes->gptwo_version = GP2_VERSION;
1691c42de6dSgd78059 
1701c42de6dSgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_allocate_node_list- returned %p\n",
1711c42de6dSgd78059 	    gptwo_new_nodes);
1721c42de6dSgd78059 
1731c42de6dSgd78059 	return (gptwo_new_nodes);
1741c42de6dSgd78059 }
1751c42de6dSgd78059 
1761c42de6dSgd78059 void
1771c42de6dSgd78059 gptwocfg_free_node_list(gptwo_new_nodes_t *gptwo_new_nodes)
1781c42de6dSgd78059 {
1791c42de6dSgd78059 	int size;
1801c42de6dSgd78059 
1811c42de6dSgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_free_node_list- %p %d nodes",
1821c42de6dSgd78059 	    gptwo_new_nodes, gptwo_new_nodes->gptwo_number_of_nodes);
1831c42de6dSgd78059 
1841c42de6dSgd78059 	size = sizeof (gptwo_new_nodes_t) +
1851c42de6dSgd78059 	    ((gptwo_new_nodes->gptwo_number_of_nodes - 1) *
1861c42de6dSgd78059 	    sizeof (dev_info_t *));
1871c42de6dSgd78059 
1881c42de6dSgd78059 	kmem_free(gptwo_new_nodes, size);
1891c42de6dSgd78059 }
1901c42de6dSgd78059 
1911c42de6dSgd78059 void
1921c42de6dSgd78059 gptwocfg_register_ops(uint_t type, gptwo_cfgfunc_t *cfg_func,
1931c42de6dSgd78059     gptwo_uncfgfunc_t *uncfg_func)
1941c42de6dSgd78059 {
1951c42de6dSgd78059 	/* KM_SLEEP guarantees success */
1961c42de6dSgd78059 	gptwocfg_ops_t *ops = kmem_zalloc(sizeof (gptwocfg_ops_t), KM_SLEEP);
1971c42de6dSgd78059 
1981c42de6dSgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_register_ops: type=%x ops=%lx\n",
1991c42de6dSgd78059 	    type, ops);
2001c42de6dSgd78059 	ASSERT(type < GPTWO_NUMBER_OF_DEVICE_TYPES);
2011c42de6dSgd78059 	ops->gptwocfg_type = type;
2021c42de6dSgd78059 	ops->gptwocfg_version = GPTWOCFG_OPS_VERSION;
2031c42de6dSgd78059 	ops->gptwocfg_configure = cfg_func;
2041c42de6dSgd78059 	ops->gptwocfg_unconfigure = uncfg_func;
2051c42de6dSgd78059 
2061c42de6dSgd78059 	mutex_enter(&gptwocfg_ops_table_lock);
2071c42de6dSgd78059 	gptwocfg_ops_table[type] = ops;
2081c42de6dSgd78059 	mutex_exit(&gptwocfg_ops_table_lock);
2091c42de6dSgd78059 }
2101c42de6dSgd78059 
2111c42de6dSgd78059 
2121c42de6dSgd78059 
2131c42de6dSgd78059 void
2141c42de6dSgd78059 gptwocfg_unregister_ops(uint_t type)
2151c42de6dSgd78059 {
2161c42de6dSgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unregister_ops: type=%x\n", type);
2171c42de6dSgd78059 
2181c42de6dSgd78059 	ASSERT(type < GPTWO_NUMBER_OF_DEVICE_TYPES);
2191c42de6dSgd78059 
2201c42de6dSgd78059 	mutex_enter(&gptwocfg_ops_table_lock);
2211c42de6dSgd78059 	kmem_free(gptwocfg_ops_table[type], sizeof (gptwocfg_ops_t));
2221c42de6dSgd78059 	gptwocfg_ops_table[type] = NULL;
2231c42de6dSgd78059 	mutex_exit(&gptwocfg_ops_table_lock);
2241c42de6dSgd78059 }
2251c42de6dSgd78059 
2261c42de6dSgd78059 gptwocfg_cookie_t
2271c42de6dSgd78059 gptwocfg_configure(dev_info_t *ap, spcd_t *pcd, gptwo_aid_t id)
2281c42de6dSgd78059 {
2291c42de6dSgd78059 	gptwo_new_nodes_t *new_nodes = NULL;
2301c42de6dSgd78059 	gptwocfg_config_t *config;
2311c42de6dSgd78059 	gptwocfg_ops_t *ops;
2321c42de6dSgd78059 
2331c42de6dSgd78059 	GPTWO_DEBUG3(1, CE_CONT, "gptwocfg_configure:  ap=0x%p pcd=%p id=%x\n",
2341c42de6dSgd78059 	    ap, pcd, id);
2351c42de6dSgd78059 
2361c42de6dSgd78059 	/*
2371c42de6dSgd78059 	 * Look to see if the port is already configured.
2381c42de6dSgd78059 	 */
2391c42de6dSgd78059 	mutex_enter(&gptwo_config_list_lock);
2401c42de6dSgd78059 	config = gptwo_config_list;
2411c42de6dSgd78059 	while (config != NULL) {
2421c42de6dSgd78059 		if (&starcat_dr_name) {
2431c42de6dSgd78059 			if (starcat_dr_name(ddi_node_name(ap)) < 0) {
2441c42de6dSgd78059 				config = config->gptwo_next;
2451c42de6dSgd78059 				continue;
2461c42de6dSgd78059 			}
2471c42de6dSgd78059 		}
2481c42de6dSgd78059 		if (config->gptwo_portid == id) {
2491c42de6dSgd78059 			cmn_err(CE_WARN, "gptwocfg: gptwocfg_configure: "
2501c42de6dSgd78059 			    "0x%x Port already configured\n", id);
2511c42de6dSgd78059 			mutex_exit(&gptwo_config_list_lock);
2521c42de6dSgd78059 			return (NULL);
2531c42de6dSgd78059 		}
2541c42de6dSgd78059 		config = config->gptwo_next;
2551c42de6dSgd78059 	}
2561c42de6dSgd78059 	mutex_exit(&gptwo_config_list_lock);
2571c42de6dSgd78059 
2581c42de6dSgd78059 	if (pcd == NULL) {
2591c42de6dSgd78059 		GPTWO_DEBUG0(1, CE_CONT, "gptwocfg_configure: pcd=NULL\n");
2601c42de6dSgd78059 		return (NULL);
2611c42de6dSgd78059 	}
2621c42de6dSgd78059 
2631c42de6dSgd78059 	if ((pcd->spcd_magic != PCD_MAGIC) ||
2641c42de6dSgd78059 	    (pcd->spcd_version != PCD_VERSION)) {
2651c42de6dSgd78059 		cmn_err(CE_WARN, "gptwocfg: Invalid Port "
2661c42de6dSgd78059 		    "Configuration Descriptor\n");
2671c42de6dSgd78059 		return (NULL);
2681c42de6dSgd78059 	}
2691c42de6dSgd78059 
2701c42de6dSgd78059 	if (pcd->spcd_ptype >= GPTWO_NUMBER_OF_DEVICE_TYPES) {
2711c42de6dSgd78059 		cmn_err(CE_WARN,
2721c42de6dSgd78059 		    "gptwocfg: Invalid device type %x", pcd->spcd_ptype);
2731c42de6dSgd78059 		return (NULL);
2741c42de6dSgd78059 	}
2751c42de6dSgd78059 
2761c42de6dSgd78059 	if (pcd->spcd_prsv != SPCD_RSV_PASS) {
2771c42de6dSgd78059 		cmn_err(CE_WARN,
2781c42de6dSgd78059 		    "gptwocfg: Agent at ID %x has not passed test(s)\n", id);
2791c42de6dSgd78059 		return (NULL);
2801c42de6dSgd78059 	}
2811c42de6dSgd78059 
2821c42de6dSgd78059 	mutex_enter(&gptwocfg_ops_table_lock);
2831c42de6dSgd78059 
2841c42de6dSgd78059 	ops = gptwocfg_ops_table[pcd->spcd_ptype];
2851c42de6dSgd78059 
2861c42de6dSgd78059 	if (ops == NULL) {
2871c42de6dSgd78059 		cmn_err(CE_WARN, "gptwocfg: Ops for type %x have not been "
2881c42de6dSgd78059 		    "registered\n", pcd->spcd_ptype);
2891c42de6dSgd78059 		mutex_exit(&gptwocfg_ops_table_lock);
2901c42de6dSgd78059 		return (NULL);
2911c42de6dSgd78059 	}
2921c42de6dSgd78059 
2931c42de6dSgd78059 	if (ops->gptwocfg_configure == NULL) {
2941c42de6dSgd78059 		cmn_err(CE_WARN, "gptwocfg: no configure routine registered "
2951c42de6dSgd78059 		    "for sfaari type %x\n", pcd->spcd_ptype);
2961c42de6dSgd78059 		mutex_exit(&gptwocfg_ops_table_lock);
2971c42de6dSgd78059 		return (NULL);
2981c42de6dSgd78059 	}
2991c42de6dSgd78059 
3001c42de6dSgd78059 	new_nodes = ops->gptwocfg_configure(ap, pcd, id);
3011c42de6dSgd78059 
3021c42de6dSgd78059 	mutex_exit(&gptwocfg_ops_table_lock);
3031c42de6dSgd78059 
3041c42de6dSgd78059 	if (new_nodes != NULL) {
3051c42de6dSgd78059 		config = kmem_zalloc(sizeof (gptwocfg_config_t), KM_SLEEP);
3061c42de6dSgd78059 		config->gptwo_version = GP2_VERSION;
3071c42de6dSgd78059 		config->gptwo_ap = ap;
3081c42de6dSgd78059 		config->gptwo_portid = id;
3091c42de6dSgd78059 		config->gptwo_nodes = new_nodes;
3101c42de6dSgd78059 		config->gptwo_ops = ops;
3111c42de6dSgd78059 
3121c42de6dSgd78059 		/*
3131c42de6dSgd78059 		 * put config on config list
3141c42de6dSgd78059 		 */
3151c42de6dSgd78059 		mutex_enter(&gptwo_config_list_lock);
3161c42de6dSgd78059 		config->gptwo_next = gptwo_config_list;
3171c42de6dSgd78059 		gptwo_config_list = config;
3181c42de6dSgd78059 		mutex_exit(&gptwo_config_list_lock);
3191c42de6dSgd78059 	} else {
3201c42de6dSgd78059 		config = NULL;
3211c42de6dSgd78059 	}
3221c42de6dSgd78059 
3231c42de6dSgd78059 	return ((gptwocfg_cookie_t)config);
3241c42de6dSgd78059 }
3251c42de6dSgd78059 
3261c42de6dSgd78059 gptwocfg_cookie_t
3271c42de6dSgd78059 gptwocfg_unconfigure(dev_info_t *ap, gptwo_aid_t id)
3281c42de6dSgd78059 {
3291c42de6dSgd78059 	int i, circ;
3301c42de6dSgd78059 	int failure = 0;
3311c42de6dSgd78059 	dev_info_t *saf_dip;
3321c42de6dSgd78059 	gptwocfg_config_t *config, *temp;
3331c42de6dSgd78059 	gptwo_new_nodes_t *obp_nodes;
3341c42de6dSgd78059 	gptwocfg_ops_t *ops;
3351c42de6dSgd78059 
3361c42de6dSgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_unconfigure: ap=0x%p id=0x%lx\n",
3371c42de6dSgd78059 	    ap, id);
3381c42de6dSgd78059 
3391c42de6dSgd78059 	mutex_enter(&gptwo_config_list_lock);
3401c42de6dSgd78059 	config = gptwo_config_list;
3411c42de6dSgd78059 	while (config != NULL) {
3421c42de6dSgd78059 		if (config->gptwo_portid == id) {
3431c42de6dSgd78059 			break;
3441c42de6dSgd78059 		}
3451c42de6dSgd78059 		config = config->gptwo_next;
3461c42de6dSgd78059 	}
3471c42de6dSgd78059 	mutex_exit(&gptwo_config_list_lock);
3481c42de6dSgd78059 
3491c42de6dSgd78059 	if (config == NULL) {
3501c42de6dSgd78059 		/*
3511c42de6dSgd78059 		 * There is no config structure associated with this agent id
3521c42de6dSgd78059 		 * so it was probably built by firmware at start of day.  We
3531c42de6dSgd78059 		 * need to create a config structure before we can continue.
3541c42de6dSgd78059 		 */
3551c42de6dSgd78059 		GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure: id=0x%lx "
3561c42de6dSgd78059 		    "No config structure - Need to build one\n", id);
3571c42de6dSgd78059 
3581c42de6dSgd78059 		obp_nodes = gptwocfg_get_obp_created_nodes(ap, id);
3591c42de6dSgd78059 
3601c42de6dSgd78059 		if (obp_nodes != NULL) {
3611c42de6dSgd78059 			config = kmem_zalloc(sizeof (gptwocfg_config_t),
3621c42de6dSgd78059 			    KM_SLEEP);
3631c42de6dSgd78059 			config->gptwo_version = GP2_VERSION;
3641c42de6dSgd78059 			config->gptwo_ap = ap;
3651c42de6dSgd78059 			config->gptwo_portid = id;
3661c42de6dSgd78059 			config->gptwo_nodes = obp_nodes;
3671c42de6dSgd78059 
3681c42de6dSgd78059 			/*
3691c42de6dSgd78059 			 * put config on config list
3701c42de6dSgd78059 			 */
3711c42de6dSgd78059 			mutex_enter(&gptwo_config_list_lock);
3721c42de6dSgd78059 			config->gptwo_next = gptwo_config_list;
3731c42de6dSgd78059 			gptwo_config_list = config;
3741c42de6dSgd78059 			mutex_exit(&gptwo_config_list_lock);
3751c42de6dSgd78059 		} else {
3761c42de6dSgd78059 			cmn_err(CE_WARN, "gptwocfg: gptwocfg_unconfigure: "
3771c42de6dSgd78059 			    "No OBP created nodes for ap=0x%lx agent id=0x%x",
3781c42de6dSgd78059 			    (long)ap, id);
3791c42de6dSgd78059 			return (NULL);
3801c42de6dSgd78059 		}
3811c42de6dSgd78059 	}
3821c42de6dSgd78059 
3831c42de6dSgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure config=0x%lx\n",
3841c42de6dSgd78059 	    config);
3851c42de6dSgd78059 
3861c42de6dSgd78059 	ops = config->gptwo_ops;
3871c42de6dSgd78059 
3881c42de6dSgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure: ops=%lx\n", ops);
3891c42de6dSgd78059 
3901c42de6dSgd78059 	ndi_devi_enter(ap, &circ);
3911c42de6dSgd78059 
3921c42de6dSgd78059 	for (i = 0; i < config->gptwo_nodes->gptwo_number_of_nodes; i++) {
3931c42de6dSgd78059 		dev_info_t *fdip = NULL;
3941c42de6dSgd78059 
3951c42de6dSgd78059 		saf_dip = config->gptwo_nodes->gptwo_nodes[i];
3961c42de6dSgd78059 
3971c42de6dSgd78059 		GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure saf_dip=0x%lx\n",
3981c42de6dSgd78059 		    saf_dip);
3991c42de6dSgd78059 
4001c42de6dSgd78059 		if (saf_dip == NULL) {
4011c42de6dSgd78059 			GPTWO_DEBUG0(1, CE_CONT, "gptwocfg_unconfigure: "
4021c42de6dSgd78059 			    "skipping NULLL saf device\n");
4031c42de6dSgd78059 
4041c42de6dSgd78059 			continue;
4051c42de6dSgd78059 		}
4061c42de6dSgd78059 
4071c42de6dSgd78059 		config->gptwo_nodes->gptwo_nodes[i] = NULL;
4081c42de6dSgd78059 
4091c42de6dSgd78059 		if (ops) {
4101c42de6dSgd78059 			GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_configure "
4111c42de6dSgd78059 			    "ops->gptwocfg_configure=%lx\n",
4121c42de6dSgd78059 			    ops->gptwocfg_configure);
4131c42de6dSgd78059 
4141c42de6dSgd78059 			GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure "
4151c42de6dSgd78059 			    "ops->gptwocfg_unconfigure=%lx\n",
4161c42de6dSgd78059 			    ops->gptwocfg_unconfigure);
4171c42de6dSgd78059 
4181c42de6dSgd78059 			if (ops->gptwocfg_unconfigure != NULL) {
4191c42de6dSgd78059 				config->gptwo_nodes->gptwo_nodes[i] =
4201c42de6dSgd78059 				    ops->gptwocfg_unconfigure(saf_dip);
4211c42de6dSgd78059 
4221c42de6dSgd78059 			}
4231c42de6dSgd78059 		}
4241c42de6dSgd78059 
4251c42de6dSgd78059 		GPTWO_DEBUG1(1, CE_CONT, "e_ddi_branch_destroy <%s>\n",
4261c42de6dSgd78059 		    ddi_get_name(saf_dip));
4271c42de6dSgd78059 
4281c42de6dSgd78059 		ASSERT(e_ddi_branch_held(saf_dip));
4291c42de6dSgd78059 
4301c42de6dSgd78059 		/*
4311c42de6dSgd78059 		 * Don't hold parent busy when calling
4321c42de6dSgd78059 		 * e_ddi_branch_unconfigure/destroy/referenced()
4331c42de6dSgd78059 		 */
4341c42de6dSgd78059 		ndi_devi_exit(ap, circ);
4351c42de6dSgd78059 		if (e_ddi_branch_destroy(saf_dip, &fdip, 0)) {
4361c42de6dSgd78059 			char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4371c42de6dSgd78059 
4381c42de6dSgd78059 			/*
4391c42de6dSgd78059 			 * If non-NULL, fdip is held and must be released.
4401c42de6dSgd78059 			 */
4411c42de6dSgd78059 			if (fdip != NULL) {
4421c42de6dSgd78059 				(void) ddi_pathname(fdip, path);
4431c42de6dSgd78059 				ddi_release_devi(fdip);
4441c42de6dSgd78059 			} else {
4451c42de6dSgd78059 				(void) ddi_pathname(saf_dip, path);
4461c42de6dSgd78059 			}
4471c42de6dSgd78059 
4481c42de6dSgd78059 			cmn_err(CE_WARN, "saf node removal failed: %s (%p)",
4491c42de6dSgd78059 			    path, fdip ? (void *)fdip : (void *)saf_dip);
4501c42de6dSgd78059 
4511c42de6dSgd78059 			kmem_free(path, MAXPATHLEN);
4521c42de6dSgd78059 
4531c42de6dSgd78059 			config->gptwo_nodes->gptwo_nodes[i] = saf_dip;
4541c42de6dSgd78059 			failure = 1;
4551c42de6dSgd78059 		}
4561c42de6dSgd78059 		ndi_devi_enter(ap, &circ);
4571c42de6dSgd78059 	}
4581c42de6dSgd78059 
4591c42de6dSgd78059 	ndi_devi_exit(ap, circ);
4601c42de6dSgd78059 
4611c42de6dSgd78059 	if (!failure) {
4621c42de6dSgd78059 		gptwocfg_free_node_list(config->gptwo_nodes);
4631c42de6dSgd78059 
4641c42de6dSgd78059 		mutex_enter(&gptwo_config_list_lock);
4651c42de6dSgd78059 		if (gptwo_config_list == config) {
4661c42de6dSgd78059 			gptwo_config_list = config->gptwo_next;
4671c42de6dSgd78059 		} else {
4681c42de6dSgd78059 			temp = gptwo_config_list;
4691c42de6dSgd78059 			while (temp->gptwo_next != config) {
4701c42de6dSgd78059 				temp = temp->gptwo_next;
4711c42de6dSgd78059 			}
4721c42de6dSgd78059 			temp->gptwo_next = config->gptwo_next;
4731c42de6dSgd78059 		}
4741c42de6dSgd78059 		mutex_exit(&gptwo_config_list_lock);
4751c42de6dSgd78059 
4761c42de6dSgd78059 		kmem_free(config, sizeof (gptwocfg_config_t));
4771c42de6dSgd78059 		config = NULL;
4781c42de6dSgd78059 	}
4791c42de6dSgd78059 
4801c42de6dSgd78059 	return (config);
4811c42de6dSgd78059 }
4821c42de6dSgd78059 
4831c42de6dSgd78059 int
4841c42de6dSgd78059 gptwocfg_next_node(gptwocfg_cookie_t c, dev_info_t *previous, dev_info_t **next)
4851c42de6dSgd78059 {
4861c42de6dSgd78059 	gptwocfg_config_t *cookie;
4871c42de6dSgd78059 	int i, j;
4881c42de6dSgd78059 
4891c42de6dSgd78059 	GPTWO_DEBUG3(1, CE_WARN, "gptwocfg_next_node"
4901c42de6dSgd78059 	    "(c=0x%lx, previous=0x%lx, next=0x%lx)\n", c, previous, next);
4911c42de6dSgd78059 
4921c42de6dSgd78059 	cookie = (gptwocfg_config_t *)c;
4931c42de6dSgd78059 
4941c42de6dSgd78059 	for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes; i++) {
4951c42de6dSgd78059 		GPTWO_DEBUG1(1, CE_WARN, "0x%lx\n",
4961c42de6dSgd78059 		    cookie->gptwo_nodes->gptwo_nodes[i]);
4971c42de6dSgd78059 	}
4981c42de6dSgd78059 
4991c42de6dSgd78059 	if (previous == NULL) {
5001c42de6dSgd78059 		for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes;
5011c42de6dSgd78059 		    i++) {
5021c42de6dSgd78059 			if (cookie->gptwo_nodes->gptwo_nodes[i]) {
5031c42de6dSgd78059 				*next = cookie->gptwo_nodes->gptwo_nodes[i];
5041c42de6dSgd78059 				GPTWO_DEBUG1(1, CE_WARN, "returned 0x%lx\n",
5051c42de6dSgd78059 				    *next);
5061c42de6dSgd78059 				return (1);
5071c42de6dSgd78059 			}
5081c42de6dSgd78059 		}
5091c42de6dSgd78059 		return (0);
5101c42de6dSgd78059 	}
5111c42de6dSgd78059 
5121c42de6dSgd78059 	for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes; i++) {
5131c42de6dSgd78059 		if (cookie->gptwo_nodes->gptwo_nodes[i] == previous) {
5141c42de6dSgd78059 			for (j = i + 1;
5151c42de6dSgd78059 			    j < cookie->gptwo_nodes->gptwo_number_of_nodes;
5161c42de6dSgd78059 			    j++) {
5171c42de6dSgd78059 				if (cookie->gptwo_nodes->gptwo_nodes[j]) {
5181c42de6dSgd78059 					*next =
5191c42de6dSgd78059 					    cookie->gptwo_nodes->gptwo_nodes[j];
5201c42de6dSgd78059 					GPTWO_DEBUG1(1, CE_WARN,
5211c42de6dSgd78059 					    "returned 0x%lx\n",	*next);
5221c42de6dSgd78059 					return (1);
5231c42de6dSgd78059 				}
5241c42de6dSgd78059 			}
5251c42de6dSgd78059 			*next = NULL;
5261c42de6dSgd78059 			GPTWO_DEBUG1(1, CE_WARN, "returned 0x%lx\n",
5271c42de6dSgd78059 			    *next);
5281c42de6dSgd78059 			return (1);
5291c42de6dSgd78059 		}
5301c42de6dSgd78059 	}
5311c42de6dSgd78059 
5321c42de6dSgd78059 	/*
5331c42de6dSgd78059 	 * previous is probably an invalid dev_info.
5341c42de6dSgd78059 	 */
5351c42de6dSgd78059 	return (0);
5361c42de6dSgd78059 }
5371c42de6dSgd78059 
5381c42de6dSgd78059 static gptwo_new_nodes_t *
5391c42de6dSgd78059 gptwocfg_get_obp_created_nodes(dev_info_t *ap, uint_t id)
5401c42de6dSgd78059 {
5411c42de6dSgd78059 	gptwo_new_nodes_t *obp_nodes;
5421c42de6dSgd78059 	dev_info_t *saf_dev;
5431c42de6dSgd78059 	int i = 0, nodes = 0;
5441c42de6dSgd78059 	int circular_count;
5451c42de6dSgd78059 
5461c42de6dSgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_get_obp_created_nodes - ap=0x%lx "
5471c42de6dSgd78059 	    "id=0x%x\n", ap, id);
5481c42de6dSgd78059 
5491c42de6dSgd78059 	ndi_devi_enter(ap, &circular_count);
5501c42de6dSgd78059 
5511c42de6dSgd78059 	/*
5521c42de6dSgd78059 	 * First go through all the children of the attachment point
5531c42de6dSgd78059 	 * to count matching safari agent ids
5541c42de6dSgd78059 	 */
5551c42de6dSgd78059 	saf_dev = ddi_get_child(ap);
5561c42de6dSgd78059 	while (saf_dev != NULL) {
5571c42de6dSgd78059 		if (ddi_getprop(DDI_DEV_T_ANY, saf_dev, DDI_PROP_DONTPASS,
5581c42de6dSgd78059 		    "portid", -1) == id) {
5591c42de6dSgd78059 			if (&starcat_dr_name) {
5601c42de6dSgd78059 				if (starcat_dr_name(ddi_node_name(saf_dev))
5611c42de6dSgd78059 				    < 0) {
5621c42de6dSgd78059 					saf_dev = ddi_get_next_sibling(saf_dev);
5631c42de6dSgd78059 					continue;
5641c42de6dSgd78059 				}
5651c42de6dSgd78059 			}
5661c42de6dSgd78059 			nodes++;
5671c42de6dSgd78059 		}
5681c42de6dSgd78059 		saf_dev = ddi_get_next_sibling(saf_dev);
5691c42de6dSgd78059 	}
5701c42de6dSgd78059 
5711c42de6dSgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_obp_created_nodes - %d nodes "
5721c42de6dSgd78059 	    "found\n", nodes);
5731c42de6dSgd78059 
5741c42de6dSgd78059 	obp_nodes = gptwocfg_allocate_node_list(nodes);
5751c42de6dSgd78059 
5761c42de6dSgd78059 	/*
5771c42de6dSgd78059 	 * Then fill in the nodes structure.
5781c42de6dSgd78059 	 */
5791c42de6dSgd78059 	saf_dev = ddi_get_child(ap);
5801c42de6dSgd78059 	while ((saf_dev != NULL) && (i < nodes)) {
5811c42de6dSgd78059 		if (ddi_getprop(DDI_DEV_T_ANY, saf_dev, DDI_PROP_DONTPASS,
5821c42de6dSgd78059 		    "portid", -1) == id) {
5831c42de6dSgd78059 			if (&starcat_dr_name) {
5841c42de6dSgd78059 				if (starcat_dr_name(ddi_node_name(saf_dev))
5851c42de6dSgd78059 				    < 0) {
5861c42de6dSgd78059 					saf_dev = ddi_get_next_sibling(saf_dev);
5871c42de6dSgd78059 					continue;
5881c42de6dSgd78059 				}
5891c42de6dSgd78059 			}
5901c42de6dSgd78059 			/*
5911c42de6dSgd78059 			 * Branch rooted at this dip must have been
5921c42de6dSgd78059 			 * held by the DR driver.
5931c42de6dSgd78059 			 */
5941c42de6dSgd78059 			ASSERT(e_ddi_branch_held(saf_dev));
5951c42de6dSgd78059 			obp_nodes->gptwo_nodes[i++] = saf_dev;
5961c42de6dSgd78059 		}
5971c42de6dSgd78059 		saf_dev = ddi_get_next_sibling(saf_dev);
5981c42de6dSgd78059 	}
5991c42de6dSgd78059 
6001c42de6dSgd78059 	ndi_devi_exit(ap, circular_count);
6011c42de6dSgd78059 
6021c42de6dSgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_obp_created_nodes - "
6031c42de6dSgd78059 	    "Returning 0x%lx\n", obp_nodes);
6041c42de6dSgd78059 
6051c42de6dSgd78059 	return (obp_nodes);
6061c42de6dSgd78059 }
6071c42de6dSgd78059 
6081c42de6dSgd78059 void
6091c42de6dSgd78059 gptwocfg_save_handle(dev_info_t *dip, fco_handle_t fco_handle)
6101c42de6dSgd78059 {
6111c42de6dSgd78059 	gptwocfg_handle_list_t *h;
6121c42de6dSgd78059 
6131c42de6dSgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_save_handle - "
6141c42de6dSgd78059 	    "dip=%lx fco_handle=%lx\n", dip, fco_handle);
6151c42de6dSgd78059 
6161c42de6dSgd78059 	h = kmem_zalloc(sizeof (gptwocfg_handle_list_t), KM_SLEEP);
6171c42de6dSgd78059 
6181c42de6dSgd78059 	mutex_enter(&gptwo_handle_list_lock);
6191c42de6dSgd78059 
6201c42de6dSgd78059 	h->next = gptwocfg_handle_list;
6211c42de6dSgd78059 	h->dip = dip;
6221c42de6dSgd78059 	h->fco_handle = fco_handle;
6231c42de6dSgd78059 	gptwocfg_handle_list = h;
6241c42de6dSgd78059 
6251c42de6dSgd78059 	mutex_exit(&gptwo_handle_list_lock);
6261c42de6dSgd78059 }
6271c42de6dSgd78059 
6281c42de6dSgd78059 fco_handle_t
6291c42de6dSgd78059 gptwocfg_get_handle(dev_info_t *dip)
6301c42de6dSgd78059 {
6311c42de6dSgd78059 	gptwocfg_handle_list_t *h, *last;
6321c42de6dSgd78059 	fco_handle_t fco_handle;
6331c42de6dSgd78059 
6341c42de6dSgd78059 	mutex_enter(&gptwo_handle_list_lock);
6351c42de6dSgd78059 
6361c42de6dSgd78059 	h = last = gptwocfg_handle_list;
6371c42de6dSgd78059 
6381c42de6dSgd78059 	while (h != NULL) {
6391c42de6dSgd78059 		if (h->dip == dip) {
6401c42de6dSgd78059 			if (h == gptwocfg_handle_list)
6411c42de6dSgd78059 				gptwocfg_handle_list = h->next;
6421c42de6dSgd78059 			else
6431c42de6dSgd78059 				last->next = h->next;
6441c42de6dSgd78059 
6451c42de6dSgd78059 			mutex_exit(&gptwo_handle_list_lock);
6461c42de6dSgd78059 
6471c42de6dSgd78059 			fco_handle = h->fco_handle;
6481c42de6dSgd78059 
6491c42de6dSgd78059 			kmem_free(h, sizeof (gptwocfg_handle_list_t));
6501c42de6dSgd78059 
6511c42de6dSgd78059 			GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_get_handle - "
6521c42de6dSgd78059 			    "dip=%lx fco_handle=%lx\n", dip, fco_handle);
6531c42de6dSgd78059 
6541c42de6dSgd78059 			return (fco_handle);
6551c42de6dSgd78059 		}
6561c42de6dSgd78059 		last = h;
6571c42de6dSgd78059 		h = h->next;
6581c42de6dSgd78059 	}
6591c42de6dSgd78059 
6601c42de6dSgd78059 	mutex_exit(&gptwo_handle_list_lock);
6611c42de6dSgd78059 
6621c42de6dSgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_handle - dip=%lx NO HANDLE\n",
6631c42de6dSgd78059 	    dip);
6641c42de6dSgd78059 
6651c42de6dSgd78059 	return (0);
6661c42de6dSgd78059 }
6671c42de6dSgd78059 
6681c42de6dSgd78059 void
6691c42de6dSgd78059 gptwocfg_devi_attach_to_parent(dev_info_t *dip)
6701c42de6dSgd78059 {
6711c42de6dSgd78059 	(void) i_ndi_config_node(dip, DS_LINKED, 0);
6721c42de6dSgd78059 }
6731c42de6dSgd78059 
6741c42de6dSgd78059 #ifdef DEBUG
6751c42de6dSgd78059 static void
6761c42de6dSgd78059 debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
6771c42de6dSgd78059     uintptr_t a4, uintptr_t a5)
6781c42de6dSgd78059 {
6791c42de6dSgd78059 	cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
6801c42de6dSgd78059 }
6811c42de6dSgd78059 #endif
682