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