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
_init(void)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
_fini(void)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
_info(modinfop)147 _info(modinfop)
148 struct modinfo *modinfop;
149 {
150 return (mod_info(&modlinkage, modinfop));
151 }
152
153 gptwo_new_nodes_t *
gptwocfg_allocate_node_list(int number_of_nodes)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
gptwocfg_free_node_list(gptwo_new_nodes_t * gptwo_new_nodes)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
gptwocfg_register_ops(uint_t type,gptwo_cfgfunc_t * cfg_func,gptwo_uncfgfunc_t * uncfg_func)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
gptwocfg_unregister_ops(uint_t type)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
gptwocfg_configure(dev_info_t * ap,spcd_t * pcd,gptwo_aid_t id)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
gptwocfg_unconfigure(dev_info_t * ap,gptwo_aid_t id)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
gptwocfg_next_node(gptwocfg_cookie_t c,dev_info_t * previous,dev_info_t ** next)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 *
gptwocfg_get_obp_created_nodes(dev_info_t * ap,uint_t id)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
gptwocfg_save_handle(dev_info_t * dip,fco_handle_t fco_handle)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
gptwocfg_get_handle(dev_info_t * dip)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
gptwocfg_devi_attach_to_parent(dev_info_t * dip)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
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)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