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
78int	do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
79void	*get_prop_val(Prop *prop);
80Prop	*find_prop(Prom_node *pnode, char *name);
81char	*get_node_name(Prom_node *pnode);
82char	*get_node_type(Prom_node *pnode);
83void	add_node(Sys_tree *, Prom_node *);
84void	display_pci(Board_node *);
85void	display_ffb(Board_node *, int);
86void	display_io_cards(struct io_card *list);
87void	display_cpu_devices(Sys_tree *tree);
88void	display_cpus(Board_node *board);
89void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
90void	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);
92void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
93		struct system_kstat_data *kstats);
94
95/* Local Functions */
96static void	starcat_disp_hw_revisions(Prom_node *root);
97static void display_io_max_bus_speed(struct io_card *p);
98static void display_io_slot_info(struct io_card *p);
99
100/* The bus max freq is determined based on board level in use */
101int	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 */
107void
108display_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*/
506void
507display_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 */
517void
518add_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 */
565void
566display_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
647static void
648display_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
689static void
690display_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
723void
724display_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 */
773void
774display_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*/
912void
913display_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 */
979void
980print_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*/
1013void
1014display_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
1049static void
1050starcat_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 */
1082int
1083do_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 */
1094void *
1095get_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 */
1107Prop *
1108find_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 */
1129char *
1130get_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 */
1152char *
1153get_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