display_sun4v.c revision 6014:305c84c90724
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 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <alloca.h>
31#include <unistd.h>
32#include <ctype.h>
33#include <string.h>
34#include <kvm.h>
35#include <varargs.h>
36#include <time.h>
37#include <dirent.h>
38#include <fcntl.h>
39#include <sys/param.h>
40#include <sys/stat.h>
41#include <sys/types.h>
42#include <sys/utsname.h>
43#include <sys/openpromio.h>
44#include <libintl.h>
45#include <syslog.h>
46#include <sys/dkio.h>
47#include <sys/systeminfo.h>
48#include <picldefs.h>
49#include <math.h>
50#include <errno.h>
51#include "pdevinfo.h"
52#include "display.h"
53#include "display_sun4v.h"
54#include "libprtdiag.h"
55
56#if !defined(TEXT_DOMAIN)
57#define	TEXT_DOMAIN	"SYS_TEST"
58#endif
59
60#define	MOTHERBOARD			"MB"
61#define	NETWORK				"network"
62#define	SUN4V_MACHINE			"sun4v"
63#define	PARENT_NAMES			10
64
65/*
66 * Additional OBP properties
67 */
68#define	OBP_PROP_COMPATIBLE		"compatible"
69#define	OBP_PROP_MODEL			"model"
70#define	OBP_PROP_SLOT_NAMES		"slot-names"
71#define	OBP_PROP_VERSION		"version"
72
73#define	PICL_NODE_PHYSICAL_PLATFORM	"physical-platform"
74#define	PICL_NODE_CHASSIS		"chassis"
75#define	MEMORY_SIZE_FIELD		11
76#define	INVALID_THRESHOLD		1000000
77
78/*
79 * Additional picl classes
80 */
81#ifndef	PICL_CLASS_SUN4V
82#define	PICL_CLASS_SUN4V		"sun4v"
83#endif
84
85#ifndef	PICL_PROP_NAC
86#define	PICL_PROP_NAC			"nac"
87#endif
88
89extern int sys_clk;
90extern picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *,
91	picl_nodehdl_t *);
92
93static picl_nodehdl_t rooth = 0, phyplatformh = 0;
94static picl_nodehdl_t chassish = 0;
95static int class_node_found;
96static int syserrlog;
97static int all_status_ok;
98
99/* local functions */
100static int sun4v_get_first_compatible_value(picl_nodehdl_t, char **);
101static void sun4v_display_memory_conf(picl_nodehdl_t);
102static int sun4v_disp_env_status();
103static void sun4v_env_print_fan_sensors();
104static void sun4v_env_print_fan_indicators();
105static void sun4v_env_print_temp_sensors();
106static void sun4v_env_print_temp_indicators();
107static void sun4v_env_print_current_sensors();
108static void sun4v_env_print_current_indicators();
109static void sun4v_env_print_voltage_sensors();
110static void sun4v_env_print_voltage_indicators();
111static void sun4v_env_print_LEDs();
112static void sun4v_print_fru_status();
113static void sun4v_print_fw_rev();
114static void sun4v_print_chassis_serial_no();
115static int openprom_callback(picl_nodehdl_t openpromh, void *arg);
116static void sun4v_print_openprom_rev();
117
118int
119sun4v_display(Sys_tree *tree, Prom_node *root, int log,
120	picl_nodehdl_t plafh)
121{
122	void *value;		/* used for opaque PROM data */
123	struct mem_total memory_total;	/* Total memory in system */
124	struct grp_info grps;	/* Info on all groups in system */
125	char machine[MAXSTRLEN];
126	int	exit_code = 0;
127
128	if (sysinfo(SI_MACHINE, machine, sizeof (machine)) == -1)
129		return (1);
130	if (strncmp(machine, SUN4V_MACHINE, strlen(SUN4V_MACHINE)) != 0)
131		return (1);
132
133	sys_clk = -1;  /* System clock freq. (in MHz) */
134
135	/*
136	 * Now display the machine's configuration. We do this if we
137	 * are not logging.
138	 */
139	if (!logging) {
140		struct utsname uts_buf;
141
142		/*
143		 * Display system banner
144		 */
145		(void) uname(&uts_buf);
146
147		log_printf(dgettext(TEXT_DOMAIN, "System Configuration:  "
148		    "Sun Microsystems  %s %s\n"), uts_buf.machine,
149		    get_prop_val(find_prop(root, "banner-name")), 0);
150
151		/* display system clock frequency */
152		value = get_prop_val(find_prop(root, "clock-frequency"));
153		if (value != NULL) {
154			sys_clk = ((*((int *)value)) + 500000) / 1000000;
155			log_printf(dgettext(TEXT_DOMAIN, "System clock "
156			    "frequency: %d MHz\n"), sys_clk, 0);
157		}
158
159		/* Display the Memory Size */
160		display_memorysize(tree, NULL, &grps, &memory_total);
161
162		/* Display the CPU devices */
163		sun4v_display_cpu_devices(plafh);
164
165		/* Display the Memory configuration */
166		class_node_found = 0;
167		sun4v_display_memory_conf(plafh);
168
169		/* Display all the IO cards. */
170		(void) sun4v_display_pci(plafh);
171		sun4v_display_diaginfo((log || (logging)), root, plafh);
172
173		if (picl_get_root(&rooth) != PICL_SUCCESS)
174			return (1);
175
176		/*
177		 * The physical-platform node may be missing on systems with
178		 * older firmware so don't consider that an error.
179		 */
180		if (sun4v_get_node_by_name(rooth, PICL_NODE_PHYSICAL_PLATFORM,
181		    &phyplatformh) != PICL_SUCCESS)
182			return (0);
183
184		if (picl_find_node(phyplatformh, PICL_PROP_CLASSNAME,
185		    PICL_PTYPE_CHARSTRING, (void *)PICL_CLASS_CHASSIS,
186		    strlen(PICL_CLASS_CHASSIS), &chassish) != PICL_SUCCESS)
187			return (1);
188
189		syserrlog = log;
190		exit_code = sun4v_disp_env_status();
191	}
192	return (exit_code);
193}
194
195/*
196 * The binding-name property encodes the bus type.
197 */
198static void
199get_bus_type(picl_nodehdl_t nodeh, struct io_card *card)
200{
201	char val[PICL_PROPNAMELEN_MAX], *p, *q;
202
203	card->bus_type[0] = '\0';
204
205	if (picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, val,
206	    sizeof (val)) == PICL_SUCCESS) {
207		if (strstr(val, PICL_CLASS_PCIEX))
208			(void) strlcpy(card->bus_type, "PCIE",
209			    sizeof (card->bus_type));
210		else if (strstr(val, PICL_CLASS_PCI))
211			(void) strlcpy(card->bus_type, "PCIX",
212			    sizeof (card->bus_type));
213		else {
214			/*
215			 * Not perfect: process the binding-name until
216			 * we encounter something that we don't think would
217			 * be part of a bus type.  This may get confused a bit
218			 * if a device or vendor id is encoded right after
219			 * the bus class since there's no delimiter.  If the
220			 * id number begins with a hex digit [abcdef] then
221			 * this will become part of the bus type string
222			 * reported by prtdiag.  This is all an effort to
223			 * print something potentially useful for bus types
224			 * other than PCI/PCIe.
225			 *
226			 * We do this because this code will get called for
227			 * non-PCI class devices like the xaui (class sun4v.)
228			 */
229			if (strstr(val, "SUNW,") != NULL)
230				p = strchr(val, ',') + 1;
231			else
232				p = val;
233			q = p;
234			while (*p != '\0') {
235				if (isdigit((char)*p) || ispunct((char)*p)) {
236					*p = '\0';
237					break;
238				}
239				*p = (char)_toupper((int)*p);
240				++p;
241			}
242			(void) strlcpy(card->bus_type, q,
243			    sizeof (card->bus_type));
244		}
245	}
246}
247
248/*
249 * Fetch the Label property for this device.  If none is found then
250 * search all the siblings with the same device ID for a
251 * Label and return that Label.  The plug-in can only match the canonical
252 * path from the PRI with a specific devfs path.  So we take care of
253 * devices with multiple functions here.  A leaf device downstream of
254 * a bridge should fall out of here with PICL_PROPNOTFOUND, and the
255 * caller can walk back up the tree in search of the slot's Label.
256 */
257static picl_errno_t
258get_slot_label(picl_nodehdl_t nodeh, struct io_card *card)
259{
260	char val[PICL_PROPNAMELEN_MAX];
261	picl_errno_t err;
262	picl_nodehdl_t pnodeh;
263	uint32_t devid, sib_devid;
264	int32_t instance;
265
266	/*
267	 * If there's a Label at this node then return it - we're
268	 * done.
269	 */
270	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
271	    sizeof (val));
272	if (err == PICL_SUCCESS) {
273		(void) strlcpy(card->slot_str, val, sizeof (card->slot_str));
274		return (err);
275	} else if (err != PICL_PROPNOTFOUND)
276		return (err);
277
278	/*
279	 * At this point we're starting to extrapolate what the Label
280	 * should be since there is none at this specific node.
281	 * Note that until the value of "err" is overwritten in the
282	 * loop below, its value should be PICL_PROPNOTFOUND.
283	 */
284
285	/*
286	 * The device must be attached, and we can figure that out if
287	 * the instance number is present and is not equal to -1.
288	 * This will prevent is from returning a Label for a sibling
289	 * node when the node passed in would have a unique Label if the
290	 * device were attached.  But if the device is downstream of a
291	 * node with a Label then pci_callback() will still find that
292	 * and use it.
293	 */
294	if (picl_get_propval_by_name(nodeh, PICL_PROP_INSTANCE, &instance,
295	    sizeof (instance)) != PICL_SUCCESS)
296		return (err);
297	if (instance == -1)
298		return (err);
299
300	/*
301	 * Narrow the search to just the one device ID.
302	 */
303	if (picl_get_propval_by_name(nodeh, PICL_PROP_DEVICE_ID, &devid,
304	    sizeof (devid)) != PICL_SUCCESS)
305		return (err);
306
307	/*
308	 * Go find the first child of the parent so we can search
309	 * all of the siblings.
310	 */
311	if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
312	    sizeof (pnodeh)) != PICL_SUCCESS)
313		return (err);
314	if (picl_get_propval_by_name(pnodeh, PICL_PROP_CHILD, &pnodeh,
315	    sizeof (pnodeh)) != PICL_SUCCESS)
316		return (err);
317
318	/*
319	 * If the child's device ID matches, then fetch the Label and
320	 * return it.  The first child/device ID should have a Label
321	 * associated with it.
322	 */
323	do {
324		if (picl_get_propval_by_name(pnodeh, PICL_PROP_DEVICE_ID,
325		    &sib_devid, sizeof (sib_devid)) == PICL_SUCCESS) {
326			if (sib_devid == devid) {
327				if ((err = picl_get_propval_by_name(pnodeh,
328				    PICL_PROP_LABEL, val, sizeof (val))) ==
329				    PICL_SUCCESS) {
330					(void) strlcpy(card->slot_str, val,
331					    sizeof (card->slot_str));
332					break;
333				}
334			}
335		}
336	} while (picl_get_propval_by_name(pnodeh, PICL_PROP_PEER, &pnodeh,
337	    sizeof (pnodeh)) == PICL_SUCCESS);
338
339	return (err);
340}
341
342static void
343get_slot_number(picl_nodehdl_t nodeh, struct io_card *card)
344{
345	picl_errno_t err;
346	picl_prophdl_t proph;
347	picl_propinfo_t pinfo;
348	picl_nodehdl_t pnodeh;
349	uint8_t *pval;
350	uint32_t dev_mask;
351	char uaddr[MAXSTRLEN];
352	int i;
353
354	err = PICL_SUCCESS;
355	while (err == PICL_SUCCESS) {
356		if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
357		    sizeof (pnodeh)) != PICL_SUCCESS) {
358			(void) strlcpy(card->slot_str, MOTHERBOARD,
359			    sizeof (card->slot_str));
360			card->slot = -1;
361			return;
362		}
363		if (picl_get_propinfo_by_name(pnodeh, OBP_PROP_SLOT_NAMES,
364		    &pinfo, &proph) == PICL_SUCCESS) {
365			break;
366		}
367		nodeh = pnodeh;
368	}
369	if (picl_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, uaddr,
370	    sizeof (uaddr)) != PICL_SUCCESS) {
371		(void) strlcpy(card->slot_str, MOTHERBOARD,
372		    sizeof (card->slot_str));
373		card->slot = -1;
374		return;
375	}
376	pval = (uint8_t *)malloc(pinfo.size);
377	if (!pval) {
378		(void) strlcpy(card->slot_str, MOTHERBOARD,
379		    sizeof (card->slot_str));
380		card->slot = -1;
381		return;
382	}
383	if (picl_get_propval(proph, pval, pinfo.size) != PICL_SUCCESS) {
384		(void) strlcpy(card->slot_str, MOTHERBOARD,
385		    sizeof (card->slot_str));
386		card->slot = -1;
387		free(pval);
388		return;
389	}
390
391	dev_mask = 0;
392	for (i = 0; i < sizeof (dev_mask); i++)
393		dev_mask |= (*(pval+i) << 8*(sizeof (dev_mask)-1-i));
394	for (i = 0; i < sizeof (uaddr) && uaddr[i] != '\0'; i++) {
395		if (uaddr[i] == ',') {
396			uaddr[i] = '\0';
397			break;
398		}
399	}
400	card->slot = atol(uaddr);
401	if (((1 << card->slot) & dev_mask) == 0) {
402		(void) strlcpy(card->slot_str, MOTHERBOARD,
403		    sizeof (card->slot_str));
404		card->slot = -1;
405	} else {
406		char *p = (char *)(pval+sizeof (dev_mask));
407		int shift = sizeof (uint32_t)*8-1-card->slot;
408		uint32_t x = (dev_mask << shift) >> shift;
409		int count = 0;	/* count # of 1's in x */
410		int i = 0;
411		while (x != 0) {
412			count++;
413			x &= x-1;
414		}
415		while (count > 1) {
416			while (p[i++] != '\0')
417				;
418			count--;
419		}
420		(void) strlcpy(card->slot_str, (char *)(p+i),
421		    sizeof (card->slot_str));
422	}
423	free(pval);
424}
425
426/*
427 * add all io devices under pci in io list
428 */
429/* ARGSUSED */
430static int
431sun4v_pci_callback(picl_nodehdl_t pcih, void *args)
432{
433	char path[PICL_PROPNAMELEN_MAX];
434	char class[PICL_CLASSNAMELEN_MAX];
435	char name[PICL_PROPNAMELEN_MAX];
436	char model[PICL_PROPNAMELEN_MAX];
437	char binding_name[PICL_PROPNAMELEN_MAX];
438	char val[PICL_PROPNAMELEN_MAX];
439	char *compatible;
440	picl_errno_t err;
441	picl_nodehdl_t nodeh, pnodeh;
442	struct io_card pci_card;
443
444	/* Walk through the children */
445
446	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
447	    sizeof (picl_nodehdl_t));
448
449	while (err == PICL_SUCCESS) {
450		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
451		    class, sizeof (class));
452		if (err !=  PICL_SUCCESS)
453			return (err);
454
455		if (args) {
456			char *val = args;
457			if (strcmp(class, val) == 0) {
458				err = picl_get_propval_by_name(nodeh,
459				    PICL_PROP_PEER, &nodeh,
460				    sizeof (picl_nodehdl_t));
461				continue;
462			} else if (strcmp(val, PICL_CLASS_PCIEX) == 0 &&
463			    strcmp(class, PICL_CLASS_PCI) == 0) {
464				err = picl_get_propval_by_name(nodeh,
465				    PICL_PROP_PEER, &nodeh,
466				    sizeof (picl_nodehdl_t));
467				continue;
468			} else if (strcmp(val, PICL_CLASS_PCI) == 0 &&
469			    strcmp(class, PICL_CLASS_PCIEX) == 0) {
470				err = picl_get_propval_by_name(nodeh,
471				    PICL_PROP_PEER, &nodeh,
472				    sizeof (picl_nodehdl_t));
473				continue;
474			}
475		}
476
477		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
478		    path, sizeof (path));
479		if (err != PICL_SUCCESS)
480			return (err);
481
482		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
483
484		pnodeh = nodeh;
485		err = get_slot_label(nodeh, &pci_card);
486
487		/*
488		 * No Label at this node, maybe we're looking at a device
489		 * downstream of a bridge.  Walk back up and find a Label and
490		 * record that node in "pnodeh".
491		 */
492		while (err != PICL_SUCCESS) {
493			if (err != PICL_PROPNOTFOUND)
494				break;
495			else if (picl_get_propval_by_name(pnodeh,
496			    PICL_PROP_PARENT, &pnodeh, sizeof (pnodeh)) ==
497			    PICL_SUCCESS)
498				err = get_slot_label(pnodeh, &pci_card);
499			else
500				break;
501		}
502
503		/*
504		 * Can't find a Label for this device in the PCI heirarchy.
505		 * Try to synthesize a slot name from atoms.  This depends
506		 * on the OBP slot_names property being implemented, and this
507		 * so far doesn't seem to be on sun4v.  But just in case that
508		 * is resurrected, the code is here.
509		 */
510		if (err != PICL_SUCCESS) {
511			pnodeh = nodeh;
512			get_slot_number(nodeh, &pci_card);
513		}
514
515		/*
516		 * Passing in pnodeh instead of nodeh will cause prtdiag
517		 * to display the type of IO slot for the leaf node.  For
518		 * built-in devices and a lot of IO cards these will be
519		 * the same thing.  But for IO cards with bridge chips or
520		 * for things like expansion chassis, prtdiag will report
521		 * the bus type of the IO slot and not the leaf, which
522		 * could be different things.
523		 */
524		get_bus_type(pnodeh, &pci_card);
525
526		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, name,
527		    sizeof (name));
528		if (err == PICL_PROPNOTFOUND)
529			(void) strlcpy(name, "", sizeof (name));
530		else if (err != PICL_SUCCESS)
531			return (err);
532
533		err = picl_get_propval_by_name(nodeh, PICL_PROP_STATUS, val,
534		    sizeof (val));
535		if (err == PICL_PROPNOTFOUND)
536			(void) strlcpy(val, "", sizeof (val));
537		else if (err != PICL_SUCCESS)
538			return (err);
539
540		(void) snprintf(pci_card.status, sizeof (pci_card.status),
541		    "%s", pci_card.slot_str);
542
543		/*
544		 * Get the name of this card. If binding_name is found,
545		 * name will be <nodename>-<binding_name>.
546		 */
547		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
548		    binding_name, sizeof (binding_name));
549		if (err == PICL_SUCCESS) {
550			if (strcmp(name, binding_name) != 0) {
551				(void) strlcat(name, "-", sizeof (name));
552				(void) strlcat(name, binding_name,
553				    sizeof (name));
554			}
555		} else if (err == PICL_PROPNOTFOUND) {
556			/*
557			 * if compatible prop is not found, name will be
558			 * <nodename>-<compatible>
559			 */
560			err = sun4v_get_first_compatible_value(nodeh,
561			    &compatible);
562			if (err == PICL_SUCCESS) {
563				(void) strlcat(name, "-", sizeof (name));
564				(void) strlcat(name, compatible,
565				    sizeof (name));
566				free(compatible);
567			}
568		} else
569			return (err);
570
571		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
572
573		/* Get the model of this card */
574
575		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
576		    model, sizeof (model));
577		if (err == PICL_PROPNOTFOUND)
578			(void) strlcpy(model, "", sizeof (model));
579		else if (err != PICL_SUCCESS)
580			return (err);
581		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
582
583		/* Print NAC name */
584		log_printf("%-18s", pci_card.status);
585		/* Print IO Type */
586		log_printf("%-6s", pci_card.bus_type);
587		/* Printf Card Name */
588		log_printf("%-34s", pci_card.name);
589		/* Print Card Model */
590		log_printf("%-8s", pci_card.model);
591		log_printf("\n");
592		/* Print Status */
593		log_printf("%-18s", val);
594		/* Print IO Type */
595		log_printf("%-6s", "");
596		/* Print Parent Path */
597		log_printf("%-44s", pci_card.notes);
598		log_printf("\n");
599
600		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
601		    sizeof (picl_nodehdl_t));
602	}
603	return (PICL_WALK_CONTINUE);
604}
605
606/*
607 * display_pci
608 * Display all the PCI IO cards on this board.
609 */
610void
611sun4v_display_pci(picl_nodehdl_t plafh)
612{
613	char *fmt = "%-17s %-5s %-33s %-8s";
614	/* Have we printed the column headings? */
615	static int banner = FALSE;
616
617	if (banner == FALSE) {
618		log_printf("\n");
619		log_printf("================================");
620		log_printf(" IO Devices ");
621		log_printf("================================");
622		log_printf("\n");
623		log_printf(fmt, "Slot +", "Bus", "Name +", "Model", 0);
624		log_printf("\n");
625		log_printf(fmt, "Status", "Type", "Path", "", 0);
626		log_printf("\n");
627		log_printf("---------------------------------"
628		    "-------------------------------------------\n");
629		banner = TRUE;
630	}
631
632	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX,
633	    PICL_CLASS_PCIEX, sun4v_pci_callback);
634	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
635	    PICL_CLASS_PCI, sun4v_pci_callback);
636	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_SUN4V,
637	    PICL_CLASS_SUN4V, sun4v_pci_callback);
638}
639
640/*
641 * return the first compatible value
642 */
643static int
644sun4v_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
645{
646	picl_errno_t err;
647	picl_prophdl_t proph;
648	picl_propinfo_t pinfo;
649	picl_prophdl_t tblh;
650	picl_prophdl_t rowproph;
651	char *pval;
652
653	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
654	    &pinfo, &proph);
655	if (err != PICL_SUCCESS)
656		return (err);
657
658	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
659		pval = malloc(pinfo.size);
660		if (pval == NULL)
661			return (PICL_FAILURE);
662		err = picl_get_propval(proph, pval, pinfo.size);
663		if (err != PICL_SUCCESS) {
664			free(pval);
665			return (err);
666		}
667		*outbuf = pval;
668		return (PICL_SUCCESS);
669	}
670
671	if (pinfo.type != PICL_PTYPE_TABLE)
672		return (PICL_FAILURE);
673
674	/* get first string from table */
675	err = picl_get_propval(proph, &tblh, pinfo.size);
676	if (err != PICL_SUCCESS)
677		return (err);
678
679	err = picl_get_next_by_row(tblh, &rowproph);
680	if (err != PICL_SUCCESS)
681		return (err);
682
683	err = picl_get_propinfo(rowproph, &pinfo);
684	if (err != PICL_SUCCESS)
685		return (err);
686
687	pval = malloc(pinfo.size);
688	if (pval == NULL)
689		return (PICL_FAILURE);
690
691	err = picl_get_propval(rowproph, pval, pinfo.size);
692	if (err != PICL_SUCCESS) {
693		free(pval);
694		return (err);
695	}
696
697	*outbuf = pval;
698	return (PICL_SUCCESS);
699}
700
701/*
702 * print size of a memory segment
703 */
704static void
705print_memory_segment_size(uint64_t size)
706{
707	uint64_t kbyte = 1024;
708	uint64_t mbyte = kbyte * kbyte;
709	uint64_t gbyte = kbyte * mbyte;
710	uint64_t tbyte = kbyte * gbyte;
711	char buf[MEMORY_SIZE_FIELD];
712
713	if (size >= tbyte) {
714		if (size % tbyte == 0)
715			(void) snprintf(buf, sizeof (buf), "%d TB",
716			    (int)(size / tbyte));
717		else
718			(void) snprintf(buf, sizeof (buf), "%.2f TB",
719			    (float)size / tbyte);
720	} else if (size >= gbyte) {
721		if (size % gbyte == 0)
722			(void) snprintf(buf, sizeof (buf), "%d GB",
723			    (int)(size / gbyte));
724		else
725			(void) snprintf(buf, sizeof (buf), "%.2f GB",
726			    (float)size / gbyte);
727	} else if (size >= mbyte) {
728		if (size % mbyte == 0)
729			(void) snprintf(buf, sizeof (buf), "%d MB",
730			    (int)(size / mbyte));
731		else
732			(void) snprintf(buf, sizeof (buf), "%.2f MB",
733			    (float)size / mbyte);
734	} else {
735		if (size % kbyte == 0)
736			(void) snprintf(buf, sizeof (buf), "%d KB",
737			    (int)(size / kbyte));
738		else
739			(void) snprintf(buf, sizeof (buf), "%.2f KB",
740			    (float)size / kbyte);
741	}
742	log_printf("%-9s", buf);
743}
744
745/*
746 * Enumerate banks and dimms within a memory segment.  We're handed
747 * the first bank within the segment - we assume there are dimms
748 * (memory-module) nodes underneath.
749 */
750static void
751print_memory_segment_contain(picl_nodehdl_t bank_nodeh)
752{
753	char val[PICL_PROPNAMELEN_MAX];
754	picl_nodehdl_t module_nodeh;
755	int flag = 0;
756	uint64_t size;
757
758	do {
759		if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_CHILD,
760		    &module_nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
761			continue;
762		if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_SIZE,
763		    &size, sizeof (size)) == PICL_SUCCESS) {
764			if (!flag) {
765				print_memory_segment_size(size);
766			} else {
767				log_printf("                "
768				    "                    ");
769				print_memory_segment_size(size);
770				flag = 0;
771			}
772		}
773		do {
774			if (picl_get_propval_by_name(module_nodeh,
775			    PICL_PROP_NAC, val, sizeof (val)) !=
776			    PICL_SUCCESS)
777				continue;
778			else {
779				if (!flag) {
780					log_printf("%s\n", val);
781					flag = 1;
782				} else {
783					log_printf("%s%s\n",
784					    "                       "
785					    "                      ",
786					    val);
787				}
788			}
789		} while (picl_get_propval_by_name(module_nodeh, PICL_PROP_PEER,
790		    &module_nodeh, sizeof (picl_nodehdl_t)) ==
791		    PICL_SUCCESS);
792	} while (picl_get_propval_by_name(bank_nodeh, PICL_PROP_PEER,
793	    &bank_nodeh, sizeof (picl_nodehdl_t)) == PICL_SUCCESS);
794}
795
796/*
797 * Search node where _class=="memory-segment"
798 * print "Base Address", "Size", etc
799 */
800/*ARGSUSED*/
801static int
802sun4v_memory_conf_callback(picl_nodehdl_t nodeh, void *args)
803{
804	uint64_t base;
805	uint64_t size;
806	uint64_t ifactor;
807	picl_errno_t err = PICL_SUCCESS;
808
809	if (class_node_found == 0) {
810		class_node_found = 1;
811		return (PICL_WALK_TERMINATE);
812	}
813	while (err == PICL_SUCCESS) {
814		err = picl_get_propval_by_name(nodeh, PICL_PROP_BASEADDRESS,
815		    &base, sizeof (base));
816		if (err !=  PICL_SUCCESS)
817			break;
818		err = picl_get_propval_by_name(nodeh, PICL_PROP_SIZE,
819		    &size, sizeof (size));
820		if (err !=  PICL_SUCCESS)
821			break;
822		err = picl_get_propval_by_name(nodeh,
823		    PICL_PROP_INTERLEAVE_FACTOR, &ifactor,
824		    sizeof (ifactor));
825		if (err !=  PICL_SUCCESS)
826			break;
827		log_printf("0x%-13llx", base);
828		print_memory_segment_size(size);
829		log_printf("%-12lld", ifactor);
830		err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
831		    &nodeh, sizeof (nodeh));
832		if (err ==  PICL_SUCCESS)
833			print_memory_segment_contain(nodeh);
834		log_printf("\n");
835		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
836		    sizeof (picl_nodehdl_t));
837	}
838
839	return (PICL_WALK_CONTINUE);
840}
841
842/*ARGSUSED*/
843void
844sun4v_display_memory_conf(picl_nodehdl_t plafh)
845{
846	char *fmt = "%-14s %-8s %-11s %-8s %-s";
847	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
848	    NULL, sun4v_memory_conf_callback);
849	if (class_node_found == 0)
850		return;
851	log_printf("\n");
852	log_printf("=======================");
853	log_printf(" Physical Memory Configuration ");
854	log_printf("========================");
855	log_printf("\n");
856	log_printf("Segment Table:\n");
857	log_printf(
858	    "--------------------------------------------------------------\n");
859	log_printf(fmt, "Base", "Segment", "Interleave", "Bank", "Contains", 0);
860	log_printf("\n");
861	log_printf(fmt, "Address", "Size", "Factor", "Size", "Modules", 0);
862	log_printf("\n");
863	log_printf(
864	    "--------------------------------------------------------------\n");
865	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
866	    NULL, sun4v_memory_conf_callback);
867}
868
869void
870sun4v_display_cpu_devices(picl_nodehdl_t plafh)
871{
872	char *fmt = "%-6s %-9s %-22s %-6s";
873
874	/*
875	 * Display the table header for CPUs . Then display the CPU
876	 * frequency, cache size, and processor revision of all cpus.
877	 */
878	log_printf(dgettext(TEXT_DOMAIN,
879	    "\n"
880	    "================================"
881	    " Virtual CPUs "
882	    "================================"
883	    "\n"
884	    "\n"));
885	log_printf("\n");
886	log_printf(fmt, "CPU ID", "Frequency", "Implementation",
887	    "Status", 0);
888	log_printf("\n");
889	log_printf(fmt, "------", "---------",
890	    "----------------------", "-------", 0);
891	log_printf("\n");
892
893	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU,
894	    sun4v_display_cpus);
895}
896
897/*
898 * Display the CPUs present on this board.
899 */
900/*ARGSUSED*/
901int
902sun4v_display_cpus(picl_nodehdl_t cpuh, void* args)
903{
904	int status;
905	picl_prophdl_t proph;
906	picl_prophdl_t tblh;
907	picl_prophdl_t rowproph;
908	picl_propinfo_t propinfo;
909	int *int_value;
910	int cpuid;
911	char *comp_value;
912	char *no_prop_value = "   ";
913	char freq_str[MAXSTRLEN];
914	char state[MAXSTRLEN];
915
916	/*
917	 * Get cpuid property and print it and the NAC name
918	 */
919	status = picl_get_propinfo_by_name(cpuh, OBP_PROP_CPUID, &propinfo,
920	    &proph);
921	if (status == PICL_SUCCESS) {
922		status = picl_get_propval(proph, &cpuid, sizeof (cpuid));
923		if (status != PICL_SUCCESS) {
924			log_printf("%-7s", no_prop_value);
925		} else {
926			log_printf("%-7d", cpuid);
927		}
928	} else {
929		log_printf("%-7s", no_prop_value);
930	}
931
932clock_freq:
933	status = picl_get_propinfo_by_name(cpuh, "clock-frequency", &propinfo,
934	    &proph);
935	if (status == PICL_SUCCESS) {
936		int_value = malloc(propinfo.size);
937		if (int_value == NULL) {
938			log_printf("%-10s", no_prop_value);
939			goto compatible;
940		}
941		status = picl_get_propval(proph, int_value, propinfo.size);
942		if (status != PICL_SUCCESS) {
943			log_printf("%-10s", no_prop_value);
944		} else {
945			/* Running frequency */
946			(void) snprintf(freq_str, sizeof (freq_str), "%d MHz",
947			    CLK_FREQ_TO_MHZ(*int_value));
948			log_printf("%-10s", freq_str);
949		}
950		free(int_value);
951	} else
952		log_printf("%-10s", no_prop_value);
953
954compatible:
955	status = picl_get_propinfo_by_name(cpuh, "compatible", &propinfo,
956	    &proph);
957	if (status == PICL_SUCCESS) {
958		if (propinfo.type == PICL_PTYPE_CHARSTRING) {
959			/*
960			 * Compatible Property only has 1 value
961			 */
962			comp_value = malloc(propinfo.size);
963			if (comp_value == NULL) {
964				log_printf("%-23s", no_prop_value, 0);
965				goto state;
966			}
967			status = picl_get_propval(proph, comp_value,
968			    propinfo.size);
969			if (status != PICL_SUCCESS)
970				log_printf("%-23s", no_prop_value, 0);
971			else
972				log_printf("%-23s", comp_value, 0);
973			free(comp_value);
974		} else if (propinfo.type == PICL_PTYPE_TABLE) {
975			/*
976			 * Compatible Property has multiple values
977			 */
978			status = picl_get_propval(proph, &tblh, propinfo.size);
979			if (status != PICL_SUCCESS) {
980				log_printf("%-23s", no_prop_value, 0);
981				goto state;
982			}
983			status = picl_get_next_by_row(tblh, &rowproph);
984			if (status != PICL_SUCCESS) {
985				log_printf("%-23s", no_prop_value, 0);
986				goto state;
987			}
988
989			status = picl_get_propinfo(rowproph, &propinfo);
990			if (status != PICL_SUCCESS) {
991				log_printf("%-23s", no_prop_value, 0);
992				goto state;
993			}
994
995			comp_value = malloc(propinfo.size);
996			if (comp_value == NULL) {
997				log_printf("%-23s", no_prop_value, 0);
998				goto state;
999			}
1000			status = picl_get_propval(rowproph, comp_value,
1001			    propinfo.size);
1002			if (status != PICL_SUCCESS)
1003				log_printf("%-23s", no_prop_value, 0);
1004			else
1005				log_printf("%-23s", comp_value, 0);
1006			free(comp_value);
1007		}
1008	} else
1009		log_printf("%-23s", no_prop_value, 0);
1010
1011state:
1012	status = picl_get_propinfo_by_name(cpuh, PICL_PROP_STATE,
1013	    &propinfo, &proph);
1014	if (status == PICL_SUCCESS) {
1015		status = picl_get_propval(proph, state, sizeof (state));
1016		if (status != PICL_SUCCESS) {
1017			log_printf("%-9s", no_prop_value);
1018		} else {
1019			log_printf("%-9s", state);
1020		}
1021	} else
1022		log_printf("%-9s", no_prop_value);
1023
1024done:
1025	log_printf("\n");
1026	return (PICL_WALK_CONTINUE);
1027}
1028
1029void
1030sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
1031{
1032#ifdef	lint
1033	flag = flag;
1034	root = root;
1035	plafh = plafh;
1036#endif
1037	/*
1038	 * This function is intentionally empty
1039	 */
1040}
1041
1042void
1043display_boardnum(int num)
1044{
1045	log_printf("%2d   ", num, 0);
1046}
1047
1048static int
1049sun4v_disp_env_status()
1050{
1051	int	exit_code = 0;
1052
1053	if (phyplatformh == 0)
1054		return (0);
1055	log_printf("\n");
1056	log_printf("============================");
1057	log_printf(" Environmental Status ");
1058	log_printf("============================");
1059	log_printf("\n");
1060
1061	class_node_found = 0;
1062	all_status_ok = 1;
1063	sun4v_env_print_fan_sensors();
1064	exit_code |= (!all_status_ok);
1065
1066	class_node_found = 0;
1067	all_status_ok = 1;
1068	sun4v_env_print_fan_indicators();
1069	exit_code |= (!all_status_ok);
1070
1071	class_node_found = 0;
1072	all_status_ok = 1;
1073	sun4v_env_print_temp_sensors();
1074	exit_code |= (!all_status_ok);
1075
1076	class_node_found = 0;
1077	all_status_ok = 1;
1078	sun4v_env_print_temp_indicators();
1079	exit_code |= (!all_status_ok);
1080
1081	class_node_found = 0;
1082	all_status_ok = 1;
1083	sun4v_env_print_current_sensors();
1084	exit_code |= (!all_status_ok);
1085
1086	class_node_found = 0;
1087	all_status_ok = 1;
1088	sun4v_env_print_current_indicators();
1089	exit_code |= (!all_status_ok);
1090
1091	class_node_found = 0;
1092	all_status_ok = 1;
1093	sun4v_env_print_voltage_sensors();
1094	exit_code |= (!all_status_ok);
1095
1096	class_node_found = 0;
1097	all_status_ok = 1;
1098	sun4v_env_print_voltage_indicators();
1099	exit_code |= (!all_status_ok);
1100
1101	class_node_found = 0;
1102	all_status_ok = 1;
1103	sun4v_env_print_LEDs();
1104	exit_code |= (!all_status_ok);
1105
1106	class_node_found = 0;
1107	all_status_ok = 1;
1108	sun4v_print_fru_status();
1109	exit_code |= (!all_status_ok);
1110
1111	class_node_found = 0;
1112	sun4v_print_fw_rev();
1113
1114	class_node_found = 0;
1115	sun4v_print_openprom_rev();
1116
1117	sun4v_print_chassis_serial_no();
1118
1119	return (exit_code);
1120}
1121
1122/*ARGSUSED*/
1123static int
1124sun4v_env_print_sensor_callback(picl_nodehdl_t nodeh, void *args)
1125{
1126	char val[PICL_PROPNAMELEN_MAX];
1127	picl_nodehdl_t parenth;
1128	char *names[PARENT_NAMES];
1129	char *base_units[PICL_PROPNAMELEN_MAX];
1130	char *loc;
1131	int i;
1132	char *prop;
1133	picl_errno_t err;
1134	int32_t lo_warning, lo_shutdown, lo_poweroff;
1135	int32_t hi_warning, hi_shutdown, hi_poweroff;
1136	int32_t current_val;
1137	int32_t exponent;
1138	double display_val;
1139	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
1140	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
1141	sensor_status_t sensor_status = SENSOR_OK;
1142
1143	if (class_node_found == 0) {
1144		class_node_found = 1;
1145		return (PICL_WALK_TERMINATE);
1146	}
1147
1148	prop = (char *)args;
1149	if (!prop) {
1150		sensor_status = SENSOR_UNKNOWN;
1151		all_status_ok = 0;
1152	} else {
1153		err = picl_get_propval_by_name(nodeh,
1154		    PICL_PROP_OPERATIONAL_STATUS, val,
1155		    sizeof (val));
1156		if (err == PICL_SUCCESS) {
1157			if (strcmp(val, "disabled") == 0) {
1158				sensor_status = SENSOR_DISABLED;
1159			}
1160		}
1161	}
1162
1163	if (sensor_status != SENSOR_DISABLED &&
1164	    sensor_status != SENSOR_UNKNOWN) {
1165		if (picl_get_propval_by_name(nodeh, prop, &current_val,
1166		    sizeof (current_val)) != PICL_SUCCESS) {
1167			sensor_status = SENSOR_UNKNOWN;
1168		} else {
1169			if (picl_get_propval_by_name(nodeh,
1170			    PICL_PROP_LOW_WARNING,
1171			    &lo_warning, sizeof (lo_warning)) != PICL_SUCCESS)
1172				lo_warning = INVALID_THRESHOLD;
1173			if (picl_get_propval_by_name(nodeh,
1174			    PICL_PROP_LOW_SHUTDOWN,
1175			    &lo_shutdown, sizeof (lo_shutdown)) != PICL_SUCCESS)
1176				lo_shutdown = INVALID_THRESHOLD;
1177			if (picl_get_propval_by_name(nodeh,
1178			    PICL_PROP_LOW_POWER_OFF,
1179			    &lo_poweroff, sizeof (lo_poweroff)) != PICL_SUCCESS)
1180				lo_poweroff = INVALID_THRESHOLD;
1181			if (picl_get_propval_by_name(nodeh,
1182			    PICL_PROP_HIGH_WARNING,
1183			    &hi_warning, sizeof (hi_warning)) != PICL_SUCCESS)
1184				hi_warning = INVALID_THRESHOLD;
1185			if (picl_get_propval_by_name(nodeh,
1186			    PICL_PROP_HIGH_SHUTDOWN,
1187			    &hi_shutdown, sizeof (hi_shutdown)) != PICL_SUCCESS)
1188				hi_shutdown = INVALID_THRESHOLD;
1189			if (picl_get_propval_by_name(nodeh,
1190			    PICL_PROP_HIGH_POWER_OFF,
1191			    &hi_poweroff, sizeof (hi_poweroff)) != PICL_SUCCESS)
1192				hi_poweroff = INVALID_THRESHOLD;
1193
1194			if ((lo_poweroff != INVALID_THRESHOLD &&
1195			    current_val <= lo_poweroff) ||
1196			    (hi_poweroff != INVALID_THRESHOLD &&
1197			    current_val >= hi_poweroff)) {
1198				sensor_status = SENSOR_FAILED;
1199			} else if ((lo_shutdown != INVALID_THRESHOLD &&
1200			    current_val <= lo_shutdown) ||
1201			    (hi_shutdown != INVALID_THRESHOLD &&
1202			    current_val >= hi_shutdown)) {
1203				sensor_status = SENSOR_FAILED;
1204			} else if ((lo_warning != INVALID_THRESHOLD &&
1205			    current_val <= lo_warning) ||
1206			    (hi_warning != INVALID_THRESHOLD &&
1207			    current_val >= hi_warning)) {
1208				sensor_status = SENSOR_WARN;
1209			} else {
1210				sensor_status = SENSOR_OK;
1211			}
1212		}
1213	}
1214
1215	if (syserrlog == 0) {
1216		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
1217			all_status_ok = 0;
1218			return (PICL_WALK_TERMINATE);
1219		}
1220		if (sensor_status == SENSOR_OK) {
1221			return (PICL_WALK_CONTINUE);
1222		}
1223	}
1224
1225	/*
1226	 * If we're here then prtdiag was invoked with "-v" or we have
1227	 * a sensor that is beyond a threshold, so give them a book to
1228	 * read instead of the Cliff Notes.
1229	 */
1230	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
1231	    sizeof (parenth));
1232	if (err != PICL_SUCCESS) {
1233		log_printf("\n");
1234		return (PICL_WALK_CONTINUE);
1235	}
1236
1237	/* gather up the path name for the sensor */
1238	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
1239		for (i = 0; i < PARENT_NAMES; i++) {
1240			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
1241			    NULL) {
1242				while (--i > -1)
1243					free(names[i]);
1244				free(loc);
1245				loc = NULL;
1246			}
1247		}
1248	}
1249	i = 0;
1250	if (loc != 0) {
1251		while (err == PICL_SUCCESS) {
1252			if (parenth == phyplatformh)
1253				break;
1254			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
1255			    names[i++], PICL_PROPNAMELEN_MAX);
1256			if (err != PICL_SUCCESS) {
1257				i--;
1258				break;
1259			}
1260			if (i == PARENT_NAMES)
1261				break;
1262			err = picl_get_propval_by_name(parenth,
1263			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
1264		}
1265		loc[0] = '\0';
1266		if (--i > -1) {
1267			(void) strlcat(loc, names[i],
1268			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1269		}
1270		while (--i > -1) {
1271			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
1272			    PARENT_NAMES);
1273			(void) strlcat(loc, names[i],
1274			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1275		}
1276		log_printf("%-35s", loc);
1277		for (i = 0; i < PARENT_NAMES; i++)
1278			free(names[i]);
1279		free(loc);
1280	} else {
1281		log_printf("%-35s", " ");
1282	}
1283	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
1284	    sizeof (val));
1285	if (err == PICL_SUCCESS)
1286		log_printf("%-15s", val);
1287
1288	/*
1289	 * Get the exponent if present, and do a little math so that
1290	 * if we need to we can print a normalized value for the
1291	 * sensor reading.
1292	 */
1293	if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPONENT,
1294	    &exponent, sizeof (exponent)) != PICL_SUCCESS)
1295		exponent = 0;
1296	if (exponent == 0)
1297		display_val = (double)current_val;
1298	else {
1299		display_val = (double)current_val *
1300		    pow((double)10, (double)exponent);
1301
1302		/*
1303		 * Sometimes ILOM will scale a sensor reading but
1304		 * there will be nothing to the right of the decimal
1305		 * once that value is normalized.  Setting the
1306		 * exponent to zero will prevent the printf below
1307		 * from printing extraneous zeros.  Otherwise a
1308		 * negative exponent is used to set the precision
1309		 * for the printf.
1310		 */
1311		if ((int)display_val == display_val || exponent > 0)
1312			exponent = 0;
1313	}
1314
1315	err = picl_get_propval_by_name(nodeh, PICL_PROP_BASE_UNITS,
1316	    base_units, sizeof (base_units));
1317	if (err != PICL_SUCCESS)
1318		base_units[0] = '\0';
1319
1320	switch (sensor_status) {
1321	case SENSOR_FAILED:
1322		log_printf("%-s", "failed (");
1323		log_printf("%-.*f", abs(exponent), display_val);
1324		log_printf("%-s %s", base_units, ")");
1325		break;
1326	case SENSOR_WARN:
1327		log_printf("%-s", "warning (");
1328		log_printf("%-.*f", abs(exponent), display_val);
1329		log_printf("%-s %s", base_units, ")");
1330		break;
1331	case SENSOR_DISABLED:
1332		log_printf("%-s", "disabled");
1333		break;
1334	case SENSOR_OK:
1335		log_printf("%-s", "ok");
1336		break;
1337	default:
1338		log_printf("%-s", "unknown");
1339		break;
1340	}
1341
1342	log_printf("\n");
1343	return (PICL_WALK_CONTINUE);
1344}
1345
1346/*ARGSUSED*/
1347static int
1348sun4v_env_print_indicator_callback(picl_nodehdl_t nodeh, void *args)
1349{
1350	char current_val[PICL_PROPNAMELEN_MAX];
1351	char expected_val[PICL_PROPNAMELEN_MAX];
1352	char label[PICL_PROPNAMELEN_MAX];
1353	picl_nodehdl_t parenth;
1354	char *names[PARENT_NAMES];
1355	char *loc;
1356	int i = 0;
1357	char *prop = (char *)args;
1358	picl_errno_t err = PICL_SUCCESS;
1359	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
1360	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
1361	sensor_status_t sensor_status = SENSOR_OK;
1362
1363	if (class_node_found == 0) {
1364		class_node_found = 1;
1365		return (PICL_WALK_TERMINATE);
1366	}
1367
1368	prop = (char *)args;
1369	if (!prop) {
1370		sensor_status = SENSOR_UNKNOWN;
1371		all_status_ok = 0;
1372	} else {
1373		err = picl_get_propval_by_name(nodeh,
1374		    PICL_PROP_OPERATIONAL_STATUS, current_val,
1375		    sizeof (current_val));
1376		if (err == PICL_SUCCESS) {
1377			if (strcmp(current_val, "disabled") == 0) {
1378				sensor_status = SENSOR_DISABLED;
1379			}
1380		}
1381	}
1382
1383	if (sensor_status != SENSOR_DISABLED &&
1384	    sensor_status != SENSOR_UNKNOWN) {
1385		if (picl_get_propval_by_name(nodeh, prop, &current_val,
1386		    sizeof (current_val)) != PICL_SUCCESS) {
1387			(void) strlcpy(current_val, "unknown",
1388			    sizeof (current_val));
1389			sensor_status = SENSOR_UNKNOWN;
1390		} else {
1391			if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPECTED,
1392			    &expected_val, sizeof (expected_val)) !=
1393			    PICL_SUCCESS) {
1394				sensor_status = SENSOR_UNKNOWN;
1395			} else {
1396				if (strncmp(current_val, expected_val,
1397				    sizeof (current_val)) == 0) {
1398					sensor_status = SENSOR_OK;
1399				} else {
1400					sensor_status = SENSOR_FAILED;
1401				}
1402			}
1403		}
1404	}
1405
1406	if (syserrlog == 0) {
1407		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
1408			all_status_ok = 0;
1409			return (PICL_WALK_TERMINATE);
1410		}
1411		if (sensor_status == SENSOR_OK) {
1412			return (PICL_WALK_CONTINUE);
1413		}
1414	}
1415
1416	/*
1417	 * If we're here then prtdiag was invoked with "-v" or we have
1418	 * a sensor that is beyond a threshold, so give them a book to
1419	 * read instead of the Cliff Notes.
1420	 */
1421	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
1422	    sizeof (parenth));
1423	if (err != PICL_SUCCESS) {
1424		log_printf("\n");
1425		return (PICL_WALK_CONTINUE);
1426	}
1427	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
1428		for (i = 0; i < PARENT_NAMES; i++) {
1429			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
1430			    NULL) {
1431				while (--i > -1)
1432					free(names[i]);
1433				free(loc);
1434				loc = NULL;
1435			}
1436		}
1437	}
1438	i = 0;
1439	if (loc) {
1440		while (err == PICL_SUCCESS) {
1441			if (parenth == phyplatformh)
1442				break;
1443			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
1444			    names[i++], PICL_PROPNAMELEN_MAX);
1445			if (err != PICL_SUCCESS) {
1446				i--;
1447				break;
1448			}
1449			if (i == PARENT_NAMES)
1450				break;
1451			err = picl_get_propval_by_name(parenth,
1452			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
1453		}
1454		loc[0] = '\0';
1455		if (--i > -1) {
1456			(void) strlcat(loc, names[i],
1457			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1458		}
1459		while (--i > -1) {
1460			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
1461			    PARENT_NAMES);
1462			(void) strlcat(loc, names[i],
1463			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1464		}
1465		log_printf("%-35s", loc);
1466		for (i = 0; i < PARENT_NAMES; i++)
1467			free(names[i]);
1468		free(loc);
1469	} else {
1470		log_printf("%-35s", "");
1471	}
1472
1473	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
1474	    sizeof (label));
1475	if (err != PICL_SUCCESS)
1476		(void) strlcpy(label, "", sizeof (label));
1477	log_printf("%-15s", label);
1478
1479	log_printf("%-8s", current_val);
1480
1481	log_printf("\n");
1482	return (PICL_WALK_CONTINUE);
1483}
1484
1485static void
1486sun4v_env_print_fan_sensors()
1487{
1488	char *fmt = "%-34s %-14s %-10s\n";
1489	/*
1490	 * If there isn't any fan sensor node, return now.
1491	 */
1492	(void) picl_walk_tree_by_class(phyplatformh,
1493	    PICL_CLASS_RPM_SENSOR, (void *)PICL_PROP_SPEED,
1494	    sun4v_env_print_sensor_callback);
1495	if (!class_node_found)
1496		return;
1497	log_printf("Fan sensors:\n");
1498	if (syserrlog == 0) {
1499		(void) picl_walk_tree_by_class(phyplatformh,
1500		    PICL_CLASS_RPM_SENSOR,
1501		    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
1502		if (all_status_ok) {
1503			log_printf("All fan sensors are OK.\n");
1504			return;
1505		}
1506	}
1507	log_printf("-------------------------------------------------"
1508	    "-----------\n");
1509	log_printf(fmt, "Location", "Sensor", "Status", 0);
1510	log_printf("-------------------------------------------------"
1511	    "-----------\n");
1512	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_SENSOR,
1513	    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
1514}
1515
1516static void
1517sun4v_env_print_fan_indicators()
1518{
1519	char *fmt = "%-34s %-14s %-10s\n";
1520	(void) picl_walk_tree_by_class(phyplatformh,
1521	    PICL_CLASS_RPM_INDICATOR, (void *)PICL_PROP_CONDITION,
1522	    sun4v_env_print_indicator_callback);
1523	if (!class_node_found)
1524		return;
1525	log_printf("\nFan indicators:\n");
1526	if (syserrlog == 0) {
1527		(void) picl_walk_tree_by_class(phyplatformh,
1528		    PICL_CLASS_RPM_INDICATOR,
1529		    (void *)PICL_PROP_CONDITION,
1530		    sun4v_env_print_indicator_callback);
1531		if (all_status_ok) {
1532			log_printf("All fan indicators are OK.\n");
1533			return;
1534		}
1535	}
1536	log_printf("-------------------------------------------------"
1537	    "-----------\n");
1538	log_printf(fmt, "Location", "Sensor", "Condition", 0);
1539	log_printf("-------------------------------------------------"
1540	    "-----------\n");
1541	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_INDICATOR,
1542	    (void *)PICL_PROP_CONDITION, sun4v_env_print_indicator_callback);
1543}
1544
1545static void
1546sun4v_env_print_temp_sensors()
1547{
1548	char *fmt = "%-34s %-14s %-10s\n";
1549	(void) picl_walk_tree_by_class(phyplatformh,
1550	    PICL_CLASS_TEMPERATURE_SENSOR,
1551	    (void *)PICL_PROP_TEMPERATURE,
1552	    sun4v_env_print_sensor_callback);
1553	if (!class_node_found)
1554		return;
1555
1556	log_printf("\nTemperature sensors:\n");
1557	if (syserrlog == 0) {
1558		(void) picl_walk_tree_by_class(phyplatformh,
1559		    PICL_CLASS_TEMPERATURE_SENSOR,
1560		    PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
1561		if (all_status_ok) {
1562			log_printf("All temperature sensors are OK.\n");
1563			return;
1564		}
1565	}
1566	log_printf("-------------------------------------------------"
1567	    "-----------\n");
1568	log_printf(fmt, "Location", "Sensor", "Status", 0);
1569	log_printf("-------------------------------------------------"
1570	    "-----------\n");
1571	(void) picl_walk_tree_by_class(phyplatformh,
1572	    PICL_CLASS_TEMPERATURE_SENSOR,
1573	    (void *)PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
1574}
1575
1576static void
1577sun4v_env_print_temp_indicators()
1578{
1579	char *fmt = "%-34s %-14s %-8s\n";
1580	(void) picl_walk_tree_by_class(phyplatformh,
1581	    PICL_CLASS_TEMPERATURE_INDICATOR, (void *)PICL_PROP_CONDITION,
1582	    sun4v_env_print_indicator_callback);
1583	if (!class_node_found)
1584		return;
1585	log_printf("\nTemperature indicators:\n");
1586	if (syserrlog == 0) {
1587		(void) picl_walk_tree_by_class(phyplatformh,
1588		    PICL_CLASS_TEMPERATURE_INDICATOR,
1589		    (void *)PICL_PROP_CONDITION,
1590		    sun4v_env_print_indicator_callback);
1591		if (all_status_ok) {
1592			log_printf("All temperature indicators are OK.\n");
1593			return;
1594		}
1595	}
1596	log_printf("-------------------------------------------------"
1597	    "-----------\n");
1598	log_printf(fmt, "Location", "Indicator", "Condition", 0);
1599	log_printf("-------------------------------------------------"
1600	    "-----------\n");
1601	(void) picl_walk_tree_by_class(phyplatformh,
1602	    PICL_CLASS_TEMPERATURE_INDICATOR,
1603	    (void *)PICL_PROP_CONDITION,
1604	    sun4v_env_print_indicator_callback);
1605}
1606
1607static void
1608sun4v_env_print_current_sensors()
1609{
1610	char *fmt = "%-34s %-14s %-10s\n";
1611	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_CURRENT_SENSOR,
1612	    (void *)PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
1613	if (!class_node_found)
1614		return;
1615	log_printf("\nCurrent sensors:\n");
1616	if (syserrlog == 0) {
1617		(void) picl_walk_tree_by_class(phyplatformh,
1618		    PICL_CLASS_CURRENT_SENSOR,
1619		    PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
1620		if (all_status_ok) {
1621			log_printf("All current sensors are OK.\n");
1622			return;
1623		}
1624	}
1625	log_printf("-------------------------------------------------"
1626	    "-----------\n");
1627	log_printf(fmt, "Location", "Sensor", "Status", 0);
1628	log_printf("-------------------------------------------------"
1629	    "-----------\n");
1630	(void) picl_walk_tree_by_class(phyplatformh,
1631	    PICL_CLASS_CURRENT_SENSOR, (void *)PICL_PROP_CURRENT,
1632	    sun4v_env_print_sensor_callback);
1633}
1634
1635static void
1636sun4v_env_print_current_indicators()
1637{
1638	char *fmt = "%-34s %-14s %-8s\n";
1639	(void) picl_walk_tree_by_class(phyplatformh,
1640	    PICL_CLASS_CURRENT_INDICATOR,
1641	    (void *)PICL_PROP_CONDITION,
1642	    sun4v_env_print_indicator_callback);
1643	if (!class_node_found)
1644		return;
1645	log_printf("\nCurrent indicators:\n");
1646	if (syserrlog == 0) {
1647		(void) picl_walk_tree_by_class(phyplatformh,
1648		    PICL_CLASS_CURRENT_INDICATOR, (void *)PICL_PROP_CONDITION,
1649		    sun4v_env_print_indicator_callback);
1650		if (all_status_ok) {
1651			log_printf("All current indicators are OK.\n");
1652			return;
1653		}
1654	}
1655	log_printf("-------------------------------------------------"
1656	    "-----------\n");
1657	log_printf(fmt, "Location", "Indicator", "Condition", 0);
1658	log_printf("-------------------------------------------------"
1659	    "-----------\n");
1660	(void) picl_walk_tree_by_class(phyplatformh,
1661	    PICL_CLASS_CURRENT_INDICATOR,
1662	    (void *)PICL_PROP_CONDITION,
1663	    sun4v_env_print_indicator_callback);
1664}
1665
1666static void
1667sun4v_env_print_voltage_sensors()
1668{
1669	char *fmt = "%-34s %-14s %-10s\n";
1670	(void) picl_walk_tree_by_class(phyplatformh,
1671	    PICL_CLASS_VOLTAGE_SENSOR,
1672	    PICL_PROP_VOLTAGE,
1673	    sun4v_env_print_sensor_callback);
1674	if (!class_node_found)
1675		return;
1676	log_printf("\nVoltage sensors:\n");
1677	if (syserrlog == 0) {
1678		(void) picl_walk_tree_by_class(phyplatformh,
1679		    PICL_CLASS_VOLTAGE_SENSOR,
1680		    PICL_PROP_VOLTAGE, sun4v_env_print_sensor_callback);
1681		if (all_status_ok) {
1682			log_printf("All voltage sensors are OK.\n");
1683			return;
1684		}
1685	}
1686	log_printf("-------------------------------------------------"
1687	    "-----------\n");
1688	log_printf(fmt, "Location", "Sensor", "Status", 0);
1689	log_printf("-------------------------------------------------"
1690	    "-----------\n");
1691	(void) picl_walk_tree_by_class(phyplatformh,
1692	    PICL_CLASS_VOLTAGE_SENSOR,
1693	    (void *)PICL_PROP_VOLTAGE,
1694	    sun4v_env_print_sensor_callback);
1695}
1696
1697static void
1698sun4v_env_print_voltage_indicators()
1699{
1700	char *fmt = "%-34s %-14s %-8s\n";
1701	(void) picl_walk_tree_by_class(phyplatformh,
1702	    PICL_CLASS_VOLTAGE_INDICATOR,
1703	    (void *)PICL_PROP_CONDITION,
1704	    sun4v_env_print_indicator_callback);
1705	if (!class_node_found)
1706		return;
1707	log_printf("\nVoltage indicators:\n");
1708	if (syserrlog == 0) {
1709		(void) picl_walk_tree_by_class(phyplatformh,
1710		    PICL_CLASS_VOLTAGE_INDICATOR, (void *)PICL_PROP_CONDITION,
1711		    sun4v_env_print_indicator_callback);
1712		if (all_status_ok) {
1713			log_printf("All voltage indicators are OK.\n");
1714			return;
1715		}
1716	}
1717	log_printf("-------------------------------------------------"
1718	    "-----------\n");
1719	log_printf(fmt, "Location", "Indicator", "Condition", 0);
1720	log_printf("-------------------------------------------------"
1721	    "-----------\n");
1722	(void) picl_walk_tree_by_class(phyplatformh,
1723	    PICL_CLASS_VOLTAGE_INDICATOR,
1724	    (void *)PICL_PROP_CONDITION,
1725	    sun4v_env_print_indicator_callback);
1726}
1727
1728static void
1729sun4v_env_print_LEDs()
1730{
1731	char *fmt = "%-34s %-14s %-8s\n";
1732	if (syserrlog == 0)
1733		return;
1734	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
1735	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
1736	if (!class_node_found)
1737		return;
1738	log_printf("\nLEDs:\n");
1739	log_printf("-------------------------------------------------"
1740	    "-----------\n");
1741	log_printf(fmt, "Location", "LED", "State", 0);
1742	log_printf("-------------------------------------------------"
1743	    "-----------\n");
1744	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
1745	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
1746}
1747
1748/*ARGSUSED*/
1749static int
1750sun4v_print_fru_status_callback(picl_nodehdl_t nodeh, void *args)
1751{
1752	char label[PICL_PROPNAMELEN_MAX];
1753	char status[PICL_PROPNAMELEN_MAX];
1754	picl_errno_t err;
1755	picl_prophdl_t proph;
1756	picl_nodehdl_t parenth;
1757	char *names[PARENT_NAMES];
1758	char *loc;
1759	int i;
1760
1761	if (!class_node_found) {
1762		class_node_found = 1;
1763		return (PICL_WALK_TERMINATE);
1764	}
1765	err = picl_get_prop_by_name(nodeh, PICL_PROP_IS_FRU, &proph);
1766	if (err != PICL_SUCCESS)
1767		return (PICL_WALK_CONTINUE);
1768	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
1769	    sizeof (label));
1770	if (err != PICL_SUCCESS)
1771		return (PICL_WALK_CONTINUE);
1772	err = picl_get_propval_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
1773	    status, sizeof (status));
1774	if (err != PICL_SUCCESS)
1775		return (PICL_WALK_CONTINUE);
1776	if (syserrlog == 0) {
1777		if (strcmp(status, "disabled") == 0) {
1778			if (all_status_ok) {
1779				all_status_ok = 0;
1780				return (PICL_WALK_TERMINATE);
1781			}
1782		} else
1783			return (PICL_WALK_CONTINUE);
1784	}
1785	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
1786	    sizeof (parenth));
1787	if (err != PICL_SUCCESS) {
1788		log_printf("\n");
1789		return (PICL_WALK_CONTINUE);
1790	}
1791	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL)
1792		return (PICL_WALK_TERMINATE);
1793	for (i = 0; i < PARENT_NAMES; i++)
1794		if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) {
1795			while (--i > -1)
1796				free(names[i]);
1797			free(loc);
1798			return (PICL_WALK_TERMINATE);
1799		}
1800	i = 0;
1801	while (err == PICL_SUCCESS) {
1802		if (parenth == phyplatformh)
1803			break;
1804		err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
1805		    names[i++], PICL_PROPNAMELEN_MAX);
1806		if (err != PICL_SUCCESS) {
1807			i--;
1808			break;
1809		}
1810		if (i == PARENT_NAMES)
1811			break;
1812		err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
1813		    &parenth, sizeof (parenth));
1814	}
1815	loc[0] = '\0';
1816	if (--i > -1) {
1817		(void) strlcat(loc, names[i],
1818		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1819	}
1820	while (--i > -1) {
1821		(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1822		(void) strlcat(loc, names[i],
1823		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1824	}
1825	log_printf("%-35s", loc);
1826	for (i = 0; i < PARENT_NAMES; i++)
1827		free(names[i]);
1828	free(loc);
1829	log_printf("%-10s", label);
1830	log_printf("%-9s", status);
1831	log_printf("\n");
1832	return (PICL_WALK_CONTINUE);
1833}
1834
1835static void
1836sun4v_print_fru_status()
1837{
1838	char *fmt = "%-34s %-9s %-8s\n";
1839
1840	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1841	    sun4v_print_fru_status_callback);
1842	if (!class_node_found)
1843		return;
1844
1845	log_printf("\n");
1846	log_printf("============================");
1847	log_printf(" FRU Status ");
1848	log_printf("============================");
1849	log_printf("\n");
1850
1851	if (syserrlog == 0) {
1852		(void) picl_walk_tree_by_class(phyplatformh,
1853		    NULL, NULL,
1854		    sun4v_print_fru_status_callback);
1855		if (all_status_ok) {
1856			log_printf("All FRUs are enabled.\n");
1857			return;
1858		}
1859	}
1860	log_printf(fmt, "Location", "Name", "Status", 0);
1861	log_printf("------------------------------------------------------\n");
1862	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1863	    sun4v_print_fru_status_callback);
1864}
1865
1866/*ARGSUSED*/
1867static int
1868sun4v_print_fw_rev_callback(picl_nodehdl_t nodeh, void *args)
1869{
1870	char rev[PICL_PROPNAMELEN_MAX];
1871	picl_errno_t err;
1872
1873	if (!class_node_found) {
1874		class_node_found = 1;
1875		return (PICL_WALK_TERMINATE);
1876	}
1877
1878	err = picl_get_propval_by_name(nodeh, PICL_PROP_FW_REVISION, rev,
1879	    sizeof (rev));
1880	if (err != PICL_SUCCESS)
1881		return (PICL_WALK_CONTINUE);
1882	if (strlen(rev) == 0)
1883		return (PICL_WALK_CONTINUE);
1884	log_printf("%s", rev);
1885	log_printf("\n");
1886	return (PICL_WALK_CONTINUE);
1887}
1888
1889static void
1890sun4v_print_fw_rev()
1891{
1892	if (syserrlog == 0)
1893		return;
1894
1895	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1896	    sun4v_print_fw_rev_callback);
1897	if (!class_node_found)
1898		return;
1899
1900	log_printf("\n");
1901	log_printf("============================");
1902	log_printf(" FW Version ");
1903	log_printf("============================");
1904	log_printf("\n");
1905	log_printf("Version\n");
1906	log_printf("-------------------------------------------------"
1907	    "-----------\n");
1908	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1909	    sun4v_print_fw_rev_callback);
1910}
1911
1912static void
1913sun4v_print_openprom_rev()
1914{
1915	if (syserrlog == 0)
1916		return;
1917
1918	(void) picl_walk_tree_by_class(rooth, "openprom", NULL,
1919	    openprom_callback);
1920	if (!class_node_found)
1921		return;
1922
1923	log_printf("\n");
1924	log_printf("======================");
1925	log_printf(" System PROM revisions ");
1926	log_printf("=======================");
1927	log_printf("\n");
1928	log_printf("Version\n");
1929	log_printf("-------------------------------------------------"
1930	    "-----------\n");
1931	(void) picl_walk_tree_by_class(rooth, "openprom", NULL,
1932	    openprom_callback);
1933}
1934
1935/*
1936 * display the OBP and POST prom revisions (if present)
1937 */
1938/* ARGSUSED */
1939static int
1940openprom_callback(picl_nodehdl_t openpromh, void *arg)
1941{
1942	picl_prophdl_t	proph;
1943	picl_prophdl_t	tblh;
1944	picl_prophdl_t	rowproph;
1945	picl_propinfo_t	pinfo;
1946	char		*prom_version = NULL;
1947	char		*obp_version = NULL;
1948	int		err;
1949
1950	if (!class_node_found) {
1951		class_node_found = 1;
1952		return (PICL_WALK_TERMINATE);
1953	}
1954
1955	err = picl_get_propinfo_by_name(openpromh, OBP_PROP_VERSION,
1956	    &pinfo, &proph);
1957	if (err == PICL_PROPNOTFOUND)
1958		return (PICL_WALK_TERMINATE);
1959	else if (err != PICL_SUCCESS)
1960		return (err);
1961
1962	/*
1963	 * If it's a table prop, the first element is OBP revision
1964	 * The second one is POST revision.
1965	 * If it's a charstring prop, the value will be only OBP revision
1966	 */
1967	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
1968		prom_version = (char *)alloca(pinfo.size);
1969		if (prom_version == NULL)
1970			return (PICL_FAILURE);
1971		err = picl_get_propval(proph, prom_version, pinfo.size);
1972		if (err != PICL_SUCCESS)
1973			return (err);
1974		log_printf("%s\n", prom_version);
1975	}
1976
1977	if (pinfo.type != PICL_PTYPE_TABLE)	/* not supported type */
1978		return (PICL_WALK_TERMINATE);
1979
1980	err = picl_get_propval(proph, &tblh, pinfo.size);
1981	if (err != PICL_SUCCESS)
1982		return (err);
1983
1984	err = picl_get_next_by_row(tblh, &rowproph);
1985	if (err == PICL_SUCCESS) {
1986		/* get first row */
1987		err = picl_get_propinfo(rowproph, &pinfo);
1988		if (err != PICL_SUCCESS)
1989			return (err);
1990
1991		prom_version = (char *)alloca(pinfo.size);
1992		if (prom_version == NULL)
1993			return (PICL_FAILURE);
1994
1995		err = picl_get_propval(rowproph, prom_version, pinfo.size);
1996		if (err != PICL_SUCCESS)
1997			return (err);
1998		log_printf("%s\n", prom_version);
1999
2000		/* get second row */
2001		err = picl_get_next_by_col(rowproph, &rowproph);
2002		if (err == PICL_SUCCESS) {
2003			err = picl_get_propinfo(rowproph, &pinfo);
2004			if (err != PICL_SUCCESS)
2005				return (err);
2006
2007			obp_version = (char *)alloca(pinfo.size);
2008			if (obp_version == NULL)
2009				return (PICL_FAILURE);
2010			err = picl_get_propval(rowproph, obp_version,
2011			    pinfo.size);
2012			if (err != PICL_SUCCESS)
2013				return (err);
2014			log_printf("%s\n", obp_version);
2015		}
2016	}
2017
2018	return (PICL_WALK_TERMINATE);
2019}
2020
2021static void
2022sun4v_print_chassis_serial_no()
2023{
2024	char val[PICL_PROPNAMELEN_MAX];
2025	picl_errno_t err;
2026	if (syserrlog == 0 || chassish == 0)
2027		return;
2028
2029	log_printf("\n");
2030	log_printf("Chassis Serial Number");
2031	log_printf("\n");
2032	log_printf("---------------------\n");
2033	err = picl_get_propval_by_name(chassish, PICL_PROP_SERIAL_NUMBER,
2034	    val, sizeof (val));
2035	if (err == PICL_SUCCESS)
2036		log_printf("%s", val);
2037	log_printf("\n");
2038}
2039