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