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/*
27 *
28 * Cherrystone platform-specific functions
29 *
30 */
31
32#pragma ident	"%Z%%M%	%I%	%E% SMI"
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <kstat.h>
38#include <string.h>
39#include <assert.h>
40#include <libintl.h>
41#include <note.h>
42#include <syslog.h>
43
44#include <sys/openpromio.h>
45#include <sys/sysmacros.h>
46
47#include <pdevinfo.h>
48#include <display.h>
49#include <pdevinfo_sun4u.h>
50#include <display_sun4u.h>
51
52#include <picl.h>
53
54#include <sys/cheetahregs.h>
55#include <sys/cherrystone.h>
56#include "workfile.c"
57
58#define	SCHIZO_COMPAT_PROP	"pci108e,8001"
59
60#define	MULTIPLE_BITS_SET(x)	((x)&((x)-1))
61
62#define	MAX_PS		2
63#define	MAX_PS_SENSORS	3
64#define	MAX_DISKS	2
65#define	MAX_FANS	5
66#define	NUM_PCI_SLOTS	5
67
68/*
69 * these functions will overlay the symbol table of libprtdiag
70 * at runtime (workgroup server systems only)
71 */
72void	display_cpu_devices(Sys_tree *tree);
73void	display_pci(Board_node *board);
74void	display_io_cards(struct io_card *list);
75void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
76				struct system_kstat_data *kstats);
77void	display_ffb(Board_node *board, int table);
78void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
79
80/* local functions */
81static void disp_envc_status(void);
82static int print_temps(picl_nodehdl_t);
83static int print_keyswitch(picl_nodehdl_t);
84static int print_FSP_LEDS(picl_nodehdl_t);
85static int print_disk(picl_nodehdl_t);
86static int print_fans(picl_nodehdl_t);
87static int print_ps(picl_nodehdl_t);
88
89static void display_hw_revisions(Prom_node *root,
90					Board_node *bnode);
91static void display_schizo_revisions(Board_node *bdlist);
92
93
94void
95display_cpu_devices(Sys_tree *tree)
96{
97	Board_node *bnode;
98
99	log_printf(dgettext(TEXT_DOMAIN,
100	    "\n========================= CPUs "
101	    "===============================================\n\n"
102	    "          Run   E$  CPU     CPU  \n"
103	    "Brd  CPU  MHz   MB  Impl.   Mask \n"
104	    "--- ----- ---- ---- ------- ---- \n"));
105
106	bnode = tree->bd_list;
107	while (bnode != NULL) {
108		display_cpus(bnode);
109		bnode = bnode->next;
110	}
111
112	log_printf("\n");
113}
114void
115display_cpus(Board_node *board)
116{
117	Prom_node 	*cpu;
118	uint_t freq;
119	int ecache_size;
120	int *l3_shares;
121	int *mid;
122	int *impl;
123	int *mask;
124	int *coreid;
125	char fru_prev = 'X'; /* Valid frus are 'A','B' */
126	int mid_prev;
127	int ecache_size_prev = 0;
128	char fru_name;
129
130	/*
131	 * display the CPUs' operating frequency, cache size, impl. field
132	 * and mask revision.
133	 */
134
135	for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
136	    cpu = dev_next_type(cpu, "cpu")) {
137
138		mid = (int *)get_prop_val(find_prop(cpu, "portid"));
139		if (mid == NULL)
140			mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
141		freq = HZ_TO_MHZ(get_cpu_freq(cpu));
142		ecache_size = get_ecache_size(cpu);
143		impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
144		mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
145		l3_shares =
146		    (int *)get_prop_val(find_prop(cpu, "l3-cache-sharing"));
147
148		/* Do not display a failed CPU node */
149		if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
150			continue;
151
152		fru_name = CHERRYSTONE_GETSLOT_LABEL(*mid);
153		if (CPU_IMPL_IS_CMP(*impl)) {
154			coreid = (int *)get_prop_val(find_prop(cpu, "reg"));
155			if (coreid == NULL) {
156				continue;
157			}
158			if ((fru_prev == 'X') ||
159			    ((fru_prev != 'X') &&
160			    (fru_name != fru_prev))) {
161				fru_prev = fru_name;
162				mid_prev = *mid;
163				ecache_size_prev = ecache_size;
164				continue;
165			} else {
166				/*
167				 * Some CMP chips have a split E$,
168				 * so the size for both cores is added
169				 * together to get the total size for
170				 * the chip.
171				 *
172				 * Still, other CMP chips have E$ (L3)
173				 * which is logically shared, so the
174				 * total size is equal to the core size.
175				 */
176				if ((l3_shares == NULL) ||
177				    ((l3_shares != NULL) &&
178				    MULTIPLE_BITS_SET(*l3_shares))) {
179					ecache_size += ecache_size_prev;
180				}
181				ecache_size_prev = 0;
182				fru_prev = 'X';
183			}
184		}
185
186		log_printf(" %c", fru_name);
187
188		/* CPU Module ID */
189		if (CPU_IMPL_IS_CMP(*impl)) {
190			log_printf("%3d,%3d ", mid_prev, *mid, 0);
191		} else
192			log_printf("   %2d   ", *mid);
193
194		/* Running frequency */
195		log_printf("%4u", freq);
196
197		if (ecache_size == 0)
198			log_printf(" N/A  ");
199		else
200			log_printf(" %4.1f ",
201			    (float)ecache_size / (float)(1<<20));
202			/* Implementation */
203		if (impl == NULL) {
204			log_printf(dgettext(TEXT_DOMAIN, "  N/A   "));
205		} else {
206			if (IS_CHEETAH(*impl))
207				log_printf(dgettext(TEXT_DOMAIN,
208				    "US-III  "));
209			else if (IS_CHEETAH_PLUS(*impl))
210				log_printf(dgettext(TEXT_DOMAIN,
211				    "US-III+ "));
212			else if (IS_JAGUAR(*impl))
213				log_printf(dgettext(TEXT_DOMAIN,
214				    "US-IV   "));
215			else if (IS_PANTHER(*impl))
216				log_printf(dgettext(TEXT_DOMAIN,
217				    "US-IV+  "));
218			else
219				log_printf("%-6x  ", *impl);
220		}
221
222		/* CPU Mask */
223		if (mask == NULL) {
224			log_printf(dgettext(TEXT_DOMAIN, " N/A\n"));
225		} else {
226			log_printf(dgettext(TEXT_DOMAIN, " %d.%d\n"),
227			    (*mask >> 4) & 0xf, *mask & 0xf);
228		}
229	}
230}
231
232/*ARGSUSED0*/
233void
234display_memoryconf(Sys_tree *tree, struct grp_info *grps)
235{
236	Board_node	*bnode = tree->bd_list;
237
238	log_printf(dgettext(TEXT_DOMAIN,
239	    "========================= Memory Configuration"
240	    " ===============================\n\n"
241	    "          Logical  Logical  Logical\n"
242	    "     MC   Bank     Bank     Bank         DIMM    "
243	    "Interleave  Interleaved\n"
244	    "Brd  ID   num      size     Status       Size    "
245	    "Factor      with\n"
246	    "---  ---  ----     ------   -----------  ------  "
247	    "----------  -----------"));
248
249	while (bnode != NULL) {
250		if (get_us3_mem_regs(bnode)) {
251			log_printf(dgettext(TEXT_DOMAIN,
252			    "\nFailed to get memory information.\n"));
253			return;
254		}
255		bnode = bnode->next;
256	}
257
258	/* Display what we have found */
259	display_us3_banks();
260}
261
262/*ARGSUSED3*/
263void
264display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
265	struct system_kstat_data *kstats)
266{
267	/*
268	 * Now display the last powerfail time and the fatal hardware
269	 * reset information. We do this under a couple of conditions.
270	 * First if the user asks for it. The second is if the user
271	 * told us to do logging, and we found a system failure.
272	 */
273
274	if (flag) {
275		/*
276		 * display time of latest powerfail. Not all systems
277		 * have this capability. For those that do not, this
278		 * is just a no-op.
279		 */
280		disp_powerfail(root);
281
282		disp_envc_status();
283
284		display_hw_revisions(root, tree->bd_list);
285	}
286	return;
287
288}
289
290/*
291 * display_pci
292 * Display all the PCI IO cards on this board.
293 */
294void
295display_pci(Board_node *board)
296{
297	struct io_card	*card_list = NULL;
298	struct io_card	card;
299	void		*value;
300	Prom_node	*pci;
301	Prom_node	*card_node;
302	static int	banner = FALSE;
303
304	char		*slot_name_arr[NUM_PCI_SLOTS];
305	int		i;
306
307	if (board == NULL)
308		return;
309
310	(void) memset(&card, 0, sizeof (struct io_card));
311	/* Initialize all the common information */
312	card.display = TRUE;
313	card.board = board->board_num;
314
315	/*
316	 * Search for each pci instance, then find/display all nodes under
317	 * each instance node found.
318	 */
319	for (pci = dev_find_node_by_compat(board->nodes, SCHIZO_COMPAT_PROP);
320	    pci != NULL;
321	    pci = dev_next_node_by_compat(pci, SCHIZO_COMPAT_PROP)) {
322		(void) snprintf(card.bus_type, MAXSTRLEN,
323		    dgettext(TEXT_DOMAIN, "PCI"));
324		/*
325		 * Get slot-name properties from parent node and
326		 * store them in an array.
327		 */
328		value = (char *)get_prop_val(
329		    find_prop(pci, "slot-names"));
330
331		if (value != NULL) {
332			/* array starts after first int */
333			slot_name_arr[0] = (char *)value + sizeof (int);
334			for (i = 1; i < NUM_PCI_SLOTS; i++) {
335				slot_name_arr[i] = (char *)slot_name_arr[i - 1]
336				    + strlen(slot_name_arr[i - 1]) +1;
337			}
338		}
339		/*
340		 * Search for Children of this node ie. Cards.
341		 * Note: any of these cards can be a pci-bridge
342		 *	that itself has children. If we find a
343		 *	pci-bridge we need to handle it specially.
344		 */
345		card_node = pci->child;
346		/* Generate the list of pci cards on pci instance: pci */
347		fill_pci_card_list(pci, card_node, &card, &card_list,
348		    slot_name_arr);
349	} /* end-for */
350
351	if (!banner && card_list != NULL) {
352		log_printf(dgettext(TEXT_DOMAIN,
353		    "                    Bus  Max\n"
354		    " IO  Port Bus       Freq Bus  Dev,\n"
355		    "Type  ID  Side Slot MHz  Freq Func State "
356		    "Name                              Model"
357#ifdef DEBUG
358		    "                   Notes"
359#endif
360		    "\n"
361		    "---- ---- ---- ---- ---- ---- ---- ----- "
362		    "--------------------------------  "
363#ifdef DEBUG
364		    "----------------------  "
365#endif
366		    "----------------------\n"));
367		banner = TRUE;
368	}
369
370	display_io_cards(card_list);
371	free_io_cards(card_list);
372}
373
374/*
375 * Print out all the io cards in the list.  Also print the column
376 * headers if told to do so.
377 */
378void
379display_io_cards(struct io_card *list)
380{
381	struct io_card *p;
382
383	for (p = list; p != NULL; p = p -> next) {
384		log_printf(dgettext(TEXT_DOMAIN,
385		    "%-4s  %-3d  %c    %-1s    %-3d"),
386		    p->bus_type, p->schizo_portid, p->pci_bus,
387		    p->slot_str, p->freq);
388
389		switch (p->pci_bus) {
390		case 'A':
391			log_printf(dgettext(TEXT_DOMAIN, "  66  "));
392			break;
393		case 'B':
394			log_printf(dgettext(TEXT_DOMAIN, "  33  "));
395			break;
396		default:
397			assert(0);
398			break;
399		}
400
401		log_printf(dgettext(TEXT_DOMAIN,
402		    "%-1d,%-1d  %-5s %-32.32s"),
403		    p->dev_no, p->func_no, p->status, p->name);
404		if (strlen(p->name) > 32)
405			log_printf(dgettext(TEXT_DOMAIN, "+ "));
406		else
407			log_printf(dgettext(TEXT_DOMAIN, "  "));
408		log_printf(dgettext(TEXT_DOMAIN, "%-22.22s"), p->model);
409		if (strlen(p->model) > 22)
410			log_printf(dgettext(TEXT_DOMAIN, "+"));
411#ifdef DEBUG
412		log_printf("%s", p->notes);
413#endif
414		log_printf("\n");
415	}
416}
417
418/*ARGSUSED*/
419void
420display_ffb(Board_node *board, int table)
421{
422	/* NOP, since there are no FFB's on this platform. */
423}
424
425
426/*
427 * local functions
428 */
429
430
431static void
432disp_envc_status()
433{
434	int err;
435	char *system = "SYSTEM";
436	picl_nodehdl_t system_node, root;
437
438	log_printf(dgettext(TEXT_DOMAIN,
439	    "\n"
440	    "=========================  Environmental Status "
441	    "=========================\n\n"));
442
443	err = picl_initialize();
444	if (err != PICL_SUCCESS) {
445		exit_code = PD_INTERNAL_FAILURE;
446		goto err_out;
447	}
448	err = picl_get_root(&root);
449	if (err != PICL_SUCCESS) {
450		exit_code = PD_INTERNAL_FAILURE;
451		goto err_out;
452	}
453	err = find_child_device(root, system, &system_node);
454	if (err != PICL_SUCCESS) {
455		exit_code = PD_INTERNAL_FAILURE;
456		goto err_out;
457	}
458
459	err = print_temps(system_node);
460	err |= print_keyswitch(system_node);
461	err |= print_FSP_LEDS(system_node);
462	err |= print_disk(system_node);
463	err |= print_fans(system_node);
464	err |= print_ps(system_node);
465
466	if (err != PICL_SUCCESS)
467		goto err_out;
468
469	return;
470
471err_out:
472	log_printf(dgettext(TEXT_DOMAIN,
473	    "\nEnvironmental reporting error: %s\n"),
474	    picl_strerror(err));
475}
476
477static int
478print_ps(picl_nodehdl_t system_node)
479{
480	int		i, j, err = 0;
481	int32_t		number;
482	picl_nodehdl_t	*ps;
483	picl_nodehdl_t	*ps_fail_sensor;
484	char		name[PICL_PROPNAMELEN_MAX];
485	char		fault_state[PICL_PROPNAMELEN_MAX];
486
487	log_printf(dgettext(TEXT_DOMAIN, "\n\n"
488	    "Power Supplies:\n"
489	    "---------------\n"
490	    "\n"
491	    "Supply     Status        Fault     Fan Fail   Temp Fail\n"
492	    "------    ------------   --------  ---------  ---------\n"));
493
494	err = fill_device_array_from_id(system_node, "PSVC_PS", &number, &ps);
495	if (err != PICL_SUCCESS) {
496		return (err);
497	}
498
499	for (i = 0; i < MAX_PS; i++) {
500		err = picl_get_propval_by_name(ps[i], PICL_PROP_NAME, name,
501		    PICL_PROPNAMELEN_MAX);
502		if (err != PICL_SUCCESS)
503			continue;
504
505		log_printf(dgettext(TEXT_DOMAIN, "%6-s"), name);
506		err = picl_get_propval_by_name(ps[i], "FaultInformation",
507		    fault_state, PICL_PROPNAMELEN_MAX);
508		if (err != PICL_SUCCESS) {
509			free(ps);
510			return (err);
511		}
512		log_printf(dgettext(TEXT_DOMAIN, "   [%-12s]"), fault_state);
513		if (strcmp(fault_state, "NO AC POWER") == 0) {
514			log_printf("\n");
515			continue;
516		}
517
518		err = fill_device_array_from_id(ps[i], "PSVC_DEV_FAULT_SENSOR",
519		    &number, &ps_fail_sensor);
520
521		if (err != PICL_SUCCESS) {
522			free(ps);
523			return (err);
524		}
525		log_printf("   ");
526		for (j = 0; j < MAX_PS_SENSORS; j++) {
527			err = picl_get_propval_by_name(ps_fail_sensor[j],
528			    "State", fault_state, PICL_PROPNAMELEN_MAX);
529			if (err != PICL_SUCCESS) {
530				if (err == PICL_FAILURE) {
531					break;
532				}
533				free(ps);
534				free(ps_fail_sensor);
535				return (err);
536			}
537			log_printf(dgettext(TEXT_DOMAIN, "%-10s"), fault_state);
538		}
539		log_printf("\n");
540		free(ps_fail_sensor);
541	}
542
543	log_printf(dgettext(TEXT_DOMAIN,
544	    "\n=================================\n\n"));
545
546	free(ps);
547	return (PICL_SUCCESS);
548}
549
550static int
551print_fans(picl_nodehdl_t system_node)
552{
553	int		i, err;
554	int32_t		number;
555	picl_nodehdl_t	*fans;
556	picl_nodehdl_t	phdl;
557	char		prop[PICL_PROPNAMELEN_MAX];
558	char		parent[PICL_PROPNAMELEN_MAX];
559	int32_t		rpm;
560
561	err = fill_device_array_from_id(system_node, "PSVC_FAN", &number,
562	    &fans);
563	if (err != PICL_SUCCESS) {
564		return (err);
565	}
566
567	log_printf(dgettext(TEXT_DOMAIN,
568	    "\n=================================\n\n"
569	    "Fan Status:\n"
570	    "-----------\n\n"
571	    "Fan Tray        Fan              RPM    Status\n"
572	    "-----------     ----            -----   ----------\n"));
573
574	for (i = 0; i < MAX_FANS; i++) {
575		err = picl_get_propval_by_name(fans[i], PICL_PROP_NAME, prop,
576		    PICL_PROPNAMELEN_MAX);
577		if (err != PICL_SUCCESS)
578			continue;
579
580		err = fill_device_from_id(fans[i], "PSVC_PARENT", &phdl);
581		if (err != PICL_SUCCESS)
582			continue;
583		err = picl_get_propval_by_name(phdl, PICL_PROP_NAME, parent,
584		    PICL_PROPNAMELEN_MAX);
585		if (err != PICL_SUCCESS)
586			continue;
587
588		log_printf(dgettext(TEXT_DOMAIN, "%-16s"), parent);
589
590
591		log_printf(dgettext(TEXT_DOMAIN, "%-16s"), prop);
592
593		err = picl_get_propval_by_name(fans[i], "Fan-speed",
594		    &rpm, sizeof (rpm));
595		if (err != PICL_SUCCESS) {
596			free(fans);
597			return (err);
598		}
599		log_printf(dgettext(TEXT_DOMAIN, "%5d "), rpm);
600
601		err = picl_get_propval_by_name(fans[i], "FaultInformation",
602		    prop, PICL_PROPNAMELEN_MAX);
603		if (err != PICL_SUCCESS) {
604			free(fans);
605			return (err);
606		}
607		log_printf(dgettext(TEXT_DOMAIN, "  [%s]\n"), prop);
608	}
609	log_printf(dgettext(TEXT_DOMAIN,
610	    "\n=================================\n\n"));
611	free(fans);
612	return (PICL_SUCCESS);
613}
614
615static int
616print_disk(picl_nodehdl_t system_node)
617{
618	int		i, err;
619	int32_t		number;
620	picl_nodehdl_t	*disks;
621	char		state[PICL_PROPNAMELEN_MAX];
622
623	err = fill_device_array_from_id(system_node, "PSVC_DISK", &number,
624	    &disks);
625	if (err != PICL_SUCCESS) {
626		return (err);
627	}
628
629	log_printf(dgettext(TEXT_DOMAIN,
630	    "Disk Status:\n"
631	    "------------\n"));
632	for (i = 0; i < MAX_DISKS; i++) {
633		err = picl_get_propval_by_name(disks[i], "FaultInformation",
634		    state, PICL_PROPNAMELEN_MAX);
635
636		switch (err) {
637		case PICL_SUCCESS:
638			log_printf(dgettext(TEXT_DOMAIN,
639			    "DISK %d: [%3s]\n"), i, state);
640			break;
641		case PICL_INVALIDHANDLE:
642			log_printf(dgettext(TEXT_DOMAIN,
643			    "DISK %d: [ NOT PRESENT ]\n"), i);
644			break;
645		default:
646			free(disks);
647			return (err);
648		}
649	}
650	free(disks);
651	return (PICL_SUCCESS);
652}
653
654static int
655print_FSP_LEDS(picl_nodehdl_t system_node)
656{
657	int		err;
658	int32_t		number;
659	picl_nodehdl_t	*fsp_led;
660	char		fault_state[PICL_PROPNAMELEN_MAX];
661	char		locate_state[PICL_PROPNAMELEN_MAX];
662
663	err = fill_device_array_from_id(system_node, "PSVC_FSP_LED", &number,
664	    &fsp_led);
665	if (err != PICL_SUCCESS) {
666		return (err);
667	}
668
669	assert(number == 2);
670	err = picl_get_propval_by_name(fsp_led[0], "State", &fault_state,
671	    PICL_PROPNAMELEN_MAX);
672	if (err != PICL_SUCCESS) {
673		free(fsp_led);
674		return (err);
675	}
676
677	if (strcmp(fault_state, PSVC_LED_ON) == 0)
678		exit_code = PD_SYSTEM_FAILURE;
679
680	err = picl_get_propval_by_name(fsp_led[1], "State", &locate_state,
681	    PICL_PROPNAMELEN_MAX);
682	if (err != PICL_SUCCESS) {
683		free(fsp_led);
684		return (err);
685	}
686
687	log_printf(dgettext(TEXT_DOMAIN,
688	    "System LED Status:\n\n"
689	    "  LOCATOR   FAULT    POWER\n"
690	    "  -------  -------  -------\n"
691	    "   [%3s]    [%3s]    [ ON]"),
692	    locate_state, fault_state);
693
694	log_printf(dgettext(TEXT_DOMAIN,
695	    "\n\n=================================\n\n"));
696	free(fsp_led);
697	return (err);
698}
699
700static int
701print_keyswitch(picl_nodehdl_t system_node)
702{
703	int		err;
704	picl_nodehdl_t	*keyswitch;
705	int32_t		number;
706	char		ks_pos[PICL_PROPNAMELEN_MAX];
707
708	err = fill_device_array_from_id(system_node, "PSVC_KEYSWITCH", &number,
709	    &keyswitch);
710	if (err != PICL_SUCCESS) {
711		return (err);
712	}
713	err = picl_get_propval_by_name(keyswitch[0], "State", ks_pos,
714	    PICL_PROPNAMELEN_MAX);
715	if (err != PICL_SUCCESS) {
716		free(keyswitch);
717		return (err);
718	}
719
720	log_printf(dgettext(TEXT_DOMAIN,
721	    "Front Status Panel:\n"
722	    "-------------------\n"
723	    "Keyswitch position: %s\n\n"), ks_pos);
724	free(keyswitch);
725	return (err);
726}
727
728static int
729print_temps(picl_nodehdl_t system_node)
730{
731	int		i;
732	int		err;
733	picl_nodehdl_t	*system_ts_nodes;
734	int32_t		temp;
735	int32_t		number;
736	char		label[PICL_PROPNAMELEN_MAX];
737	char		state[PICL_PROPNAMELEN_MAX];
738	char		*p;
739
740	err = fill_device_array_from_id(system_node, "PSVC_TS", &number,
741	    &system_ts_nodes);
742	if (err != PICL_SUCCESS) {
743		return (err);
744	}
745
746	log_printf(dgettext(TEXT_DOMAIN,
747	    "System Temperatures (Celsius):\n"
748	    "-------------------------------\n"
749	    "Device\t\tTemperature\tStatus\n"
750	    "---------------------------------------\n"));
751
752	for (i = 0; i < number; i++) {
753		err = picl_get_propval_by_name(system_ts_nodes[i],
754		    "State", state, sizeof (state));
755		if (err != PICL_SUCCESS) {
756			if (err == PICL_INVALIDHANDLE) {
757				(void) strcpy(state, "n/a");
758			} else {
759				free(system_ts_nodes);
760				return (err);
761			}
762		}
763		err = picl_get_propval_by_name(system_ts_nodes[i],
764		    PICL_PROP_NAME, label, PICL_PROPNAMELEN_MAX);
765		if (err != PICL_SUCCESS) {
766			if (err == PICL_INVALIDHANDLE)
767				/* This FRU isn't present. Skip it. */
768				continue;
769			free(system_ts_nodes);
770			return (err);
771		}
772
773		/*
774		 * The names in the tree are like "CPU0_DIE_TEMPERATURE_SENSOR".
775		 * All we want to print is up to the first underscore.
776		 */
777		p = strchr(label, '_');
778		if (p != NULL)
779			*p = '\0';
780
781		err = picl_get_propval_by_name(system_ts_nodes[i],
782		    "Temperature", &temp, sizeof (temp));
783		if (err != PICL_SUCCESS) {
784			free(system_ts_nodes);
785			return (err);
786		}
787		log_printf("%s\t\t%3d\t\t%s\n", label, temp, state);
788	}
789
790	log_printf(dgettext(TEXT_DOMAIN,
791	    "\n=================================\n\n"));
792
793	free(system_ts_nodes);
794	return (PICL_SUCCESS);
795}
796
797static void
798display_hw_revisions(Prom_node *root, Board_node *bdlist)
799{
800	Prom_node	*pnode;
801	char		*value;
802
803	log_printf(dgettext(TEXT_DOMAIN, "\n"
804	    "========================= HW Revisions "
805	    "=======================================\n\n"));
806
807	log_printf(dgettext(TEXT_DOMAIN,
808	    "System PROM revisions:\n"
809	    "----------------------\n"));
810
811	pnode = dev_find_node(root, "openprom");
812	if (pnode != NULL) {
813		value = (char *)get_prop_val(find_prop(pnode, "version"));
814		log_printf(value);
815	}
816
817	log_printf(dgettext(TEXT_DOMAIN, "\n\n"
818	    "IO ASIC revisions:\n"
819	    "------------------\n"
820	    "         Port\n"
821	    "Model     ID  Status Version\n"
822	    "-------- ---- ------ -------\n"));
823
824	display_schizo_revisions(bdlist);
825}
826
827
828static void
829display_schizo_revisions(Board_node *bdlist)
830{
831	Prom_node	*pnode;
832	int		*int_val;
833	int		portid;
834	int		prev_portid = -1;
835	char		*status_a = NULL;
836	char		*status_b = NULL;
837	int		revision;
838#ifdef DEBUG
839	uint32_t	a_notes, b_notes;
840#endif
841	int		pci_bus;
842	Board_node	*bnode;
843	bnode = bdlist;
844
845	while (bnode != NULL) {
846		/*
847		 * search this board node for all Schizos
848		 */
849
850		for (pnode = dev_find_node_by_compat(bnode->nodes,
851		    SCHIZO_COMPAT_PROP); pnode != NULL;
852		    pnode = dev_next_node_by_compat(pnode,
853		    SCHIZO_COMPAT_PROP)) {
854
855			/*
856			 * get the reg property to determine
857			 * whether we are looking at side A or B
858			 */
859
860			int_val = (int *)get_prop_val
861			    (find_prop(pnode, "reg"));
862			if (int_val != NULL) {
863				int_val ++; /* second integer in array */
864				pci_bus = ((*int_val) & 0x7f0000);
865			}
866
867			/* get portid */
868			int_val = (int *)get_prop_val
869			    (find_prop(pnode, "portid"));
870			if (int_val == NULL)
871				continue;
872
873			portid = *int_val;
874
875			/*
876			 * If this is a new portid and it is PCI bus B,
877			 * we skip onto the PCI bus A.
878			 */
879			if ((portid != prev_portid) && (pci_bus == 0x700000)) {
880				prev_portid = portid;
881				/* status */
882				status_b = (char *)get_prop_val
883				    (find_prop(pnode, "status"));
884#ifdef DEBUG
885				b_notes = pci_bus;
886#endif
887				continue; /* skip to the next schizo */
888			}
889
890			/*
891			 * This must be side A of the same Schizo.
892			 * Gather all its props and display them.
893			 */
894#ifdef DEBUG
895			a_notes = pci_bus;
896#endif
897
898			prev_portid = portid;
899
900			int_val = (int *)get_prop_val
901			    (find_prop(pnode, "version#"));
902			if (int_val != NULL)
903				revision = *int_val;
904			else
905				revision = -1;
906
907			status_a = (char *)get_prop_val(find_prop
908			    (pnode, "status"));
909
910			log_printf(dgettext(TEXT_DOMAIN, "Schizo    "));
911
912			log_printf(dgettext(TEXT_DOMAIN, "%-3d "), portid, 0);
913
914
915			log_printf((status_a == NULL && status_b == NULL) ?
916			    dgettext(TEXT_DOMAIN, "  ok  ") :
917			    dgettext(TEXT_DOMAIN, " fail "));
918
919			log_printf(dgettext(TEXT_DOMAIN, " %4d   "),
920			    revision);
921#ifdef DEBUG
922			log_printf(" 0x%x 0x%x", a_notes, b_notes);
923#endif
924			log_printf("\n");
925		}
926		bnode = bnode->next;
927	}
928}
929