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