OpenSolaris_b135/lib/libprtdiag_psr/sparc/starcat/common/starcat.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 * Starcat Platform specific functions.
 *
 * 	called when :
 *	machine_type == MTYPE_STARCAT
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <kvm.h>
#include <varargs.h>
#include <time.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/openpromio.h>
#include <libintl.h>
#include <syslog.h>
#include <sys/dkio.h>
#include <pdevinfo.h>
#include <display.h>
#include <pdevinfo_sun4u.h>
#include <display_sun4u.h>
#include <libprtdiag.h>

#define	HZ_TO_MHZ(x)		(((x) + 500000) / 1000000)
#define	PORTID_TO_EXPANDER(p)	(((p) >> 5) & 0x1f)
#define	PORTID_TO_SLOT(p)	(((p) >> 3) & 0x1)
#define	PORTID_TO_INSTANCE(p)	((p) & 0x3)
#define	SCHIZO_COMPATIBLE	"pci108e,8001"
#define	XMITS_COMPATIBLE	"pci108e,8002"
#define	SC_BOARD_TYPE(id)	(PORTID_TO_SLOT(id) ? "IO" : "SB")

#ifndef	TEXT_DOMAIN
#define	TEXT_DOMAIN	"SYS_TEST"
#endif	/* TEXT_DOMAIN */

#define	DEFAULT_MAX_FREQ	66	/* 66 MHz */
#define	PCIX_MAX_FREQ		90	/* 90 MHz */

/*
 * these functions will overlay the symbol table of libprtdiag
 * at runtime (Starcat systems only)
 */

int	do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
void	*get_prop_val(Prop *prop);
Prop	*find_prop(Prom_node *pnode, char *name);
char	*get_node_name(Prom_node *pnode);
char	*get_node_type(Prom_node *pnode);
void	add_node(Sys_tree *, Prom_node *);
void	display_pci(Board_node *);
void	display_ffb(Board_node *, int);
void	display_io_cards(struct io_card *list);
void	display_cpu_devices(Sys_tree *tree);
void	display_cpus(Board_node *board);
void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
void	print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
	    char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
		struct system_kstat_data *kstats);

/* Local Functions */
static void	starcat_disp_hw_revisions(Prom_node *root);
static void display_io_max_bus_speed(struct io_card *p);
static void display_io_slot_info(struct io_card *p);

/* The bus max freq is determined based on board level in use */
int	board_bus_max_freq = DEFAULT_MAX_FREQ;	/* 66MHz default */

/*
 * display_pci
 * Display all the PCI IO cards on this board.
 */
void
display_pci(Board_node *board)
{
	struct io_card *card_list = NULL;
	struct io_card card;
	void *value;
	Prom_node *pci;
	Prom_node *card_node;
	Prom_node *pci_bridge_node = NULL;
	char	*slot_name_arr[MAX_SLOTS_PER_IO_BD] = {NULL};
	char	*slot_name = NULL;
	int	slot_name_bits;
	int	slot_name_offset = 0;
	char	*child_name;
	char	*name, *type;
	char	buf[MAXSTRLEN];
	int	*int_val;
	int	pci_bus;
	int	pci_bridge = 0;
	int	pci_bridge_dev_no;
	int	child_dev_no;
	int	i;
	int	portid;
	int	version, *pversion;

	if (board == NULL)
		return;

	/* Initialize all the common information */
	card.display = TRUE;
	card.board = board->board_num;
	card.node_id = board->node_id;

	/*
	 * Search for each schizo, then find/display all nodes under
	 * each schizo node found.  Since the model property "SUNW,schizo"
	 * is not supported on Starcat, we must match on the compatible
	 * property "pci108e,8001".
	 */
	for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
	    pci != NULL;
	    pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {

		/* set max freq for this board */
		board_bus_max_freq = DEFAULT_MAX_FREQ;
		/*
		 * Find out if this is a PCI or cPCI IO Board.
		 * If "enum-impl" property exists in pci node => cPCI.
		 */
		value = get_prop_val(find_prop(pci, "enum-impl"));
		if (value == NULL) {
			(void) sprintf(card.bus_type, "PCI");
		} else {
			(void) sprintf(card.bus_type, "cPCI");
		}

		if (strstr((char *)get_prop_val(
		    find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
			sprintf(card.notes, "%s", XMITS_COMPATIBLE);
			/*
			 * With XMITS 3.X and PCI-X mode, the bus speed
			 * can be higher than 66MHZ.
			 */
			value = (int *)get_prop_val
			    (find_prop(pci, "module-revision#"));
			if (value) {
				pversion = (int *)value;
				version = *pversion;
				if (version >= 4)
					board_bus_max_freq = PCIX_MAX_FREQ;
			}
		} else if (strstr((char *)get_prop_val(
		    find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
			sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
		else
			sprintf(card.notes, " ");

		/*
		 * Get slot-names property from parent node and
		 * store the individual slot names in an array.
		 * This is more general than Starcat requires, but
		 * it is correct, according to the slot-names property.
		 */
		value = (char *)get_prop_val(find_prop(pci, "slot-names"));
		if (value == NULL) {
			/*
			 * No slot_names property.  This could be an Xmits
			 * card, so check the child node for slot-names property
			 */
			value = (char *)get_prop_val(
			    find_prop(pci->child, "slot-names"));
		}

		if (value != NULL) {
			/* Get the 4 byte bitmask and pointer to first name */
			slot_name_bits = *(int *)value;
			if (slot_name_bits > 0)
				slot_name_offset = slot_name_bits - 1;
			slot_name = (char *)value + sizeof (int);

			for (i = 0; i < MAX_SLOTS_PER_IO_BD; i++) {
				if (! (slot_name_bits & (1 << i))) {
					slot_name_arr[i] = (char *)NULL;
					continue;
				}

				/*
				 * Save the name pointer into the array
				 * and advance it past the end of this
				 * slot name
				 */
				slot_name_arr[i] = slot_name;
				slot_name += strlen(slot_name) + 1;
			}
			slot_name = (char *)NULL;
		}

		/*
		 * Search for Children of this node ie. Cards.
		 * Note: any of these cards can be a pci-bridge
		 *	that itself has children. If we find a
		 *	pci-bridge we need to handle it specially.
		 */
		card_node = pci->child;
		while (card_node != NULL) {
			pci_bridge = 0;

			/* If it doesn't have a name, skip it */
			name = (char *)get_prop_val(
			    find_prop(card_node, "name"));
			if (name == NULL) {
				card_node = card_node->sibling;
				continue;
			}

			/*
			 * get dev# and func# for this card from the
			 * 'reg' property.
			 */
			int_val = (int *)get_prop_val(
			    find_prop(card_node, "reg"));
			if (int_val != NULL) {
				card.dev_no = (((*int_val) & 0xF800) >> 11);
				card.func_no = (((*int_val) & 0x700) >> 8);
			} else {
				card.dev_no = -1;
				card.func_no = -1;
			}

			/*
			 * If this is a pci-bridge, then store it's dev#
			 * as its children nodes need this to get their slot#.
			 * We set the pci_bridge flag so that we know we are
			 * looking at a pci-bridge node. This flag gets reset
			 * every time we enter this while loop.
			 */

			/*
			 * Check for a PCI-PCI Bridge for PCI and cPCI
			 * IO Boards using the name and type properties.
			 */
			type = (char *)get_prop_val(
			    find_prop(card_node, "device_type"));
			if ((type != NULL) &&
			    (strncmp(name, "pci", 3) == 0) &&
			    (strcmp(type, "pci") == 0)) {
				pci_bridge_dev_no = card.dev_no;
				pci_bridge_node = card_node;
				pci_bridge = TRUE;
			}

			/*
			 * Get slot-names property from slot_names_arr.
			 * If we are the child of a pci_bridge we use the
			 * dev# of the pci_bridge as an index to get
			 * the slot number. We know that we are a child of
			 * a pci-bridge if our parent is the same as the last
			 * pci_bridge node found above.
			 */
			if (card.dev_no != -1) {
				/*
				 * We compare this card's parent node with the
				 * pci_bridge_node to see if it's a child.
				 */
				if (card_node->parent == pci_bridge_node) {
					/* use dev_no of pci_bridge */
					child_dev_no = pci_bridge_dev_no - 1;
				} else {
					/* use card's own dev_no */
					child_dev_no = card.dev_no - 1;
				}

				if (child_dev_no < MAX_SLOTS_PER_IO_BD &&
				    child_dev_no >= 0 &&
				    slot_name_arr
				    [child_dev_no + slot_name_offset] != NULL) {

					slot_name = slot_name_arr[
					    child_dev_no + slot_name_offset];
				} else
					slot_name = (char *)NULL;

				if (slot_name != NULL && slot_name[0] != '\0') {
					(void) sprintf(card.slot_str, "%s",
					    slot_name);
				} else {
					(void) sprintf(card.slot_str, "-");
				}
			} else {
				(void) sprintf(card.slot_str, "%c", '-');
			}

			/*
			 * Get the portid of the schizo that this card
			 * lives under.
			 */
			portid = -1;
			value = get_prop_val(find_prop(pci, "portid"));
			if (value != NULL) {
				portid = *(int *)value;
			}
			card.schizo_portid = portid;

#ifdef	DEBUG
			(void) sprintf(card.notes, "%s portid [%d]"
			    " dev_no [%d] slot_name[%s] name_bits[%#x]",
			    card.notes, portid, card.dev_no,
			    ((slot_name != NULL) ? slot_name : "NULL"),
			    slot_name_bits);
#endif	/* DEBUG */

			/*
			 * Find out whether this is PCI bus A or B
			 * using the 'reg' property.
			 */
			int_val = (int *)get_prop_val
			    (find_prop(pci, "reg"));

			if (int_val != NULL) {
				int_val ++; /* skip over first integer */
				pci_bus = ((*int_val) & 0x7f0000);
				if (pci_bus == 0x600000)
					card.pci_bus = 'A';
				else if (pci_bus == 0x700000)
					card.pci_bus = 'B';
				else
					card.pci_bus = '-';
			} else {
				card.pci_bus = '-';
			}


			/*
			 * Check for failed status.
			 */
			if (node_failed(card_node))
				strcpy(card.status, "fail");
			else
				strcpy(card.status, "ok");

			/* Get the model of this card */
			value = get_prop_val(find_prop(card_node, "model"));
			if (value == NULL)
				card.model[0] = '\0';
			else {
				(void) sprintf(card.model, "%s", (char *)value);
				/*
				 * If we wish to exclude onboard devices
				 * (such as SBBC) then this is the place
				 * and here is how to do it:
				 *
				 * if (strcmp(card.model, "SUNW,sbbc") == 0) {
				 *	card_node = card_node->sibling;
				 *	continue;
				 * }
				 */
			}

			/*
			 * The card may have a "clock-frequency" but we
			 * are not interested in that. Instead we get the
			 * "clock-frequency" of the PCI Bus that the card
			 * resides on. PCI-A can operate at 33Mhz or 66Mhz
			 * depending on what card is plugged into the Bus.
			 * PCI-B always operates at 33Mhz.
			 *
			 */
			int_val = get_prop_val(find_prop(pci,
			    "clock-frequency"));
			if (int_val != NULL) {
				card.freq = HZ_TO_MHZ(*int_val);
			} else {
				card.freq = -1;
			}

			/*
			 * Figure out how we want to display the name
			 */
			value = get_prop_val(find_prop(card_node,
			    "compatible"));
			if (value != NULL) {
				/* use 'name'-'compatible' */
				(void) sprintf(buf, "%s-%s", name,
				    (char *)value);
			} else {
				/* just use 'name' */
				(void) sprintf(buf, "%s", name);
			}
			name = buf;

			/*
			 * If this node has children, add the device_type
			 * of the child to the name value of this card.
			 */
			child_name = (char *)get_node_name(card_node->child);
			if ((card_node->child != NULL) &&
			    (child_name != NULL)) {
				value = get_prop_val(find_prop(card_node->child,
				    "device_type"));
				if (value != NULL) {
					/* add device_type of child to name */
					(void) sprintf(card.name, "%s/%s (%s)",
					    name, child_name,
					    (char *)value);
				} else {
					/* just add child's name */
					(void) sprintf(card.name, "%s/%s",
					    name, child_name);
				}
			} else {
				/* childless, just the card's name */
				(void) sprintf(card.name, "%s", (char *)name);
			}

			/*
			 * If this is a pci-bridge, then add the word
			 * 'pci-bridge' to its model.
			 */
			if (pci_bridge) {
				if (card.model[0] == '\0')
					(void) sprintf(card.model,
					    "%s", "pci-bridge");
				else
					(void) strcat(card.model,
					    "/pci-bridge");
			}

			/* insert this card in the list to be displayed later */
			card_list = insert_io_card(card_list, &card);

			/*
			 * If we are dealing with a pci-bridge, we need to move
			 * down to the children of this bridge, if there are
			 * any, otherwise its siblings.
			 *
			 * If not a bridge, we are either dealing with a regular
			 * card (in which case we move onto the sibling of this
			 * card) or we are dealing with a child of a pci-bridge
			 * (in which case we move onto the child's siblings or
			 * if there are no more siblings for this child, we
			 * move onto the parent's siblings).  I hope you're
			 * getting all this, there will be an exam later.
			 */
			if (pci_bridge) {
				if (card_node->child != NULL)
					card_node = card_node->child;
				else
					card_node = card_node->sibling;
			} else {
				/*
				 * If our parent is a pci-bridge but there
				 * are no more of its children to process we
				 * move back up to our parent's sibling,
				 * otherwise we move onto our own sibling.
				 */
				if ((card_node->parent == pci_bridge_node) &&
				    (card_node->sibling == NULL))
					card_node =
					    pci_bridge_node->sibling;
				else
					card_node = card_node->sibling;
			}

		} /* end while (card_node ...) loop */

	} /* end for (pci ...) loop */

	display_io_cards(card_list);
	free_io_cards(card_list);
}

/*
 * display_ffb
 *
 * There are no FFB's on a Starcat, however in the generic library,
 * the display_ffb() function is implemented so we have to define an
 * empty function here.
 */
/*ARGSUSED0*/
void
display_ffb(Board_node *board, int table)
{
}

/*
 * add_node
 *
 * This function adds a board node to the board structure where that
 * that node's physical component lives.
 */
void
add_node(Sys_tree *root, Prom_node *pnode)
{
	int	portid = -1;
	int	nodeid = -1;
	void	*value;
	Board_node	*bnode;
	Prom_node	*p;
	char	*type;

	/* Get the board number of this board from the portid prop */
	if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
		if (type = get_node_type(pnode))
			if (strcmp(type, "cpu") == 0)
				value = get_prop_val(find_prop(pnode->parent,
				    "portid"));
	}
	if (value != NULL) {
		portid = *(int *)value;
		nodeid = PORTID_TO_EXPANDER(portid);
	}

	/* find the board node with the same board number */
	if ((bnode = find_board(root, portid)) == NULL) {
		bnode = insert_board(root, portid);
		bnode->board_type = UNKNOWN_BOARD;
		bnode->node_id = nodeid;
	}

	/* now attach this prom node to the board list */
	/* Insert this node at the end of the list */
	pnode->sibling = NULL;
	if (bnode->nodes == NULL)
		bnode->nodes = pnode;
	else {
		p = bnode->nodes;
		while (p->sibling != NULL)
			p = p->sibling;
		p->sibling = pnode;
	}
}



/*
 * Print out all the io cards in the list.  Also print the column
 * headers if told to do so.
 */
void
display_io_cards(struct io_card *list)
{
	char	*hdrfmt = "%-10.10s  %-4.4s %-4.4s %-4.4s %-4.4s %-4.4s"
	    " %-4.4s %-5.5s %-32.32s  %-22.22s"
#ifdef	DEBUG
	    "  %-22.22s"
#endif	/* DEBUG */
	    "\n";

	static int banner = FALSE; /* Have we printed the column headings? */
	struct io_card *p;

	if (list == NULL)
		return;

	(void) textdomain(TEXT_DOMAIN);

	if (banner == FALSE) {
		log_printf(hdrfmt,
		    "", "", "", "",
		    gettext("Bus"),
		    gettext("Max"),
		    "", "", "", "",
#ifdef	DEBUG
		    "",
#endif	/* DEBUG */
		    0);

		log_printf(hdrfmt,
		    "",
		    gettext("IO"),
		    gettext("Port"),
		    gettext("Bus"),
		    gettext("Freq"),
		    gettext("Bus"),
		    gettext("Dev,"),
		    "", "", "",
#ifdef	DEBUG
		    "",
#endif	/* DEBUG */
		    0);

		log_printf(hdrfmt,
		    gettext("Slot ID"),
		    gettext("Type"),
		    gettext(" ID"),
		    gettext("Side"),
		    gettext("MHz"),
		    gettext("Freq"),
		    gettext("Func"),
		    gettext("State"),
		    gettext("Name"),
		    gettext("Model"),
#ifdef	DEBUG
		    gettext("Notes"),
#endif	/* DEBUG */
		    0);

		log_printf(hdrfmt,
		    "----------", "----", "----", "----", "----", "----",
		    "----", "-----", "--------------------------------",
		    "----------------------",
#ifdef	DEBUG
		    "----------------------",
#endif	/* DEBUG */
		    0);

		banner = TRUE;
	}

	for (p = list; p != NULL; p = p -> next) {

		display_io_slot_info(p);

		display_io_max_bus_speed(p);

		log_printf("\n", 0);
	}
}


static void
display_io_slot_info(struct io_card *p)
{
	/*
	 * Onboard devices are distinguished by Slot IDs that
	 * indicate only the I/O board.  Plug-in cards indicate
	 * their leaf and Schizo.
	 */

	if (p->slot_str[0] == '-') {
		log_printf("/%-2s%02d       ",
		    SC_BOARD_TYPE(p->board),
		    PORTID_TO_EXPANDER(p->board), 0);
	} else {
		char	c;
		if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
			log_printf("/%-2s%02d/%s  ",
			    SC_BOARD_TYPE(p->board),
			    PORTID_TO_EXPANDER(p->board),
			    p->slot_str, 0);
		} else {
			if (p->pci_bus == 'A')
				c = '3';
			else if (p->pci_bus == 'B') {
				c = '5';
			} else
				c = '-';
			log_printf("/%-2s%02d/C%cV%1d  ",
			    SC_BOARD_TYPE(p->board),
			    PORTID_TO_EXPANDER(p->board), c,
			    PORTID_TO_INSTANCE(p->schizo_portid),
			    0);
		}
	}
	log_printf("%-4.4s ", gettext(p->bus_type), 0);
	log_printf("%3d  ", p->schizo_portid, 0);
	log_printf(" %c  ", p->pci_bus, 0);
	log_printf(" %3d  ", p->freq, 0);
}

#define	BUS_SPEED_PRINT(speed)	log_printf(" %d  ", speed, 0)

static void
display_io_max_bus_speed(struct io_card *p)
{
	int speed = board_bus_max_freq;

	switch (p->pci_bus) {
	case 'A':
		BUS_SPEED_PRINT(speed);
		break;
	case 'B':
		if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
			if (PORTID_TO_INSTANCE(p->schizo_portid) == 0)
				BUS_SPEED_PRINT(33);
			else
				BUS_SPEED_PRINT(speed);
		} else
			BUS_SPEED_PRINT(33);
		break;
	default:
		log_printf("  -  ", 0);
		break;
	}

	log_printf("%-1d,%-1d  ", p->dev_no, p->func_no, 0);
	log_printf("%-5.5s ", gettext(p->status), 0);
	log_printf("%-32.32s%c ", p->name,
	    ((strlen(p->name) > 32) ? '+' : ' '), 0);
	log_printf("%-22.22s%c", p->model,
	    ((strlen(p->model) > 22) ? '+' : ' '), 0);
#ifdef	DEBUG
	log_printf(" %s", p->notes, 0);
#endif	/* DEBUG */
}

void
display_cpu_devices(Sys_tree *tree)
{
	Board_node *bnode;
	char	*hdrfmt = "%-8.8s  %-7.7s  %-4.4s  %-4.4s  %-7.7s  %-4.4s\n";

	(void) textdomain(TEXT_DOMAIN);

	/*
	 * Display the table header for CPUs . Then display the CPU
	 * frequency, cache size, and processor revision of all cpus.
	 */
	log_printf("\n", 0);
	log_printf("=========================", 0);
	log_printf(gettext(" CPUs "), 0);
	log_printf("=========================", 0);
	log_printf("\n\n", 0);

	log_printf(hdrfmt,
	    "",
	    gettext("CPU "),
	    gettext("Run"),
	    gettext(" E$"),
	    gettext(" CPU"),
	    gettext("CPU"), 0);

	log_printf(hdrfmt,
	    gettext("Slot ID"),
	    gettext("ID "),
	    gettext("MHz"),
	    gettext(" MB"),
	    gettext("Impl."),
	    gettext("Mask"), 0);

	log_printf(hdrfmt,
	    "--------", "-------", "----", "----", "-------",  "----", 0);

	/* Now display all of the cpus on each board */
	bnode = tree->bd_list;
	while (bnode != NULL) {
		display_cpus(bnode);
		bnode = bnode->next;
	}

	log_printf("\n", 0);
}

/*
 * Display the CPUs present on this board.
 */
void
display_cpus(Board_node *board)
{
	Prom_node *cpu;
	uint_t freq;		/* CPU clock frequency */
	int ecache_size;	/* External cache size */
	int *impl;
	int *mask;
	int decoded_mask;
	int *cpuid;
	int *coreid;
	int cpuid_prev = -1;
	int ecache_size_prev = 0;

	(void) textdomain(TEXT_DOMAIN);
	/*
	 * display the CPUs' operating frequency, cache size, impl. field
	 * and mask revision.
	 */
	for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
	    cpu = dev_next_type(cpu, "cpu")) {

		freq = HZ_TO_MHZ(get_cpu_freq(cpu));
		ecache_size = get_ecache_size(cpu);
		impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
		mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
		cpuid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
		if (cpuid == NULL)
			cpuid = &board->board_num;

		/* Do not display a failed CPU node */
		if ((freq == 0) || (impl == 0) || (node_failed(cpu)))
			continue;

		if (CPU_IMPL_IS_CMP(*impl)) {
			coreid = (int *)get_prop_val(find_prop(cpu,
			    "reg"));
			if (coreid == NULL) {
				continue;
			}

			/*
			 * The assumption is made that 2 cores will always be
			 * listed together in the device tree. If either core
			 * is "bad" then the FRU will not be listed.
			 */
			if (cpuid_prev == -1) {
				cpuid_prev = *cpuid;
				ecache_size_prev = ecache_size;
				continue;
			} else {
				/*
				 * Jaguar has a split E$, so the size for both
				 * cores must be added together to get the total
				 * size for the entire chip.
				 *
				 * Panther E$ (L3) is logically shared, so the
				 * total size is equal to the core size.
				 */
				if (IS_JAGUAR(*impl)) {
					ecache_size += ecache_size_prev;
				}

				ecache_size_prev = 0;
			}
		}

		/*
		 * Print out cpu data.
		 *
		 * Slot ID
		 */
		log_printf("/%-2s%02d/P%1d  ",
		    SC_BOARD_TYPE(*cpuid),
		    PORTID_TO_EXPANDER(*cpuid),
		    PORTID_TO_INSTANCE(*cpuid), 0);

		/* CPU ID */
		if (CPU_IMPL_IS_CMP(*impl)) {
			log_printf("%3d,%3d  ", cpuid_prev,
			    *cpuid, 0);
			cpuid_prev = -1;
		} else
			log_printf("%3d      ", *cpuid, 0);

		/* Running frequency */
		log_printf("%4u  ", freq, 0);

		/* Ecache size */
		if (ecache_size == 0)
			log_printf("%-4.4s  ", gettext("N/A"), 0);
		else
			log_printf("%4.1f  ",
			    (float)ecache_size / (float)(1<<20),
			    0);

		/* Implementation */
		switch (*impl) {
		case CHEETAH_IMPL:
			log_printf("%-7.7s  ",
			    gettext("US-III"), 0);
			break;
		case CHEETAH_PLUS_IMPL:
			log_printf("%-7.7s  ",
			    gettext("US-III+"), 0);
			break;
		case JAGUAR_IMPL:
			log_printf("%-7.7s  ",
			    gettext("US-IV"), 0);
			break;
		case PANTHER_IMPL:
			log_printf("%-7.7s  ",
			    gettext("US-IV+"), 0);
			break;
		default:
			log_printf("%-7x  ", *impl, 0);
			break;
		}

		/* CPU Mask */
		if (mask == NULL) {
			log_printf("%-4.4s", gettext("N/A"), 0);
		} else {
			if (IS_CHEETAH(*impl))
				decoded_mask = REMAP_CHEETAH_MASK(*mask);
			else
				decoded_mask = *mask;

			log_printf("%d.%d",
			    (decoded_mask >> 4) & 0xf,
			    decoded_mask & 0xf, 0);
		}

		log_printf("\n", 0);
	}
}


/*ARGSUSED1*/
void
display_memoryconf(Sys_tree *tree, struct grp_info *grps)
{
	Board_node	*bnode = tree->bd_list;
	char	*hdrfmt = "\n%-11.11s  %-4.4s  %-7.7s  %-7.7s  %-8.8s  %-6.6s"
	    "  %-10.10s  %-10.10s";

	(void) textdomain(TEXT_DOMAIN);

	log_printf("=========================", 0);
	log_printf(gettext(" Memory Configuration "), 0);
	log_printf("=========================", 0);
	log_printf("\n", 0);

	log_printf(hdrfmt,
	    "", "",
	    gettext("Logical"),
	    gettext("Logical"),
	    gettext("Logical"),
	    "", "", "", 0);

	log_printf(hdrfmt,
	    "",
	    gettext("Port"),
	    gettext("Bank"),
	    gettext("Bank"),
	    gettext("Bank"),
	    gettext(" DIMM"),
	    gettext("Interleave"),
	    gettext("Interleave"), 0);

	log_printf(hdrfmt,
	    gettext("Slot ID"),
	    gettext(" ID"),
	    gettext("Number"),
	    gettext("Size"),
	    gettext("Status"),
	    gettext(" Size"),
	    gettext("Factor"),
	    gettext("Segment"), 0);

	log_printf(hdrfmt,
	    "-----------", "----", "-------", "-------", "--------",
	    "------", "----------", "----------", 0);

	while (bnode != NULL) {
		if (get_us3_mem_regs(bnode)) {
			log_printf(
			    gettext(
			    "\nFailed to get memory information.\n"),
			    0);
			return;
		}
		bnode = bnode->next;
	}

	/* Display what we have found */
	display_us3_banks();
}


/*
 * This function provides Starcat's formatting of the memory config
 * information that get_us3_mem_regs() and display_us3_banks() code has
 * gathered. It overrides the generic print_us3_memory_line() code
 * which prints an error message.
 */
void
print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
	char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
{
	(void) textdomain(TEXT_DOMAIN);

	/* Slot ID */
	log_printf("\n/%-2s%02d/P%1d/B%1d  ",
	    SC_BOARD_TYPE(portid), PORTID_TO_EXPANDER(portid),
	    PORTID_TO_INSTANCE(portid), (bank_id & 0x1), 0);

	/* Port ID */
	log_printf("%3d   ", portid, 0);

	/* Logical Bank Number */
	log_printf("   %1d     ", (bank_id & 0x3), 0);

	/* Logical Bank Size */
	log_printf("%4lldMB   ", bank_size, 0);

	/* Logical Bank Status */
	log_printf("%-8.8s  ", gettext(bank_status), 0);

	/* DIMM Size */
	log_printf("%4lldMB  ", dimm_size, 0);

	/* Interleave Factor */
	log_printf("  %2d-%-3.3s    ", intlv, gettext("way"), 0);

	/* Interleave Segment */
	log_printf("   %3d", seg_id, 0);
}

/*ARGSUSED2*/
void
display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
	struct system_kstat_data *kstats)
{
	if (flag) {
		/*
		 * display time of latest powerfail. Not all systems
		 * have this capability. For those that do not, this
		 * is just a no-op.
		 */
		disp_powerfail(root);

		(void) textdomain(TEXT_DOMAIN);

		/* Print the header */
		log_printf("\n", 0);
		log_printf("=========================", 0);
		log_printf(gettext(" Diagnostic Information "), 0);
		log_printf("=========================", 0);
		log_printf("\n\n", 0);
		log_printf(gettext("For diagnostic information,"), 0);
		log_printf("\n", 0);
		log_printf(gettext(
		    "see /var/opt/SUNWSMS/adm/[A-R]/messages on the SC."),
		    0);
		log_printf("\n", 0);

		/* Print the PROM revisions here */
		starcat_disp_hw_revisions(root);
	}
}

/*
 * local functions -  functions that are only needed inside this library
 */

static void
starcat_disp_hw_revisions(Prom_node *root)
{
	Prom_node	*pnode;
	char		*version;

	(void) textdomain(TEXT_DOMAIN);

	/* Print the header */
	log_printf("\n", 0);
	log_printf("=========================", 0);
	log_printf(gettext(" Hardware Revisions "), 0);
	log_printf("=========================", 0);
	log_printf("\n\n", 0);

	/* Display Prom revision header */
	log_printf(gettext("OpenBoot firmware revision:"), 0);
	log_printf("\n---------------------------\n", 0);

	/*
	 * Display OBP version info
	 */
	pnode = dev_find_node(root, "openprom");
	if (pnode != NULL) {
		version = (char *)get_prop_val(find_prop(pnode, "version"));
		log_printf("%s\n\n", version, 0);
	}
}

/*
 * We call do_devinfo() in order to use the libdevinfo device tree
 * instead of OBP's device tree.
 */
int
do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
{

	return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));

}

/*
 * return the property value for the Prop
 * passed in. (When using libdevinfo)
 */
void *
get_prop_val(Prop *prop)
{
	if (prop == NULL)
		return (NULL);

	return ((void *)(prop->value.val_ptr));
}

/*
 * Search a Prom node and retrieve the property with the correct
 * name. (When using libdevinfo)
 */
Prop *
find_prop(Prom_node *pnode, char *name)
{
	Prop *prop;

	if (pnode == NULL)
		return (NULL);

	for (prop = pnode->props; prop != NULL; prop = prop->next) {
		if (prop->name.val_ptr != NULL &&
		    strcmp((char *)(prop->name.val_ptr), name) == 0)
			break;
	}

	return (prop);
}

/*
 * This function searches through the properties of the node passed in
 * and returns a pointer to the value of the name property.
 * (When using libdevinfo)
 */
char *
get_node_name(Prom_node *pnode)
{
	Prop *prop;

	if (pnode == NULL) {
		return (NULL);
	}

	prop = pnode->props;
	while (prop != NULL) {
		if (strcmp("name", (char *)prop->name.val_ptr) == 0)
			return (prop->value.val_ptr);
		prop = prop->next;
	}
	return (NULL);
}

/*
 * This function searches through the properties of the node passed in
 * and returns a pointer to the value of the device_type property.
 * (When using libdevinfo)
 */
char *
get_node_type(Prom_node *pnode)
{
	Prop *prop;

	if (pnode == NULL) {
		return (NULL);
	}

	prop = pnode->props;
	while (prop != NULL) {
		if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
			return (prop->value.val_ptr);
		prop = prop->next;
	}
	return (NULL);
}