xref: /onnv-gate/usr/src/uts/sun4u/io/gptwocfg.c (revision 7696:21f5c73c0c15)
14135Sgd78059 /*
24135Sgd78059  * CDDL HEADER START
34135Sgd78059  *
44135Sgd78059  * The contents of this file are subject to the terms of the
54135Sgd78059  * Common Development and Distribution License (the "License").
64135Sgd78059  * You may not use this file except in compliance with the License.
74135Sgd78059  *
84135Sgd78059  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94135Sgd78059  * or http://www.opensolaris.org/os/licensing.
104135Sgd78059  * See the License for the specific language governing permissions
114135Sgd78059  * and limitations under the License.
124135Sgd78059  *
134135Sgd78059  * When distributing Covered Code, include this CDDL HEADER in each
144135Sgd78059  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154135Sgd78059  * If applicable, add the following below this CDDL HEADER, with the
164135Sgd78059  * fields enclosed by brackets "[]" replaced with your own identifying
174135Sgd78059  * information: Portions Copyright [yyyy] [name of copyright owner]
184135Sgd78059  *
194135Sgd78059  * CDDL HEADER END
204135Sgd78059  */
214135Sgd78059 /*
22*7696SRichard.Bean@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
234135Sgd78059  * Use is subject to license terms.
244135Sgd78059  */
254135Sgd78059 
264135Sgd78059 /*
274135Sgd78059  * Safari Configurator  (gptwocfg)
284135Sgd78059  *
294135Sgd78059  */
304135Sgd78059 
314135Sgd78059 #include <sys/types.h>
324135Sgd78059 #include <sys/cred.h>
334135Sgd78059 #include <sys/mman.h>
344135Sgd78059 #include <sys/kmem.h>
354135Sgd78059 #include <sys/conf.h>
364135Sgd78059 #include <sys/cmn_err.h>
374135Sgd78059 #include <sys/ddi.h>
384135Sgd78059 #include <sys/sunddi.h>
394135Sgd78059 #include <sys/sunndi.h>
404135Sgd78059 #include <sys/modctl.h>
414135Sgd78059 #include <sys/stat.h>
424135Sgd78059 #include <sys/param.h>
434135Sgd78059 #include <sys/autoconf.h>
444135Sgd78059 #include <sys/ksynch.h>
454135Sgd78059 #include <sys/promif.h>
464135Sgd78059 #include <sys/ndi_impldefs.h>
474135Sgd78059 #include <sys/ddi_impldefs.h>
484135Sgd78059 #include <sys/gp2cfg.h>
494135Sgd78059 #include <sys/machsystm.h>
504135Sgd78059 #include <sys/platform_module.h>
514135Sgd78059 #pragma weak starcat_dr_name
524135Sgd78059 
534135Sgd78059 #ifdef DEBUG
544135Sgd78059 int gptwocfg_debug = 0;
554135Sgd78059 
564135Sgd78059 static void debug(char *, uintptr_t, uintptr_t,
574135Sgd78059     uintptr_t, uintptr_t, uintptr_t);
584135Sgd78059 
594135Sgd78059 #define	GPTWO_DEBUG0(level, flag, s) if (gptwocfg_debug >= level) \
604135Sgd78059     cmn_err(flag, s)
614135Sgd78059 #define	GPTWO_DEBUG1(level, flag, fmt, a1) if (gptwocfg_debug >= level) \
624135Sgd78059     debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
634135Sgd78059 #define	GPTWO_DEBUG2(level, flag, fmt, a1, a2) if (gptwocfg_debug >= level) \
644135Sgd78059     debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
654135Sgd78059 #define	GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3) \
664135Sgd78059     if (gptwocfg_debug >= level) \
674135Sgd78059     debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
684135Sgd78059 #else
694135Sgd78059 #define	GPTWO_DEBUG0(level, flag, s)
704135Sgd78059 #define	GPTWO_DEBUG1(level, flag, fmt, a1)
714135Sgd78059 #define	GPTWO_DEBUG2(level, flag, fmt, a1, a2)
724135Sgd78059 #define	GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3)
734135Sgd78059 #endif
744135Sgd78059 
754135Sgd78059 kmutex_t gptwo_handle_list_lock;
764135Sgd78059 gptwocfg_handle_list_t *gptwocfg_handle_list;
774135Sgd78059 
784135Sgd78059 static kmutex_t gptwo_config_list_lock;
794135Sgd78059 static gptwocfg_config_t *gptwo_config_list;
804135Sgd78059 
814135Sgd78059 static gptwo_new_nodes_t *
824135Sgd78059     gptwocfg_get_obp_created_nodes(dev_info_t *, uint_t);
834135Sgd78059 
844135Sgd78059 void (*gptwocfg_unclaim_address)(uint_t);
854135Sgd78059 
864135Sgd78059 extern caddr_t efcode_vaddr;
874135Sgd78059 extern int efcode_size;
884135Sgd78059 
894135Sgd78059 #define		GPTWO_NUMBER_OF_DEVICE_TYPES	6
904135Sgd78059 
914135Sgd78059 static kmutex_t gptwocfg_ops_table_lock;
924135Sgd78059 gptwocfg_ops_t *gptwocfg_ops_table[GPTWO_NUMBER_OF_DEVICE_TYPES];
934135Sgd78059 
944135Sgd78059 /*
954135Sgd78059  * Module linkage information for the kernel.
964135Sgd78059  */
974135Sgd78059 
984135Sgd78059 extern struct mod_ops mod_miscops;
994135Sgd78059 
1004135Sgd78059 static struct modlmisc modlmisc = {
1014135Sgd78059 	&mod_miscops, /* Type of module */
102*7696SRichard.Bean@Sun.COM 	"gptwo configurator",
1034135Sgd78059 };
1044135Sgd78059 
1054135Sgd78059 static struct modlinkage modlinkage = {
1064135Sgd78059 	MODREV_1, (void *)&modlmisc, NULL
1074135Sgd78059 };
1084135Sgd78059 
1094135Sgd78059 int
_init(void)1104135Sgd78059 _init(void)
1114135Sgd78059 {
1124135Sgd78059 	unsigned int i;
1134135Sgd78059 
1144135Sgd78059 	GPTWO_DEBUG0(1, CE_WARN, "gptwocfg (Safari Configurator) "
1154135Sgd78059 	    "has been loaded\n");
1164135Sgd78059 
1174135Sgd78059 	mutex_init(&gptwo_config_list_lock, NULL, MUTEX_DRIVER, NULL);
1184135Sgd78059 	mutex_init(&gptwocfg_ops_table_lock, NULL, MUTEX_DRIVER, NULL);
1194135Sgd78059 	gptwo_config_list = NULL;
1204135Sgd78059 
1214135Sgd78059 	mutex_init(&gptwo_handle_list_lock, NULL, MUTEX_DRIVER, NULL);
1224135Sgd78059 	gptwocfg_handle_list = NULL;
1234135Sgd78059 
1244135Sgd78059 	for (i = 0; i < GPTWO_NUMBER_OF_DEVICE_TYPES; i++)
1254135Sgd78059 		gptwocfg_ops_table[i] = NULL;
1264135Sgd78059 
1274135Sgd78059 	return (mod_install(&modlinkage));
1284135Sgd78059 }
1294135Sgd78059 
1304135Sgd78059 int
_fini(void)1314135Sgd78059 _fini(void)
1324135Sgd78059 {
1334135Sgd78059 	int	error;
1344135Sgd78059 
1354135Sgd78059 	error = mod_remove(&modlinkage);
1364135Sgd78059 	if (error != 0) {
1374135Sgd78059 		return (error);
1384135Sgd78059 	}
1394135Sgd78059 	mutex_destroy(&gptwo_config_list_lock);
1404135Sgd78059 	mutex_destroy(&gptwocfg_ops_table_lock);
1414135Sgd78059 	mutex_destroy(&gptwo_handle_list_lock);
1424135Sgd78059 
1434135Sgd78059 	return (0);
1444135Sgd78059 }
1454135Sgd78059 
1464135Sgd78059 int
_info(modinfop)1474135Sgd78059 _info(modinfop)
1484135Sgd78059 struct modinfo *modinfop;
1494135Sgd78059 {
1504135Sgd78059 	return (mod_info(&modlinkage, modinfop));
1514135Sgd78059 }
1524135Sgd78059 
1534135Sgd78059 gptwo_new_nodes_t *
gptwocfg_allocate_node_list(int number_of_nodes)1544135Sgd78059 gptwocfg_allocate_node_list(int number_of_nodes)
1554135Sgd78059 {
1564135Sgd78059 	gptwo_new_nodes_t	*gptwo_new_nodes;
1574135Sgd78059 	int size;
1584135Sgd78059 
1594135Sgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_allocate_node_list- %d nodes",
1604135Sgd78059 	    number_of_nodes);
1614135Sgd78059 
1624135Sgd78059 	size = sizeof (gptwo_new_nodes_t) +
1634135Sgd78059 	    ((number_of_nodes -1) * sizeof (dev_info_t *));
1644135Sgd78059 
1654135Sgd78059 	gptwo_new_nodes = kmem_zalloc(size, KM_SLEEP);
1664135Sgd78059 
1674135Sgd78059 	gptwo_new_nodes->gptwo_number_of_nodes = number_of_nodes;
1684135Sgd78059 	gptwo_new_nodes->gptwo_version = GP2_VERSION;
1694135Sgd78059 
1704135Sgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_allocate_node_list- returned %p\n",
1714135Sgd78059 	    gptwo_new_nodes);
1724135Sgd78059 
1734135Sgd78059 	return (gptwo_new_nodes);
1744135Sgd78059 }
1754135Sgd78059 
1764135Sgd78059 void
gptwocfg_free_node_list(gptwo_new_nodes_t * gptwo_new_nodes)1774135Sgd78059 gptwocfg_free_node_list(gptwo_new_nodes_t *gptwo_new_nodes)
1784135Sgd78059 {
1794135Sgd78059 	int size;
1804135Sgd78059 
1814135Sgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_free_node_list- %p %d nodes",
1824135Sgd78059 	    gptwo_new_nodes, gptwo_new_nodes->gptwo_number_of_nodes);
1834135Sgd78059 
1844135Sgd78059 	size = sizeof (gptwo_new_nodes_t) +
1854135Sgd78059 	    ((gptwo_new_nodes->gptwo_number_of_nodes - 1) *
1864135Sgd78059 	    sizeof (dev_info_t *));
1874135Sgd78059 
1884135Sgd78059 	kmem_free(gptwo_new_nodes, size);
1894135Sgd78059 }
1904135Sgd78059 
1914135Sgd78059 void
gptwocfg_register_ops(uint_t type,gptwo_cfgfunc_t * cfg_func,gptwo_uncfgfunc_t * uncfg_func)1924135Sgd78059 gptwocfg_register_ops(uint_t type, gptwo_cfgfunc_t *cfg_func,
1934135Sgd78059     gptwo_uncfgfunc_t *uncfg_func)
1944135Sgd78059 {
1954135Sgd78059 	/* KM_SLEEP guarantees success */
1964135Sgd78059 	gptwocfg_ops_t *ops = kmem_zalloc(sizeof (gptwocfg_ops_t), KM_SLEEP);
1974135Sgd78059 
1984135Sgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_register_ops: type=%x ops=%lx\n",
1994135Sgd78059 	    type, ops);
2004135Sgd78059 	ASSERT(type < GPTWO_NUMBER_OF_DEVICE_TYPES);
2014135Sgd78059 	ops->gptwocfg_type = type;
2024135Sgd78059 	ops->gptwocfg_version = GPTWOCFG_OPS_VERSION;
2034135Sgd78059 	ops->gptwocfg_configure = cfg_func;
2044135Sgd78059 	ops->gptwocfg_unconfigure = uncfg_func;
2054135Sgd78059 
2064135Sgd78059 	mutex_enter(&gptwocfg_ops_table_lock);
2074135Sgd78059 	gptwocfg_ops_table[type] = ops;
2084135Sgd78059 	mutex_exit(&gptwocfg_ops_table_lock);
2094135Sgd78059 }
2104135Sgd78059 
2114135Sgd78059 
2124135Sgd78059 
2134135Sgd78059 void
gptwocfg_unregister_ops(uint_t type)2144135Sgd78059 gptwocfg_unregister_ops(uint_t type)
2154135Sgd78059 {
2164135Sgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unregister_ops: type=%x\n", type);
2174135Sgd78059 
2184135Sgd78059 	ASSERT(type < GPTWO_NUMBER_OF_DEVICE_TYPES);
2194135Sgd78059 
2204135Sgd78059 	mutex_enter(&gptwocfg_ops_table_lock);
2214135Sgd78059 	kmem_free(gptwocfg_ops_table[type], sizeof (gptwocfg_ops_t));
2224135Sgd78059 	gptwocfg_ops_table[type] = NULL;
2234135Sgd78059 	mutex_exit(&gptwocfg_ops_table_lock);
2244135Sgd78059 }
2254135Sgd78059 
2264135Sgd78059 gptwocfg_cookie_t
gptwocfg_configure(dev_info_t * ap,spcd_t * pcd,gptwo_aid_t id)2274135Sgd78059 gptwocfg_configure(dev_info_t *ap, spcd_t *pcd, gptwo_aid_t id)
2284135Sgd78059 {
2294135Sgd78059 	gptwo_new_nodes_t *new_nodes = NULL;
2304135Sgd78059 	gptwocfg_config_t *config;
2314135Sgd78059 	gptwocfg_ops_t *ops;
2324135Sgd78059 
2334135Sgd78059 	GPTWO_DEBUG3(1, CE_CONT, "gptwocfg_configure:  ap=0x%p pcd=%p id=%x\n",
2344135Sgd78059 	    ap, pcd, id);
2354135Sgd78059 
2364135Sgd78059 	/*
2374135Sgd78059 	 * Look to see if the port is already configured.
2384135Sgd78059 	 */
2394135Sgd78059 	mutex_enter(&gptwo_config_list_lock);
2404135Sgd78059 	config = gptwo_config_list;
2414135Sgd78059 	while (config != NULL) {
2424135Sgd78059 		if (&starcat_dr_name) {
2434135Sgd78059 			if (starcat_dr_name(ddi_node_name(ap)) < 0) {
2444135Sgd78059 				config = config->gptwo_next;
2454135Sgd78059 				continue;
2464135Sgd78059 			}
2474135Sgd78059 		}
2484135Sgd78059 		if (config->gptwo_portid == id) {
2494135Sgd78059 			cmn_err(CE_WARN, "gptwocfg: gptwocfg_configure: "
2504135Sgd78059 			    "0x%x Port already configured\n", id);
2514135Sgd78059 			mutex_exit(&gptwo_config_list_lock);
2524135Sgd78059 			return (NULL);
2534135Sgd78059 		}
2544135Sgd78059 		config = config->gptwo_next;
2554135Sgd78059 	}
2564135Sgd78059 	mutex_exit(&gptwo_config_list_lock);
2574135Sgd78059 
2584135Sgd78059 	if (pcd == NULL) {
2594135Sgd78059 		GPTWO_DEBUG0(1, CE_CONT, "gptwocfg_configure: pcd=NULL\n");
2604135Sgd78059 		return (NULL);
2614135Sgd78059 	}
2624135Sgd78059 
2634135Sgd78059 	if ((pcd->spcd_magic != PCD_MAGIC) ||
2644135Sgd78059 	    (pcd->spcd_version != PCD_VERSION)) {
2654135Sgd78059 		cmn_err(CE_WARN, "gptwocfg: Invalid Port "
2664135Sgd78059 		    "Configuration Descriptor\n");
2674135Sgd78059 		return (NULL);
2684135Sgd78059 	}
2694135Sgd78059 
2704135Sgd78059 	if (pcd->spcd_ptype >= GPTWO_NUMBER_OF_DEVICE_TYPES) {
2714135Sgd78059 		cmn_err(CE_WARN,
2724135Sgd78059 		    "gptwocfg: Invalid device type %x", pcd->spcd_ptype);
2734135Sgd78059 		return (NULL);
2744135Sgd78059 	}
2754135Sgd78059 
2764135Sgd78059 	if (pcd->spcd_prsv != SPCD_RSV_PASS) {
2774135Sgd78059 		cmn_err(CE_WARN,
2784135Sgd78059 		    "gptwocfg: Agent at ID %x has not passed test(s)\n", id);
2794135Sgd78059 		return (NULL);
2804135Sgd78059 	}
2814135Sgd78059 
2824135Sgd78059 	mutex_enter(&gptwocfg_ops_table_lock);
2834135Sgd78059 
2844135Sgd78059 	ops = gptwocfg_ops_table[pcd->spcd_ptype];
2854135Sgd78059 
2864135Sgd78059 	if (ops == NULL) {
2874135Sgd78059 		cmn_err(CE_WARN, "gptwocfg: Ops for type %x have not been "
2884135Sgd78059 		    "registered\n", pcd->spcd_ptype);
2894135Sgd78059 		mutex_exit(&gptwocfg_ops_table_lock);
2904135Sgd78059 		return (NULL);
2914135Sgd78059 	}
2924135Sgd78059 
2934135Sgd78059 	if (ops->gptwocfg_configure == NULL) {
2944135Sgd78059 		cmn_err(CE_WARN, "gptwocfg: no configure routine registered "
2954135Sgd78059 		    "for sfaari type %x\n", pcd->spcd_ptype);
2964135Sgd78059 		mutex_exit(&gptwocfg_ops_table_lock);
2974135Sgd78059 		return (NULL);
2984135Sgd78059 	}
2994135Sgd78059 
3004135Sgd78059 	new_nodes = ops->gptwocfg_configure(ap, pcd, id);
3014135Sgd78059 
3024135Sgd78059 	mutex_exit(&gptwocfg_ops_table_lock);
3034135Sgd78059 
3044135Sgd78059 	if (new_nodes != NULL) {
3054135Sgd78059 		config = kmem_zalloc(sizeof (gptwocfg_config_t), KM_SLEEP);
3064135Sgd78059 		config->gptwo_version = GP2_VERSION;
3074135Sgd78059 		config->gptwo_ap = ap;
3084135Sgd78059 		config->gptwo_portid = id;
3094135Sgd78059 		config->gptwo_nodes = new_nodes;
3104135Sgd78059 		config->gptwo_ops = ops;
3114135Sgd78059 
3124135Sgd78059 		/*
3134135Sgd78059 		 * put config on config list
3144135Sgd78059 		 */
3154135Sgd78059 		mutex_enter(&gptwo_config_list_lock);
3164135Sgd78059 		config->gptwo_next = gptwo_config_list;
3174135Sgd78059 		gptwo_config_list = config;
3184135Sgd78059 		mutex_exit(&gptwo_config_list_lock);
3194135Sgd78059 	} else {
3204135Sgd78059 		config = NULL;
3214135Sgd78059 	}
3224135Sgd78059 
3234135Sgd78059 	return ((gptwocfg_cookie_t)config);
3244135Sgd78059 }
3254135Sgd78059 
3264135Sgd78059 gptwocfg_cookie_t
gptwocfg_unconfigure(dev_info_t * ap,gptwo_aid_t id)3274135Sgd78059 gptwocfg_unconfigure(dev_info_t *ap, gptwo_aid_t id)
3284135Sgd78059 {
3294135Sgd78059 	int i, circ;
3304135Sgd78059 	int failure = 0;
3314135Sgd78059 	dev_info_t *saf_dip;
3324135Sgd78059 	gptwocfg_config_t *config, *temp;
3334135Sgd78059 	gptwo_new_nodes_t *obp_nodes;
3344135Sgd78059 	gptwocfg_ops_t *ops;
3354135Sgd78059 
3364135Sgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_unconfigure: ap=0x%p id=0x%lx\n",
3374135Sgd78059 	    ap, id);
3384135Sgd78059 
3394135Sgd78059 	mutex_enter(&gptwo_config_list_lock);
3404135Sgd78059 	config = gptwo_config_list;
3414135Sgd78059 	while (config != NULL) {
3424135Sgd78059 		if (config->gptwo_portid == id) {
3434135Sgd78059 			break;
3444135Sgd78059 		}
3454135Sgd78059 		config = config->gptwo_next;
3464135Sgd78059 	}
3474135Sgd78059 	mutex_exit(&gptwo_config_list_lock);
3484135Sgd78059 
3494135Sgd78059 	if (config == NULL) {
3504135Sgd78059 		/*
3514135Sgd78059 		 * There is no config structure associated with this agent id
3524135Sgd78059 		 * so it was probably built by firmware at start of day.  We
3534135Sgd78059 		 * need to create a config structure before we can continue.
3544135Sgd78059 		 */
3554135Sgd78059 		GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure: id=0x%lx "
3564135Sgd78059 		    "No config structure - Need to build one\n", id);
3574135Sgd78059 
3584135Sgd78059 		obp_nodes = gptwocfg_get_obp_created_nodes(ap, id);
3594135Sgd78059 
3604135Sgd78059 		if (obp_nodes != NULL) {
3614135Sgd78059 			config = kmem_zalloc(sizeof (gptwocfg_config_t),
3624135Sgd78059 			    KM_SLEEP);
3634135Sgd78059 			config->gptwo_version = GP2_VERSION;
3644135Sgd78059 			config->gptwo_ap = ap;
3654135Sgd78059 			config->gptwo_portid = id;
3664135Sgd78059 			config->gptwo_nodes = obp_nodes;
3674135Sgd78059 
3684135Sgd78059 			/*
3694135Sgd78059 			 * put config on config list
3704135Sgd78059 			 */
3714135Sgd78059 			mutex_enter(&gptwo_config_list_lock);
3724135Sgd78059 			config->gptwo_next = gptwo_config_list;
3734135Sgd78059 			gptwo_config_list = config;
3744135Sgd78059 			mutex_exit(&gptwo_config_list_lock);
3754135Sgd78059 		} else {
3764135Sgd78059 			cmn_err(CE_WARN, "gptwocfg: gptwocfg_unconfigure: "
3774135Sgd78059 			    "No OBP created nodes for ap=0x%lx agent id=0x%x",
3784135Sgd78059 			    (long)ap, id);
3794135Sgd78059 			return (NULL);
3804135Sgd78059 		}
3814135Sgd78059 	}
3824135Sgd78059 
3834135Sgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure config=0x%lx\n",
3844135Sgd78059 	    config);
3854135Sgd78059 
3864135Sgd78059 	ops = config->gptwo_ops;
3874135Sgd78059 
3884135Sgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure: ops=%lx\n", ops);
3894135Sgd78059 
3904135Sgd78059 	ndi_devi_enter(ap, &circ);
3914135Sgd78059 
3924135Sgd78059 	for (i = 0; i < config->gptwo_nodes->gptwo_number_of_nodes; i++) {
3934135Sgd78059 		dev_info_t *fdip = NULL;
3944135Sgd78059 
3954135Sgd78059 		saf_dip = config->gptwo_nodes->gptwo_nodes[i];
3964135Sgd78059 
3974135Sgd78059 		GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure saf_dip=0x%lx\n",
3984135Sgd78059 		    saf_dip);
3994135Sgd78059 
4004135Sgd78059 		if (saf_dip == NULL) {
4014135Sgd78059 			GPTWO_DEBUG0(1, CE_CONT, "gptwocfg_unconfigure: "
4024135Sgd78059 			    "skipping NULLL saf device\n");
4034135Sgd78059 
4044135Sgd78059 			continue;
4054135Sgd78059 		}
4064135Sgd78059 
4074135Sgd78059 		config->gptwo_nodes->gptwo_nodes[i] = NULL;
4084135Sgd78059 
4094135Sgd78059 		if (ops) {
4104135Sgd78059 			GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_configure "
4114135Sgd78059 			    "ops->gptwocfg_configure=%lx\n",
4124135Sgd78059 			    ops->gptwocfg_configure);
4134135Sgd78059 
4144135Sgd78059 			GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure "
4154135Sgd78059 			    "ops->gptwocfg_unconfigure=%lx\n",
4164135Sgd78059 			    ops->gptwocfg_unconfigure);
4174135Sgd78059 
4184135Sgd78059 			if (ops->gptwocfg_unconfigure != NULL) {
4194135Sgd78059 				config->gptwo_nodes->gptwo_nodes[i] =
4204135Sgd78059 				    ops->gptwocfg_unconfigure(saf_dip);
4214135Sgd78059 
4224135Sgd78059 			}
4234135Sgd78059 		}
4244135Sgd78059 
4254135Sgd78059 		GPTWO_DEBUG1(1, CE_CONT, "e_ddi_branch_destroy <%s>\n",
4264135Sgd78059 		    ddi_get_name(saf_dip));
4274135Sgd78059 
4284135Sgd78059 		ASSERT(e_ddi_branch_held(saf_dip));
4294135Sgd78059 
4304135Sgd78059 		/*
4314135Sgd78059 		 * Don't hold parent busy when calling
4324135Sgd78059 		 * e_ddi_branch_unconfigure/destroy/referenced()
4334135Sgd78059 		 */
4344135Sgd78059 		ndi_devi_exit(ap, circ);
4354135Sgd78059 		if (e_ddi_branch_destroy(saf_dip, &fdip, 0)) {
4364135Sgd78059 			char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4374135Sgd78059 
4384135Sgd78059 			/*
4394135Sgd78059 			 * If non-NULL, fdip is held and must be released.
4404135Sgd78059 			 */
4414135Sgd78059 			if (fdip != NULL) {
4424135Sgd78059 				(void) ddi_pathname(fdip, path);
4434135Sgd78059 				ddi_release_devi(fdip);
4444135Sgd78059 			} else {
4454135Sgd78059 				(void) ddi_pathname(saf_dip, path);
4464135Sgd78059 			}
4474135Sgd78059 
4484135Sgd78059 			cmn_err(CE_WARN, "saf node removal failed: %s (%p)",
4494135Sgd78059 			    path, fdip ? (void *)fdip : (void *)saf_dip);
4504135Sgd78059 
4514135Sgd78059 			kmem_free(path, MAXPATHLEN);
4524135Sgd78059 
4534135Sgd78059 			config->gptwo_nodes->gptwo_nodes[i] = saf_dip;
4544135Sgd78059 			failure = 1;
4554135Sgd78059 		}
4564135Sgd78059 		ndi_devi_enter(ap, &circ);
4574135Sgd78059 	}
4584135Sgd78059 
4594135Sgd78059 	ndi_devi_exit(ap, circ);
4604135Sgd78059 
4614135Sgd78059 	if (!failure) {
4624135Sgd78059 		gptwocfg_free_node_list(config->gptwo_nodes);
4634135Sgd78059 
4644135Sgd78059 		mutex_enter(&gptwo_config_list_lock);
4654135Sgd78059 		if (gptwo_config_list == config) {
4664135Sgd78059 			gptwo_config_list = config->gptwo_next;
4674135Sgd78059 		} else {
4684135Sgd78059 			temp = gptwo_config_list;
4694135Sgd78059 			while (temp->gptwo_next != config) {
4704135Sgd78059 				temp = temp->gptwo_next;
4714135Sgd78059 			}
4724135Sgd78059 			temp->gptwo_next = config->gptwo_next;
4734135Sgd78059 		}
4744135Sgd78059 		mutex_exit(&gptwo_config_list_lock);
4754135Sgd78059 
4764135Sgd78059 		kmem_free(config, sizeof (gptwocfg_config_t));
4774135Sgd78059 		config = NULL;
4784135Sgd78059 	}
4794135Sgd78059 
4804135Sgd78059 	return (config);
4814135Sgd78059 }
4824135Sgd78059 
4834135Sgd78059 int
gptwocfg_next_node(gptwocfg_cookie_t c,dev_info_t * previous,dev_info_t ** next)4844135Sgd78059 gptwocfg_next_node(gptwocfg_cookie_t c, dev_info_t *previous, dev_info_t **next)
4854135Sgd78059 {
4864135Sgd78059 	gptwocfg_config_t *cookie;
4874135Sgd78059 	int i, j;
4884135Sgd78059 
4894135Sgd78059 	GPTWO_DEBUG3(1, CE_WARN, "gptwocfg_next_node"
4904135Sgd78059 	    "(c=0x%lx, previous=0x%lx, next=0x%lx)\n", c, previous, next);
4914135Sgd78059 
4924135Sgd78059 	cookie = (gptwocfg_config_t *)c;
4934135Sgd78059 
4944135Sgd78059 	for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes; i++) {
4954135Sgd78059 		GPTWO_DEBUG1(1, CE_WARN, "0x%lx\n",
4964135Sgd78059 		    cookie->gptwo_nodes->gptwo_nodes[i]);
4974135Sgd78059 	}
4984135Sgd78059 
4994135Sgd78059 	if (previous == NULL) {
5004135Sgd78059 		for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes;
5014135Sgd78059 		    i++) {
5024135Sgd78059 			if (cookie->gptwo_nodes->gptwo_nodes[i]) {
5034135Sgd78059 				*next = cookie->gptwo_nodes->gptwo_nodes[i];
5044135Sgd78059 				GPTWO_DEBUG1(1, CE_WARN, "returned 0x%lx\n",
5054135Sgd78059 				    *next);
5064135Sgd78059 				return (1);
5074135Sgd78059 			}
5084135Sgd78059 		}
5094135Sgd78059 		return (0);
5104135Sgd78059 	}
5114135Sgd78059 
5124135Sgd78059 	for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes; i++) {
5134135Sgd78059 		if (cookie->gptwo_nodes->gptwo_nodes[i] == previous) {
5144135Sgd78059 			for (j = i + 1;
5154135Sgd78059 			    j < cookie->gptwo_nodes->gptwo_number_of_nodes;
5164135Sgd78059 			    j++) {
5174135Sgd78059 				if (cookie->gptwo_nodes->gptwo_nodes[j]) {
5184135Sgd78059 					*next =
5194135Sgd78059 					    cookie->gptwo_nodes->gptwo_nodes[j];
5204135Sgd78059 					GPTWO_DEBUG1(1, CE_WARN,
5214135Sgd78059 					    "returned 0x%lx\n",	*next);
5224135Sgd78059 					return (1);
5234135Sgd78059 				}
5244135Sgd78059 			}
5254135Sgd78059 			*next = NULL;
5264135Sgd78059 			GPTWO_DEBUG1(1, CE_WARN, "returned 0x%lx\n",
5274135Sgd78059 			    *next);
5284135Sgd78059 			return (1);
5294135Sgd78059 		}
5304135Sgd78059 	}
5314135Sgd78059 
5324135Sgd78059 	/*
5334135Sgd78059 	 * previous is probably an invalid dev_info.
5344135Sgd78059 	 */
5354135Sgd78059 	return (0);
5364135Sgd78059 }
5374135Sgd78059 
5384135Sgd78059 static gptwo_new_nodes_t *
gptwocfg_get_obp_created_nodes(dev_info_t * ap,uint_t id)5394135Sgd78059 gptwocfg_get_obp_created_nodes(dev_info_t *ap, uint_t id)
5404135Sgd78059 {
5414135Sgd78059 	gptwo_new_nodes_t *obp_nodes;
5424135Sgd78059 	dev_info_t *saf_dev;
5434135Sgd78059 	int i = 0, nodes = 0;
5444135Sgd78059 	int circular_count;
5454135Sgd78059 
5464135Sgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_get_obp_created_nodes - ap=0x%lx "
5474135Sgd78059 	    "id=0x%x\n", ap, id);
5484135Sgd78059 
5494135Sgd78059 	ndi_devi_enter(ap, &circular_count);
5504135Sgd78059 
5514135Sgd78059 	/*
5524135Sgd78059 	 * First go through all the children of the attachment point
5534135Sgd78059 	 * to count matching safari agent ids
5544135Sgd78059 	 */
5554135Sgd78059 	saf_dev = ddi_get_child(ap);
5564135Sgd78059 	while (saf_dev != NULL) {
5574135Sgd78059 		if (ddi_getprop(DDI_DEV_T_ANY, saf_dev, DDI_PROP_DONTPASS,
5584135Sgd78059 		    "portid", -1) == id) {
5594135Sgd78059 			if (&starcat_dr_name) {
5604135Sgd78059 				if (starcat_dr_name(ddi_node_name(saf_dev))
5614135Sgd78059 				    < 0) {
5624135Sgd78059 					saf_dev = ddi_get_next_sibling(saf_dev);
5634135Sgd78059 					continue;
5644135Sgd78059 				}
5654135Sgd78059 			}
5664135Sgd78059 			nodes++;
5674135Sgd78059 		}
5684135Sgd78059 		saf_dev = ddi_get_next_sibling(saf_dev);
5694135Sgd78059 	}
5704135Sgd78059 
5714135Sgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_obp_created_nodes - %d nodes "
5724135Sgd78059 	    "found\n", nodes);
5734135Sgd78059 
5744135Sgd78059 	obp_nodes = gptwocfg_allocate_node_list(nodes);
5754135Sgd78059 
5764135Sgd78059 	/*
5774135Sgd78059 	 * Then fill in the nodes structure.
5784135Sgd78059 	 */
5794135Sgd78059 	saf_dev = ddi_get_child(ap);
5804135Sgd78059 	while ((saf_dev != NULL) && (i < nodes)) {
5814135Sgd78059 		if (ddi_getprop(DDI_DEV_T_ANY, saf_dev, DDI_PROP_DONTPASS,
5824135Sgd78059 		    "portid", -1) == id) {
5834135Sgd78059 			if (&starcat_dr_name) {
5844135Sgd78059 				if (starcat_dr_name(ddi_node_name(saf_dev))
5854135Sgd78059 				    < 0) {
5864135Sgd78059 					saf_dev = ddi_get_next_sibling(saf_dev);
5874135Sgd78059 					continue;
5884135Sgd78059 				}
5894135Sgd78059 			}
5904135Sgd78059 			/*
5914135Sgd78059 			 * Branch rooted at this dip must have been
5924135Sgd78059 			 * held by the DR driver.
5934135Sgd78059 			 */
5944135Sgd78059 			ASSERT(e_ddi_branch_held(saf_dev));
5954135Sgd78059 			obp_nodes->gptwo_nodes[i++] = saf_dev;
5964135Sgd78059 		}
5974135Sgd78059 		saf_dev = ddi_get_next_sibling(saf_dev);
5984135Sgd78059 	}
5994135Sgd78059 
6004135Sgd78059 	ndi_devi_exit(ap, circular_count);
6014135Sgd78059 
6024135Sgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_obp_created_nodes - "
6034135Sgd78059 	    "Returning 0x%lx\n", obp_nodes);
6044135Sgd78059 
6054135Sgd78059 	return (obp_nodes);
6064135Sgd78059 }
6074135Sgd78059 
6084135Sgd78059 void
gptwocfg_save_handle(dev_info_t * dip,fco_handle_t fco_handle)6094135Sgd78059 gptwocfg_save_handle(dev_info_t *dip, fco_handle_t fco_handle)
6104135Sgd78059 {
6114135Sgd78059 	gptwocfg_handle_list_t *h;
6124135Sgd78059 
6134135Sgd78059 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_save_handle - "
6144135Sgd78059 	    "dip=%lx fco_handle=%lx\n", dip, fco_handle);
6154135Sgd78059 
6164135Sgd78059 	h = kmem_zalloc(sizeof (gptwocfg_handle_list_t), KM_SLEEP);
6174135Sgd78059 
6184135Sgd78059 	mutex_enter(&gptwo_handle_list_lock);
6194135Sgd78059 
6204135Sgd78059 	h->next = gptwocfg_handle_list;
6214135Sgd78059 	h->dip = dip;
6224135Sgd78059 	h->fco_handle = fco_handle;
6234135Sgd78059 	gptwocfg_handle_list = h;
6244135Sgd78059 
6254135Sgd78059 	mutex_exit(&gptwo_handle_list_lock);
6264135Sgd78059 }
6274135Sgd78059 
6284135Sgd78059 fco_handle_t
gptwocfg_get_handle(dev_info_t * dip)6294135Sgd78059 gptwocfg_get_handle(dev_info_t *dip)
6304135Sgd78059 {
6314135Sgd78059 	gptwocfg_handle_list_t *h, *last;
6324135Sgd78059 	fco_handle_t fco_handle;
6334135Sgd78059 
6344135Sgd78059 	mutex_enter(&gptwo_handle_list_lock);
6354135Sgd78059 
6364135Sgd78059 	h = last = gptwocfg_handle_list;
6374135Sgd78059 
6384135Sgd78059 	while (h != NULL) {
6394135Sgd78059 		if (h->dip == dip) {
6404135Sgd78059 			if (h == gptwocfg_handle_list)
6414135Sgd78059 				gptwocfg_handle_list = h->next;
6424135Sgd78059 			else
6434135Sgd78059 				last->next = h->next;
6444135Sgd78059 
6454135Sgd78059 			mutex_exit(&gptwo_handle_list_lock);
6464135Sgd78059 
6474135Sgd78059 			fco_handle = h->fco_handle;
6484135Sgd78059 
6494135Sgd78059 			kmem_free(h, sizeof (gptwocfg_handle_list_t));
6504135Sgd78059 
6514135Sgd78059 			GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_get_handle - "
6524135Sgd78059 			    "dip=%lx fco_handle=%lx\n", dip, fco_handle);
6534135Sgd78059 
6544135Sgd78059 			return (fco_handle);
6554135Sgd78059 		}
6564135Sgd78059 		last = h;
6574135Sgd78059 		h = h->next;
6584135Sgd78059 	}
6594135Sgd78059 
6604135Sgd78059 	mutex_exit(&gptwo_handle_list_lock);
6614135Sgd78059 
6624135Sgd78059 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_handle - dip=%lx NO HANDLE\n",
6634135Sgd78059 	    dip);
6644135Sgd78059 
6654135Sgd78059 	return (0);
6664135Sgd78059 }
6674135Sgd78059 
6684135Sgd78059 void
gptwocfg_devi_attach_to_parent(dev_info_t * dip)6694135Sgd78059 gptwocfg_devi_attach_to_parent(dev_info_t *dip)
6704135Sgd78059 {
6714135Sgd78059 	(void) i_ndi_config_node(dip, DS_LINKED, 0);
6724135Sgd78059 }
6734135Sgd78059 
6744135Sgd78059 #ifdef DEBUG
6754135Sgd78059 static void
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)6764135Sgd78059 debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
6774135Sgd78059     uintptr_t a4, uintptr_t a5)
6784135Sgd78059 {
6794135Sgd78059 	cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
6804135Sgd78059 }
6814135Sgd78059 #endif
682