11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
55019Skd93003  * Common Development and Distribution License (the "License").
65019Skd93003  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel /*
22*5889Szk194757  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
231708Sstevel  * Use is subject to license terms.
241708Sstevel  */
251708Sstevel 
261708Sstevel /*
271708Sstevel  *
281708Sstevel  * Cherrystone platform-specific functions
291708Sstevel  *
301708Sstevel  */
311708Sstevel 
321708Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
331708Sstevel 
341708Sstevel #include <stdio.h>
351708Sstevel #include <stdlib.h>
361708Sstevel #include <unistd.h>
371708Sstevel #include <kstat.h>
381708Sstevel #include <string.h>
391708Sstevel #include <assert.h>
401708Sstevel #include <libintl.h>
411708Sstevel #include <note.h>
421708Sstevel #include <syslog.h>
431708Sstevel 
441708Sstevel #include <sys/openpromio.h>
451708Sstevel #include <sys/sysmacros.h>
461708Sstevel 
471708Sstevel #include <pdevinfo.h>
481708Sstevel #include <display.h>
491708Sstevel #include <pdevinfo_sun4u.h>
501708Sstevel #include <display_sun4u.h>
511708Sstevel 
521708Sstevel #include <picl.h>
531708Sstevel 
541708Sstevel #include <sys/cheetahregs.h>
551708Sstevel #include <sys/cherrystone.h>
561708Sstevel #include "workfile.c"
571708Sstevel 
581708Sstevel #define	SCHIZO_COMPAT_PROP	"pci108e,8001"
591708Sstevel 
601708Sstevel #define	MULTIPLE_BITS_SET(x)	((x)&((x)-1))
611708Sstevel 
621708Sstevel #define	MAX_PS		2
631708Sstevel #define	MAX_PS_SENSORS	3
641708Sstevel #define	MAX_DISKS	2
651708Sstevel #define	MAX_FANS	5
661708Sstevel #define	NUM_PCI_SLOTS	5
671708Sstevel 
681708Sstevel /*
691708Sstevel  * these functions will overlay the symbol table of libprtdiag
701708Sstevel  * at runtime (workgroup server systems only)
711708Sstevel  */
721708Sstevel void	display_cpu_devices(Sys_tree *tree);
731708Sstevel void	display_pci(Board_node *board);
741708Sstevel void	display_io_cards(struct io_card *list);
751708Sstevel void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
761708Sstevel 				struct system_kstat_data *kstats);
771708Sstevel void	display_ffb(Board_node *board, int table);
781708Sstevel void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
791708Sstevel 
801708Sstevel /* local functions */
811708Sstevel static void disp_envc_status(void);
821708Sstevel static int print_temps(picl_nodehdl_t);
831708Sstevel static int print_keyswitch(picl_nodehdl_t);
841708Sstevel static int print_FSP_LEDS(picl_nodehdl_t);
851708Sstevel static int print_disk(picl_nodehdl_t);
861708Sstevel static int print_fans(picl_nodehdl_t);
871708Sstevel static int print_ps(picl_nodehdl_t);
881708Sstevel 
891708Sstevel static void display_hw_revisions(Prom_node *root,
901708Sstevel 					Board_node *bnode);
911708Sstevel static void display_schizo_revisions(Board_node *bdlist);
921708Sstevel 
931708Sstevel 
941708Sstevel void
display_cpu_devices(Sys_tree * tree)951708Sstevel display_cpu_devices(Sys_tree *tree)
961708Sstevel {
971708Sstevel 	Board_node *bnode;
981708Sstevel 
991708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
1005019Skd93003 	    "\n========================= CPUs "
1015019Skd93003 	    "===============================================\n\n"
1025019Skd93003 	    "          Run   E$  CPU     CPU  \n"
1035019Skd93003 	    "Brd  CPU  MHz   MB  Impl.   Mask \n"
1045019Skd93003 	    "--- ----- ---- ---- ------- ---- \n"));
1051708Sstevel 
1061708Sstevel 	bnode = tree->bd_list;
1071708Sstevel 	while (bnode != NULL) {
1081708Sstevel 		display_cpus(bnode);
1091708Sstevel 		bnode = bnode->next;
1101708Sstevel 	}
1111708Sstevel 
1121708Sstevel 	log_printf("\n");
1131708Sstevel }
1141708Sstevel void
display_cpus(Board_node * board)1151708Sstevel display_cpus(Board_node *board)
1161708Sstevel {
1171708Sstevel 	Prom_node 	*cpu;
118*5889Szk194757 	uint_t freq;
1191708Sstevel 	int ecache_size;
1201708Sstevel 	int *l3_shares;
1211708Sstevel 	int *mid;
1221708Sstevel 	int *impl;
1231708Sstevel 	int *mask;
1241708Sstevel 	int *coreid;
1251708Sstevel 	char fru_prev = 'X'; /* Valid frus are 'A','B' */
1261708Sstevel 	int mid_prev;
1271708Sstevel 	int ecache_size_prev = 0;
1281708Sstevel 	char fru_name;
1291708Sstevel 
1301708Sstevel 	/*
1311708Sstevel 	 * display the CPUs' operating frequency, cache size, impl. field
1321708Sstevel 	 * and mask revision.
1331708Sstevel 	 */
1341708Sstevel 
1351708Sstevel 	for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
1361708Sstevel 	    cpu = dev_next_type(cpu, "cpu")) {
1371708Sstevel 
1381708Sstevel 		mid = (int *)get_prop_val(find_prop(cpu, "portid"));
1391708Sstevel 		if (mid == NULL)
1401708Sstevel 			mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
1411708Sstevel 		freq = HZ_TO_MHZ(get_cpu_freq(cpu));
1421708Sstevel 		ecache_size = get_ecache_size(cpu);
1431708Sstevel 		impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
1441708Sstevel 		mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
1451708Sstevel 		l3_shares =
1465019Skd93003 		    (int *)get_prop_val(find_prop(cpu, "l3-cache-sharing"));
1471708Sstevel 
1481708Sstevel 		/* Do not display a failed CPU node */
1491708Sstevel 		if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
1501708Sstevel 			continue;
1511708Sstevel 
1521708Sstevel 		fru_name = CHERRYSTONE_GETSLOT_LABEL(*mid);
1531708Sstevel 		if (CPU_IMPL_IS_CMP(*impl)) {
1541708Sstevel 			coreid = (int *)get_prop_val(find_prop(cpu, "reg"));
1551708Sstevel 			if (coreid == NULL) {
1561708Sstevel 				continue;
1571708Sstevel 			}
1581708Sstevel 			if ((fru_prev == 'X') ||
1595019Skd93003 			    ((fru_prev != 'X') &&
1605019Skd93003 			    (fru_name != fru_prev))) {
1611708Sstevel 				fru_prev = fru_name;
1621708Sstevel 				mid_prev = *mid;
1631708Sstevel 				ecache_size_prev = ecache_size;
1641708Sstevel 				continue;
1651708Sstevel 			} else {
1661708Sstevel 				/*
1671708Sstevel 				 * Some CMP chips have a split E$,
1681708Sstevel 				 * so the size for both cores is added
1691708Sstevel 				 * together to get the total size for
1701708Sstevel 				 * the chip.
1711708Sstevel 				 *
1721708Sstevel 				 * Still, other CMP chips have E$ (L3)
1731708Sstevel 				 * which is logically shared, so the
1741708Sstevel 				 * total size is equal to the core size.
1751708Sstevel 				 */
1761708Sstevel 				if ((l3_shares == NULL) ||
1775019Skd93003 				    ((l3_shares != NULL) &&
1785019Skd93003 				    MULTIPLE_BITS_SET(*l3_shares))) {
1791708Sstevel 					ecache_size += ecache_size_prev;
1801708Sstevel 				}
1811708Sstevel 				ecache_size_prev = 0;
1821708Sstevel 				fru_prev = 'X';
1831708Sstevel 			}
1841708Sstevel 		}
1851708Sstevel 
1861708Sstevel 		log_printf(" %c", fru_name);
1871708Sstevel 
1881708Sstevel 		/* CPU Module ID */
1891708Sstevel 		if (CPU_IMPL_IS_CMP(*impl)) {
1901708Sstevel 			log_printf("%3d,%3d ", mid_prev, *mid, 0);
1911708Sstevel 		} else
1921708Sstevel 			log_printf("   %2d   ", *mid);
1931708Sstevel 
1941708Sstevel 		/* Running frequency */
195*5889Szk194757 		log_printf("%4u", freq);
1961708Sstevel 
1971708Sstevel 		if (ecache_size == 0)
1981708Sstevel 			log_printf(" N/A  ");
1991708Sstevel 		else
2001708Sstevel 			log_printf(" %4.1f ",
2015019Skd93003 			    (float)ecache_size / (float)(1<<20));
2021708Sstevel 			/* Implementation */
2031708Sstevel 		if (impl == NULL) {
2041708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "  N/A   "));
2051708Sstevel 		} else {
2061708Sstevel 			if (IS_CHEETAH(*impl))
2071708Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
2085019Skd93003 				    "US-III  "));
2091708Sstevel 			else if (IS_CHEETAH_PLUS(*impl))
2101708Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
2115019Skd93003 				    "US-III+ "));
2121708Sstevel 			else if (IS_JAGUAR(*impl))
2131708Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
2145019Skd93003 				    "US-IV   "));
2151708Sstevel 			else if (IS_PANTHER(*impl))
2161708Sstevel 				log_printf(dgettext(TEXT_DOMAIN,
2175019Skd93003 				    "US-IV+  "));
2181708Sstevel 			else
2191708Sstevel 				log_printf("%-6x  ", *impl);
2201708Sstevel 		}
2211708Sstevel 
2221708Sstevel 		/* CPU Mask */
2231708Sstevel 		if (mask == NULL) {
2241708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, " N/A\n"));
2251708Sstevel 		} else {
2261708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, " %d.%d\n"),
2271708Sstevel 			    (*mask >> 4) & 0xf, *mask & 0xf);
2281708Sstevel 		}
2291708Sstevel 	}
2301708Sstevel }
2311708Sstevel 
2321708Sstevel /*ARGSUSED0*/
2331708Sstevel void
display_memoryconf(Sys_tree * tree,struct grp_info * grps)2341708Sstevel display_memoryconf(Sys_tree *tree, struct grp_info *grps)
2351708Sstevel {
2361708Sstevel 	Board_node	*bnode = tree->bd_list;
2371708Sstevel 
2381708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
2391708Sstevel 	    "========================= Memory Configuration"
2401708Sstevel 	    " ===============================\n\n"
2411708Sstevel 	    "          Logical  Logical  Logical\n"
2421708Sstevel 	    "     MC   Bank     Bank     Bank         DIMM    "
2435019Skd93003 	    "Interleave  Interleaved\n"
2441708Sstevel 	    "Brd  ID   num      size     Status       Size    "
2455019Skd93003 	    "Factor      with\n"
2461708Sstevel 	    "---  ---  ----     ------   -----------  ------  "
2475019Skd93003 	    "----------  -----------"));
2481708Sstevel 
2491708Sstevel 	while (bnode != NULL) {
2501708Sstevel 		if (get_us3_mem_regs(bnode)) {
2511708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
2521708Sstevel 			    "\nFailed to get memory information.\n"));
2531708Sstevel 			return;
2541708Sstevel 		}
2551708Sstevel 		bnode = bnode->next;
2561708Sstevel 	}
2571708Sstevel 
2581708Sstevel 	/* Display what we have found */
2591708Sstevel 	display_us3_banks();
2601708Sstevel }
2611708Sstevel 
2621708Sstevel /*ARGSUSED3*/
2631708Sstevel void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)2641708Sstevel display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
2651708Sstevel 	struct system_kstat_data *kstats)
2661708Sstevel {
2671708Sstevel 	/*
2681708Sstevel 	 * Now display the last powerfail time and the fatal hardware
2691708Sstevel 	 * reset information. We do this under a couple of conditions.
2701708Sstevel 	 * First if the user asks for it. The second is if the user
2711708Sstevel 	 * told us to do logging, and we found a system failure.
2721708Sstevel 	 */
2731708Sstevel 
2741708Sstevel 	if (flag) {
2751708Sstevel 		/*
2761708Sstevel 		 * display time of latest powerfail. Not all systems
2771708Sstevel 		 * have this capability. For those that do not, this
2781708Sstevel 		 * is just a no-op.
2791708Sstevel 		 */
2801708Sstevel 		disp_powerfail(root);
2811708Sstevel 
2821708Sstevel 		disp_envc_status();
2831708Sstevel 
2841708Sstevel 		display_hw_revisions(root, tree->bd_list);
2851708Sstevel 	}
2861708Sstevel 	return;
2871708Sstevel 
2881708Sstevel }
2891708Sstevel 
2901708Sstevel /*
2911708Sstevel  * display_pci
2921708Sstevel  * Display all the PCI IO cards on this board.
2931708Sstevel  */
2941708Sstevel void
display_pci(Board_node * board)2951708Sstevel display_pci(Board_node *board)
2961708Sstevel {
2971708Sstevel 	struct io_card	*card_list = NULL;
2981708Sstevel 	struct io_card	card;
2991708Sstevel 	void		*value;
3001708Sstevel 	Prom_node	*pci;
3011708Sstevel 	Prom_node	*card_node;
3021708Sstevel 	static int	banner = FALSE;
3031708Sstevel 
3041708Sstevel 	char		*slot_name_arr[NUM_PCI_SLOTS];
3051708Sstevel 	int		i;
3061708Sstevel 
3071708Sstevel 	if (board == NULL)
3081708Sstevel 		return;
3091708Sstevel 
3105019Skd93003 	(void) memset(&card, 0, sizeof (struct io_card));
3111708Sstevel 	/* Initialize all the common information */
3121708Sstevel 	card.display = TRUE;
3131708Sstevel 	card.board = board->board_num;
3141708Sstevel 
3151708Sstevel 	/*
3161708Sstevel 	 * Search for each pci instance, then find/display all nodes under
3171708Sstevel 	 * each instance node found.
3181708Sstevel 	 */
3191708Sstevel 	for (pci = dev_find_node_by_compat(board->nodes, SCHIZO_COMPAT_PROP);
3205019Skd93003 	    pci != NULL;
3215019Skd93003 	    pci = dev_next_node_by_compat(pci, SCHIZO_COMPAT_PROP)) {
3221708Sstevel 		(void) snprintf(card.bus_type, MAXSTRLEN,
3235019Skd93003 		    dgettext(TEXT_DOMAIN, "PCI"));
3241708Sstevel 		/*
3251708Sstevel 		 * Get slot-name properties from parent node and
3261708Sstevel 		 * store them in an array.
3271708Sstevel 		 */
3281708Sstevel 		value = (char *)get_prop_val(
3295019Skd93003 		    find_prop(pci, "slot-names"));
3301708Sstevel 
3311708Sstevel 		if (value != NULL) {
3321708Sstevel 			/* array starts after first int */
3331708Sstevel 			slot_name_arr[0] = (char *)value + sizeof (int);
3341708Sstevel 			for (i = 1; i < NUM_PCI_SLOTS; i++) {
3351708Sstevel 				slot_name_arr[i] = (char *)slot_name_arr[i - 1]
3365019Skd93003 				    + strlen(slot_name_arr[i - 1]) +1;
3371708Sstevel 			}
3381708Sstevel 		}
3391708Sstevel 		/*
3401708Sstevel 		 * Search for Children of this node ie. Cards.
3411708Sstevel 		 * Note: any of these cards can be a pci-bridge
3421708Sstevel 		 *	that itself has children. If we find a
3431708Sstevel 		 *	pci-bridge we need to handle it specially.
3441708Sstevel 		 */
3451708Sstevel 		card_node = pci->child;
3461708Sstevel 		/* Generate the list of pci cards on pci instance: pci */
3471708Sstevel 		fill_pci_card_list(pci, card_node, &card, &card_list,
3485019Skd93003 		    slot_name_arr);
3491708Sstevel 	} /* end-for */
3501708Sstevel 
3511708Sstevel 	if (!banner && card_list != NULL) {
3521708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
3535019Skd93003 		    "                    Bus  Max\n"
3545019Skd93003 		    " IO  Port Bus       Freq Bus  Dev,\n"
3555019Skd93003 		    "Type  ID  Side Slot MHz  Freq Func State "
3565019Skd93003 		    "Name                              Model"
3571708Sstevel #ifdef DEBUG
3585019Skd93003 		    "                   Notes"
3591708Sstevel #endif
3605019Skd93003 		    "\n"
3615019Skd93003 		    "---- ---- ---- ---- ---- ---- ---- ----- "
3625019Skd93003 		    "--------------------------------  "
3631708Sstevel #ifdef DEBUG
3645019Skd93003 		    "----------------------  "
3651708Sstevel #endif
3665019Skd93003 		    "----------------------\n"));
3671708Sstevel 		banner = TRUE;
3681708Sstevel 	}
3691708Sstevel 
3701708Sstevel 	display_io_cards(card_list);
3711708Sstevel 	free_io_cards(card_list);
3721708Sstevel }
3731708Sstevel 
3741708Sstevel /*
3751708Sstevel  * Print out all the io cards in the list.  Also print the column
3761708Sstevel  * headers if told to do so.
3771708Sstevel  */
3781708Sstevel void
display_io_cards(struct io_card * list)3791708Sstevel display_io_cards(struct io_card *list)
3801708Sstevel {
3811708Sstevel 	struct io_card *p;
3821708Sstevel 
3831708Sstevel 	for (p = list; p != NULL; p = p -> next) {
3841708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
3851708Sstevel 		    "%-4s  %-3d  %c    %-1s    %-3d"),
3861708Sstevel 		    p->bus_type, p->schizo_portid, p->pci_bus,
3871708Sstevel 		    p->slot_str, p->freq);
3881708Sstevel 
3891708Sstevel 		switch (p->pci_bus) {
3901708Sstevel 		case 'A':
3911708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "  66  "));
3921708Sstevel 			break;
3931708Sstevel 		case 'B':
3941708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "  33  "));
3951708Sstevel 			break;
3961708Sstevel 		default:
3971708Sstevel 			assert(0);
3981708Sstevel 			break;
3991708Sstevel 		}
4001708Sstevel 
4011708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
4025019Skd93003 		    "%-1d,%-1d  %-5s %-32.32s"),
4031708Sstevel 		    p->dev_no, p->func_no, p->status, p->name);
4041708Sstevel 		if (strlen(p->name) > 32)
4051708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "+ "));
4061708Sstevel 		else
4071708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "  "));
4081708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "%-22.22s"), p->model);
4091708Sstevel 		if (strlen(p->model) > 22)
4101708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "+"));
4111708Sstevel #ifdef DEBUG
4121708Sstevel 		log_printf("%s", p->notes);
4131708Sstevel #endif
4141708Sstevel 		log_printf("\n");
4151708Sstevel 	}
4161708Sstevel }
4171708Sstevel 
4181708Sstevel /*ARGSUSED*/
4191708Sstevel void
display_ffb(Board_node * board,int table)4201708Sstevel display_ffb(Board_node *board, int table)
4211708Sstevel {
4221708Sstevel 	/* NOP, since there are no FFB's on this platform. */
4231708Sstevel }
4241708Sstevel 
4251708Sstevel 
4261708Sstevel /*
4271708Sstevel  * local functions
4281708Sstevel  */
4291708Sstevel 
4301708Sstevel 
4311708Sstevel static void
disp_envc_status()4321708Sstevel disp_envc_status()
4331708Sstevel {
4341708Sstevel 	int err;
4351708Sstevel 	char *system = "SYSTEM";
4361708Sstevel 	picl_nodehdl_t system_node, root;
4371708Sstevel 
4381708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
4395019Skd93003 	    "\n"
4405019Skd93003 	    "=========================  Environmental Status "
4415019Skd93003 	    "=========================\n\n"));
4421708Sstevel 
4431708Sstevel 	err = picl_initialize();
4445019Skd93003 	if (err != PICL_SUCCESS) {
4455019Skd93003 		exit_code = PD_INTERNAL_FAILURE;
4461708Sstevel 		goto err_out;
4475019Skd93003 	}
4481708Sstevel 	err = picl_get_root(&root);
4495019Skd93003 	if (err != PICL_SUCCESS) {
4505019Skd93003 		exit_code = PD_INTERNAL_FAILURE;
4511708Sstevel 		goto err_out;
4525019Skd93003 	}
4531708Sstevel 	err = find_child_device(root, system, &system_node);
4545019Skd93003 	if (err != PICL_SUCCESS) {
4555019Skd93003 		exit_code = PD_INTERNAL_FAILURE;
4561708Sstevel 		goto err_out;
4575019Skd93003 	}
4581708Sstevel 
4591708Sstevel 	err = print_temps(system_node);
4601708Sstevel 	err |= print_keyswitch(system_node);
4611708Sstevel 	err |= print_FSP_LEDS(system_node);
4621708Sstevel 	err |= print_disk(system_node);
4631708Sstevel 	err |= print_fans(system_node);
4641708Sstevel 	err |= print_ps(system_node);
4651708Sstevel 
4661708Sstevel 	if (err != PICL_SUCCESS)
4671708Sstevel 		goto err_out;
4681708Sstevel 
4691708Sstevel 	return;
4701708Sstevel 
4711708Sstevel err_out:
4721708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
4735019Skd93003 	    "\nEnvironmental reporting error: %s\n"),
4745019Skd93003 	    picl_strerror(err));
4751708Sstevel }
4761708Sstevel 
4771708Sstevel static int
print_ps(picl_nodehdl_t system_node)4781708Sstevel print_ps(picl_nodehdl_t system_node)
4791708Sstevel {
4801708Sstevel 	int		i, j, err = 0;
4811708Sstevel 	int32_t		number;
4821708Sstevel 	picl_nodehdl_t	*ps;
4831708Sstevel 	picl_nodehdl_t	*ps_fail_sensor;
4841708Sstevel 	char		name[PICL_PROPNAMELEN_MAX];
4851708Sstevel 	char		fault_state[PICL_PROPNAMELEN_MAX];
4861708Sstevel 
4871708Sstevel 	log_printf(dgettext(TEXT_DOMAIN, "\n\n"
4885019Skd93003 	    "Power Supplies:\n"
4895019Skd93003 	    "---------------\n"
4905019Skd93003 	    "\n"
4915019Skd93003 	    "Supply     Status        Fault     Fan Fail   Temp Fail\n"
4925019Skd93003 	    "------    ------------   --------  ---------  ---------\n"));
4931708Sstevel 
4941708Sstevel 	err = fill_device_array_from_id(system_node, "PSVC_PS", &number, &ps);
4951708Sstevel 	if (err != PICL_SUCCESS) {
4961708Sstevel 		return (err);
4971708Sstevel 	}
4981708Sstevel 
4991708Sstevel 	for (i = 0; i < MAX_PS; i++) {
5001708Sstevel 		err = picl_get_propval_by_name(ps[i], PICL_PROP_NAME, name,
5011708Sstevel 		    PICL_PROPNAMELEN_MAX);
5021708Sstevel 		if (err != PICL_SUCCESS)
5031708Sstevel 			continue;
5041708Sstevel 
5051708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "%6-s"), name);
5061708Sstevel 		err = picl_get_propval_by_name(ps[i], "FaultInformation",
5075019Skd93003 		    fault_state, PICL_PROPNAMELEN_MAX);
5081708Sstevel 		if (err != PICL_SUCCESS) {
5091708Sstevel 			free(ps);
5101708Sstevel 			return (err);
5111708Sstevel 		}
5121708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "   [%-12s]"), fault_state);
5131708Sstevel 		if (strcmp(fault_state, "NO AC POWER") == 0) {
5141708Sstevel 			log_printf("\n");
5151708Sstevel 			continue;
5161708Sstevel 		}
5171708Sstevel 
5181708Sstevel 		err = fill_device_array_from_id(ps[i], "PSVC_DEV_FAULT_SENSOR",
5195019Skd93003 		    &number, &ps_fail_sensor);
5201708Sstevel 
5211708Sstevel 		if (err != PICL_SUCCESS) {
5221708Sstevel 			free(ps);
5231708Sstevel 			return (err);
5241708Sstevel 		}
5251708Sstevel 		log_printf("   ");
5261708Sstevel 		for (j = 0; j < MAX_PS_SENSORS; j++) {
5271708Sstevel 			err = picl_get_propval_by_name(ps_fail_sensor[j],
5285019Skd93003 			    "State", fault_state, PICL_PROPNAMELEN_MAX);
5291708Sstevel 			if (err != PICL_SUCCESS) {
5301708Sstevel 				if (err == PICL_FAILURE) {
5311708Sstevel 					break;
5321708Sstevel 				}
5331708Sstevel 				free(ps);
5341708Sstevel 				free(ps_fail_sensor);
5351708Sstevel 				return (err);
5361708Sstevel 			}
5371708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "%-10s"), fault_state);
5381708Sstevel 		}
5391708Sstevel 		log_printf("\n");
5401708Sstevel 		free(ps_fail_sensor);
5411708Sstevel 	}
5421708Sstevel 
5431708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
5445019Skd93003 	    "\n=================================\n\n"));
5451708Sstevel 
5461708Sstevel 	free(ps);
5471708Sstevel 	return (PICL_SUCCESS);
5481708Sstevel }
5491708Sstevel 
5501708Sstevel static int
print_fans(picl_nodehdl_t system_node)5511708Sstevel print_fans(picl_nodehdl_t system_node)
5521708Sstevel {
5531708Sstevel 	int		i, err;
5541708Sstevel 	int32_t		number;
5551708Sstevel 	picl_nodehdl_t	*fans;
5561708Sstevel 	picl_nodehdl_t	phdl;
5571708Sstevel 	char		prop[PICL_PROPNAMELEN_MAX];
5581708Sstevel 	char		parent[PICL_PROPNAMELEN_MAX];
5591708Sstevel 	int32_t		rpm;
5601708Sstevel 
5611708Sstevel 	err = fill_device_array_from_id(system_node, "PSVC_FAN", &number,
5625019Skd93003 	    &fans);
5631708Sstevel 	if (err != PICL_SUCCESS) {
5641708Sstevel 		return (err);
5651708Sstevel 	}
5661708Sstevel 
5671708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
5685019Skd93003 	    "\n=================================\n\n"
5695019Skd93003 	    "Fan Status:\n"
5705019Skd93003 	    "-----------\n\n"
5715019Skd93003 	    "Fan Tray        Fan              RPM    Status\n"
5725019Skd93003 	    "-----------     ----            -----   ----------\n"));
5731708Sstevel 
5741708Sstevel 	for (i = 0; i < MAX_FANS; i++) {
5751708Sstevel 		err = picl_get_propval_by_name(fans[i], PICL_PROP_NAME, prop,
5765019Skd93003 		    PICL_PROPNAMELEN_MAX);
5771708Sstevel 		if (err != PICL_SUCCESS)
5781708Sstevel 			continue;
5791708Sstevel 
5801708Sstevel 		err = fill_device_from_id(fans[i], "PSVC_PARENT", &phdl);
5811708Sstevel 		if (err != PICL_SUCCESS)
5821708Sstevel 			continue;
5831708Sstevel 		err = picl_get_propval_by_name(phdl, PICL_PROP_NAME, parent,
5845019Skd93003 		    PICL_PROPNAMELEN_MAX);
5851708Sstevel 		if (err != PICL_SUCCESS)
5861708Sstevel 			continue;
5871708Sstevel 
5881708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "%-16s"), parent);
5891708Sstevel 
5901708Sstevel 
5911708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "%-16s"), prop);
5921708Sstevel 
5931708Sstevel 		err = picl_get_propval_by_name(fans[i], "Fan-speed",
5941708Sstevel 		    &rpm, sizeof (rpm));
5951708Sstevel 		if (err != PICL_SUCCESS) {
5961708Sstevel 			free(fans);
5971708Sstevel 			return (err);
5981708Sstevel 		}
5991708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "%5d "), rpm);
6001708Sstevel 
6011708Sstevel 		err = picl_get_propval_by_name(fans[i], "FaultInformation",
6021708Sstevel 		    prop, PICL_PROPNAMELEN_MAX);
6031708Sstevel 		if (err != PICL_SUCCESS) {
6041708Sstevel 			free(fans);
6051708Sstevel 			return (err);
6061708Sstevel 		}
6071708Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "  [%s]\n"), prop);
6081708Sstevel 	}
6091708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
6105019Skd93003 	    "\n=================================\n\n"));
6111708Sstevel 	free(fans);
6121708Sstevel 	return (PICL_SUCCESS);
6131708Sstevel }
6141708Sstevel 
6151708Sstevel static int
print_disk(picl_nodehdl_t system_node)6161708Sstevel print_disk(picl_nodehdl_t system_node)
6171708Sstevel {
6181708Sstevel 	int		i, err;
6191708Sstevel 	int32_t		number;
6201708Sstevel 	picl_nodehdl_t	*disks;
6211708Sstevel 	char		state[PICL_PROPNAMELEN_MAX];
6221708Sstevel 
6231708Sstevel 	err = fill_device_array_from_id(system_node, "PSVC_DISK", &number,
6241708Sstevel 	    &disks);
6251708Sstevel 	if (err != PICL_SUCCESS) {
6261708Sstevel 		return (err);
6271708Sstevel 	}
6281708Sstevel 
6291708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
6305019Skd93003 	    "Disk Status:\n"
6315019Skd93003 	    "------------\n"));
6321708Sstevel 	for (i = 0; i < MAX_DISKS; i++) {
6331708Sstevel 		err = picl_get_propval_by_name(disks[i], "FaultInformation",
6341708Sstevel 		    state, PICL_PROPNAMELEN_MAX);
6351708Sstevel 
6361708Sstevel 		switch (err) {
6371708Sstevel 		case PICL_SUCCESS:
6381708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
6395019Skd93003 			    "DISK %d: [%3s]\n"), i, state);
6401708Sstevel 			break;
6411708Sstevel 		case PICL_INVALIDHANDLE:
6421708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
6435019Skd93003 			    "DISK %d: [ NOT PRESENT ]\n"), i);
6441708Sstevel 			break;
6451708Sstevel 		default:
6461708Sstevel 			free(disks);
6471708Sstevel 			return (err);
6481708Sstevel 		}
6491708Sstevel 	}
6501708Sstevel 	free(disks);
6511708Sstevel 	return (PICL_SUCCESS);
6521708Sstevel }
6531708Sstevel 
6541708Sstevel static int
print_FSP_LEDS(picl_nodehdl_t system_node)6551708Sstevel print_FSP_LEDS(picl_nodehdl_t system_node)
6561708Sstevel {
6571708Sstevel 	int		err;
6581708Sstevel 	int32_t		number;
6591708Sstevel 	picl_nodehdl_t	*fsp_led;
6601708Sstevel 	char		fault_state[PICL_PROPNAMELEN_MAX];
6611708Sstevel 	char		locate_state[PICL_PROPNAMELEN_MAX];
6621708Sstevel 
6631708Sstevel 	err = fill_device_array_from_id(system_node, "PSVC_FSP_LED", &number,
6641708Sstevel 	    &fsp_led);
6651708Sstevel 	if (err != PICL_SUCCESS) {
6661708Sstevel 		return (err);
6671708Sstevel 	}
6681708Sstevel 
6691708Sstevel 	assert(number == 2);
6701708Sstevel 	err = picl_get_propval_by_name(fsp_led[0], "State", &fault_state,
6715019Skd93003 	    PICL_PROPNAMELEN_MAX);
6721708Sstevel 	if (err != PICL_SUCCESS) {
6731708Sstevel 		free(fsp_led);
6741708Sstevel 		return (err);
6751708Sstevel 	}
6765019Skd93003 
6775019Skd93003 	if (strcmp(fault_state, PSVC_LED_ON) == 0)
6785019Skd93003 		exit_code = PD_SYSTEM_FAILURE;
6795019Skd93003 
6801708Sstevel 	err = picl_get_propval_by_name(fsp_led[1], "State", &locate_state,
6815019Skd93003 	    PICL_PROPNAMELEN_MAX);
6821708Sstevel 	if (err != PICL_SUCCESS) {
6831708Sstevel 		free(fsp_led);
6841708Sstevel 		return (err);
6851708Sstevel 	}
6861708Sstevel 
6871708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
6885019Skd93003 	    "System LED Status:\n\n"
6895019Skd93003 	    "  LOCATOR   FAULT    POWER\n"
6905019Skd93003 	    "  -------  -------  -------\n"
6915019Skd93003 	    "   [%3s]    [%3s]    [ ON]"),
6925019Skd93003 	    locate_state, fault_state);
6931708Sstevel 
6941708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
6955019Skd93003 	    "\n\n=================================\n\n"));
6961708Sstevel 	free(fsp_led);
6971708Sstevel 	return (err);
6981708Sstevel }
6991708Sstevel 
7001708Sstevel static int
print_keyswitch(picl_nodehdl_t system_node)7011708Sstevel print_keyswitch(picl_nodehdl_t system_node)
7021708Sstevel {
7031708Sstevel 	int		err;
7041708Sstevel 	picl_nodehdl_t	*keyswitch;
7051708Sstevel 	int32_t		number;
7061708Sstevel 	char		ks_pos[PICL_PROPNAMELEN_MAX];
7071708Sstevel 
7081708Sstevel 	err = fill_device_array_from_id(system_node, "PSVC_KEYSWITCH", &number,
7091708Sstevel 	    &keyswitch);
7101708Sstevel 	if (err != PICL_SUCCESS) {
7111708Sstevel 		return (err);
7121708Sstevel 	}
7131708Sstevel 	err = picl_get_propval_by_name(keyswitch[0], "State", ks_pos,
7145019Skd93003 	    PICL_PROPNAMELEN_MAX);
7151708Sstevel 	if (err != PICL_SUCCESS) {
7161708Sstevel 		free(keyswitch);
7171708Sstevel 		return (err);
7181708Sstevel 	}
7191708Sstevel 
7201708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
7215019Skd93003 	    "Front Status Panel:\n"
7225019Skd93003 	    "-------------------\n"
7235019Skd93003 	    "Keyswitch position: %s\n\n"), ks_pos);
7241708Sstevel 	free(keyswitch);
7251708Sstevel 	return (err);
7261708Sstevel }
7271708Sstevel 
7281708Sstevel static int
print_temps(picl_nodehdl_t system_node)7291708Sstevel print_temps(picl_nodehdl_t system_node)
7301708Sstevel {
7311708Sstevel 	int		i;
7321708Sstevel 	int		err;
7331708Sstevel 	picl_nodehdl_t	*system_ts_nodes;
7341708Sstevel 	int32_t		temp;
7351708Sstevel 	int32_t		number;
7361708Sstevel 	char		label[PICL_PROPNAMELEN_MAX];
7371708Sstevel 	char		state[PICL_PROPNAMELEN_MAX];
7381708Sstevel 	char		*p;
7391708Sstevel 
7401708Sstevel 	err = fill_device_array_from_id(system_node, "PSVC_TS", &number,
7411708Sstevel 	    &system_ts_nodes);
7421708Sstevel 	if (err != PICL_SUCCESS) {
7431708Sstevel 		return (err);
7441708Sstevel 	}
7451708Sstevel 
7461708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
7475019Skd93003 	    "System Temperatures (Celsius):\n"
7485019Skd93003 	    "-------------------------------\n"
7495019Skd93003 	    "Device\t\tTemperature\tStatus\n"
7505019Skd93003 	    "---------------------------------------\n"));
7511708Sstevel 
7521708Sstevel 	for (i = 0; i < number; i++) {
7531708Sstevel 		err = picl_get_propval_by_name(system_ts_nodes[i],
7541708Sstevel 		    "State", state, sizeof (state));
7551708Sstevel 		if (err != PICL_SUCCESS) {
7561708Sstevel 			if (err == PICL_INVALIDHANDLE) {
7575019Skd93003 				(void) strcpy(state, "n/a");
7581708Sstevel 			} else {
7591708Sstevel 				free(system_ts_nodes);
7601708Sstevel 				return (err);
7611708Sstevel 			}
7621708Sstevel 		}
7631708Sstevel 		err = picl_get_propval_by_name(system_ts_nodes[i],
7641708Sstevel 		    PICL_PROP_NAME, label, PICL_PROPNAMELEN_MAX);
7651708Sstevel 		if (err != PICL_SUCCESS) {
7661708Sstevel 			if (err == PICL_INVALIDHANDLE)
7671708Sstevel 				/* This FRU isn't present. Skip it. */
7681708Sstevel 				continue;
7691708Sstevel 			free(system_ts_nodes);
7701708Sstevel 			return (err);
7711708Sstevel 		}
7721708Sstevel 
7731708Sstevel 		/*
7741708Sstevel 		 * The names in the tree are like "CPU0_DIE_TEMPERATURE_SENSOR".
7751708Sstevel 		 * All we want to print is up to the first underscore.
7761708Sstevel 		 */
7771708Sstevel 		p = strchr(label, '_');
7781708Sstevel 		if (p != NULL)
7791708Sstevel 			*p = '\0';
7801708Sstevel 
7811708Sstevel 		err = picl_get_propval_by_name(system_ts_nodes[i],
7825019Skd93003 		    "Temperature", &temp, sizeof (temp));
7831708Sstevel 		if (err != PICL_SUCCESS) {
7841708Sstevel 			free(system_ts_nodes);
7851708Sstevel 			return (err);
7861708Sstevel 		}
7871708Sstevel 		log_printf("%s\t\t%3d\t\t%s\n", label, temp, state);
7881708Sstevel 	}
7891708Sstevel 
7901708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
7915019Skd93003 	    "\n=================================\n\n"));
7921708Sstevel 
7931708Sstevel 	free(system_ts_nodes);
7941708Sstevel 	return (PICL_SUCCESS);
7951708Sstevel }
7961708Sstevel 
7971708Sstevel static void
display_hw_revisions(Prom_node * root,Board_node * bdlist)7981708Sstevel display_hw_revisions(Prom_node *root, Board_node *bdlist)
7991708Sstevel {
8001708Sstevel 	Prom_node	*pnode;
8011708Sstevel 	char		*value;
8021708Sstevel 
8031708Sstevel 	log_printf(dgettext(TEXT_DOMAIN, "\n"
8045019Skd93003 	    "========================= HW Revisions "
8055019Skd93003 	    "=======================================\n\n"));
8061708Sstevel 
8071708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
8085019Skd93003 	    "System PROM revisions:\n"
8095019Skd93003 	    "----------------------\n"));
8101708Sstevel 
8111708Sstevel 	pnode = dev_find_node(root, "openprom");
8121708Sstevel 	if (pnode != NULL) {
8135019Skd93003 		value = (char *)get_prop_val(find_prop(pnode, "version"));
8145019Skd93003 		log_printf(value);
8151708Sstevel 	}
8161708Sstevel 
8171708Sstevel 	log_printf(dgettext(TEXT_DOMAIN, "\n\n"
8185019Skd93003 	    "IO ASIC revisions:\n"
8195019Skd93003 	    "------------------\n"
8205019Skd93003 	    "         Port\n"
8215019Skd93003 	    "Model     ID  Status Version\n"
8225019Skd93003 	    "-------- ---- ------ -------\n"));
8231708Sstevel 
8241708Sstevel 	display_schizo_revisions(bdlist);
8251708Sstevel }
8261708Sstevel 
8271708Sstevel 
8281708Sstevel static void
display_schizo_revisions(Board_node * bdlist)8291708Sstevel display_schizo_revisions(Board_node *bdlist)
8301708Sstevel {
8311708Sstevel 	Prom_node	*pnode;
8321708Sstevel 	int		*int_val;
8331708Sstevel 	int		portid;
8341708Sstevel 	int		prev_portid = -1;
8351708Sstevel 	char		*status_a = NULL;
8361708Sstevel 	char		*status_b = NULL;
8371708Sstevel 	int		revision;
8381708Sstevel #ifdef DEBUG
8391708Sstevel 	uint32_t	a_notes, b_notes;
8401708Sstevel #endif
8411708Sstevel 	int		pci_bus;
8421708Sstevel 	Board_node	*bnode;
8431708Sstevel 	bnode = bdlist;
8441708Sstevel 
8451708Sstevel 	while (bnode != NULL) {
8461708Sstevel 		/*
8471708Sstevel 		 * search this board node for all Schizos
8481708Sstevel 		 */
8491708Sstevel 
8501708Sstevel 		for (pnode = dev_find_node_by_compat(bnode->nodes,
8515019Skd93003 		    SCHIZO_COMPAT_PROP); pnode != NULL;
8525019Skd93003 		    pnode = dev_next_node_by_compat(pnode,
8535019Skd93003 		    SCHIZO_COMPAT_PROP)) {
8541708Sstevel 
8551708Sstevel 			/*
8561708Sstevel 			 * get the reg property to determine
8571708Sstevel 			 * whether we are looking at side A or B
8581708Sstevel 			 */
8591708Sstevel 
8601708Sstevel 			int_val = (int *)get_prop_val
8615019Skd93003 			    (find_prop(pnode, "reg"));
8621708Sstevel 			if (int_val != NULL) {
8631708Sstevel 				int_val ++; /* second integer in array */
8641708Sstevel 				pci_bus = ((*int_val) & 0x7f0000);
8651708Sstevel 			}
8661708Sstevel 
8671708Sstevel 			/* get portid */
8681708Sstevel 			int_val = (int *)get_prop_val
8695019Skd93003 			    (find_prop(pnode, "portid"));
8701708Sstevel 			if (int_val == NULL)
8711708Sstevel 				continue;
8721708Sstevel 
8731708Sstevel 			portid = *int_val;
8741708Sstevel 
8751708Sstevel 			/*
8761708Sstevel 			 * If this is a new portid and it is PCI bus B,
8771708Sstevel 			 * we skip onto the PCI bus A.
8781708Sstevel 			 */
8791708Sstevel 			if ((portid != prev_portid) && (pci_bus == 0x700000)) {
8801708Sstevel 				prev_portid = portid;
8811708Sstevel 				/* status */
8821708Sstevel 				status_b = (char *)get_prop_val
8831708Sstevel 				    (find_prop(pnode, "status"));
8841708Sstevel #ifdef DEBUG
8851708Sstevel 				b_notes = pci_bus;
8861708Sstevel #endif
8871708Sstevel 				continue; /* skip to the next schizo */
8881708Sstevel 			}
8891708Sstevel 
8901708Sstevel 			/*
8911708Sstevel 			 * This must be side A of the same Schizo.
8921708Sstevel 			 * Gather all its props and display them.
8931708Sstevel 			 */
8941708Sstevel #ifdef DEBUG
8951708Sstevel 			a_notes = pci_bus;
8961708Sstevel #endif
8971708Sstevel 
8981708Sstevel 			prev_portid = portid;
8991708Sstevel 
9001708Sstevel 			int_val = (int *)get_prop_val
9015019Skd93003 			    (find_prop(pnode, "version#"));
9021708Sstevel 			if (int_val != NULL)
9031708Sstevel 				revision = *int_val;
9041708Sstevel 			else
9051708Sstevel 				revision = -1;
9061708Sstevel 
9071708Sstevel 			status_a = (char *)get_prop_val(find_prop
9085019Skd93003 			    (pnode, "status"));
9091708Sstevel 
9101708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "Schizo    "));
9111708Sstevel 
9121708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "%-3d "), portid, 0);
9131708Sstevel 
9141708Sstevel 
9151708Sstevel 			log_printf((status_a == NULL && status_b == NULL) ?
9165019Skd93003 			    dgettext(TEXT_DOMAIN, "  ok  ") :
9175019Skd93003 			    dgettext(TEXT_DOMAIN, " fail "));
9181708Sstevel 
9191708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, " %4d   "),
9201708Sstevel 			    revision);
9211708Sstevel #ifdef DEBUG
9221708Sstevel 			log_printf(" 0x%x 0x%x", a_notes, b_notes);
9231708Sstevel #endif
9241708Sstevel 			log_printf("\n");
9251708Sstevel 		}
9261708Sstevel 		bnode = bnode->next;
9271708Sstevel 	}
9281708Sstevel }
929