xref: /titanic_52/usr/src/uts/sun4u/starcat/io/sc_gptwocfg.c (revision 71269a2275bf5a143dad6461eee2710a344e7261)
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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *     Starcat Specific Glue for Safari Configurator
29  */
30 
31 #include <sys/isa_defs.h>
32 #include <sys/conf.h>
33 #include <sys/kmem.h>
34 #include <sys/debug.h>
35 #include <sys/modctl.h>
36 #include <sys/autoconf.h>
37 #include <sys/hwconf.h>
38 #include <sys/ddi_impldefs.h>
39 #include <sys/ddi.h>
40 #include <sys/sunddi.h>
41 #include <sys/sunndi.h>
42 #include <sys/ndi_impldefs.h>
43 #include <sys/safari_pcd.h>
44 #include <sys/gp2cfg.h>
45 #include <sys/gptwo_cpu.h>
46 #include <sys/gptwo_pci.h>
47 #include <sys/sc_gptwocfg.h>
48 #include <post/scat_dcd.h>
49 #include <sys/machsystm.h>
50 
51 int sc_gptwocfg_debug = 0;
52 
53 #define	SC_DEBUG(level, args) if (sc_gptwocfg_debug >= level) cmn_err args
54 
55 typedef struct sc_gptwocfg_config {
56 	int				board;
57 	struct gptwocfg_config		*port_cookie;
58 	gptwo_aid_t			portid;
59 	struct sc_gptwocfg_config	*link;
60 	struct sc_gptwocfg_config	*next;
61 } sc_gptwocfg_config_t;
62 
63 static kmutex_t sc_gptwo_config_list_lock;
64 static sc_gptwocfg_config_t *sc_gptwo_config_list;
65 static dev_info_t *sc_find_axq_node(uint_t);
66 static sc_gptwocfg_cookie_t sc_configure(uint_t, int);
67 static spcd_t *sc_get_common_pcd(uint_t, uint_t);
68 static void sc_free_common_pcd(spcd_t *);
69 static gptwo_new_nodes_t *sc_gptwocfg_configure_axq(dev_info_t *, uint_t, int);
70 static gptwocfg_config_t *sc_gptwocfg_unconfigure_axq(gptwocfg_config_t *);
71 static void dump_config(sc_gptwocfg_config_t *);
72 static void dump_pcd(spcd_t *);
73 static uint_t sc_get_agent_id(spcd_t *, uint_t, uint_t, uint_t);
74 static char *rsv_string(prdrsv_t);
75 
76 extern gptwo_new_nodes_t *gptwocfg_allocate_node_list(int);
77 extern void gptwocfg_free_node_list(gptwo_new_nodes_t *);
78 
79 static uint8_t *get_memlayout(uint32_t, uint32_t *);
80 
81 #ifdef NO_IOSRAM
82 int iosram_rd(uint32_t, uint32_t, uint32_t, caddr_t);
83 #else
84 extern int iosram_rd(uint32_t, uint32_t, uint32_t, caddr_t);
85 #endif
86 extern void gptwocfg_devi_attach_to_parent(dev_info_t *);
87 
88 /*
89  * Module control operations
90  */
91 
92 extern struct mod_ops mod_miscops;
93 
94 static struct modlmisc modlmisc = {
95 	&mod_miscops, /* Type of module */
96 	"Sun Fire 15000 gptwocfg"
97 };
98 
99 static struct modlinkage modlinkage = {
100 	MODREV_1, (void *)&modlmisc, NULL
101 };
102 
103 int
104 _init()
105 {
106 	int err = 0;
107 
108 	mutex_init(&sc_gptwo_config_list_lock, NULL, MUTEX_DRIVER, NULL);
109 	sc_gptwo_config_list = NULL;
110 
111 	/*
112 	 * CPU/PCI devices are already registered by their respective modules,
113 	 * so all we need to do now is install.
114 	 */
115 	if ((err = mod_install(&modlinkage)) != 0) {
116 		SC_DEBUG(1, (CE_WARN, "sc_gptwocfg failed to load, error=%d\n",
117 		    err));
118 		mutex_destroy(&sc_gptwo_config_list_lock);
119 	} else {
120 		SC_DEBUG(1, (CE_WARN, "sc_gptwocfg has been loaded.\n"));
121 	}
122 	return (err);
123 }
124 
125 int
126 _fini(void)
127 {
128 	mutex_destroy(&sc_gptwo_config_list_lock);
129 	return (mod_remove(&modlinkage));
130 }
131 
132 int
133 _info(modinfop)
134 struct modinfo *modinfop;
135 {
136 	return (mod_info(&modlinkage, modinfop));
137 }
138 
139 static spcd_t *
140 sc_get_common_pcd(uint_t expander, uint_t prd_slot)
141 {
142 	spcd_t *pcd;
143 	gdcd_t *gdcd;
144 	int portid;
145 	int i, j, slot;
146 	int dimm;
147 	char *label1, *label2;
148 
149 	SC_DEBUG(1, (CE_WARN, "sc_get_common_pcd() expander=%d prd_slot=%d\n",
150 	    expander, prd_slot));
151 
152 	gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t), KM_SLEEP);
153 
154 	/*
155 	 * Get the Starcat Specific Global DCD Structure from the golden
156 	 * IOSRAM.
157 	 */
158 	if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) {
159 		cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD "
160 		    "From IOSRAM\n");
161 		kmem_free(gdcd, sizeof (gdcd_t));
162 		return (NULL);
163 	}
164 
165 	if (gdcd->h.dcd_magic != GDCD_MAGIC) {
166 
167 		cmn_err(CE_WARN, "sc_gptwocfg: GDCD Bad Magic 0x%x\n",
168 		    gdcd->h.dcd_magic);
169 
170 		kmem_free(gdcd, sizeof (gdcd_t));
171 		return (NULL);
172 	}
173 
174 	if (gdcd->h.dcd_version != DCD_VERSION) {
175 		cmn_err(CE_WARN, "sc_gptwocfg: GDCD Bad Version: "
176 		    "GDCD Version 0x%x Expecting 0x%x\n",
177 		    gdcd->h.dcd_version, DCD_VERSION);
178 
179 		kmem_free(gdcd, sizeof (gdcd_t));
180 		return (NULL);
181 	}
182 
183 	pcd = (spcd_t *)kmem_zalloc(sizeof (spcd_t), KM_SLEEP);
184 
185 	/*
186 	 * Copy various information from the platform specific Port
187 	 * Resource Descriptor (PRD) To the platform independent
188 	 * Port Configuration Descriptor.
189 	 */
190 	pcd->spcd_magic = PCD_MAGIC;
191 	pcd->spcd_version = PCD_VERSION;
192 	pcd->spcd_ptype = gdcd->dcd_prd[expander][prd_slot].prd_ptype;
193 	pcd->spcd_ver_reg = gdcd->dcd_prd[expander][prd_slot].prd_ver_reg;
194 
195 	if (pcd->spcd_ptype == SAFPTYPE_CPU) {
196 		/*
197 		 * This will calculate the cpu speed based on the
198 		 * the actual frequency ratio * interconnect frequency
199 		 * converted to Mhz.
200 		 */
201 		pcd->spcd_afreq = gdcd->dcd_prd[expander][prd_slot].
202 		    prd_afreq_ratio *
203 		    (uint16_t)((gdcd->dcd_intercon_freq + 500000) / 1000000);
204 	} else {
205 		/*
206 		 * For non-cpu devices, just pass through the frequency
207 		 * unchanged.
208 		 */
209 		pcd->spcd_afreq =
210 		    gdcd->dcd_prd[expander][prd_slot].prd_afreq_ratio;
211 	}
212 
213 	pcd->spcd_cache = gdcd->dcd_prd[expander][prd_slot].prd_cache;
214 
215 	SC_DEBUG(1, (CE_WARN, "Safari Device Status status=0x%x\n",
216 	    gdcd->dcd_prd[expander][prd_slot].prd_prsv));
217 
218 	/*
219 	 * Fill in the entire port status.
220 	 */
221 	if (RSV_GOOD(gdcd->dcd_prd[expander][prd_slot].prd_prsv)) {
222 		pcd->spcd_prsv = SPCD_RSV_PASS;
223 	} else {
224 		pcd->spcd_prsv = SPCD_RSV_FAIL;
225 	}
226 
227 	/*
228 	 * Fill in the per agent status.
229 	 */
230 	if (gdcd->dcd_prd[expander][prd_slot].prd_agent[1] == RSV_UNKNOWN) {
231 		pcd->spcd_agent[0] = pcd->spcd_prsv;
232 		pcd->spcd_agent[1] = SPCD_RSV_FAIL;
233 	} else {
234 		for (i = 0; i < AGENTS_PER_PORT; i++) {
235 
236 			if (RSV_GOOD(
237 			    gdcd->dcd_prd[expander][prd_slot].prd_agent[i]))
238 				pcd->spcd_agent[i] = SPCD_RSV_PASS;
239 			else
240 				pcd->spcd_agent[i] = SPCD_RSV_FAIL;
241 		}
242 	}
243 
244 	/*
245 	 * If this is a CPU device calculate the cpuid for it.  For Starcat
246 	 * the cpuid is in the following format.
247 	 *
248 	 * EEEEEPPAPP
249 	 *
250 	 * where:	EEEEE is the expander
251 	 *		PP_PP is the portid
252 	 *		__A__ is the sub-agent identifier.
253 	 */
254 	if (pcd->spcd_ptype == SAFPTYPE_CPU) {
255 		for (i = 0; i < AGENTS_PER_PORT; i++) {
256 			switch (prd_slot) {
257 			case 0:
258 			case 1:
259 			case 2:
260 			case 3:
261 				portid = (expander << 5) | prd_slot;
262 				break;
263 			case 4: /* Maxcat */
264 				portid = (expander << 5) | 8;
265 				break;
266 			case 5: /* Maxcat */
267 				portid = (expander << 5) | 9;
268 				break;
269 			default:
270 				cmn_err(CE_WARN, "sc_gptwocfg: invalid "
271 				    "prd_slot=%d\n", prd_slot);
272 			}
273 			pcd->spcd_cpuid[i] = (i << 2) | portid;
274 		}
275 	}
276 
277 	/*
278 	 * Starcat does not have ports with UPA devices so
279 	 * spcd_upadev structure will not be filled in.
280 	 */
281 
282 	/*
283 	 * Fill in IO Bus Status
284 	 */
285 	for (i = 0; i < IOBUS_PER_PORT; i++) {
286 
287 		SC_DEBUG(1, (CE_WARN, "   IO Bus Status "
288 		    "bus=%d status=0x%x\n", i,
289 		    gdcd->dcd_prd[expander][prd_slot].prd_iobus_rsv[i]));
290 
291 		if (RSV_GOOD(
292 		    gdcd->dcd_prd[expander][prd_slot].prd_iobus_rsv[i])) {
293 			pcd->spcd_iobus_rsv[i] = SPCD_RSV_PASS;
294 		} else {
295 			pcd->spcd_iobus_rsv[i] = SPCD_RSV_FAIL;
296 		}
297 
298 		for (j = 0; j < IOCARD_PER_BUS; j++)
299 			pcd->spcd_iocard_rsv[i][j] = SPCD_RSV_FAIL;
300 
301 		/*
302 		 * Fill in IO Card Status
303 		 */
304 		for (j = 0; j < IOCARD_PER_BUS; j++) {
305 
306 			SC_DEBUG(1, (CE_WARN, "       Card Status bus=%d "
307 			    "slot=%d status=0x%x\n", i, j,
308 			    gdcd->dcd_prd[expander][prd_slot].
309 			    prd_iocard_rsv[i][j]));
310 
311 			if (j == 1)
312 				continue;
313 
314 			if (j == 0)
315 				slot = 1;
316 			else
317 				slot = j;
318 
319 			/*
320 			 * If POST marked the card as GOOD or if the slot
321 			 * is empty, we want to probe for the device.
322 			 */
323 			if (RSV_GOOD(gdcd->dcd_prd[expander][prd_slot].
324 			    prd_iocard_rsv[i][j]) ||
325 			    (gdcd->dcd_prd[expander][prd_slot].
326 			    prd_iocard_rsv[i][j] == RSV_MISS) ||
327 			    (gdcd->dcd_prd[expander][prd_slot].
328 			    prd_iocard_rsv[i][j] == RSV_EMPTY_CASSETTE))
329 				pcd->spcd_iocard_rsv[i][slot] = SPCD_RSV_PASS;
330 			else
331 				pcd->spcd_iocard_rsv[i][slot] = SPCD_RSV_FAIL;
332 		}
333 	}
334 
335 	/*
336 	 * Fill in WIC Link Status
337 	 */
338 	for (i = 0; i < LINKS_PER_PORT; i++) {
339 		if (RSV_GOOD(
340 		    gdcd->dcd_prd[expander][prd_slot].prd_wic_links[i])) {
341 			pcd->spcd_wic_links[i] = SPCD_RSV_PASS;
342 
343 		} else {
344 			pcd->spcd_wic_links[i] = SPCD_RSV_FAIL;
345 		}
346 	}
347 
348 	/*
349 	 * Get data for the "bank-status" property.
350 	 */
351 	pcd->sprd_bank_rsv[0] =
352 	    rsv_string(gdcd->dcd_prd[expander][prd_slot].prd_bank_rsv[0][0]);
353 	pcd->sprd_bank_rsv[1] =
354 	    rsv_string(gdcd->dcd_prd[expander][prd_slot].prd_bank_rsv[1][0]);
355 	pcd->sprd_bank_rsv[2] =
356 	    rsv_string(gdcd->dcd_prd[expander][prd_slot].prd_bank_rsv[0][1]);
357 	pcd->sprd_bank_rsv[3] =
358 	    rsv_string(gdcd->dcd_prd[expander][prd_slot].prd_bank_rsv[1][1]);
359 
360 	dimm = 0;
361 	for (i = 0; i < PMBANKS_PER_PORT; i++) {
362 		for (j = 0; j < DIMMS_PER_PMBANK; j++) {
363 			if (dimm < MAX_DIMMS_PER_PORT) {
364 				pcd->sprd_dimm[dimm] = rsv_string(
365 				    gdcd->dcd_prd[expander][prd_slot].
366 				    prd_dimm[i][j]);
367 				dimm++;
368 			}
369 		}
370 	}
371 
372 	/*
373 	 * Get data for the "ecache-dimm-label" property.
374 	 *
375 	 * Right now it is hardcoded, but we should eventually get this
376 	 * from the SC.
377 	 */
378 	label1 = NULL;
379 	label2 = NULL;
380 
381 	switch (prd_slot) {
382 	case 0:
383 		label1 = "4400";
384 		label2 = "4300";
385 		break;
386 	case 1:
387 		label1 = "5400";
388 		label2 = "5300";
389 		break;
390 	case 2:
391 		label1 = "6400";
392 		label2 = "6300";
393 		break;
394 	case 3:
395 		label1 = "7400";
396 		label2 = "7300";
397 		break;
398 
399 	/*
400 	 * Maxcat labels.
401 	 */
402 	case 4:
403 		label1 = "6400";
404 		label2 = "6300";
405 		break;
406 	case 5:
407 		label1 = "7400";
408 		label2 = "7300";
409 		break;
410 	}
411 
412 	i = 0;
413 	if (label1) {
414 		pcd->sprd_ecache_dimm_label[i] =
415 		    kmem_alloc(strlen(label1) + 1, KM_SLEEP);
416 
417 		(void) strcpy(pcd->sprd_ecache_dimm_label[i], label1);
418 
419 		i++;
420 	}
421 	if (label2) {
422 		pcd->sprd_ecache_dimm_label[i] =
423 		    kmem_alloc(strlen(label2) + 1, KM_SLEEP);
424 
425 		(void) strcpy(pcd->sprd_ecache_dimm_label[i], label2);
426 
427 		i++;
428 
429 	}
430 
431 	kmem_free(gdcd, sizeof (gdcd_t));
432 
433 #ifdef DEBUG
434 	dump_pcd(pcd);
435 #endif
436 
437 	return (pcd);
438 }
439 
440 void
441 sc_free_common_pcd(spcd_t *pcd)
442 {
443 	int i;
444 
445 	SC_DEBUG(1, (CE_WARN, "sc_free_common_pcd pcd=%p\n", pcd));
446 
447 	if (pcd->memory_layout && pcd->memory_layout_size) {
448 		SC_DEBUG(1, (CE_WARN, "sc_free_common_pcd: memory_layout %p "
449 		    "size=%x", pcd->memory_layout, pcd->memory_layout_size));
450 		kmem_free(pcd->memory_layout, pcd->memory_layout_size);
451 	}
452 
453 	for (i = 0; i < MAX_BANKS_PER_PORT; i++) {
454 		if (pcd->sprd_bank_rsv[i]) {
455 			kmem_free(pcd->sprd_bank_rsv[i],
456 			    strlen(pcd->sprd_bank_rsv[i]) + 1);
457 
458 			pcd->sprd_bank_rsv[i] = NULL;
459 		}
460 	}
461 
462 	for (i = 0; i < MAX_DIMMS_PER_PORT; i++) {
463 		if (pcd->sprd_dimm[i]) {
464 			kmem_free(pcd->sprd_dimm[i],
465 			    strlen(pcd->sprd_dimm[i]) + 1);
466 
467 			pcd->sprd_dimm[i] = NULL;
468 		}
469 		if (pcd->sprd_ecache_dimm_label[i]) {
470 			kmem_free(pcd->sprd_ecache_dimm_label[i],
471 			    strlen(pcd->sprd_ecache_dimm_label[i]) + 1);
472 
473 			pcd->sprd_ecache_dimm_label[i] = NULL;
474 		}
475 	}
476 
477 	kmem_free(pcd, sizeof (spcd_t));
478 }
479 
480 sc_gptwocfg_cookie_t
481 sc_probe_board(uint_t board)
482 {
483 	return (sc_configure(board, 1));
484 }
485 
486 static sc_gptwocfg_cookie_t
487 sc_configure(uint_t board, int create_nodes)
488 {
489 	spcd_t *pcd;
490 	dev_info_t *ap, *axq_dip;
491 	uint_t agent_id;
492 	uint_t prd_slot, prd_slot_start, prd_slot_end;
493 	uint_t expander, slot;
494 	gptwo_new_nodes_t *new_nodes;
495 	gptwocfg_config_t *port_cookie;
496 	struct sc_gptwocfg_config *board_config, *last, *new;
497 	int created_node = 0;
498 	uint32_t size;
499 
500 	SC_DEBUG(1, (CE_WARN, "sc_configure: board=%d, create_nodes=%d\n",
501 	    board, create_nodes));
502 
503 	if (board > 35) {
504 		SC_DEBUG(1, (CE_WARN, "sc_gptwocfg - probe_board - "
505 		    "invalid board 0x%x\n", board));
506 		return (NULL);
507 	}
508 
509 	slot = board & 1;	/* Extract Slot Number */
510 	expander = board >> 1;	/* Extract Expander Number */
511 
512 	SC_DEBUG(1, (CE_WARN, "sc_configure: exp=0x%x slot=0x%x\n",
513 	    expander, slot));
514 
515 	/*
516 	 * Get the Attachment Point.  For Starcat the parent of all
517 	 * Safari children is root node.
518 	 */
519 	ap = ddi_root_node();
520 
521 	/*
522 	 * Get the agent id of the AXQ.
523 	 */
524 	agent_id = (expander << 5) | 0x1e | slot;
525 
526 	/*
527 	 * Look to see if the board is already configured by searching for
528 	 * its AXQ.
529 	 */
530 	if (create_nodes && (axq_dip = sc_find_axq_node(agent_id))) {
531 		ddi_release_devi(axq_dip);
532 		cmn_err(CE_WARN, "Board %d AXQ is already configured\n",
533 		    board);
534 		return (NULL);
535 	}
536 
537 	/*
538 	 * Probe AXQ first
539 	 */
540 	SC_DEBUG(1, (CE_WARN, "sc_configure: Probing AXQ exp=0x%x brd=0x%x\n",
541 	    expander, slot));
542 
543 	/*
544 	 * The generic gptwocfg does not support the AXQ, so we need
545 	 * to configure it. The AXQ branch is returned held.
546 	 */
547 	new_nodes = sc_gptwocfg_configure_axq(ap, agent_id, create_nodes);
548 
549 	if (new_nodes == NULL) {
550 		SC_DEBUG(1, (CE_WARN, "sc_configure: Can not probe AXQ\n"));
551 		return (NULL);
552 	}
553 
554 	port_cookie = kmem_zalloc(sizeof (gptwocfg_config_t), KM_SLEEP);
555 
556 	/*
557 	 * Build a cookie for the AXQ.
558 	 */
559 	port_cookie->gptwo_ap = ap;
560 	port_cookie->gptwo_portid = agent_id;
561 	port_cookie->gptwo_nodes = new_nodes;
562 
563 	board_config = kmem_zalloc(sizeof (sc_gptwocfg_config_t), KM_SLEEP);
564 
565 	board_config->port_cookie = port_cookie;
566 	board_config->board = board;
567 	board_config->portid = agent_id;
568 	board_config->link = NULL;
569 	last = board_config;
570 
571 	mutex_enter(&sc_gptwo_config_list_lock);
572 	board_config->next = sc_gptwo_config_list;
573 	sc_gptwo_config_list = board_config;
574 	mutex_exit(&sc_gptwo_config_list_lock);
575 
576 	SC_DEBUG(1, (CE_WARN, "sc_configure: AXQ Probing Complete. "
577 	    "%d nodes added\n", new_nodes->gptwo_number_of_nodes));
578 
579 	/*
580 	 * Determine the starting ending slots of the PRD array.
581 	 */
582 	switch (slot) {
583 	case 0:		/* Full Bandwidth Slot */
584 		prd_slot_start = 0;
585 		prd_slot_end = 3;
586 		break;
587 	case 1:		/* Half Bandwidth Slot */
588 		prd_slot_start = 4;
589 		prd_slot_end = 5;
590 		break;
591 	default:
592 		SC_DEBUG(1, (CE_WARN, "Unknown Board Address - "
593 		    "Can not probe\n"));
594 		return (board_config);
595 	}
596 
597 	/*
598 	 * For each valid PRD entry, determine the agent id which is based
599 	 * on what type of device is described by the slot, and then
600 	 * call the safari configurator.
601 	 */
602 	for (prd_slot = prd_slot_start; prd_slot <= prd_slot_end; prd_slot++) {
603 
604 		pcd = sc_get_common_pcd(expander, prd_slot);
605 
606 		if (pcd == NULL) {
607 
608 			/*
609 			 * We can not get a PCD for this port so skip it.
610 			 */
611 			cmn_err(CE_WARN, "sc_gptwocfg: Can not get PCD "
612 			    "expander 0x%x prd slot 0x%x\n",
613 			    expander, prd_slot);
614 
615 			return (board_config);
616 		}
617 
618 		/*
619 		 * Only configure good devices.
620 		 */
621 		if (pcd->spcd_prsv == SPCD_RSV_PASS) {
622 			/*
623 			 * Determine the agent id.
624 			 */
625 			agent_id = sc_get_agent_id(
626 			    pcd, expander, slot, prd_slot);
627 
628 			pcd->memory_layout = get_memlayout(agent_id, &size);
629 			pcd->memory_layout_size = size;
630 
631 			/*
632 			 * Call Platform Independent gptwo configurator to
633 			 * create node and properties.
634 			 */
635 			if (create_nodes) {
636 				port_cookie =
637 				    gptwocfg_configure(ap, pcd, agent_id);
638 				if (port_cookie)
639 					created_node++;
640 			}
641 
642 			new = kmem_zalloc
643 			    (sizeof (sc_gptwocfg_config_t), KM_SLEEP);
644 
645 			/*
646 			 * XXX Shouldn't port_cookie be NULL if
647 			 * !create_nodes ?
648 			 */
649 			new->port_cookie = port_cookie;
650 			new->portid = agent_id;
651 			new->link = NULL;
652 			last->link = new;
653 			last = new;
654 		} else {
655 			SC_DEBUG(1, (CE_WARN, "sc_configure: Bad Agent "
656 			    "Exp=0x%x PRD Slot=0x%x  prsv Status=0x%x\n",
657 			    expander, prd_slot, pcd->spcd_prsv));
658 		}
659 
660 		sc_free_common_pcd(pcd);
661 
662 	} /* for loop */
663 
664 	dump_config(board_config);
665 
666 	if (create_nodes && !created_node) {
667 		SC_DEBUG(1, (CE_WARN, "sc_configure: GPTWO Devices failed "
668 		    "to configure - unprobing board %d\n", board));
669 		board_config = sc_unprobe_board(board);
670 	}
671 
672 	SC_DEBUG(1, (CE_WARN, "sc_configure: Returning 0x%p\n",
673 	    board_config));
674 
675 	return (board_config);
676 }
677 
678 sc_gptwocfg_cookie_t
679 sc_unprobe_board(uint_t board)
680 {
681 	sc_gptwocfg_config_t *board_config, *axq_config, *prior_config;
682 	gptwocfg_cookie_t port_cookie;
683 
684 	SC_DEBUG(1, (CE_WARN, "sc_unprobe_board: board=%d\n", board));
685 
686 	if (board > 35) {
687 		SC_DEBUG(1, (CE_WARN, "sc_unprobe_board: "
688 		    "invalid board 0x%x\n", board));
689 		return (NULL);
690 	}
691 	mutex_enter(&sc_gptwo_config_list_lock);
692 	board_config = sc_gptwo_config_list;
693 	while (board_config != NULL) {
694 		if (board_config->board == board) {
695 			break;
696 		}
697 		board_config = board_config->next;
698 	}
699 	mutex_exit(&sc_gptwo_config_list_lock);
700 
701 	if (board_config == NULL) {
702 
703 		SC_DEBUG(1, (CE_WARN, "sc_unprobe_board: No "
704 		    "config structure board=0x%x\n", board));
705 
706 		/*
707 		 * Configure the board without creating nodes.
708 		 */
709 		board_config = sc_configure(board, 0);
710 
711 		if (board_config == NULL) {
712 
713 			cmn_err(CE_WARN, "sc_gptwocfg: sc_unprobe_board: "
714 			    "Unable to unconfigure board %d - board is not "
715 			    "configured\n", board);
716 
717 			return (NULL);
718 		}
719 	}
720 
721 	axq_config = board_config;
722 
723 	/*
724 	 * Walk the link of ports on this board and unconfigure them.
725 	 * Save the AXQ for last.
726 	 */
727 	while (board_config->link != NULL) {
728 		prior_config = board_config;
729 		board_config = board_config->link;
730 
731 		SC_DEBUG(1, (CE_WARN, "sc_unprobe_board: "
732 		    "calling gptwocfg_unconfigure(ap=0x%p portid=0x%x)\n",
733 		    ddi_root_node(), board_config->portid));
734 
735 		port_cookie = gptwocfg_unconfigure(ddi_root_node(),
736 		    board_config->portid);
737 
738 		SC_DEBUG(1, (CE_WARN, "sc_unprobe_board: "
739 		    "gptwocfg_unconfigure returned cookie=0x%p\n",
740 		    port_cookie));
741 
742 		if (port_cookie == NULL) {
743 			/*
744 			 * Can be removed from list.
745 			 */
746 			prior_config->link = board_config->link;
747 			kmem_free(board_config, sizeof (sc_gptwocfg_config_t));
748 			board_config = prior_config;
749 		} else {
750 			board_config->port_cookie = port_cookie;
751 		}
752 	}
753 
754 	if (axq_config->link == NULL) {
755 
756 		/*
757 		 * If all the other Safari devices have been successfully
758 		 * unconfigured, then the AXQ can be unconfigured.
759 		 */
760 		axq_config->port_cookie =
761 		    sc_gptwocfg_unconfigure_axq(axq_config->port_cookie);
762 
763 		if (axq_config->port_cookie == NULL) {
764 
765 			/*
766 			 * If the AXQ was successfully unconfigured, then
767 			 * the board is removed from the configured list.
768 			 */
769 			mutex_enter(&sc_gptwo_config_list_lock);
770 			if (sc_gptwo_config_list == axq_config) {
771 				sc_gptwo_config_list = axq_config->next;
772 			} else {
773 				board_config = sc_gptwo_config_list;
774 				while (board_config->next != axq_config) {
775 					board_config = board_config->next;
776 				}
777 				board_config->next = axq_config->next;
778 			}
779 			mutex_exit(&sc_gptwo_config_list_lock);
780 			kmem_free(axq_config, sizeof (sc_gptwocfg_config_t));
781 			axq_config = NULL;
782 		}
783 	}
784 	dump_config(axq_config);
785 	return (axq_config);
786 }
787 
788 int
789 sc_next_node(sc_gptwocfg_cookie_t c, dev_info_t *previous, dev_info_t **next)
790 {
791 	dev_info_t *dip;
792 	sc_gptwocfg_config_t *cookie;
793 
794 	SC_DEBUG(1, (CE_WARN, "sccfg: sccfg_next_node"
795 	    "(c=0x%p, previous=0x%p, next=0x%p)\n", c, previous, next));
796 
797 	cookie = (sc_gptwocfg_config_t *)c;
798 
799 	if (cookie == NULL) {
800 		cmn_err(CE_WARN, "sccfg: sccfg_next_node - "
801 		    "Invalid Cookie\n");
802 		return (0);
803 	}
804 	if (previous == NULL) {
805 		/*
806 		 * Start with the AXQ node.
807 		 */
808 		if (gptwocfg_next_node(cookie->port_cookie, NULL, &dip)) {
809 			*next = dip;
810 			return (1);
811 		} else {
812 			return (0);
813 		}
814 	}
815 
816 	while (cookie != NULL) {
817 		if (gptwocfg_next_node(cookie->port_cookie, previous, &dip)) {
818 			if ((dip == NULL) && (cookie->link == NULL)) {
819 				*next = NULL;
820 				return (1);
821 			}
822 			if (dip != NULL) {
823 				*next = dip;
824 				return (1);
825 			}
826 
827 			/* dip == NULL */
828 
829 			previous = NULL;
830 		}
831 		cookie = cookie->link;
832 	}
833 
834 	return (0);
835 }
836 
837 static dev_info_t *
838 sc_find_axq_node(uint_t axq_id)
839 {
840 	char *name;
841 	int size;
842 	gptwo_regspec_t *reg;
843 	dev_info_t *dip;
844 	uint_t id;
845 	int circ;
846 
847 	SC_DEBUG(1, (CE_CONT, "sc_find_axq_node: id=0x%x\n", axq_id));
848 
849 	/*
850 	 * Hold root node busy to walk its child list
851 	 */
852 	ndi_devi_enter(ddi_root_node(), &circ);
853 
854 	dip = ddi_get_child(ddi_root_node());
855 
856 	while (dip != NULL) {
857 
858 		SC_DEBUG(1, (CE_CONT, "Searching dip=0x%p for our AXQ\n",
859 		    dip));
860 
861 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
862 		    DDI_PROP_DONTPASS, "name", (caddr_t)&name, &size)
863 		    != DDI_PROP_SUCCESS) {
864 
865 			/*
866 			 * This node does not have a name property.
867 			 */
868 			SC_DEBUG(1, (CE_CONT, "dip=0x%p does not have a "
869 			    "'name' property\n", dip));
870 
871 			dip = ddi_get_next_sibling(dip);
872 			continue;
873 		}
874 
875 		SC_DEBUG(1, (CE_CONT, "dip=0x%p name=%s\n", dip, name));
876 
877 		if (strcmp(name, "address-extender-queue")) {
878 
879 			/*
880 			 * This node is not a AXQ node.
881 			 */
882 			SC_DEBUG(1, (CE_CONT, "dip=0x%p is not an AXQ "
883 			    "node\n", dip));
884 			kmem_free(name, size);
885 			dip = ddi_get_next_sibling(dip);
886 			continue;
887 		}
888 		kmem_free(name, size);
889 
890 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
891 		    DDI_PROP_DONTPASS, "reg", (caddr_t)&reg, &size)
892 		    != DDI_PROP_SUCCESS) {
893 
894 			/*
895 			 * This AXQ node does not have a reg property.
896 			 */
897 			SC_DEBUG(1, (CE_CONT, "dip=0x%p (AXQ Node) does "
898 			    "have a 'reg' property\n", dip));
899 			dip = ddi_get_next_sibling(dip);
900 			continue;
901 		}
902 
903 		id = ((reg[0].gptwo_phys_hi & 1) << 9) |
904 		    ((reg[0].gptwo_phys_low & 0xff800000) >> 23);
905 
906 		kmem_free(reg, size);
907 
908 		if (axq_id != id) {
909 
910 			/*
911 			 * This is the wrong AXQ node.
912 			 */
913 			SC_DEBUG(1, (CE_CONT, "dip=0x%p Wrong node id=0x%x\n",
914 			    dip, id));
915 
916 			dip = ddi_get_next_sibling(dip);
917 			continue;
918 
919 		}
920 
921 		/*
922 		 * The correct AXQ node was found.
923 		 */
924 		SC_DEBUG(1, (CE_CONT, "dip=0x%p Found AXQ Node\n", dip));
925 		ndi_hold_devi(dip);
926 		break;
927 	}
928 	ndi_devi_exit(ddi_root_node(), circ);
929 
930 	SC_DEBUG(1, (CE_CONT, "sc_find_axq_node: Returning 0x%p\n", dip));
931 
932 	return (dip);
933 }
934 
935 struct axq_arg {
936 	uint_t id;
937 	dev_info_t *axq_dip;
938 };
939 
940 /*ARGSUSED*/
941 static int
942 axq_set_prop(dev_info_t *axq_dip, void *arg, uint_t flags)
943 {
944 	struct axq_arg *aqp = (struct axq_arg *)arg;
945 	gptwo_regspec_t	reg[2];
946 	uint_t		id;
947 
948 	ASSERT(aqp);
949 
950 	id = aqp->id;
951 
952 	if (ndi_prop_update_string(DDI_DEV_T_NONE, axq_dip,
953 	    "name", "address-extender-queue") != DDI_SUCCESS) {
954 		SC_DEBUG(1, (CE_CONT, "gptwocfg_configure_pci: failed "
955 		    "to create name property\n"));
956 		return (DDI_WALK_ERROR);
957 	}
958 
959 	if (ndi_prop_update_string(DDI_DEV_T_NONE, axq_dip,
960 	    "device_type", "address-extender-queue") != DDI_SUCCESS) {
961 		SC_DEBUG(1, (CE_CONT, "gptwocfg_configure_pci: failed "
962 		    "to create device_type property\n"));
963 		return (DDI_WALK_ERROR);
964 	}
965 
966 	if (ndi_prop_update_string(DDI_DEV_T_NONE, axq_dip,
967 	    "compatible", "SUNW,axq") != DDI_SUCCESS) {
968 		SC_DEBUG(1, (CE_CONT, "sc_gptwocfg: failed "
969 		    "to create compatible property\n"));
970 		return (DDI_WALK_ERROR);
971 	}
972 
973 	if (ndi_prop_update_int(DDI_DEV_T_NONE, axq_dip,
974 	    "portid", id) != DDI_SUCCESS) {
975 		SC_DEBUG(1, (CE_CONT, "gptwocfg_configure_pci: failed "
976 		    "to create portid property\n"));
977 		return (DDI_WALK_ERROR);
978 	}
979 
980 	reg[0].gptwo_phys_hi = 0x400 | (id >> 9);
981 	reg[0].gptwo_phys_low = (id << 23);
982 	reg[0].gptwo_size_hi = 0;
983 	reg[0].gptwo_size_low = 0x520;
984 
985 	reg[1].gptwo_phys_hi = 0x401;
986 	reg[1].gptwo_phys_low = 0xf0000000;
987 	reg[1].gptwo_size_hi = 0;
988 	reg[1].gptwo_size_low = 0x520;
989 
990 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE,
991 	    axq_dip, "reg", (int *)&reg,
992 	    (sizeof (gptwo_regspec_t) * 2)/sizeof (int)) != DDI_SUCCESS) {
993 		SC_DEBUG(1, (CE_CONT, "gptwocfg_configure_pci: failed "
994 		    "to create reg property\n"));
995 		return (DDI_WALK_ERROR);
996 	}
997 
998 	return (DDI_WALK_TERMINATE);
999 }
1000 
1001 /*ARGSUSED*/
1002 static void
1003 get_axq_dip(dev_info_t *rdip, void *arg, uint_t flags)
1004 {
1005 	struct axq_arg *aqp = (struct axq_arg *)arg;
1006 
1007 	ASSERT(aqp);
1008 
1009 	aqp->axq_dip = rdip;
1010 }
1011 
1012 static gptwo_new_nodes_t *
1013 sc_gptwocfg_configure_axq(dev_info_t *ap, uint_t id, int create_nodes)
1014 {
1015 	struct axq_arg arg = {0};
1016 	devi_branch_t b = {0};
1017 	dev_info_t *axq_dip, *fdip = NULL;
1018 	gptwo_new_nodes_t *new_nodes = NULL;
1019 	int rv;
1020 
1021 	SC_DEBUG(1, (CE_CONT, "gptwocfg_configure_axq: id=0x%x "
1022 	    "create_nodes=%d\n", id, create_nodes));
1023 
1024 	if (!create_nodes) {
1025 		axq_dip = sc_find_axq_node(id);
1026 
1027 		if (axq_dip) {
1028 			new_nodes = gptwocfg_allocate_node_list(1);
1029 			new_nodes->gptwo_nodes[0] = axq_dip;
1030 			ASSERT(!e_ddi_branch_held(axq_dip));
1031 			e_ddi_branch_hold(axq_dip);
1032 			/*
1033 			 * Release hold from sc_find_axq_node()
1034 			 */
1035 			ddi_release_devi(axq_dip);
1036 		}
1037 
1038 		SC_DEBUG(1, (CE_CONT, "gptwocfg_configure_axq: "
1039 		    "Returning 0x%p\n", new_nodes));
1040 
1041 		return (new_nodes);
1042 	}
1043 
1044 	arg.id = id;
1045 	arg.axq_dip = NULL;
1046 
1047 	b.arg = &arg;
1048 	b.type = DEVI_BRANCH_SID;
1049 	b.create.sid_branch_create = axq_set_prop;
1050 	b.devi_branch_callback = get_axq_dip;
1051 
1052 	rv = e_ddi_branch_create(ap, &b, &fdip, DEVI_BRANCH_CONFIGURE);
1053 	if (rv != 0) {
1054 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1055 
1056 		/*
1057 		 * If non-NULL, fdip is held and must be released.
1058 		 */
1059 		if (fdip != NULL) {
1060 			(void) ddi_pathname(fdip, path);
1061 			ddi_release_devi(fdip);
1062 		} else {
1063 			(void) ddi_pathname(ap, path);
1064 		}
1065 
1066 		SC_DEBUG(1, (CE_WARN, "e_ddi_branch_create failed: "
1067 		    "path=%s, dip=%p, rv=%d", path, fdip ? (void *)fdip :
1068 		    (void *)ap, rv));
1069 
1070 		kmem_free(path, MAXPATHLEN);
1071 
1072 		return (NULL);
1073 	}
1074 
1075 	axq_dip = arg.axq_dip;
1076 
1077 	new_nodes = gptwocfg_allocate_node_list(1);
1078 	new_nodes->gptwo_nodes[0] = axq_dip;
1079 
1080 	return (new_nodes);
1081 }
1082 
1083 static gptwocfg_config_t *
1084 sc_gptwocfg_unconfigure_axq(gptwocfg_config_t *config)
1085 {
1086 	int i;
1087 	int failure = 0;
1088 	dev_info_t *saf_dip;
1089 
1090 	if (config == NULL) {
1091 		cmn_err(CE_WARN, "sc_gptwocfg: sc_gptwocfg_unconfigure_axq: "
1092 		    "Invalid AXQ\n");
1093 		return (NULL);
1094 	}
1095 	for (i = 0; i < config->gptwo_nodes->gptwo_number_of_nodes; i++) {
1096 		int rv;
1097 		dev_info_t *fdip = NULL;
1098 
1099 		saf_dip = config->gptwo_nodes->gptwo_nodes[i];
1100 		ASSERT(e_ddi_branch_held(saf_dip));
1101 		rv = e_ddi_branch_destroy(saf_dip, &fdip, 0);
1102 		if (rv != 0) {
1103 			char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1104 
1105 			/*
1106 			 * If non-NULL, fdip is held and must be released.
1107 			 */
1108 			if (fdip != NULL) {
1109 				(void) ddi_pathname(fdip, path);
1110 				ddi_release_devi(fdip);
1111 			} else {
1112 				(void) ddi_pathname(saf_dip, path);
1113 			}
1114 
1115 			cmn_err(CE_CONT, "AXQ node removal failed: "
1116 			    "path=%s, dip=%p, rv=%d\n", path,
1117 			    fdip ? (void *)fdip : (void *)saf_dip, rv);
1118 
1119 			kmem_free(path, MAXPATHLEN);
1120 			failure = 1;
1121 		} else {
1122 			config->gptwo_nodes->gptwo_nodes[i] = NULL;
1123 		}
1124 	}
1125 	if (!failure) {
1126 		gptwocfg_free_node_list(config->gptwo_nodes);
1127 
1128 		kmem_free(config, sizeof (gptwocfg_config_t));
1129 		config = NULL;
1130 	}
1131 	return (config);
1132 }
1133 
1134 static uint_t
1135 sc_get_agent_id(spcd_t *pcd, uint_t expander, uint_t slot, uint_t prd_slot)
1136 {
1137 	uint_t agent_id;
1138 
1139 	switch (pcd->spcd_ptype) {
1140 	case SAFPTYPE_CPU:
1141 		if (slot == 0) {
1142 			agent_id = prd_slot;
1143 		} else {
1144 			if (prd_slot == 4) {
1145 				agent_id = 8;
1146 			} else {
1147 				agent_id = 9;
1148 			}
1149 		}
1150 		break;
1151 
1152 	case SAFPTYPE_sPCI:
1153 	case SAFPTYPE_cPCI:
1154 	case SAFPTYPE_PCIX:
1155 		if (prd_slot == 4) {
1156 			agent_id = 0x1c;
1157 		} else {
1158 			agent_id = 0x1d;
1159 		}
1160 		break;
1161 	case SAFPTYPE_WCI:
1162 		agent_id = 0x1d;
1163 		break;
1164 	default:
1165 		cmn_err(CE_WARN, "sc_gptwocfg: Invalid Safari Port "
1166 		    "Type 0x%x Slot 0x%x\n",
1167 		    pcd->spcd_ptype, prd_slot);
1168 	} /* switch */
1169 
1170 	agent_id |= (expander << 5);
1171 
1172 	SC_DEBUG(1, (CE_CONT, "sc_get_agent_id(pcd=0x%p, expander=0x%x, "
1173 	    "prd_slot=0x%x) Returning agent_id=0x%x\n", pcd, expander,
1174 	    prd_slot, agent_id));
1175 
1176 	return (agent_id);
1177 }
1178 
1179 static void
1180 dump_config(sc_gptwocfg_config_t *board_config)
1181 {
1182 	gptwocfg_config_t *port;
1183 
1184 	SC_DEBUG(1, (CE_CONT, "dump_config 0x%p", board_config));
1185 	while (board_config != NULL) {
1186 		SC_DEBUG(1, (CE_CONT, "************* 0x%p ************\n",
1187 		    board_config));
1188 		SC_DEBUG(1, (CE_CONT, "port_cookie - 0x%p\n",
1189 		    board_config->port_cookie));
1190 
1191 		port = board_config->port_cookie;
1192 		if (port) {
1193 			SC_DEBUG(1, (CE_CONT, "     ap     - 0x%p\n",
1194 			    port->gptwo_ap));
1195 			SC_DEBUG(1, (CE_CONT, "     portid - 0x%x\n",
1196 			    port->gptwo_portid));
1197 		}
1198 		SC_DEBUG(1, (CE_CONT, "portid      - 0x%x\n",
1199 		    board_config->portid));
1200 		SC_DEBUG(1, (CE_CONT, "board      - 0x%x\n",
1201 		    board_config->board));
1202 		SC_DEBUG(1, (CE_CONT, "link        - 0x%p\n",
1203 		    board_config->link));
1204 		SC_DEBUG(1, (CE_CONT, "next        - 0x%p\n",
1205 		    board_config->next));
1206 		board_config = board_config->link;
1207 	}
1208 }
1209 
1210 static void
1211 dump_pcd(spcd_t *pcd)
1212 {
1213 	int i;
1214 
1215 	SC_DEBUG(1, (CE_CONT, "dump_pcd 0x%p", pcd));
1216 	SC_DEBUG(1, (CE_CONT, "     magic   - 0x%x\n", pcd->spcd_magic));
1217 	SC_DEBUG(1, (CE_CONT, "     version - 0x%x\n", pcd->spcd_version));
1218 	SC_DEBUG(1, (CE_CONT, "     ver.reg - 0x%lx\n", pcd->spcd_ver_reg));
1219 	SC_DEBUG(1, (CE_CONT, "     afreq   - %d\n", pcd->spcd_afreq));
1220 	switch (pcd->spcd_ptype) {
1221 	case SAFPTYPE_CPU:
1222 		SC_DEBUG(1, (CE_CONT, "     ptype   - CPU\n"));
1223 		break;
1224 	case SAFPTYPE_sPCI:
1225 		SC_DEBUG(1, (CE_CONT, "     ptype   - sPCI\n"));
1226 		break;
1227 	case SAFPTYPE_cPCI:
1228 		SC_DEBUG(1, (CE_CONT, "     ptype   - cPCI\n"));
1229 		break;
1230 	case SAFPTYPE_PCIX:
1231 		SC_DEBUG(1, (CE_CONT, "     ptype   - sPCI+\n"));
1232 		break;
1233 	case SAFPTYPE_WCI:
1234 		SC_DEBUG(1, (CE_CONT, "     ptype   - WIC\n"));
1235 		break;
1236 	default:
1237 		SC_DEBUG(1, (CE_CONT, "     ptype   - 0x%x\n",
1238 		    pcd->spcd_ptype));
1239 		break;
1240 	}
1241 	SC_DEBUG(1, (CE_CONT, "     cache   - %d\n", pcd->spcd_cache));
1242 
1243 	if (pcd->spcd_prsv == SPCD_RSV_PASS) {
1244 		SC_DEBUG(1, (CE_CONT, "     prsv    - SPCD_RSV_PASS\n"));
1245 	} else {
1246 		SC_DEBUG(1, (CE_CONT, "     prsv    - 0x%x (FAIL)\n",
1247 		    pcd->spcd_prsv));
1248 	}
1249 
1250 	for (i = 0; i < AGENTS_PER_PORT; i++) {
1251 		if (pcd->spcd_agent[i] == SPCD_RSV_PASS) {
1252 			SC_DEBUG(1, (CE_CONT, "     agent[%d]    "
1253 			    "- SPCD_RSV_PASS\n", i));
1254 		} else {
1255 			SC_DEBUG(1, (CE_CONT, "     agent[%d]    "
1256 			    "- 0x%x (FAIL)\n", i, pcd->spcd_agent[i]));
1257 		}
1258 	}
1259 
1260 	if (pcd->spcd_ptype == SAFPTYPE_CPU) {
1261 		for (i = 0; i < AGENTS_PER_PORT; i++) {
1262 			SC_DEBUG(1, (CE_CONT, "     cpuid[%d] - 0x%x\n",
1263 			    i, pcd->spcd_cpuid[i]));
1264 		}
1265 	}
1266 
1267 	SC_DEBUG(1, (CE_CONT, "     Banks\n"));
1268 	for (i = 0; i < MAX_BANKS_PER_PORT; i++) {
1269 		if (pcd->sprd_bank_rsv[i]) {
1270 			SC_DEBUG(1, (CE_CONT, "       %d %s\n", i,
1271 			    pcd->sprd_bank_rsv[i]));
1272 		}
1273 	}
1274 
1275 	SC_DEBUG(1, (CE_CONT, "     Dimms\n"));
1276 	for (i = 0; i < MAX_DIMMS_PER_PORT; i++) {
1277 		if (pcd->sprd_dimm[i]) {
1278 			SC_DEBUG(1, (CE_CONT, "       %d %s\n", i,
1279 			    pcd->sprd_dimm[i]));
1280 		}
1281 	}
1282 	SC_DEBUG(1, (CE_CONT, "     Ecache Dimm Labels\n"));
1283 	for (i = 0; i < MAX_DIMMS_PER_PORT; i++) {
1284 		if (pcd->sprd_ecache_dimm_label[i]) {
1285 			SC_DEBUG(1, (CE_CONT, "       %d %s\n", i,
1286 			    pcd->sprd_ecache_dimm_label[i]));
1287 		}
1288 	}
1289 }
1290 
1291 
1292 typedef struct {
1293 	char Jnumber[8][8];
1294 	uint8_t sym_flag;
1295 	uint8_t d_dimmtable[144];
1296 	uint8_t d_pintable[576];
1297 }m_layout;
1298 
1299 /*
1300  * Use 2 bits to represent each bit at a cache line. The table
1301  * is in big endian order, i.e.
1302  *      dimmtable[0], ... , dimmtable[143]
1303  * Q0:data-bits[127 126 125 124], ... , MtagEcc[3 2 1 0]
1304  *                      .
1305  *                      .
1306  * Q3:data-bits[127 126 125 124], ... , MtagEcc[3 2 1 0]
1307  */
1308 uint8_t J_dimm_pinTable[] = {
1309 /* Jnumber */
1310 /*  0 */	0x4a, 0x31, 0x33, 0x33, 0x30, 0x30, 0x00, 0x00,
1311 /*  1 */	0x4a, 0x31, 0x33, 0x34, 0x30, 0x30, 0x00, 0x00,
1312 /*  2 */	0x4a, 0x31, 0x33, 0x35, 0x30, 0x30, 0x00, 0x00,
1313 /*  3 */	0x4a, 0x31, 0x33, 0x36, 0x30, 0x30, 0x00, 0x00,
1314 /*  4 */	0x4a, 0x31, 0x33, 0x33, 0x30, 0x31, 0x00, 0x00,
1315 /*  5 */	0x4a, 0x31, 0x33, 0x34, 0x30, 0x31, 0x00, 0x00,
1316 /*  6 */	0x4a, 0x31, 0x33, 0x35, 0x30, 0x31, 0x00, 0x00,
1317 /*  7 */	0x4a, 0x31, 0x33, 0x36, 0x30, 0x31, 0x00, 0x00,
1318 /* flag */	0x01,
1319 /*  -- Q0 --  */
1320 /*  0 */	0x00, 0x55, 0xaa, 0xff, 0x00, 0x55, 0xaa, 0xff,
1321 /*  1 */	0x00, 0xaa, 0xff, 0x00, 0x56, 0xaf, 0x00, 0x55,
1322 /*  2 */	0xaa, 0x55, 0xaf, 0xc0, 0x55, 0xaa, 0xff, 0x00,
1323 /*  3 */	0x55, 0xff, 0x00, 0x55, 0xaa, 0xff, 0x6d, 0x80,
1324 /*  4 */	0xe7, 0xe3, 0x9b, 0x1b,
1325 /*  -- Q1 --  */
1326 /*  0 */	0x00, 0x55, 0xaa, 0xff, 0x00, 0x55, 0xaa, 0xff,
1327 /*  1 */	0x00, 0xaa, 0xff, 0x00, 0x56, 0xaf, 0x00, 0x55,
1328 /*  2 */	0xaa, 0x55, 0xaf, 0xc0, 0x55, 0xaa, 0xff, 0x00,
1329 /*  3 */	0x55, 0xff, 0x00, 0x55, 0xaa, 0xff, 0x6d, 0x80,
1330 /*  4 */	0xe7, 0xe3, 0x9b, 0x1b,
1331 /*  -- Q2 --  */
1332 /*  0 */	0x00, 0x55, 0xaa, 0xff, 0x00, 0x55, 0xaa, 0xff,
1333 /*  1 */	0x00, 0xaa, 0xff, 0x00, 0x56, 0xaf, 0x00, 0x55,
1334 /*  2 */	0xaa, 0x55, 0xaf, 0xc0, 0x55, 0xaa, 0xff, 0x00,
1335 /*  3 */	0x55, 0xff, 0x00, 0x55, 0xaa, 0xff, 0x6d, 0x80,
1336 /*  4 */	0xe7, 0xe3, 0x9b, 0x1b,
1337 /*  -- Q3 --  */
1338 /*  0 */	0x00, 0x55, 0xaa, 0xff, 0x00, 0x55, 0xaa, 0xff,
1339 /*  1 */	0x00, 0xaa, 0xff, 0x00, 0x56, 0xaf, 0x00, 0x55,
1340 /*  2 */	0xaa, 0x55, 0xaf, 0xc0, 0x55, 0xaa, 0xff, 0x00,
1341 /*  3 */	0x55, 0xff, 0x00, 0x55, 0xaa, 0xff, 0x6d, 0x80,
1342 /*  4 */	0xe7, 0xe3, 0x9b, 0x1b,
1343 /*
1344  * In the following order
1345  *      pintable[0], ..., pintable[575]
1346  * Quadword3, Quadword2, Quadword1, Quadword0
1347  *      MtagEcc, Mtag, Ecc, Data
1348  */
1349 /* -- Q3 -- */
1350 /*  0  */	227, 227, 227, 227, 111, 111, 111,  22,
1351 /*  1  */	22,  32, 138, 222,  81, 117, 117, 117,
1352 /*  2  */	111, 222, 106, 222, 222, 106, 106, 106,
1353 /*  3  */	217, 101, 212,  96, 217, 101, 212,  96,
1354 /*  4  */	217, 101, 212,  96, 217, 101, 212,  96,
1355 /*  5  */	207,  91, 202,  86, 187,  71, 158,  42,
1356 /*  6  */	187,  71, 158,  42, 153,  37, 148,  32,
1357 /*  7  */	153,  37, 148,  32, 153,  37, 148,  32,
1358 /*  8  */	153,  37, 148, 143,  27, 138, 143,  27,
1359 /*  9  */	143,  27, 138,  22, 207,  91, 202,  86,
1360 /*  10 */	207,  91, 202,  86, 207,  91, 202,  86,
1361 /*  11 */	192,  76,  81, 192,  76,  81, 192,  76,
1362 /*  12 */	197,  81, 192,  76, 187,  71, 158,  42,
1363 /*  13 */	187,  71, 158,  42, 143,  27, 138,  22,
1364 /*  14 */	133,  17, 128,  12, 133,  17, 128,  12,
1365 /*  15 */	133,  17, 128,  12, 133,  17, 128,  12,
1366 /*  16 */	123,  07, 118,   2, 123,  07, 118,   2,
1367 /*  17 */	123,  07, 118,   2, 123,  07, 118,   2,
1368 /* -- Q2 -- */
1369 /*  0  */	228, 228, 228, 228, 112, 112, 112,  23,
1370 /*  1  */	23,  33, 139, 223,  82, 118, 118, 118,
1371 /*  2  */	112, 223, 107, 223, 223, 107, 107, 107,
1372 /*  3  */	218, 102, 213,  97, 218, 102, 213,  97,
1373 /*  4  */	218, 102, 213,  97, 218, 102, 213,  97,
1374 /*  5  */	208,  92, 203,  87, 188,  72, 159,  43,
1375 /*  6  */	188,  72, 159,  43, 154,  38, 149,  33,
1376 /*  7  */	154,  38, 149,  33, 154,  38, 149,  33,
1377 /*  8  */	154,  38, 149, 144,  28, 139, 144,  28,
1378 /*  9  */	144,  28, 139,  23, 208,  92, 203,  87,
1379 /*  10 */	208,  92, 203,  87, 208,  92, 203,  87,
1380 /*  11 */	193,  77,  82, 193,  77,  82, 193,  77,
1381 /*  12 */	198,  82, 193,  77, 188,  72, 159,  43,
1382 /*  13 */	188,  72, 159,  43, 144,  28, 139,  23,
1383 /*  14 */	134,  18, 129,  13, 134,  18, 129,  13,
1384 /*  15 */	134,  18, 129,  13, 134,  18, 129,  13,
1385 /*  16 */	124,   8, 119,   3, 124,   8, 119,   3,
1386 /*  17 */	124,   8, 119,   3, 124,   8, 119,   3,
1387 /* -- Q1 -- */
1388 /*  0  */	229, 229, 229, 229, 113, 113, 113,  24,
1389 /*  1  */	24,  34, 140, 224,  83, 119, 119, 119,
1390 /*  2  */	113, 224, 108, 224, 224, 108, 108, 108,
1391 /*  3  */	219, 103, 214,  98, 219, 103, 214,  98,
1392 /*  4  */	219, 103, 214,  98, 219, 103, 214,  98,
1393 /*  5  */	209,  93, 204,  88, 189,  73, 160,  44,
1394 /*  6  */	189,  73, 160,  44, 155,  39, 150,  34,
1395 /*  7  */	155,  39, 150,  34, 155,  39, 150,  34,
1396 /*  8  */	155,  39, 150, 145,  29, 140, 145,  29,
1397 /*  9  */	145,  29, 140,  24, 209,  93, 204,  88,
1398 /*  10 */	209,  93, 204,  88, 209,  93, 204,  88,
1399 /*  11 */	194,  78,  83, 194,  78,  83, 194,  78,
1400 /*  12 */	199,  83, 194,  78, 189,  73, 160,  44,
1401 /*  13 */	189,  73, 160,  44, 145,  29, 140,  24,
1402 /*  14 */	135,  19, 130,  14, 135,  19, 130,  14,
1403 /*  15 */	135,  19, 130,  14, 135,  19, 130,  14,
1404 /*  16 */	125,   9, 120,   4, 125,   9, 120,   4,
1405 /*  17 */	125,   9, 120,   4, 125,   9, 120,   4,
1406 /* -- Q0 -- */
1407 /*  0  */	230, 230, 230, 230, 114, 114, 114,  25,
1408 /*  1  */	25,  35, 141, 225,  84, 200, 200, 200,
1409 /*  2  */	114, 225, 109, 225, 225, 109, 109, 109,
1410 /*  3  */	220, 104, 215,  99, 220, 104, 215,  99,
1411 /*  4  */	220, 104, 215,  99, 220, 104, 215,  99,
1412 /*  5  */	210,  94, 205,  89, 190,  74, 161,  45,
1413 /*  6  */	190,  74, 161,  45, 156,  40, 151,  35,
1414 /*  7  */	156,  40, 151,  35, 156,  40, 151,  35,
1415 /*  8  */	156,  40, 151, 146,  30, 141, 146,  30,
1416 /*  9  */	146,  30, 141,  25, 210,  94, 205,  89,
1417 /*  10 */	210,  94, 205,  89, 210,  94, 205,  89,
1418 /*  11 */	195,  79,  84, 195,  79,  84, 195,  79,
1419 /*  12 */	200,  84, 195,  79, 190,  74, 161,  45,
1420 /*  13 */	190,  74, 161,  45, 146,  30, 141,  25,
1421 /*  14 */	136,  20, 131,  15, 136,  20, 131,  15,
1422 /*  15 */	136,  20, 131,  15, 136,  20, 131,  15,
1423 /*  16 */	126,  10, 121,   5, 126,  10, 121,   5,
1424 /*  17 */	126,  10, 121,   5, 126,  10, 121,   5
1425 };
1426 
1427 /*
1428  *  This table is for internal reference
1429  *
1430  * pintable_internal[]= {
1431  * -- Q0 --
1432  * 0  143,143,143,143,139,139,139,35
1433  * 1  35,51,39,135,91,95,95,95
1434  * 2  139,135,131,135,135,131,131,131
1435  * 3  127,123,119,115,127,123,119,115
1436  * 4  127,123,119,115,127,123,119,115
1437  * 5  111,107,103,99,79,75,71,67
1438  * 6  79,75,71,67,63,59,55,51
1439  * 7  63,59,55,51,63,59,55,51
1440  * 8  63,59,55,47,43,39,47,43
1441  * 9  47,43,39,35,111,107,103,99
1442  * 10  111,107,103,99,111,107,103,99
1443  * 11  87,83,91,87,83,91,87,83
1444  * 12  95,91,87,83,79,75,71,67
1445  * 13  79,75,71,67,47,43,39,35
1446  * 14  31,27,23,19,31,27,23,19
1447  * 15  31,27,23,19,31,27,23,19
1448  * 16  15,11,7,3,15,11,7,3
1449  * 17  15,11,7,3,15,11,7,3
1450  * }
1451  */
1452 
1453 char *dimm_Jno[] = {
1454 /* P0 */	"J13300", "J13400", "J13500", "J13600",
1455 		"J13301", "J13401", "J13501", "J13601",
1456 /* P1 */	"J14300", "J14400", "J14500", "J14600",
1457 		"J14301", "J14401", "J14501", "J14601",
1458 /* P2 */	"J15300", "J15400", "J15500", "J15600",
1459 		"J15301", "J15401", "J15501", "J15601",
1460 /* P3 */	"J16300", "J16400", "J16500", "J16600",
1461 		"J16301", "J16401", "J16501", "J16601",
1462 		NULL
1463 	};
1464 
1465 
1466 static uint8_t *
1467 get_memlayout(uint32_t cpuid, uint32_t *len)
1468 {
1469 	m_layout *LayoutBuf;
1470 
1471 	if ((LayoutBuf = (m_layout *)kmem_zalloc(sizeof (m_layout),
1472 	    KM_SLEEP)) == NULL) {
1473 		*len = 0;
1474 		return (NULL);
1475 	}
1476 
1477 	bcopy(J_dimm_pinTable, LayoutBuf, sizeof (m_layout));
1478 
1479 	*len = sizeof (m_layout);
1480 	cpuid &= 0x03;	/* last 2 bits of a 10 bit number */
1481 
1482 	bcopy(dimm_Jno[cpuid << 3], LayoutBuf->Jnumber[0], 64);
1483 
1484 	return ((uint8_t *)LayoutBuf);
1485 }
1486 
1487 static char *
1488 rsv_string(prdrsv_t rsv)
1489 {
1490 	char *buffer;
1491 	char *status;
1492 
1493 	switch (rsv) {
1494 	case RSV_UNKNOWN:
1495 		buffer = "unknown";
1496 		break;
1497 	case RSV_PRESENT:
1498 		buffer = "okay";
1499 		break;
1500 	case RSV_CRUNCH:
1501 		buffer = "disabled";
1502 		break;
1503 	case RSV_UNDEFINED:
1504 		buffer = "undefined";
1505 		break;
1506 	case RSV_MISS:
1507 		buffer = "missing";
1508 		break;
1509 	case RSV_EMPTY_CASSETTE:
1510 		buffer = "disabled";
1511 		break;
1512 	case RSV_MISCONFIG:
1513 		buffer = "misconfigured";
1514 		break;
1515 	case RSV_FAIL_OBP:
1516 		buffer = "fail-obp";
1517 		break;
1518 	case RSV_BLACK:
1519 		buffer = "blacklisted";
1520 		break;
1521 	case RSV_RED:
1522 		buffer = "redlisted";
1523 		break;
1524 	case RSV_EXCLUDED:
1525 		buffer = "disabled";
1526 		break;
1527 	case RSV_UNCONFIG:
1528 		buffer = "disabled";
1529 		break;
1530 	case RSV_PASS:
1531 		buffer = "okay";
1532 		break;
1533 	case RSV_FAIL:
1534 	default:
1535 		buffer = "fail";
1536 		break;
1537 	}
1538 
1539 	status = kmem_alloc(strlen(buffer) + 1, KM_SLEEP);
1540 	(void) strcpy(status, buffer);
1541 
1542 	return (status);
1543 }
1544