Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 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  */
     72 void	display_cpu_devices(Sys_tree *tree);
     73 void	display_pci(Board_node *board);
     74 void	display_io_cards(struct io_card *list);
     75 void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
     76 				struct system_kstat_data *kstats);
     77 void	display_ffb(Board_node *board, int table);
     78 void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
     79 
     80 /* local functions */
     81 static void disp_envc_status(void);
     82 static int print_temps(picl_nodehdl_t);
     83 static int print_keyswitch(picl_nodehdl_t);
     84 static int print_FSP_LEDS(picl_nodehdl_t);
     85 static int print_disk(picl_nodehdl_t);
     86 static int print_fans(picl_nodehdl_t);
     87 static int print_ps(picl_nodehdl_t);
     88 
     89 static void display_hw_revisions(Prom_node *root,
     90 					Board_node *bnode);
     91 static void display_schizo_revisions(Board_node *bdlist);
     92 
     93 
     94 void
     95 display_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 }
    114 void
    115 display_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*/
    233 void
    234 display_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*/
    263 void
    264 display_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  */
    294 void
    295 display_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  */
    378 void
    379 display_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*/
    419 void
    420 display_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 
    431 static void
    432 disp_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 
    471 err_out:
    472 	log_printf(dgettext(TEXT_DOMAIN,
    473 	    "\nEnvironmental reporting error: %s\n"),
    474 	    picl_strerror(err));
    475 }
    476 
    477 static int
    478 print_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 
    550 static int
    551 print_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 
    615 static int
    616 print_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 
    654 static int
    655 print_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 
    700 static int
    701 print_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 
    728 static int
    729 print_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 
    797 static void
    798 display_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 
    828 static void
    829 display_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