xref: /titanic_51/usr/src/lib/libprtdiag_psr/sparc/starcat/common/starcat.c (revision e79c98e6c943cb3032f272714ff4ce6137d40394)
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