xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c (revision fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bb)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Opl Platform specific functions.
26  *
27  * 	called when :
28  *	machine_type == MTYPE_OPL
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <varargs.h>
39 #include <fcntl.h>
40 #include <assert.h>
41 #include <sys/param.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <sys/utsname.h>
45 #include <sys/systeminfo.h>
46 #include <sys/openpromio.h>
47 #include <libintl.h>
48 #include <syslog.h>
49 #include <sys/dkio.h>
50 #include <pdevinfo.h>
51 #include <libprtdiag.h>
52 #include <libdevinfo.h>
53 #include <kstat.h>
54 
55 /*
56  * Globals and externs
57  */
58 #define	KBYTE	1024
59 #define	MBYTE	(KBYTE * KBYTE)
60 #define	HZ_TO_MHZ(x)	((((uint64_t)(x)) + 500000) / 1000000)
61 #define	SCF_SECURE_MODE_KSTAT_NAMED	"secure_mode"
62 #define	SCF_STAT_MODE_UNLOCK	0
63 #define	SCF_STAT_MODE_LOCK	1
64 #define	SCF_SYSTEM_KSTAT_NAME	"scf"
65 #ifndef	TEXT_DOMAIN
66 #define	TEXT_DOMAIN	"SYS_TEST"
67 #endif	/* TEXT_DOMAIN */
68 #define	IS_PCI_BRIDGE(name, type) \
69 	(((name) != NULL) && ((type) != NULL) && \
70 	(strncmp((name), "pci", 3) == 0) && \
71 	(strncmp((type), "pci", 3) == 0))
72 
73 /*
74  * Global functions and variables
75  * these functions will overlay the symbol table of libprtdiag
76  * at runtime (Opl systems only)
77  */
78 struct  cs_status {
79 	int cs_number;
80 	int status;
81 	uint_t avail_hi;
82 	uint_t avail_lo;
83 	uint_t dimm_hi;
84 	uint_t dimm_lo;
85 	int dimms;
86 };
87 
88 int	do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
89 void	*get_prop_val(Prop *prop);
90 void	display_pci(Board_node *);
91 void	display_ffb(Board_node *, int);
92 void	display_sbus(Board_node *board);
93 void	display_cpu_devices(Sys_tree *tree);
94 void	display_cpus(Board_node *board);
95 void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
96 void	display_io_cards(struct io_card *list);
97 void	display_io_devices(Sys_tree *tree);
98 void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
99     struct system_kstat_data *kstats);
100 Prop 	*find_prop(Prom_node *pnode, char *name);
101 int	do_piclinfo(int);
102 int	get_proc_mode(void);
103 
104 /* Local functions */
105 static	void opl_disp_environ(void);
106 static	void opl_disp_hw_revisions(Sys_tree *tree, Prom_node *root);
107 static	uint64_t print_opl_memory_line(int lsb, struct cs_status *cs_stat,
108     int ngrps, int mirror_mode);
109 static	uint64_t get_opl_mem_regs(Board_node *bnode);
110 void 	add_node(Sys_tree *root, Prom_node *pnode);
111 static	int get_prop_size(Prop *prop);
112 
113 static int v_flag = 0;
114 
115 /*
116  * For display of I/O devices for "prtdiag"
117  */
118 void
119 display_io_devices(Sys_tree *tree)
120 {
121 	Board_node *bnode;
122 
123 	if (v_flag) {
124 		/*
125 		 * OPL's PICL interface for display of PCI I/O devices
126 		 * for "prtdiag -v"
127 		 */
128 		(void) do_piclinfo(v_flag);
129 	} else {
130 		log_printf("\n", 0);
131 		log_printf("=========================", 0);
132 		log_printf(dgettext(TEXT_DOMAIN, " IO Cards "), 0);
133 		log_printf("=========================", 0);
134 		log_printf("\n", 0);
135 		log_printf("\n", 0);
136 		bnode = tree->bd_list;
137 		while (bnode != NULL) {
138 			display_pci(bnode);
139 			bnode = bnode->next;
140 		}
141 	}
142 }
143 
144 /*
145  * Display all the leaf PCI nodes on this board that have "reg" property.
146  * If the "reg" property is NULL for a leaf node, skip parsing its sibling
147  * nodes and display the parent node properties.
148  */
149 void
150 display_pci(Board_node *board)
151 {
152 	struct io_card *card_list = NULL;
153 	struct io_card card;
154 	Prom_node *pci, *card_node;
155 	char	*name, *type;
156 	int	*int_val;
157 
158 	if (board == NULL)
159 		return;
160 
161 	/* Initialize common information */
162 	card.board = board->board_num;
163 
164 	pci = board->nodes;
165 	while (pci != NULL) {
166 		name = get_node_name(pci);
167 
168 		/* Skip non-PCI board nodes */
169 		if ((name == NULL) || (strcmp(name, "pci") != 0)) {
170 			pci = pci->sibling;
171 			continue;
172 		}
173 
174 		type = (char *)get_prop_val(find_prop(pci, "device_type"));
175 
176 		/*
177 		 * Skip PCI/ebus devices
178 		 * They have name == "pci" and type == "pci"
179 		 */
180 		if (strcmp(type, "pci") == 0) {
181 			pci = pci->sibling;
182 			continue;
183 		}
184 
185 		card_node = pci;
186 		while (card_node != NULL) {
187 			int pci_parent_bridge = 0;
188 
189 			/* If it does have a child, skip to leaf child */
190 			if (card_node->child != NULL) {
191 				card_node = card_node->child;
192 				continue;
193 			}
194 
195 			/* Get name of the card */
196 			name = (char *)get_prop_val(find_prop
197 			    (card_node, "name"));
198 
199 			/* Get type of card */
200 			type = (char *)get_prop_val(find_prop
201 			    (card_node, "device_type"));
202 
203 			/* Leaf pci-bridges are to be ignored */
204 			if (!IS_PCI_BRIDGE(name, type)) {
205 
206 				/* Get reg property of the node */
207 				int_val = (int *)get_prop_val(find_prop
208 				    (card_node, "reg"));
209 
210 				/*
211 				 * If no "reg" property check to see
212 				 * whether parent node has reg property.
213 				 * and check if parent is a bridge
214 				 */
215 				if (int_val == NULL) {
216 					Prom_node *cparent = card_node->parent;
217 					if (cparent == NULL)
218 						break;
219 
220 					name = (char *)get_prop_val(find_prop
221 					    (cparent, "name"));
222 
223 					type = (char *)get_prop_val(find_prop
224 					    (cparent, "device_type"));
225 
226 					/* check if parent is a bridge */
227 					if (IS_PCI_BRIDGE(name, type))
228 						pci_parent_bridge = 1;
229 
230 					int_val = (int *)get_prop_val(
231 					    find_prop(cparent, "reg"));
232 
233 					if (int_val != NULL)
234 						/* Switch to parent */
235 						card_node = cparent;
236 					else
237 						/* parent node has no reg */
238 						break;
239 				}
240 
241 				if (!pci_parent_bridge) {
242 
243 					name = (char *)get_prop_val(find_prop
244 					    (card_node, "name"));
245 
246 					if (name == NULL)
247 						card.name[0] = '\0';
248 					else {
249 						(void) snprintf(card.name,
250 						    MAXSTRLEN, "%s", name);
251 					}
252 
253 					/* Get the model of this card */
254 					name = (char *)get_prop_val(find_prop
255 					    (card_node, "model"));
256 
257 					if (name == NULL) {
258 						(void) snprintf(card.model,
259 						    MAXSTRLEN, "%s", "N/A");
260 					} else {
261 						(void) snprintf(card.model,
262 						    MAXSTRLEN, "%s", name);
263 					}
264 
265 					/* insert card to the list */
266 					card_list = insert_io_card(card_list,
267 					    &card);
268 
269 				}
270 
271 			}
272 
273 			/*
274 			 * Parse sibling nodes.
275 			 * Then move up the parent's sibling upto the top
276 			 * intermediate node
277 			 * Stop if pci board node is reached.
278 			 */
279 			if (card_node->sibling != NULL) {
280 				if (card_node == pci)
281 					card_node = NULL;
282 				else
283 					card_node = card_node->sibling;
284 			} else {
285 				Prom_node *cparent;
286 				cparent = card_node->parent;
287 				card_node = NULL;
288 				while (cparent != NULL) {
289 					if (cparent == pci)
290 						break;
291 					if (cparent->sibling != NULL) {
292 						card_node = cparent->sibling;
293 						break;
294 					}
295 					cparent = cparent->parent;
296 				}
297 			}
298 
299 		}
300 
301 	/* On to the next board node */
302 	pci = pci->sibling;
303 
304 	}
305 
306 	display_io_cards(card_list);
307 	free_io_cards(card_list);
308 }
309 
310 /*
311  * There are no FFB's on OPL.
312  */
313 /*ARGSUSED*/
314 void
315 display_ffb(Board_node *board, int table)
316 {
317 }
318 
319 /*
320  * There are no Sbus's on OPL.
321  */
322 /*ARGSUSED*/
323 void
324 display_sbus(Board_node *board)
325 {
326 }
327 
328 /*
329  * Details of I/O information. Print out all the io cards.
330  */
331 void
332 display_io_cards(struct io_card *list)
333 {
334 	char	*hdrfmt = "%-6.6s %-14.14s %-12.12s\n";
335 
336 	struct io_card *p;
337 
338 	if (list == NULL)
339 		return;
340 
341 	(void) textdomain(TEXT_DOMAIN);
342 
343 	log_printf(hdrfmt, gettext("LSB"), gettext("Name"), gettext("Model"),
344 	    0);
345 
346 	log_printf(hdrfmt, "---", "-----------------", "------------", 0);
347 
348 	for (p = list; p != NULL; p = p->next) {
349 
350 		/* Board number */
351 		log_printf(" %02d    ", p->board, 0);
352 
353 		/* Card name */
354 		log_printf("%-15.15s", p->name, 0);
355 
356 		/* Card model */
357 		log_printf("%-12.12s", p->model, 0);
358 
359 		log_printf("\n", 0);
360 	}
361 	log_printf("\n", 0);
362 }
363 
364 /*
365  * Details of CPU information.
366  */
367 void
368 display_cpu_devices(Sys_tree *tree)
369 {
370 	Board_node *bnode;
371 	char *hdrfmt =
372 	    "%-4.4s  %-4.4s  %-40.40s  %-5.5s  %-5.5s  %-5.5s %-4.4s\n";
373 
374 	(void) textdomain(TEXT_DOMAIN);
375 
376 	/*
377 	 * Display the table header for CPUs . Then display the CPU
378 	 * frequency, cache size, and processor revision of all cpus.
379 	 */
380 	log_printf("\n", 0);
381 	log_printf("====================================", 0);
382 	log_printf(gettext(" CPUs "), 0);
383 	log_printf("====================================", 0);
384 	log_printf("\n\n", 0);
385 
386 	log_printf(hdrfmt,
387 	    "",
388 	    gettext("CPU"),
389 	    gettext("              CPU                  "),
390 	    gettext("Run"),
391 	    gettext("L2$"),
392 	    gettext("CPU"),
393 	    gettext("CPU"), 0);
394 
395 	log_printf(hdrfmt,
396 	    gettext("LSB"),
397 	    gettext("Chip"),
398 	    gettext("               ID                 "),
399 	    gettext("MHz"),
400 	    gettext(" MB"),
401 	    gettext("Impl."),
402 	    gettext("Mask"), 0);
403 
404 	log_printf(hdrfmt,
405 	"---", "----", "----------------------------------------", "----",
406 	"---",  "-----", "----", 0);
407 
408 	/* Now display all of the cpus on each board */
409 	for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) {
410 		display_cpus(bnode);
411 	}
412 
413 	log_printf("\n", 0);
414 }
415 
416 /*
417  * Display the CPUs present on this board.
418  */
419 void
420 display_cpus(Board_node *board)
421 {
422 	int *impl, *mask, *cpuid, *portid, *l2cache_size;
423 	uint_t freq;		/* CPU clock frequency */
424 	Prom_node *pnode, *cpu;
425 	char *name;
426 
427 	(void) textdomain(TEXT_DOMAIN);
428 
429 	/*
430 	 * Get the Cpus' properties for display
431 	 */
432 	for (pnode = board->nodes; pnode != NULL; pnode = pnode->sibling) {
433 		char cpu_str[MAXSTRLEN], fcpu_str[MAXSTRLEN] = {0};
434 
435 		name = get_node_name(pnode);
436 		if ((name == NULL) || (strncmp(name, "cmp", 3) != 0)) {
437 			continue;
438 		}
439 
440 		portid = (int *)get_prop_val(find_prop(pnode, "portid"));
441 		freq = (HZ_TO_MHZ(get_cpu_freq(pnode->child)));
442 		l2cache_size = (int *)get_prop_val(find_prop(pnode->child,
443 		    "l2-cache-size"));
444 		impl = (int *)get_prop_val(find_prop(pnode->child,
445 		    "implementation#"));
446 		mask = (int *)get_prop_val(find_prop(pnode->child, "mask#"));
447 
448 		/* Lsb id */
449 		log_printf(" %02d   ", board->board_num, 0);
450 
451 		if (portid != NULL)
452 			log_printf("%3d   ", (((*portid)>>3)&0x3), 0);
453 
454 		/*
455 		 * OPL
456 		 * Specific parsing of the CMP/CORE/CPU chain.
457 		 * The internal cpu tree built by walk_di_tree()
458 		 * in common code can be illustrated by the diagram
459 		 * below:
460 		 *
461 		 * Olympus:
462 		 *
463 		 *   cmp->cpu->cpu->cpu->cpu->(next board nodes)
464 		 *   / \
465 		 * core core
466 		 *
467 		 * Jupiter:
468 		 *
469 		 * cmp->cpu->cpu->cpu->cpu->cpu->cpu->cpu->cpu->(board nodes)
470 		 *   |
471 		 *  _____________
472 		 * /   \    \    \
473 		 * core core core core
474 		 *
475 		 *
476 		 * where "/" or "\" are children
477 		 *    and "->" are siblings
478 		 *
479 		 */
480 		for (cpu = pnode->sibling; cpu != NULL; ) {
481 			Prom_node	*cpu_next = NULL;
482 
483 			name = get_node_name(cpu);
484 			if ((name == NULL) || (strncmp(name, "cpu", 3) != 0)) {
485 				break;
486 			}
487 
488 			/* Id assigned to Virtual processor core */
489 			cpuid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
490 			cpu_next = cpu->sibling;
491 
492 			if (cpu_next != NULL) {
493 				name = get_node_name(cpu_next);
494 
495 				if ((name == NULL) ||
496 				    (strncmp(name, "cpu", 3) != 0)) {
497 					cpu_next = NULL;
498 				}
499 			}
500 
501 			if (cpuid != NULL) {
502 				/* Used for printing in comma format */
503 				(void) sprintf(cpu_str, "%4d", *cpuid);
504 				(void) strlcat(fcpu_str, cpu_str, MAXSTRLEN);
505 
506 				if (cpu_next != NULL) {
507 					(void) strlcat(fcpu_str, ",",
508 					    MAXSTRLEN);
509 				}
510 			} else {
511 				(void) sprintf(cpu_str, "%4s", "N/A");
512 				(void) strlcat(fcpu_str, cpu_str, MAXSTRLEN);
513 
514 				if (cpu_next != NULL) {
515 					(void) strlcat(fcpu_str, ",",
516 					    MAXSTRLEN);
517 				}
518 			}
519 			cpu = cpu_next;
520 		}
521 
522 		log_printf("%-40.40s", fcpu_str, 0);
523 
524 		/* Running frequency */
525 		if (freq != 0)
526 			log_printf("  %4ld  ", freq, 0);
527 		else
528 			log_printf("  %4s  ", "N/A", 0);
529 
530 		/* L2 cache size */
531 		if (l2cache_size == NULL)
532 			log_printf(" %3s    ", "N/A", 0);
533 		else {
534 			log_printf("%4.1f   ",
535 			    (float)(*l2cache_size) / (float)(1<<20), 0);
536 		}
537 
538 
539 		/* Implementation number of processor */
540 		if (impl != NULL)
541 			log_printf("  %4d  ", *impl, 0);
542 		else
543 			log_printf(" %4s     ", "N/A", 0);
544 
545 		/* Mask Set version */
546 		/* Bits 31:24 of VER register is mask. */
547 		/* Mask value : Non MTP mode - 00-7f, MTP mode - 80-ff */
548 		if (mask == NULL)
549 			log_printf("%3s", "N/A", 0);
550 		else
551 			log_printf("%-3d", (*mask)&0xff, 0);
552 
553 		log_printf("\n", 0);
554 
555 	}
556 }
557 
558 /*
559  * Gather memory information: Details of memory information.
560  */
561 static uint64_t
562 get_opl_mem_regs(Board_node *bnode)
563 {
564 	Prom_node	*pnode;
565 	struct		cs_status	*cs_stat;
566 	uint64_t	total_mem = 0;
567 	int		cs_size, ngrps;
568 
569 	pnode = dev_find_node(bnode->nodes, "pseudo-mc");
570 	while (pnode != NULL) {
571 
572 		cs_size = get_prop_size(find_prop(pnode, "cs-status"));
573 
574 		if (cs_size > 0) {
575 			int	*mirror_mode = NULL;
576 			int	mode = 0;
577 
578 			/* OBP returns lists of 7 ints */
579 			cs_stat = (struct cs_status *)get_prop_val
580 			    (find_prop(pnode, "cs-status"));
581 
582 			mirror_mode = (int *)(get_prop_val
583 			    (find_prop(pnode, "mirror-mode")));
584 
585 			if (mirror_mode != NULL)
586 				mode = (*mirror_mode);
587 
588 			/*
589 			 * The units of cs_size will be either number of bytes
590 			 * or number of int array elements as this is derived
591 			 * from the libprtdiag Prop node size field which has
592 			 * inconsistent units.   Until this is addressed in
593 			 * libprtdiag, we need a heuristic to determine the
594 			 * number of CS groups.  Given that the maximum number
595 			 * of CS groups is 2, the maximum number of cs-status
596 			 * array elements will be 2*7=14.  Since this is smaller
597 			 * than the byte size of a single struct status, we use
598 			 * this to decide if we are dealing with bytes or array
599 			 * elements in determining the number of CS groups.
600 			 */
601 			if (cs_size < sizeof (struct cs_status)) {
602 				/* cs_size is number of total int [] elements */
603 				ngrps = cs_size / 7;
604 			} else {
605 				/* cs_size is total byte count */
606 				ngrps = cs_size/sizeof (struct cs_status);
607 			}
608 
609 			if (cs_stat != NULL) {
610 				total_mem +=
611 				    print_opl_memory_line(bnode->board_num,
612 				    cs_stat, ngrps, mode);
613 			}
614 		}
615 
616 		pnode = dev_next_node(pnode, "pseudo-mc");
617 	}
618 	return (total_mem);
619 }
620 
621 /*
622  * Display memory information.
623  */
624 /*ARGSUSED*/
625 void
626 display_memoryconf(Sys_tree *tree, struct grp_info *grps)
627 {
628 	Board_node	*bnode = tree->bd_list;
629 	uint64_t	total_mem = 0, total_sys_mem = 0;
630 	char *hdrfmt =  "\n%-5.5s  %-6.6s  %-18.18s  %-10.10s"
631 	    " %-6.6s  %-5.5s %-7.7s %-10.10s";
632 
633 	(void) textdomain(TEXT_DOMAIN);
634 
635 	log_printf("============================", 0);
636 	log_printf(gettext(" Memory Configuration "), 0);
637 	log_printf("============================", 0);
638 	log_printf("\n", 0);
639 
640 	log_printf(hdrfmt,
641 	    "",
642 	    gettext("Memory"),
643 	    gettext("Available"),
644 	    gettext("Memory"),
645 	    gettext("DIMM"),
646 	    gettext("# of"),
647 	    gettext("Mirror"),
648 	    gettext("Interleave"),
649 	    0);
650 
651 	log_printf(hdrfmt,
652 	    gettext("LSB"),
653 	    gettext("Group"),
654 	    gettext("Size"),
655 	    gettext("Status"),
656 	    gettext("Size"),
657 	    gettext("DIMMs"),
658 	    gettext("Mode"),
659 	    gettext("Factor"), 0);
660 
661 	log_printf(hdrfmt,
662 	    "---", "-------", "------------------", "-------", "------",
663 	    "-----", "-------", "----------",  0);
664 
665 	log_printf("\n", 0);
666 
667 	for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) {
668 		total_mem += get_opl_mem_regs(bnode);
669 	}
670 
671 	/*
672 	 * Sanity check to ensure that the total amount of system
673 	 * memory matches the total number of memory that
674 	 * we find here. Display error message if there is a mis-match.
675 	 */
676 	total_sys_mem = (((uint64_t)sysconf(_SC_PAGESIZE) * (uint64_t)sysconf
677 	    (_SC_PHYS_PAGES)) / MBYTE);
678 
679 	if (total_mem != total_sys_mem) {
680 		log_printf(dgettext(TEXT_DOMAIN, "\nError:total available "
681 		    "size [%lldMB] does not match total system memory "
682 		    "[%lldMB]\n"), total_mem, total_sys_mem, 0);
683 	}
684 
685 }
686 
687 /*
688  * This function provides Opl's formatting of the memory config
689  * information that get_opl_mem_regs() has gathered.
690  */
691 static uint64_t
692 print_opl_memory_line(int lsb, struct cs_status *cs_stat, int ngrps,
693 	int mirror_mode)
694 {
695 	int	i;
696 	uint64_t	total_board_mem = 0;
697 	int		i_factor = 2;   /* default to non-mirror mode */
698 	int		interleave;
699 
700 	(void) textdomain(TEXT_DOMAIN);
701 
702 	if (mirror_mode)
703 		i_factor *= 2;
704 
705 	/*
706 	 * Interleave factor calculation:
707 	 * Obtain "mirror-mode" property from pseudo-mc.
708 	 * cs_stat[0].dimms/i_factor represents interleave factor per
709 	 * pseudo-mc node. Must use cs_stat[0].dimms since this will yield
710 	 * interleave factor even if some DIMMs are isolated.
711 	 *
712 	 * Mirror mode:
713 	 *   interleave factor = (# of DIMMs on cs_stat[0]/4)
714 	 *
715 	 * Non-mirror mode:
716 	 *   interleave factor = (# of DIMMs on cs_stat[0]/2)
717 	 */
718 
719 	interleave = cs_stat[0].dimms/i_factor;
720 
721 
722 	for (i = 0; i < ngrps; i++) {
723 		uint64_t	mem_size;
724 
725 		mem_size = ((((uint64_t)cs_stat[i].avail_hi)<<32) +
726 		    cs_stat[i].avail_lo);
727 
728 		if (mem_size == 0)
729 			continue;
730 
731 		/* Lsb Id */
732 		log_printf(" %02d    ", lsb, 0);
733 
734 		/* Memory Group Number */
735 		if ((cs_stat[i].cs_number) == 0)
736 			log_printf("%-6.6s", "A", 0);
737 		else
738 			log_printf("%-6.6s", "B", 0);
739 
740 		/* Memory Group Size */
741 		log_printf("%8lldMB            ", mem_size/MBYTE, 0);
742 
743 		total_board_mem += (mem_size/MBYTE);
744 
745 		/* Memory Group Status */
746 		log_printf("%-11.11s",
747 		    cs_stat[i].status ? "partial": "okay", 0);
748 
749 		/* DIMM Size */
750 		log_printf("%4lldMB   ",
751 		    ((((uint64_t)cs_stat[i].dimm_hi)<<32)
752 		    + cs_stat[i].dimm_lo)/MBYTE, 0);
753 
754 		/* Number of DIMMs */
755 		log_printf("  %2d", cs_stat[i].dimms);
756 
757 		/* Mirror Mode */
758 		if (mirror_mode) {
759 			log_printf("%-4.4s", " yes");
760 		} else
761 			log_printf("%-4.4s", " no ");
762 
763 		/* Interleave Factor */
764 		if (interleave)
765 			log_printf("      %d-way\n", interleave);
766 		else
767 			log_printf("      None\n");
768 	}
769 	return (total_board_mem);
770 }
771 
772 /*
773  * Details of hardware revision and environmental status.
774  */
775 /*ARGSUSED*/
776 void
777 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
778 	struct system_kstat_data *kstats)
779 {
780 	/* Print the PROM revisions */
781 	opl_disp_hw_revisions(tree, root);
782 }
783 
784 /*
785  * Gather and display hardware revision and environmental status
786  */
787 /*ARGSUSED*/
788 static void
789 opl_disp_hw_revisions(Sys_tree *tree, Prom_node *root)
790 {
791 	char		*version;
792 	Prom_node	*pnode;
793 	int		value;
794 
795 	(void) textdomain(TEXT_DOMAIN);
796 
797 	/* Print the header */
798 	log_printf("\n", 0);
799 	log_printf("====================", 0);
800 	log_printf(gettext(" Hardware Revisions "), 0);
801 	log_printf("====================", 0);
802 	log_printf("\n\n", 0);
803 
804 	/* Display Prom revision header */
805 	log_printf(gettext("System PROM revisions:"), 0);
806 	log_printf("\n----------------------\n", 0);
807 	log_printf("\n", 0);
808 
809 	/* Display OBP version info */
810 	pnode = dev_find_node(root, "openprom");
811 	if (pnode != NULL) {
812 		version = (char *)get_prop_val(find_prop(pnode, "version"));
813 		if (version != NULL)
814 			log_printf("%s\n\n", version, 0);
815 		else
816 			log_printf("%s\n\n", "N/A", 0);
817 	}
818 
819 	/* Print the header */
820 	log_printf("\n", 0);
821 	log_printf("===================", 0);
822 	log_printf(gettext(" Environmental Status "), 0);
823 	log_printf("===================", 0);
824 	log_printf("\n\n", 0);
825 
826 	opl_disp_environ();
827 
828 	/*
829 	 * PICL interface needs to be used for system processor mode display.
830 	 * Check existence of OBP property "SPARC64-VII-mode".
831 	 * No display if property does not exist.
832 	 * If property exists then system is in (Jupiter) SPARC64-VII-mode.
833 	 */
834 	value = get_proc_mode();
835 
836 	if (value == 0) {
837 		/* Print the header */
838 		log_printf("\n", 0);
839 		log_printf("===================", 0);
840 		log_printf(gettext(" System Processor Mode "), 0);
841 		log_printf("===================", 0);
842 		log_printf("\n\n", 0);
843 
844 		/* Jupiter mode */
845 		log_printf("%s\n\n", "SPARC64-VII mode");
846 	}
847 }
848 
849 /*
850  * Gather environmental information
851  */
852 static void
853 opl_disp_environ(void)
854 {
855 	kstat_ctl_t *kc;
856 	kstat_t *ksp;
857 	kstat_named_t   *k;
858 
859 	if ((kc = kstat_open()) == NULL)
860 		return;
861 
862 	if ((ksp = kstat_lookup
863 	    (kc, "scfd", 0, SCF_SYSTEM_KSTAT_NAME)) == NULL) {
864 		(void) kstat_close(kc);
865 		return;
866 	}
867 
868 	if (kstat_read(kc, ksp, NULL) == -1) {
869 		(void) kstat_close(kc);
870 		return;
871 	}
872 
873 	if ((k = (kstat_named_t *)kstat_data_lookup
874 	    (ksp, SCF_SECURE_MODE_KSTAT_NAMED)) == NULL) {
875 		(void) kstat_close(kc);
876 		return;
877 	}
878 
879 	if (k->value.c[0] == SCF_STAT_MODE_LOCK)
880 		log_printf("Mode switch is in LOCK mode ", 0);
881 	else if (k->value.c[0] == SCF_STAT_MODE_UNLOCK)
882 		log_printf("Mode switch is in UNLOCK mode", 0);
883 	else
884 		log_printf("Mode switch is in UNKNOWN mode", 0);
885 
886 	log_printf("\n", 0);
887 
888 	(void) kstat_close(kc);
889 }
890 
891 
892 /*
893  * Calls do_devinfo() in order to use the libdevinfo device tree
894  * instead of OBP's device tree.
895  */
896 int
897 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
898 {
899 	v_flag = syserrlog;
900 	return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
901 }
902 
903 /*
904  * Return the property value for the Prop
905  * passed in. (When using libdevinfo)
906  */
907 void *
908 get_prop_val(Prop *prop)
909 {
910 	if (prop == NULL)
911 		return (NULL);
912 
913 	return ((void *)(prop->value.val_ptr));
914 }
915 
916 /*
917  * Return the property size for the Prop
918  * passed in. (When using libdevinfo)
919  */
920 static int
921 get_prop_size(Prop *prop)
922 {
923 
924 	if ((prop != NULL) && (prop->size > 0))
925 		return (prop->size);
926 	else
927 		return (0);
928 }
929 
930 
931 /*
932  * Search a Prom node and retrieve the property with the correct
933  * name. (When using libdevinfo)
934  */
935 Prop *
936 find_prop(Prom_node *pnode, char *name)
937 {
938 	Prop *prop;
939 
940 	if (pnode == NULL)
941 		return (NULL);
942 
943 	for (prop = pnode->props; prop != NULL; prop = prop->next) {
944 		if (prop->name.val_ptr != NULL &&
945 		    strcmp((char *)(prop->name.val_ptr), name) == 0)
946 			break;
947 	}
948 
949 	return (prop);
950 }
951 
952 /*
953  * This function adds a board node to the board structure where that
954  * that node's physical component lives.
955  */
956 void
957 add_node(Sys_tree *root, Prom_node *pnode)
958 {
959 	int board;
960 	Board_node *bnode;
961 	Prom_node *p;
962 	char *type;
963 
964 	if ((board = get_board_num(pnode)) == -1) {
965 		type = get_node_type(pnode);
966 		if ((type != NULL) && (strcmp(type, "cpu") == 0))
967 			board = get_board_num((pnode->parent)->parent);
968 	}
969 
970 	/* find the node with the same board number */
971 	if ((bnode = find_board(root, board)) == NULL) {
972 		bnode = insert_board(root, board);
973 		bnode->board_type = UNKNOWN_BOARD;
974 	}
975 
976 	/* now attach this prom node to the board list */
977 	/* Insert this node at the end of the list */
978 	pnode->sibling = NULL;
979 	if (bnode->nodes == NULL)
980 		bnode->nodes = pnode;
981 	else {
982 		p = bnode->nodes;
983 		while (p->sibling != NULL)
984 			p = p->sibling;
985 		p->sibling = pnode;
986 	}
987 
988 }
989