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