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