xref: /illumos-gate/usr/src/uts/sun4u/io/gptwocfg.c (revision defc4c8acfa01dba1ef3c13ca0cafccfcede51c0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Safari Configurator  (gptwocfg)
28  *
29  */
30 
31 #include <sys/types.h>
32 #include <sys/cred.h>
33 #include <sys/mman.h>
34 #include <sys/kmem.h>
35 #include <sys/conf.h>
36 #include <sys/cmn_err.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/sunndi.h>
40 #include <sys/modctl.h>
41 #include <sys/stat.h>
42 #include <sys/param.h>
43 #include <sys/autoconf.h>
44 #include <sys/ksynch.h>
45 #include <sys/promif.h>
46 #include <sys/ndi_impldefs.h>
47 #include <sys/ddi_impldefs.h>
48 #include <sys/gp2cfg.h>
49 #include <sys/machsystm.h>
50 #include <sys/platform_module.h>
51 #pragma weak starcat_dr_name
52 
53 #ifdef DEBUG
54 int gptwocfg_debug = 0;
55 
56 static void debug(char *, uintptr_t, uintptr_t,
57     uintptr_t, uintptr_t, uintptr_t);
58 
59 #define	GPTWO_DEBUG0(level, flag, s) if (gptwocfg_debug >= level) \
60     cmn_err(flag, s)
61 #define	GPTWO_DEBUG1(level, flag, fmt, a1) if (gptwocfg_debug >= level) \
62     debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
63 #define	GPTWO_DEBUG2(level, flag, fmt, a1, a2) if (gptwocfg_debug >= level) \
64     debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
65 #define	GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3) \
66     if (gptwocfg_debug >= level) \
67     debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
68 #else
69 #define	GPTWO_DEBUG0(level, flag, s)
70 #define	GPTWO_DEBUG1(level, flag, fmt, a1)
71 #define	GPTWO_DEBUG2(level, flag, fmt, a1, a2)
72 #define	GPTWO_DEBUG3(level, flag, fmt, a1, a2, a3)
73 #endif
74 
75 kmutex_t gptwo_handle_list_lock;
76 gptwocfg_handle_list_t *gptwocfg_handle_list;
77 
78 static kmutex_t gptwo_config_list_lock;
79 static gptwocfg_config_t *gptwo_config_list;
80 
81 static gptwo_new_nodes_t *
82     gptwocfg_get_obp_created_nodes(dev_info_t *, uint_t);
83 
84 void (*gptwocfg_unclaim_address)(uint_t);
85 
86 extern caddr_t efcode_vaddr;
87 extern int efcode_size;
88 
89 #define		GPTWO_NUMBER_OF_DEVICE_TYPES	6
90 
91 static kmutex_t gptwocfg_ops_table_lock;
92 gptwocfg_ops_t *gptwocfg_ops_table[GPTWO_NUMBER_OF_DEVICE_TYPES];
93 
94 /*
95  * Module linkage information for the kernel.
96  */
97 
98 extern struct mod_ops mod_miscops;
99 
100 static struct modlmisc modlmisc = {
101 	&mod_miscops, /* Type of module */
102 	"gptwo configurator",
103 };
104 
105 static struct modlinkage modlinkage = {
106 	MODREV_1, (void *)&modlmisc, NULL
107 };
108 
109 int
110 _init(void)
111 {
112 	unsigned int i;
113 
114 	GPTWO_DEBUG0(1, CE_WARN, "gptwocfg (Safari Configurator) "
115 	    "has been loaded\n");
116 
117 	mutex_init(&gptwo_config_list_lock, NULL, MUTEX_DRIVER, NULL);
118 	mutex_init(&gptwocfg_ops_table_lock, NULL, MUTEX_DRIVER, NULL);
119 	gptwo_config_list = NULL;
120 
121 	mutex_init(&gptwo_handle_list_lock, NULL, MUTEX_DRIVER, NULL);
122 	gptwocfg_handle_list = NULL;
123 
124 	for (i = 0; i < GPTWO_NUMBER_OF_DEVICE_TYPES; i++)
125 		gptwocfg_ops_table[i] = NULL;
126 
127 	return (mod_install(&modlinkage));
128 }
129 
130 int
131 _fini(void)
132 {
133 	int	error;
134 
135 	error = mod_remove(&modlinkage);
136 	if (error != 0) {
137 		return (error);
138 	}
139 	mutex_destroy(&gptwo_config_list_lock);
140 	mutex_destroy(&gptwocfg_ops_table_lock);
141 	mutex_destroy(&gptwo_handle_list_lock);
142 
143 	return (0);
144 }
145 
146 int
147 _info(modinfop)
148 struct modinfo *modinfop;
149 {
150 	return (mod_info(&modlinkage, modinfop));
151 }
152 
153 gptwo_new_nodes_t *
154 gptwocfg_allocate_node_list(int number_of_nodes)
155 {
156 	gptwo_new_nodes_t	*gptwo_new_nodes;
157 	int size;
158 
159 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_allocate_node_list- %d nodes",
160 	    number_of_nodes);
161 
162 	size = sizeof (gptwo_new_nodes_t) +
163 	    ((number_of_nodes -1) * sizeof (dev_info_t *));
164 
165 	gptwo_new_nodes = kmem_zalloc(size, KM_SLEEP);
166 
167 	gptwo_new_nodes->gptwo_number_of_nodes = number_of_nodes;
168 	gptwo_new_nodes->gptwo_version = GP2_VERSION;
169 
170 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_allocate_node_list- returned %p\n",
171 	    gptwo_new_nodes);
172 
173 	return (gptwo_new_nodes);
174 }
175 
176 void
177 gptwocfg_free_node_list(gptwo_new_nodes_t *gptwo_new_nodes)
178 {
179 	int size;
180 
181 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_free_node_list- %p %d nodes",
182 	    gptwo_new_nodes, gptwo_new_nodes->gptwo_number_of_nodes);
183 
184 	size = sizeof (gptwo_new_nodes_t) +
185 	    ((gptwo_new_nodes->gptwo_number_of_nodes - 1) *
186 	    sizeof (dev_info_t *));
187 
188 	kmem_free(gptwo_new_nodes, size);
189 }
190 
191 void
192 gptwocfg_register_ops(uint_t type, gptwo_cfgfunc_t *cfg_func,
193     gptwo_uncfgfunc_t *uncfg_func)
194 {
195 	/* KM_SLEEP guarantees success */
196 	gptwocfg_ops_t *ops = kmem_zalloc(sizeof (gptwocfg_ops_t), KM_SLEEP);
197 
198 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_register_ops: type=%x ops=%lx\n",
199 	    type, ops);
200 	ASSERT(type < GPTWO_NUMBER_OF_DEVICE_TYPES);
201 	ops->gptwocfg_type = type;
202 	ops->gptwocfg_version = GPTWOCFG_OPS_VERSION;
203 	ops->gptwocfg_configure = cfg_func;
204 	ops->gptwocfg_unconfigure = uncfg_func;
205 
206 	mutex_enter(&gptwocfg_ops_table_lock);
207 	gptwocfg_ops_table[type] = ops;
208 	mutex_exit(&gptwocfg_ops_table_lock);
209 }
210 
211 
212 
213 void
214 gptwocfg_unregister_ops(uint_t type)
215 {
216 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unregister_ops: type=%x\n", type);
217 
218 	ASSERT(type < GPTWO_NUMBER_OF_DEVICE_TYPES);
219 
220 	mutex_enter(&gptwocfg_ops_table_lock);
221 	kmem_free(gptwocfg_ops_table[type], sizeof (gptwocfg_ops_t));
222 	gptwocfg_ops_table[type] = NULL;
223 	mutex_exit(&gptwocfg_ops_table_lock);
224 }
225 
226 gptwocfg_cookie_t
227 gptwocfg_configure(dev_info_t *ap, spcd_t *pcd, gptwo_aid_t id)
228 {
229 	gptwo_new_nodes_t *new_nodes = NULL;
230 	gptwocfg_config_t *config;
231 	gptwocfg_ops_t *ops;
232 
233 	GPTWO_DEBUG3(1, CE_CONT, "gptwocfg_configure:  ap=0x%p pcd=%p id=%x\n",
234 	    ap, pcd, id);
235 
236 	/*
237 	 * Look to see if the port is already configured.
238 	 */
239 	mutex_enter(&gptwo_config_list_lock);
240 	config = gptwo_config_list;
241 	while (config != NULL) {
242 		if (&starcat_dr_name) {
243 			if (starcat_dr_name(ddi_node_name(ap)) < 0) {
244 				config = config->gptwo_next;
245 				continue;
246 			}
247 		}
248 		if (config->gptwo_portid == id) {
249 			cmn_err(CE_WARN, "gptwocfg: gptwocfg_configure: "
250 			    "0x%x Port already configured\n", id);
251 			mutex_exit(&gptwo_config_list_lock);
252 			return (NULL);
253 		}
254 		config = config->gptwo_next;
255 	}
256 	mutex_exit(&gptwo_config_list_lock);
257 
258 	if (pcd == NULL) {
259 		GPTWO_DEBUG0(1, CE_CONT, "gptwocfg_configure: pcd=NULL\n");
260 		return (NULL);
261 	}
262 
263 	if ((pcd->spcd_magic != PCD_MAGIC) ||
264 	    (pcd->spcd_version != PCD_VERSION)) {
265 		cmn_err(CE_WARN, "gptwocfg: Invalid Port "
266 		    "Configuration Descriptor\n");
267 		return (NULL);
268 	}
269 
270 	if (pcd->spcd_ptype >= GPTWO_NUMBER_OF_DEVICE_TYPES) {
271 		cmn_err(CE_WARN,
272 		    "gptwocfg: Invalid device type %x", pcd->spcd_ptype);
273 		return (NULL);
274 	}
275 
276 	if (pcd->spcd_prsv != SPCD_RSV_PASS) {
277 		cmn_err(CE_WARN,
278 		    "gptwocfg: Agent at ID %x has not passed test(s)\n", id);
279 		return (NULL);
280 	}
281 
282 	mutex_enter(&gptwocfg_ops_table_lock);
283 
284 	ops = gptwocfg_ops_table[pcd->spcd_ptype];
285 
286 	if (ops == NULL) {
287 		cmn_err(CE_WARN, "gptwocfg: Ops for type %x have not been "
288 		    "registered\n", pcd->spcd_ptype);
289 		mutex_exit(&gptwocfg_ops_table_lock);
290 		return (NULL);
291 	}
292 
293 	if (ops->gptwocfg_configure == NULL) {
294 		cmn_err(CE_WARN, "gptwocfg: no configure routine registered "
295 		    "for sfaari type %x\n", pcd->spcd_ptype);
296 		mutex_exit(&gptwocfg_ops_table_lock);
297 		return (NULL);
298 	}
299 
300 	new_nodes = ops->gptwocfg_configure(ap, pcd, id);
301 
302 	mutex_exit(&gptwocfg_ops_table_lock);
303 
304 	if (new_nodes != NULL) {
305 		config = kmem_zalloc(sizeof (gptwocfg_config_t), KM_SLEEP);
306 		config->gptwo_version = GP2_VERSION;
307 		config->gptwo_ap = ap;
308 		config->gptwo_portid = id;
309 		config->gptwo_nodes = new_nodes;
310 		config->gptwo_ops = ops;
311 
312 		/*
313 		 * put config on config list
314 		 */
315 		mutex_enter(&gptwo_config_list_lock);
316 		config->gptwo_next = gptwo_config_list;
317 		gptwo_config_list = config;
318 		mutex_exit(&gptwo_config_list_lock);
319 	} else {
320 		config = NULL;
321 	}
322 
323 	return ((gptwocfg_cookie_t)config);
324 }
325 
326 gptwocfg_cookie_t
327 gptwocfg_unconfigure(dev_info_t *ap, gptwo_aid_t id)
328 {
329 	int i, circ;
330 	int failure = 0;
331 	dev_info_t *saf_dip;
332 	gptwocfg_config_t *config, *temp;
333 	gptwo_new_nodes_t *obp_nodes;
334 	gptwocfg_ops_t *ops;
335 
336 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_unconfigure: ap=0x%p id=0x%lx\n",
337 	    ap, id);
338 
339 	mutex_enter(&gptwo_config_list_lock);
340 	config = gptwo_config_list;
341 	while (config != NULL) {
342 		if (config->gptwo_portid == id) {
343 			break;
344 		}
345 		config = config->gptwo_next;
346 	}
347 	mutex_exit(&gptwo_config_list_lock);
348 
349 	if (config == NULL) {
350 		/*
351 		 * There is no config structure associated with this agent id
352 		 * so it was probably built by firmware at start of day.  We
353 		 * need to create a config structure before we can continue.
354 		 */
355 		GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure: id=0x%lx "
356 		    "No config structure - Need to build one\n", id);
357 
358 		obp_nodes = gptwocfg_get_obp_created_nodes(ap, id);
359 
360 		if (obp_nodes != NULL) {
361 			config = kmem_zalloc(sizeof (gptwocfg_config_t),
362 			    KM_SLEEP);
363 			config->gptwo_version = GP2_VERSION;
364 			config->gptwo_ap = ap;
365 			config->gptwo_portid = id;
366 			config->gptwo_nodes = obp_nodes;
367 
368 			/*
369 			 * put config on config list
370 			 */
371 			mutex_enter(&gptwo_config_list_lock);
372 			config->gptwo_next = gptwo_config_list;
373 			gptwo_config_list = config;
374 			mutex_exit(&gptwo_config_list_lock);
375 		} else {
376 			cmn_err(CE_WARN, "gptwocfg: gptwocfg_unconfigure: "
377 			    "No OBP created nodes for ap=0x%lx agent id=0x%x",
378 			    (long)ap, id);
379 			return (NULL);
380 		}
381 	}
382 
383 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure config=0x%lx\n",
384 	    config);
385 
386 	ops = config->gptwo_ops;
387 
388 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure: ops=%lx\n", ops);
389 
390 	ndi_devi_enter(ap, &circ);
391 
392 	for (i = 0; i < config->gptwo_nodes->gptwo_number_of_nodes; i++) {
393 		dev_info_t *fdip = NULL;
394 
395 		saf_dip = config->gptwo_nodes->gptwo_nodes[i];
396 
397 		GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure saf_dip=0x%lx\n",
398 		    saf_dip);
399 
400 		if (saf_dip == NULL) {
401 			GPTWO_DEBUG0(1, CE_CONT, "gptwocfg_unconfigure: "
402 			    "skipping NULLL saf device\n");
403 
404 			continue;
405 		}
406 
407 		config->gptwo_nodes->gptwo_nodes[i] = NULL;
408 
409 		if (ops) {
410 			GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_configure "
411 			    "ops->gptwocfg_configure=%lx\n",
412 			    ops->gptwocfg_configure);
413 
414 			GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_unconfigure "
415 			    "ops->gptwocfg_unconfigure=%lx\n",
416 			    ops->gptwocfg_unconfigure);
417 
418 			if (ops->gptwocfg_unconfigure != NULL) {
419 				config->gptwo_nodes->gptwo_nodes[i] =
420 				    ops->gptwocfg_unconfigure(saf_dip);
421 
422 			}
423 		}
424 
425 		GPTWO_DEBUG1(1, CE_CONT, "e_ddi_branch_destroy <%s>\n",
426 		    ddi_get_name(saf_dip));
427 
428 		ASSERT(e_ddi_branch_held(saf_dip));
429 
430 		/*
431 		 * Don't hold parent busy when calling
432 		 * e_ddi_branch_unconfigure/destroy/referenced()
433 		 */
434 		ndi_devi_exit(ap, circ);
435 		if (e_ddi_branch_destroy(saf_dip, &fdip, 0)) {
436 			char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
437 
438 			/*
439 			 * If non-NULL, fdip is held and must be released.
440 			 */
441 			if (fdip != NULL) {
442 				(void) ddi_pathname(fdip, path);
443 				ddi_release_devi(fdip);
444 			} else {
445 				(void) ddi_pathname(saf_dip, path);
446 			}
447 
448 			cmn_err(CE_WARN, "saf node removal failed: %s (%p)",
449 			    path, fdip ? (void *)fdip : (void *)saf_dip);
450 
451 			kmem_free(path, MAXPATHLEN);
452 
453 			config->gptwo_nodes->gptwo_nodes[i] = saf_dip;
454 			failure = 1;
455 		}
456 		ndi_devi_enter(ap, &circ);
457 	}
458 
459 	ndi_devi_exit(ap, circ);
460 
461 	if (!failure) {
462 		gptwocfg_free_node_list(config->gptwo_nodes);
463 
464 		mutex_enter(&gptwo_config_list_lock);
465 		if (gptwo_config_list == config) {
466 			gptwo_config_list = config->gptwo_next;
467 		} else {
468 			temp = gptwo_config_list;
469 			while (temp->gptwo_next != config) {
470 				temp = temp->gptwo_next;
471 			}
472 			temp->gptwo_next = config->gptwo_next;
473 		}
474 		mutex_exit(&gptwo_config_list_lock);
475 
476 		kmem_free(config, sizeof (gptwocfg_config_t));
477 		config = NULL;
478 	}
479 
480 	return (config);
481 }
482 
483 int
484 gptwocfg_next_node(gptwocfg_cookie_t c, dev_info_t *previous, dev_info_t **next)
485 {
486 	gptwocfg_config_t *cookie;
487 	int i, j;
488 
489 	GPTWO_DEBUG3(1, CE_WARN, "gptwocfg_next_node"
490 	    "(c=0x%lx, previous=0x%lx, next=0x%lx)\n", c, previous, next);
491 
492 	cookie = (gptwocfg_config_t *)c;
493 
494 	for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes; i++) {
495 		GPTWO_DEBUG1(1, CE_WARN, "0x%lx\n",
496 		    cookie->gptwo_nodes->gptwo_nodes[i]);
497 	}
498 
499 	if (previous == NULL) {
500 		for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes;
501 		    i++) {
502 			if (cookie->gptwo_nodes->gptwo_nodes[i]) {
503 				*next = cookie->gptwo_nodes->gptwo_nodes[i];
504 				GPTWO_DEBUG1(1, CE_WARN, "returned 0x%lx\n",
505 				    *next);
506 				return (1);
507 			}
508 		}
509 		return (0);
510 	}
511 
512 	for (i = 0; i < cookie->gptwo_nodes->gptwo_number_of_nodes; i++) {
513 		if (cookie->gptwo_nodes->gptwo_nodes[i] == previous) {
514 			for (j = i + 1;
515 			    j < cookie->gptwo_nodes->gptwo_number_of_nodes;
516 			    j++) {
517 				if (cookie->gptwo_nodes->gptwo_nodes[j]) {
518 					*next =
519 					    cookie->gptwo_nodes->gptwo_nodes[j];
520 					GPTWO_DEBUG1(1, CE_WARN,
521 					    "returned 0x%lx\n",	*next);
522 					return (1);
523 				}
524 			}
525 			*next = NULL;
526 			GPTWO_DEBUG1(1, CE_WARN, "returned 0x%lx\n",
527 			    *next);
528 			return (1);
529 		}
530 	}
531 
532 	/*
533 	 * previous is probably an invalid dev_info.
534 	 */
535 	return (0);
536 }
537 
538 static gptwo_new_nodes_t *
539 gptwocfg_get_obp_created_nodes(dev_info_t *ap, uint_t id)
540 {
541 	gptwo_new_nodes_t *obp_nodes;
542 	dev_info_t *saf_dev;
543 	int i = 0, nodes = 0;
544 	int circular_count;
545 
546 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_get_obp_created_nodes - ap=0x%lx "
547 	    "id=0x%x\n", ap, id);
548 
549 	ndi_devi_enter(ap, &circular_count);
550 
551 	/*
552 	 * First go through all the children of the attachment point
553 	 * to count matching safari agent ids
554 	 */
555 	saf_dev = ddi_get_child(ap);
556 	while (saf_dev != NULL) {
557 		if (ddi_getprop(DDI_DEV_T_ANY, saf_dev, DDI_PROP_DONTPASS,
558 		    "portid", -1) == id) {
559 			if (&starcat_dr_name) {
560 				if (starcat_dr_name(ddi_node_name(saf_dev))
561 				    < 0) {
562 					saf_dev = ddi_get_next_sibling(saf_dev);
563 					continue;
564 				}
565 			}
566 			nodes++;
567 		}
568 		saf_dev = ddi_get_next_sibling(saf_dev);
569 	}
570 
571 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_obp_created_nodes - %d nodes "
572 	    "found\n", nodes);
573 
574 	obp_nodes = gptwocfg_allocate_node_list(nodes);
575 
576 	/*
577 	 * Then fill in the nodes structure.
578 	 */
579 	saf_dev = ddi_get_child(ap);
580 	while ((saf_dev != NULL) && (i < nodes)) {
581 		if (ddi_getprop(DDI_DEV_T_ANY, saf_dev, DDI_PROP_DONTPASS,
582 		    "portid", -1) == id) {
583 			if (&starcat_dr_name) {
584 				if (starcat_dr_name(ddi_node_name(saf_dev))
585 				    < 0) {
586 					saf_dev = ddi_get_next_sibling(saf_dev);
587 					continue;
588 				}
589 			}
590 			/*
591 			 * Branch rooted at this dip must have been
592 			 * held by the DR driver.
593 			 */
594 			ASSERT(e_ddi_branch_held(saf_dev));
595 			obp_nodes->gptwo_nodes[i++] = saf_dev;
596 		}
597 		saf_dev = ddi_get_next_sibling(saf_dev);
598 	}
599 
600 	ndi_devi_exit(ap, circular_count);
601 
602 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_obp_created_nodes - "
603 	    "Returning 0x%lx\n", obp_nodes);
604 
605 	return (obp_nodes);
606 }
607 
608 void
609 gptwocfg_save_handle(dev_info_t *dip, fco_handle_t fco_handle)
610 {
611 	gptwocfg_handle_list_t *h;
612 
613 	GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_save_handle - "
614 	    "dip=%lx fco_handle=%lx\n", dip, fco_handle);
615 
616 	h = kmem_zalloc(sizeof (gptwocfg_handle_list_t), KM_SLEEP);
617 
618 	mutex_enter(&gptwo_handle_list_lock);
619 
620 	h->next = gptwocfg_handle_list;
621 	h->dip = dip;
622 	h->fco_handle = fco_handle;
623 	gptwocfg_handle_list = h;
624 
625 	mutex_exit(&gptwo_handle_list_lock);
626 }
627 
628 fco_handle_t
629 gptwocfg_get_handle(dev_info_t *dip)
630 {
631 	gptwocfg_handle_list_t *h, *last;
632 	fco_handle_t fco_handle;
633 
634 	mutex_enter(&gptwo_handle_list_lock);
635 
636 	h = last = gptwocfg_handle_list;
637 
638 	while (h != NULL) {
639 		if (h->dip == dip) {
640 			if (h == gptwocfg_handle_list)
641 				gptwocfg_handle_list = h->next;
642 			else
643 				last->next = h->next;
644 
645 			mutex_exit(&gptwo_handle_list_lock);
646 
647 			fco_handle = h->fco_handle;
648 
649 			kmem_free(h, sizeof (gptwocfg_handle_list_t));
650 
651 			GPTWO_DEBUG2(1, CE_CONT, "gptwocfg_get_handle - "
652 			    "dip=%lx fco_handle=%lx\n", dip, fco_handle);
653 
654 			return (fco_handle);
655 		}
656 		last = h;
657 		h = h->next;
658 	}
659 
660 	mutex_exit(&gptwo_handle_list_lock);
661 
662 	GPTWO_DEBUG1(1, CE_CONT, "gptwocfg_get_handle - dip=%lx NO HANDLE\n",
663 	    dip);
664 
665 	return (0);
666 }
667 
668 void
669 gptwocfg_devi_attach_to_parent(dev_info_t *dip)
670 {
671 	(void) i_ndi_config_node(dip, DS_LINKED, 0);
672 }
673 
674 #ifdef DEBUG
675 static void
676 debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
677     uintptr_t a4, uintptr_t a5)
678 {
679 	cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
680 }
681 #endif
682