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  * Starcat Platform specific functions.
     26  *
     27  * 	called when :
     28  *	machine_type == MTYPE_STARCAT
     29  */
     30 
     31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     32 
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <unistd.h>
     36 #include <ctype.h>
     37 #include <string.h>
     38 #include <kvm.h>
     39 #include <varargs.h>
     40 #include <time.h>
     41 #include <dirent.h>
     42 #include <fcntl.h>
     43 #include <assert.h>
     44 #include <sys/param.h>
     45 #include <sys/stat.h>
     46 #include <sys/types.h>
     47 #include <sys/utsname.h>
     48 #include <sys/openpromio.h>
     49 #include <libintl.h>
     50 #include <syslog.h>
     51 #include <sys/dkio.h>
     52 #include <pdevinfo.h>
     53 #include <display.h>
     54 #include <pdevinfo_sun4u.h>
     55 #include <display_sun4u.h>
     56 #include <libprtdiag.h>
     57 
     58 #define	HZ_TO_MHZ(x)		(((x) + 500000) / 1000000)
     59 #define	PORTID_TO_EXPANDER(p)	(((p) >> 5) & 0x1f)
     60 #define	PORTID_TO_SLOT(p)	(((p) >> 3) & 0x1)
     61 #define	PORTID_TO_INSTANCE(p)	((p) & 0x3)
     62 #define	SCHIZO_COMPATIBLE	"pci108e,8001"
     63 #define	XMITS_COMPATIBLE	"pci108e,8002"
     64 #define	SC_BOARD_TYPE(id)	(PORTID_TO_SLOT(id) ? "IO" : "SB")
     65 
     66 #ifndef	TEXT_DOMAIN
     67 #define	TEXT_DOMAIN	"SYS_TEST"
     68 #endif	/* TEXT_DOMAIN */
     69 
     70 #define	DEFAULT_MAX_FREQ	66	/* 66 MHz */
     71 #define	PCIX_MAX_FREQ		90	/* 90 MHz */
     72 
     73 /*
     74  * these functions will overlay the symbol table of libprtdiag
     75  * at runtime (Starcat systems only)
     76  */
     77 
     78 int	do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
     79 void	*get_prop_val(Prop *prop);
     80 Prop	*find_prop(Prom_node *pnode, char *name);
     81 char	*get_node_name(Prom_node *pnode);
     82 char	*get_node_type(Prom_node *pnode);
     83 void	add_node(Sys_tree *, Prom_node *);
     84 void	display_pci(Board_node *);
     85 void	display_ffb(Board_node *, int);
     86 void	display_io_cards(struct io_card *list);
     87 void	display_cpu_devices(Sys_tree *tree);
     88 void	display_cpus(Board_node *board);
     89 void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
     90 void	print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
     91 	    char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
     92 void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
     93 		struct system_kstat_data *kstats);
     94 
     95 /* Local Functions */
     96 static void	starcat_disp_hw_revisions(Prom_node *root);
     97 static void display_io_max_bus_speed(struct io_card *p);
     98 static void display_io_slot_info(struct io_card *p);
     99 
    100 /* The bus max freq is determined based on board level in use */
    101 int	board_bus_max_freq = DEFAULT_MAX_FREQ;	/* 66MHz default */
    102 
    103 /*
    104  * display_pci
    105  * Display all the PCI IO cards on this board.
    106  */
    107 void
    108 display_pci(Board_node *board)
    109 {
    110 	struct io_card *card_list = NULL;
    111 	struct io_card card;
    112 	void *value;
    113 	Prom_node *pci;
    114 	Prom_node *card_node;
    115 	Prom_node *pci_bridge_node = NULL;
    116 	char	*slot_name_arr[MAX_SLOTS_PER_IO_BD] = {NULL};
    117 	char	*slot_name = NULL;
    118 	int	slot_name_bits;
    119 	int	slot_name_offset = 0;
    120 	char	*child_name;
    121 	char	*name, *type;
    122 	char	buf[MAXSTRLEN];
    123 	int	*int_val;
    124 	int	pci_bus;
    125 	int	pci_bridge = 0;
    126 	int	pci_bridge_dev_no;
    127 	int	child_dev_no;
    128 	int	i;
    129 	int	portid;
    130 	int	version, *pversion;
    131 
    132 	if (board == NULL)
    133 		return;
    134 
    135 	/* Initialize all the common information */
    136 	card.display = TRUE;
    137 	card.board = board->board_num;
    138 	card.node_id = board->node_id;
    139 
    140 	/*
    141 	 * Search for each schizo, then find/display all nodes under
    142 	 * each schizo node found.  Since the model property "SUNW,schizo"
    143 	 * is not supported on Starcat, we must match on the compatible
    144 	 * property "pci108e,8001".
    145 	 */
    146 	for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
    147 	    pci != NULL;
    148 	    pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {
    149 
    150 		/* set max freq for this board */
    151 		board_bus_max_freq = DEFAULT_MAX_FREQ;
    152 		/*
    153 		 * Find out if this is a PCI or cPCI IO Board.
    154 		 * If "enum-impl" property exists in pci node => cPCI.
    155 		 */
    156 		value = get_prop_val(find_prop(pci, "enum-impl"));
    157 		if (value == NULL) {
    158 			(void) sprintf(card.bus_type, "PCI");
    159 		} else {
    160 			(void) sprintf(card.bus_type, "cPCI");
    161 		}
    162 
    163 		if (strstr((char *)get_prop_val(
    164 		    find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
    165 			sprintf(card.notes, "%s", XMITS_COMPATIBLE);
    166 			/*
    167 			 * With XMITS 3.X and PCI-X mode, the bus speed
    168 			 * can be higher than 66MHZ.
    169 			 */
    170 			value = (int *)get_prop_val
    171 			    (find_prop(pci, "module-revision#"));
    172 			if (value) {
    173 				pversion = (int *)value;
    174 				version = *pversion;
    175 				if (version >= 4)
    176 					board_bus_max_freq = PCIX_MAX_FREQ;
    177 			}
    178 		} else if (strstr((char *)get_prop_val(
    179 		    find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
    180 			sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
    181 		else
    182 			sprintf(card.notes, " ");
    183 
    184 		/*
    185 		 * Get slot-names property from parent node and
    186 		 * store the individual slot names in an array.
    187 		 * This is more general than Starcat requires, but
    188 		 * it is correct, according to the slot-names property.
    189 		 */
    190 		value = (char *)get_prop_val(find_prop(pci, "slot-names"));
    191 		if (value == NULL) {
    192 			/*
    193 			 * No slot_names property.  This could be an Xmits
    194 			 * card, so check the child node for slot-names property
    195 			 */
    196 			value = (char *)get_prop_val(
    197 			    find_prop(pci->child, "slot-names"));
    198 		}
    199 
    200 		if (value != NULL) {
    201 			/* Get the 4 byte bitmask and pointer to first name */
    202 			slot_name_bits = *(int *)value;
    203 			if (slot_name_bits > 0)
    204 				slot_name_offset = slot_name_bits - 1;
    205 			slot_name = (char *)value + sizeof (int);
    206 
    207 			for (i = 0; i < MAX_SLOTS_PER_IO_BD; i++) {
    208 				if (! (slot_name_bits & (1 << i))) {
    209 					slot_name_arr[i] = (char *)NULL;
    210 					continue;
    211 				}
    212 
    213 				/*
    214 				 * Save the name pointer into the array
    215 				 * and advance it past the end of this
    216 				 * slot name
    217 				 */
    218 				slot_name_arr[i] = slot_name;
    219 				slot_name += strlen(slot_name) + 1;
    220 			}
    221 			slot_name = (char *)NULL;
    222 		}
    223 
    224 		/*
    225 		 * Search for Children of this node ie. Cards.
    226 		 * Note: any of these cards can be a pci-bridge
    227 		 *	that itself has children. If we find a
    228 		 *	pci-bridge we need to handle it specially.
    229 		 */
    230 		card_node = pci->child;
    231 		while (card_node != NULL) {
    232 			pci_bridge = 0;
    233 
    234 			/* If it doesn't have a name, skip it */
    235 			name = (char *)get_prop_val(
    236 			    find_prop(card_node, "name"));
    237 			if (name == NULL) {
    238 				card_node = card_node->sibling;
    239 				continue;
    240 			}
    241 
    242 			/*
    243 			 * get dev# and func# for this card from the
    244 			 * 'reg' property.
    245 			 */
    246 			int_val = (int *)get_prop_val(
    247 			    find_prop(card_node, "reg"));
    248 			if (int_val != NULL) {
    249 				card.dev_no = (((*int_val) & 0xF800) >> 11);
    250 				card.func_no = (((*int_val) & 0x700) >> 8);
    251 			} else {
    252 				card.dev_no = -1;
    253 				card.func_no = -1;
    254 			}
    255 
    256 			/*
    257 			 * If this is a pci-bridge, then store it's dev#
    258 			 * as its children nodes need this to get their slot#.
    259 			 * We set the pci_bridge flag so that we know we are
    260 			 * looking at a pci-bridge node. This flag gets reset
    261 			 * every time we enter this while loop.
    262 			 */
    263 
    264 			/*
    265 			 * Check for a PCI-PCI Bridge for PCI and cPCI
    266 			 * IO Boards using the name and type properties.
    267 			 */
    268 			type = (char *)get_prop_val(
    269 			    find_prop(card_node, "device_type"));
    270 			if ((type != NULL) &&
    271 			    (strncmp(name, "pci", 3) == 0) &&
    272 			    (strcmp(type, "pci") == 0)) {
    273 				pci_bridge_dev_no = card.dev_no;
    274 				pci_bridge_node = card_node;
    275 				pci_bridge = TRUE;
    276 			}
    277 
    278 			/*
    279 			 * Get slot-names property from slot_names_arr.
    280 			 * If we are the child of a pci_bridge we use the
    281 			 * dev# of the pci_bridge as an index to get
    282 			 * the slot number. We know that we are a child of
    283 			 * a pci-bridge if our parent is the same as the last
    284 			 * pci_bridge node found above.
    285 			 */
    286 			if (card.dev_no != -1) {
    287 				/*
    288 				 * We compare this card's parent node with the
    289 				 * pci_bridge_node to see if it's a child.
    290 				 */
    291 				if (card_node->parent == pci_bridge_node) {
    292 					/* use dev_no of pci_bridge */
    293 					child_dev_no = pci_bridge_dev_no - 1;
    294 				} else {
    295 					/* use card's own dev_no */
    296 					child_dev_no = card.dev_no - 1;
    297 				}
    298 
    299 				if (child_dev_no < MAX_SLOTS_PER_IO_BD &&
    300 				    child_dev_no >= 0 &&
    301 				    slot_name_arr
    302 				    [child_dev_no + slot_name_offset] != NULL) {
    303 
    304 					slot_name = slot_name_arr[
    305 					    child_dev_no + slot_name_offset];
    306 				} else
    307 					slot_name = (char *)NULL;
    308 
    309 				if (slot_name != NULL && slot_name[0] != '\0') {
    310 					(void) sprintf(card.slot_str, "%s",
    311 					    slot_name);
    312 				} else {
    313 					(void) sprintf(card.slot_str, "-");
    314 				}
    315 			} else {
    316 				(void) sprintf(card.slot_str, "%c", '-');
    317 			}
    318 
    319 			/*
    320 			 * Get the portid of the schizo that this card
    321 			 * lives under.
    322 			 */
    323 			portid = -1;
    324 			value = get_prop_val(find_prop(pci, "portid"));
    325 			if (value != NULL) {
    326 				portid = *(int *)value;
    327 			}
    328 			card.schizo_portid = portid;
    329 
    330 #ifdef	DEBUG
    331 			(void) sprintf(card.notes, "%s portid [%d]"
    332 			    " dev_no [%d] slot_name[%s] name_bits[%#x]",
    333 			    card.notes, portid, card.dev_no,
    334 			    ((slot_name != NULL) ? slot_name : "NULL"),
    335 			    slot_name_bits);
    336 #endif	/* DEBUG */
    337 
    338 			/*
    339 			 * Find out whether this is PCI bus A or B
    340 			 * using the 'reg' property.
    341 			 */
    342 			int_val = (int *)get_prop_val
    343 			    (find_prop(pci, "reg"));
    344 
    345 			if (int_val != NULL) {
    346 				int_val ++; /* skip over first integer */
    347 				pci_bus = ((*int_val) & 0x7f0000);
    348 				if (pci_bus == 0x600000)
    349 					card.pci_bus = 'A';
    350 				else if (pci_bus == 0x700000)
    351 					card.pci_bus = 'B';
    352 				else
    353 					card.pci_bus = '-';
    354 			} else {
    355 				card.pci_bus = '-';
    356 			}
    357 
    358 
    359 			/*
    360 			 * Check for failed status.
    361 			 */
    362 			if (node_failed(card_node))
    363 				strcpy(card.status, "fail");
    364 			else
    365 				strcpy(card.status, "ok");
    366 
    367 			/* Get the model of this card */
    368 			value = get_prop_val(find_prop(card_node, "model"));
    369 			if (value == NULL)
    370 				card.model[0] = '\0';
    371 			else {
    372 				(void) sprintf(card.model, "%s", (char *)value);
    373 				/*
    374 				 * If we wish to exclude onboard devices
    375 				 * (such as SBBC) then this is the place
    376 				 * and here is how to do it:
    377 				 *
    378 				 * if (strcmp(card.model, "SUNW,sbbc") == 0) {
    379 				 *	card_node = card_node->sibling;
    380 				 *	continue;
    381 				 * }
    382 				 */
    383 			}
    384 
    385 			/*
    386 			 * The card may have a "clock-frequency" but we
    387 			 * are not interested in that. Instead we get the
    388 			 * "clock-frequency" of the PCI Bus that the card
    389 			 * resides on. PCI-A can operate at 33Mhz or 66Mhz
    390 			 * depending on what card is plugged into the Bus.
    391 			 * PCI-B always operates at 33Mhz.
    392 			 *
    393 			 */
    394 			int_val = get_prop_val(find_prop(pci,
    395 			    "clock-frequency"));
    396 			if (int_val != NULL) {
    397 				card.freq = HZ_TO_MHZ(*int_val);
    398 			} else {
    399 				card.freq = -1;
    400 			}
    401 
    402 			/*
    403 			 * Figure out how we want to display the name
    404 			 */
    405 			value = get_prop_val(find_prop(card_node,
    406 			    "compatible"));
    407 			if (value != NULL) {
    408 				/* use 'name'-'compatible' */
    409 				(void) sprintf(buf, "%s-%s", name,
    410 				    (char *)value);
    411 			} else {
    412 				/* just use 'name' */
    413 				(void) sprintf(buf, "%s", name);
    414 			}
    415 			name = buf;
    416 
    417 			/*
    418 			 * If this node has children, add the device_type
    419 			 * of the child to the name value of this card.
    420 			 */
    421 			child_name = (char *)get_node_name(card_node->child);
    422 			if ((card_node->child != NULL) &&
    423 			    (child_name != NULL)) {
    424 				value = get_prop_val(find_prop(card_node->child,
    425 				    "device_type"));
    426 				if (value != NULL) {
    427 					/* add device_type of child to name */
    428 					(void) sprintf(card.name, "%s/%s (%s)",
    429 					    name, child_name,
    430 					    (char *)value);
    431 				} else {
    432 					/* just add child's name */
    433 					(void) sprintf(card.name, "%s/%s",
    434 					    name, child_name);
    435 				}
    436 			} else {
    437 				/* childless, just the card's name */
    438 				(void) sprintf(card.name, "%s", (char *)name);
    439 			}
    440 
    441 			/*
    442 			 * If this is a pci-bridge, then add the word
    443 			 * 'pci-bridge' to its model.
    444 			 */
    445 			if (pci_bridge) {
    446 				if (card.model[0] == '\0')
    447 					(void) sprintf(card.model,
    448 					    "%s", "pci-bridge");
    449 				else
    450 					(void) strcat(card.model,
    451 					    "/pci-bridge");
    452 			}
    453 
    454 			/* insert this card in the list to be displayed later */
    455 			card_list = insert_io_card(card_list, &card);
    456 
    457 			/*
    458 			 * If we are dealing with a pci-bridge, we need to move
    459 			 * down to the children of this bridge, if there are
    460 			 * any, otherwise its siblings.
    461 			 *
    462 			 * If not a bridge, we are either dealing with a regular
    463 			 * card (in which case we move onto the sibling of this
    464 			 * card) or we are dealing with a child of a pci-bridge
    465 			 * (in which case we move onto the child's siblings or
    466 			 * if there are no more siblings for this child, we
    467 			 * move onto the parent's siblings).  I hope you're
    468 			 * getting all this, there will be an exam later.
    469 			 */
    470 			if (pci_bridge) {
    471 				if (card_node->child != NULL)
    472 					card_node = card_node->child;
    473 				else
    474 					card_node = card_node->sibling;
    475 			} else {
    476 				/*
    477 				 * If our parent is a pci-bridge but there
    478 				 * are no more of its children to process we
    479 				 * move back up to our parent's sibling,
    480 				 * otherwise we move onto our own sibling.
    481 				 */
    482 				if ((card_node->parent == pci_bridge_node) &&
    483 				    (card_node->sibling == NULL))
    484 					card_node =
    485 					    pci_bridge_node->sibling;
    486 				else
    487 					card_node = card_node->sibling;
    488 			}
    489 
    490 		} /* end while (card_node ...) loop */
    491 
    492 	} /* end for (pci ...) loop */
    493 
    494 	display_io_cards(card_list);
    495 	free_io_cards(card_list);
    496 }
    497 
    498 /*
    499  * display_ffb
    500  *
    501  * There are no FFB's on a Starcat, however in the generic library,
    502  * the display_ffb() function is implemented so we have to define an
    503  * empty function here.
    504  */
    505 /*ARGSUSED0*/
    506 void
    507 display_ffb(Board_node *board, int table)
    508 {
    509 }
    510 
    511 /*
    512  * add_node
    513  *
    514  * This function adds a board node to the board structure where that
    515  * that node's physical component lives.
    516  */
    517 void
    518 add_node(Sys_tree *root, Prom_node *pnode)
    519 {
    520 	int	portid = -1;
    521 	int	nodeid = -1;
    522 	void	*value;
    523 	Board_node	*bnode;
    524 	Prom_node	*p;
    525 	char	*type;
    526 
    527 	/* Get the board number of this board from the portid prop */
    528 	if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
    529 		if (type = get_node_type(pnode))
    530 			if (strcmp(type, "cpu") == 0)
    531 				value = get_prop_val(find_prop(pnode->parent,
    532 				    "portid"));
    533 	}
    534 	if (value != NULL) {
    535 		portid = *(int *)value;
    536 		nodeid = PORTID_TO_EXPANDER(portid);
    537 	}
    538 
    539 	/* find the board node with the same board number */
    540 	if ((bnode = find_board(root, portid)) == NULL) {
    541 		bnode = insert_board(root, portid);
    542 		bnode->board_type = UNKNOWN_BOARD;
    543 		bnode->node_id = nodeid;
    544 	}
    545 
    546 	/* now attach this prom node to the board list */
    547 	/* Insert this node at the end of the list */
    548 	pnode->sibling = NULL;
    549 	if (bnode->nodes == NULL)
    550 		bnode->nodes = pnode;
    551 	else {
    552 		p = bnode->nodes;
    553 		while (p->sibling != NULL)
    554 			p = p->sibling;
    555 		p->sibling = pnode;
    556 	}
    557 }
    558 
    559 
    560 
    561 /*
    562  * Print out all the io cards in the list.  Also print the column
    563  * headers if told to do so.
    564  */
    565 void
    566 display_io_cards(struct io_card *list)
    567 {
    568 	char	*hdrfmt = "%-10.10s  %-4.4s %-4.4s %-4.4s %-4.4s %-4.4s"
    569 	    " %-4.4s %-5.5s %-32.32s  %-22.22s"
    570 #ifdef	DEBUG
    571 	    "  %-22.22s"
    572 #endif	/* DEBUG */
    573 	    "\n";
    574 
    575 	static int banner = FALSE; /* Have we printed the column headings? */
    576 	struct io_card *p;
    577 
    578 	if (list == NULL)
    579 		return;
    580 
    581 	(void) textdomain(TEXT_DOMAIN);
    582 
    583 	if (banner == FALSE) {
    584 		log_printf(hdrfmt,
    585 		    "", "", "", "",
    586 		    gettext("Bus"),
    587 		    gettext("Max"),
    588 		    "", "", "", "",
    589 #ifdef	DEBUG
    590 		    "",
    591 #endif	/* DEBUG */
    592 		    0);
    593 
    594 		log_printf(hdrfmt,
    595 		    "",
    596 		    gettext("IO"),
    597 		    gettext("Port"),
    598 		    gettext("Bus"),
    599 		    gettext("Freq"),
    600 		    gettext("Bus"),
    601 		    gettext("Dev,"),
    602 		    "", "", "",
    603 #ifdef	DEBUG
    604 		    "",
    605 #endif	/* DEBUG */
    606 		    0);
    607 
    608 		log_printf(hdrfmt,
    609 		    gettext("Slot ID"),
    610 		    gettext("Type"),
    611 		    gettext(" ID"),
    612 		    gettext("Side"),
    613 		    gettext("MHz"),
    614 		    gettext("Freq"),
    615 		    gettext("Func"),
    616 		    gettext("State"),
    617 		    gettext("Name"),
    618 		    gettext("Model"),
    619 #ifdef	DEBUG
    620 		    gettext("Notes"),
    621 #endif	/* DEBUG */
    622 		    0);
    623 
    624 		log_printf(hdrfmt,
    625 		    "----------", "----", "----", "----", "----", "----",
    626 		    "----", "-----", "--------------------------------",
    627 		    "----------------------",
    628 #ifdef	DEBUG
    629 		    "----------------------",
    630 #endif	/* DEBUG */
    631 		    0);
    632 
    633 		banner = TRUE;
    634 	}
    635 
    636 	for (p = list; p != NULL; p = p -> next) {
    637 
    638 		display_io_slot_info(p);
    639 
    640 		display_io_max_bus_speed(p);
    641 
    642 		log_printf("\n", 0);
    643 	}
    644 }
    645 
    646 
    647 static void
    648 display_io_slot_info(struct io_card *p)
    649 {
    650 	/*
    651 	 * Onboard devices are distinguished by Slot IDs that
    652 	 * indicate only the I/O board.  Plug-in cards indicate
    653 	 * their leaf and Schizo.
    654 	 */
    655 
    656 	if (p->slot_str[0] == '-') {
    657 		log_printf("/%-2s%02d       ",
    658 		    SC_BOARD_TYPE(p->board),
    659 		    PORTID_TO_EXPANDER(p->board), 0);
    660 	} else {
    661 		char	c;
    662 		if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
    663 			log_printf("/%-2s%02d/%s  ",
    664 			    SC_BOARD_TYPE(p->board),
    665 			    PORTID_TO_EXPANDER(p->board),
    666 			    p->slot_str, 0);
    667 		} else {
    668 			if (p->pci_bus == 'A')
    669 				c = '3';
    670 			else if (p->pci_bus == 'B') {
    671 				c = '5';
    672 			} else
    673 				c = '-';
    674 			log_printf("/%-2s%02d/C%cV%1d  ",
    675 			    SC_BOARD_TYPE(p->board),
    676 			    PORTID_TO_EXPANDER(p->board), c,
    677 			    PORTID_TO_INSTANCE(p->schizo_portid),
    678 			    0);
    679 		}
    680 	}
    681 	log_printf("%-4.4s ", gettext(p->bus_type), 0);
    682 	log_printf("%3d  ", p->schizo_portid, 0);
    683 	log_printf(" %c  ", p->pci_bus, 0);
    684 	log_printf(" %3d  ", p->freq, 0);
    685 }
    686 
    687 #define	BUS_SPEED_PRINT(speed)	log_printf(" %d  ", speed, 0)
    688 
    689 static void
    690 display_io_max_bus_speed(struct io_card *p)
    691 {
    692 	int speed = board_bus_max_freq;
    693 
    694 	switch (p->pci_bus) {
    695 	case 'A':
    696 		BUS_SPEED_PRINT(speed);
    697 		break;
    698 	case 'B':
    699 		if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
    700 			if (PORTID_TO_INSTANCE(p->schizo_portid) == 0)
    701 				BUS_SPEED_PRINT(33);
    702 			else
    703 				BUS_SPEED_PRINT(speed);
    704 		} else
    705 			BUS_SPEED_PRINT(33);
    706 		break;
    707 	default:
    708 		log_printf("  -  ", 0);
    709 		break;
    710 	}
    711 
    712 	log_printf("%-1d,%-1d  ", p->dev_no, p->func_no, 0);
    713 	log_printf("%-5.5s ", gettext(p->status), 0);
    714 	log_printf("%-32.32s%c ", p->name,
    715 	    ((strlen(p->name) > 32) ? '+' : ' '), 0);
    716 	log_printf("%-22.22s%c", p->model,
    717 	    ((strlen(p->model) > 22) ? '+' : ' '), 0);
    718 #ifdef	DEBUG
    719 	log_printf(" %s", p->notes, 0);
    720 #endif	/* DEBUG */
    721 }
    722 
    723 void
    724 display_cpu_devices(Sys_tree *tree)
    725 {
    726 	Board_node *bnode;
    727 	char	*hdrfmt = "%-8.8s  %-7.7s  %-4.4s  %-4.4s  %-7.7s  %-4.4s\n";
    728 
    729 	(void) textdomain(TEXT_DOMAIN);
    730 
    731 	/*
    732 	 * Display the table header for CPUs . Then display the CPU
    733 	 * frequency, cache size, and processor revision of all cpus.
    734 	 */
    735 	log_printf("\n", 0);
    736 	log_printf("=========================", 0);
    737 	log_printf(gettext(" CPUs "), 0);
    738 	log_printf("=========================", 0);
    739 	log_printf("\n\n", 0);
    740 
    741 	log_printf(hdrfmt,
    742 	    "",
    743 	    gettext("CPU "),
    744 	    gettext("Run"),
    745 	    gettext(" E$"),
    746 	    gettext(" CPU"),
    747 	    gettext("CPU"), 0);
    748 
    749 	log_printf(hdrfmt,
    750 	    gettext("Slot ID"),
    751 	    gettext("ID "),
    752 	    gettext("MHz"),
    753 	    gettext(" MB"),
    754 	    gettext("Impl."),
    755 	    gettext("Mask"), 0);
    756 
    757 	log_printf(hdrfmt,
    758 	    "--------", "-------", "----", "----", "-------",  "----", 0);
    759 
    760 	/* Now display all of the cpus on each board */
    761 	bnode = tree->bd_list;
    762 	while (bnode != NULL) {
    763 		display_cpus(bnode);
    764 		bnode = bnode->next;
    765 	}
    766 
    767 	log_printf("\n", 0);
    768 }
    769 
    770 /*
    771  * Display the CPUs present on this board.
    772  */
    773 void
    774 display_cpus(Board_node *board)
    775 {
    776 	Prom_node *cpu;
    777 	uint_t freq;		/* CPU clock frequency */
    778 	int ecache_size;	/* External cache size */
    779 	int *impl;
    780 	int *mask;
    781 	int decoded_mask;
    782 	int *cpuid;
    783 	int *coreid;
    784 	int cpuid_prev = -1;
    785 	int ecache_size_prev = 0;
    786 
    787 	(void) textdomain(TEXT_DOMAIN);
    788 	/*
    789 	 * display the CPUs' operating frequency, cache size, impl. field
    790 	 * and mask revision.
    791 	 */
    792 	for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
    793 	    cpu = dev_next_type(cpu, "cpu")) {
    794 
    795 		freq = HZ_TO_MHZ(get_cpu_freq(cpu));
    796 		ecache_size = get_ecache_size(cpu);
    797 		impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
    798 		mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
    799 		cpuid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
    800 		if (cpuid == NULL)
    801 			cpuid = &board->board_num;
    802 
    803 		/* Do not display a failed CPU node */
    804 		if ((freq == 0) || (impl == 0) || (node_failed(cpu)))
    805 			continue;
    806 
    807 		if (CPU_IMPL_IS_CMP(*impl)) {
    808 			coreid = (int *)get_prop_val(find_prop(cpu,
    809 			    "reg"));
    810 			if (coreid == NULL) {
    811 				continue;
    812 			}
    813 
    814 			/*
    815 			 * The assumption is made that 2 cores will always be
    816 			 * listed together in the device tree. If either core
    817 			 * is "bad" then the FRU will not be listed.
    818 			 */
    819 			if (cpuid_prev == -1) {
    820 				cpuid_prev = *cpuid;
    821 				ecache_size_prev = ecache_size;
    822 				continue;
    823 			} else {
    824 				/*
    825 				 * Jaguar has a split E$, so the size for both
    826 				 * cores must be added together to get the total
    827 				 * size for the entire chip.
    828 				 *
    829 				 * Panther E$ (L3) is logically shared, so the
    830 				 * total size is equal to the core size.
    831 				 */
    832 				if (IS_JAGUAR(*impl)) {
    833 					ecache_size += ecache_size_prev;
    834 				}
    835 
    836 				ecache_size_prev = 0;
    837 			}
    838 		}
    839 
    840 		/*
    841 		 * Print out cpu data.
    842 		 *
    843 		 * Slot ID
    844 		 */
    845 		log_printf("/%-2s%02d/P%1d  ",
    846 		    SC_BOARD_TYPE(*cpuid),
    847 		    PORTID_TO_EXPANDER(*cpuid),
    848 		    PORTID_TO_INSTANCE(*cpuid), 0);
    849 
    850 		/* CPU ID */
    851 		if (CPU_IMPL_IS_CMP(*impl)) {
    852 			log_printf("%3d,%3d  ", cpuid_prev,
    853 			    *cpuid, 0);
    854 			cpuid_prev = -1;
    855 		} else
    856 			log_printf("%3d      ", *cpuid, 0);
    857 
    858 		/* Running frequency */
    859 		log_printf("%4u  ", freq, 0);
    860 
    861 		/* Ecache size */
    862 		if (ecache_size == 0)
    863 			log_printf("%-4.4s  ", gettext("N/A"), 0);
    864 		else
    865 			log_printf("%4.1f  ",
    866 			    (float)ecache_size / (float)(1<<20),
    867 			    0);
    868 
    869 		/* Implementation */
    870 		switch (*impl) {
    871 		case CHEETAH_IMPL:
    872 			log_printf("%-7.7s  ",
    873 			    gettext("US-III"), 0);
    874 			break;
    875 		case CHEETAH_PLUS_IMPL:
    876 			log_printf("%-7.7s  ",
    877 			    gettext("US-III+"), 0);
    878 			break;
    879 		case JAGUAR_IMPL:
    880 			log_printf("%-7.7s  ",
    881 			    gettext("US-IV"), 0);
    882 			break;
    883 		case PANTHER_IMPL:
    884 			log_printf("%-7.7s  ",
    885 			    gettext("US-IV+"), 0);
    886 			break;
    887 		default:
    888 			log_printf("%-7x  ", *impl, 0);
    889 			break;
    890 		}
    891 
    892 		/* CPU Mask */
    893 		if (mask == NULL) {
    894 			log_printf("%-4.4s", gettext("N/A"), 0);
    895 		} else {
    896 			if (IS_CHEETAH(*impl))
    897 				decoded_mask = REMAP_CHEETAH_MASK(*mask);
    898 			else
    899 				decoded_mask = *mask;
    900 
    901 			log_printf("%d.%d",
    902 			    (decoded_mask >> 4) & 0xf,
    903 			    decoded_mask & 0xf, 0);
    904 		}
    905 
    906 		log_printf("\n", 0);
    907 	}
    908 }
    909 
    910 
    911 /*ARGSUSED1*/
    912 void
    913 display_memoryconf(Sys_tree *tree, struct grp_info *grps)
    914 {
    915 	Board_node	*bnode = tree->bd_list;
    916 	char	*hdrfmt = "\n%-11.11s  %-4.4s  %-7.7s  %-7.7s  %-8.8s  %-6.6s"
    917 	    "  %-10.10s  %-10.10s";
    918 
    919 	(void) textdomain(TEXT_DOMAIN);
    920 
    921 	log_printf("=========================", 0);
    922 	log_printf(gettext(" Memory Configuration "), 0);
    923 	log_printf("=========================", 0);
    924 	log_printf("\n", 0);
    925 
    926 	log_printf(hdrfmt,
    927 	    "", "",
    928 	    gettext("Logical"),
    929 	    gettext("Logical"),
    930 	    gettext("Logical"),
    931 	    "", "", "", 0);
    932 
    933 	log_printf(hdrfmt,
    934 	    "",
    935 	    gettext("Port"),
    936 	    gettext("Bank"),
    937 	    gettext("Bank"),
    938 	    gettext("Bank"),
    939 	    gettext(" DIMM"),
    940 	    gettext("Interleave"),
    941 	    gettext("Interleave"), 0);
    942 
    943 	log_printf(hdrfmt,
    944 	    gettext("Slot ID"),
    945 	    gettext(" ID"),
    946 	    gettext("Number"),
    947 	    gettext("Size"),
    948 	    gettext("Status"),
    949 	    gettext(" Size"),
    950 	    gettext("Factor"),
    951 	    gettext("Segment"), 0);
    952 
    953 	log_printf(hdrfmt,
    954 	    "-----------", "----", "-------", "-------", "--------",
    955 	    "------", "----------", "----------", 0);
    956 
    957 	while (bnode != NULL) {
    958 		if (get_us3_mem_regs(bnode)) {
    959 			log_printf(
    960 			    gettext(
    961 			    "\nFailed to get memory information.\n"),
    962 			    0);
    963 			return;
    964 		}
    965 		bnode = bnode->next;
    966 	}
    967 
    968 	/* Display what we have found */
    969 	display_us3_banks();
    970 }
    971 
    972 
    973 /*
    974  * This function provides Starcat's formatting of the memory config
    975  * information that get_us3_mem_regs() and display_us3_banks() code has
    976  * gathered. It overrides the generic print_us3_memory_line() code
    977  * which prints an error message.
    978  */
    979 void
    980 print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
    981 	char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
    982 {
    983 	(void) textdomain(TEXT_DOMAIN);
    984 
    985 	/* Slot ID */
    986 	log_printf("\n/%-2s%02d/P%1d/B%1d  ",
    987 	    SC_BOARD_TYPE(portid), PORTID_TO_EXPANDER(portid),
    988 	    PORTID_TO_INSTANCE(portid), (bank_id & 0x1), 0);
    989 
    990 	/* Port ID */
    991 	log_printf("%3d   ", portid, 0);
    992 
    993 	/* Logical Bank Number */
    994 	log_printf("   %1d     ", (bank_id & 0x3), 0);
    995 
    996 	/* Logical Bank Size */
    997 	log_printf("%4lldMB   ", bank_size, 0);
    998 
    999 	/* Logical Bank Status */
   1000 	log_printf("%-8.8s  ", gettext(bank_status), 0);
   1001 
   1002 	/* DIMM Size */
   1003 	log_printf("%4lldMB  ", dimm_size, 0);
   1004 
   1005 	/* Interleave Factor */
   1006 	log_printf("  %2d-%-3.3s    ", intlv, gettext("way"), 0);
   1007 
   1008 	/* Interleave Segment */
   1009 	log_printf("   %3d", seg_id, 0);
   1010 }
   1011 
   1012 /*ARGSUSED2*/
   1013 void
   1014 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
   1015 	struct system_kstat_data *kstats)
   1016 {
   1017 	if (flag) {
   1018 		/*
   1019 		 * display time of latest powerfail. Not all systems
   1020 		 * have this capability. For those that do not, this
   1021 		 * is just a no-op.
   1022 		 */
   1023 		disp_powerfail(root);
   1024 
   1025 		(void) textdomain(TEXT_DOMAIN);
   1026 
   1027 		/* Print the header */
   1028 		log_printf("\n", 0);
   1029 		log_printf("=========================", 0);
   1030 		log_printf(gettext(" Diagnostic Information "), 0);
   1031 		log_printf("=========================", 0);
   1032 		log_printf("\n\n", 0);
   1033 		log_printf(gettext("For diagnostic information,"), 0);
   1034 		log_printf("\n", 0);
   1035 		log_printf(gettext(
   1036 		    "see /var/opt/SUNWSMS/adm/[A-R]/messages on the SC."),
   1037 		    0);
   1038 		log_printf("\n", 0);
   1039 
   1040 		/* Print the PROM revisions here */
   1041 		starcat_disp_hw_revisions(root);
   1042 	}
   1043 }
   1044 
   1045 /*
   1046  * local functions -  functions that are only needed inside this library
   1047  */
   1048 
   1049 static void
   1050 starcat_disp_hw_revisions(Prom_node *root)
   1051 {
   1052 	Prom_node	*pnode;
   1053 	char		*version;
   1054 
   1055 	(void) textdomain(TEXT_DOMAIN);
   1056 
   1057 	/* Print the header */
   1058 	log_printf("\n", 0);
   1059 	log_printf("=========================", 0);
   1060 	log_printf(gettext(" Hardware Revisions "), 0);
   1061 	log_printf("=========================", 0);
   1062 	log_printf("\n\n", 0);
   1063 
   1064 	/* Display Prom revision header */
   1065 	log_printf(gettext("OpenBoot firmware revision:"), 0);
   1066 	log_printf("\n---------------------------\n", 0);
   1067 
   1068 	/*
   1069 	 * Display OBP version info
   1070 	 */
   1071 	pnode = dev_find_node(root, "openprom");
   1072 	if (pnode != NULL) {
   1073 		version = (char *)get_prop_val(find_prop(pnode, "version"));
   1074 		log_printf("%s\n\n", version, 0);
   1075 	}
   1076 }
   1077 
   1078 /*
   1079  * We call do_devinfo() in order to use the libdevinfo device tree
   1080  * instead of OBP's device tree.
   1081  */
   1082 int
   1083 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
   1084 {
   1085 
   1086 	return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
   1087 
   1088 }
   1089 
   1090 /*
   1091  * return the property value for the Prop
   1092  * passed in. (When using libdevinfo)
   1093  */
   1094 void *
   1095 get_prop_val(Prop *prop)
   1096 {
   1097 	if (prop == NULL)
   1098 		return (NULL);
   1099 
   1100 	return ((void *)(prop->value.val_ptr));
   1101 }
   1102 
   1103 /*
   1104  * Search a Prom node and retrieve the property with the correct
   1105  * name. (When using libdevinfo)
   1106  */
   1107 Prop *
   1108 find_prop(Prom_node *pnode, char *name)
   1109 {
   1110 	Prop *prop;
   1111 
   1112 	if (pnode == NULL)
   1113 		return (NULL);
   1114 
   1115 	for (prop = pnode->props; prop != NULL; prop = prop->next) {
   1116 		if (prop->name.val_ptr != NULL &&
   1117 		    strcmp((char *)(prop->name.val_ptr), name) == 0)
   1118 			break;
   1119 	}
   1120 
   1121 	return (prop);
   1122 }
   1123 
   1124 /*
   1125  * This function searches through the properties of the node passed in
   1126  * and returns a pointer to the value of the name property.
   1127  * (When using libdevinfo)
   1128  */
   1129 char *
   1130 get_node_name(Prom_node *pnode)
   1131 {
   1132 	Prop *prop;
   1133 
   1134 	if (pnode == NULL) {
   1135 		return (NULL);
   1136 	}
   1137 
   1138 	prop = pnode->props;
   1139 	while (prop != NULL) {
   1140 		if (strcmp("name", (char *)prop->name.val_ptr) == 0)
   1141 			return (prop->value.val_ptr);
   1142 		prop = prop->next;
   1143 	}
   1144 	return (NULL);
   1145 }
   1146 
   1147 /*
   1148  * This function searches through the properties of the node passed in
   1149  * and returns a pointer to the value of the device_type property.
   1150  * (When using libdevinfo)
   1151  */
   1152 char *
   1153 get_node_type(Prom_node *pnode)
   1154 {
   1155 	Prop *prop;
   1156 
   1157 	if (pnode == NULL) {
   1158 		return (NULL);
   1159 	}
   1160 
   1161 	prop = pnode->props;
   1162 	while (prop != NULL) {
   1163 		if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
   1164 			return (prop->value.val_ptr);
   1165 		prop = prop->next;
   1166 	}
   1167 	return (NULL);
   1168 }
   1169