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 1999-2002 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Javelin Platform specific functions.
27 *
28 *	called when :
29 *	machine_type ==  MTYPE_JAVELIN
30 *
31 */
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 <errno.h>
41#include <time.h>
42#include <dirent.h>
43#include <fcntl.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 <kstat.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#if !defined(TEXT_DOMAIN)
60#define	TEXT_DOMAIN	"SYS_TEST"
61#endif
62
63extern	int	print_flag;
64
65/*
66 * these functions will overlay the symbol table of libprtdiag
67 * at runtime (workgroup server systems only)
68 */
69int	error_check(Sys_tree *tree, struct system_kstat_data *kstats);
70void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
71int	disp_fail_parts(Sys_tree *tree);
72void	display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
73void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
74				struct system_kstat_data *kstats);
75void	display_boardnum(int num);
76void	display_pci(Board_node *);
77void	display_io_cards(struct io_card *list);
78void	display_ffb(Board_node *, int);
79void	read_platform_kstats(Sys_tree *tree,
80		struct system_kstat_data *sys_kstat,
81		struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep);
82
83/* local functions */
84static	int disp_envc_status(struct system_kstat_data *);
85static	void tazjav_disp_asic_revs(Sys_tree *);
86static	int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *);
87static	Prom_node *dev_next_node_sibling(Prom_node *root, char *name);
88
89
90int
91error_check(Sys_tree *tree, struct system_kstat_data *kstats)
92{
93	int exit_code = 0;	/* init to all OK */
94
95#ifdef	lint
96	kstats = kstats;
97#endif
98	/*
99	 * silently check for any types of machine errors
100	 */
101	print_flag = 0;
102	if (disp_fail_parts(tree) || disp_envc_status(kstats)) {
103		/* set exit_code to show failures */
104		exit_code = 1;
105	}
106	print_flag = 1;
107
108	return (exit_code);
109}
110
111/* Search for and return the node's sibling */
112static Prom_node *
113dev_next_node_sibling(Prom_node *root, char *name)
114{
115	if (root == NULL)
116		return (NULL);
117
118	/* look at your siblings */
119	if (dev_find_node(root->sibling, name) != NULL)
120		return (root->sibling);
121
122	return (NULL);  /* not found */
123}
124
125/*
126 * This function displays memory configurations specific to Tazmo/Javelin.
127 * The PROM device tree is read to obtain this information.
128 * Some of the information obtained is memory interleave factor,
129 * DIMM sizes, DIMM socket names.
130 */
131void
132display_memoryconf(Sys_tree *tree, struct grp_info *grps)
133{
134	Board_node *bnode;
135	Prom_node *memory;
136	Prom_node *bank;
137	Prom_node *dimm;
138	uint_t *preg;
139	uint_t interlv;
140	unsigned long size = 0;
141	int bank_count = 0;
142	char *sock_name;
143	char *status;
144	Prop *status_prop;
145	char interleave[8];
146	int total_size = 0;
147#ifdef lint
148	grps = grps;
149#endif
150
151	log_printf("\n", 0);
152	log_printf("=========================", 0);
153	log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0);
154	log_printf("=========================", 0);
155	log_printf("\n", 0);
156	log_printf("\n", 0);
157	bnode = tree->bd_list;
158	memory = dev_find_node(bnode->nodes, "memory");
159	preg = (uint_t *)(get_prop_val(find_prop(memory, "interleave")));
160	if (preg) {
161		interlv = preg[4];
162		log_printf("Memory Interleave Factor = %d-way\n\n", interlv, 0);
163	}
164	log_printf("       Interlv.  Socket   Size\n", 0);
165	log_printf("Bank    Group     Name    (MB)  Status\n", 0);
166	log_printf("----    -----    ------   ----  ------\n", 0);
167
168	dimm = bnode->nodes;
169	for (bank = dev_find_node(bnode->nodes, "bank"); bank != NULL;
170	    bank = dev_next_node(bank, "bank")) {
171		int bank_size = 0;
172		uint_t *reg_prop;
173
174		preg = (uint_t *)(get_prop_val(
175		    find_prop(bank, "bank-interleave")));
176
177		reg_prop = (uint_t *)(get_prop_val(
178		    find_prop(bank, "reg")));
179
180		/*
181		 * Skip empty banks
182		 */
183		if (((reg_prop[2]<<12) + (reg_prop[3]>>20)) == 0) {
184			bank_count++;
185			continue;
186		}
187
188		if (preg) {
189			interlv = preg[2];
190			(void) sprintf(interleave, " %d ", interlv);
191			bank_size = (preg[0]<<12) + (preg[1]>>20);
192		} else {
193			(void) sprintf(interleave, "%s", "none");
194			preg = (uint_t *)(get_prop_val(find_prop(bank, "reg")));
195			if (preg) {
196				bank_size = (preg[2]<<12) + (preg[3]>>20);
197			}
198		}
199		for (dimm = dev_find_node(bank, "dimm"); dimm != NULL;
200		    dimm = dev_next_node_sibling(dimm, "dimm")) {
201			char dimm_status[16];
202
203			sock_name = (char *)(get_prop_val(
204			    find_prop(dimm, "socket-name")));
205			preg = (uint_t *)(get_prop_val(find_prop(dimm, "reg")));
206			size = (preg[2]<<12) + (preg[3]>>20);
207			if ((status_prop = find_prop(dimm, "status")) == NULL) {
208				(void) sprintf(dimm_status, "%s", "OK");
209			} else {
210				status = (char *)(get_prop_val(status_prop));
211				(void) sprintf(dimm_status, "%s", status);
212			}
213			log_printf("%3d     %5s    %6s  %4d  %6s\n",
214			    bank_count, interleave, sock_name,
215			    size, dimm_status, 0);
216		}
217		total_size += bank_size;
218		bank_count++;
219	}
220	log_printf("\n", 0);
221}
222
223/*
224 * disp_fail_parts
225 *
226 * Display the failed parts in the system. This function looks for
227 * the status property in all PROM nodes. On systems where
228 * the PROM does not supports passing diagnostic information
229 * thruogh the device tree, this routine will be silent.
230 */
231int
232disp_fail_parts(Sys_tree *tree)
233{
234	int exit_code;
235	int system_failed = 0;
236	Board_node *bnode = tree->bd_list;
237	Prom_node *pnode;
238	char *fru;
239	char *sock_name;
240	char slot_str[MAXSTRLEN];
241
242	exit_code = 0;
243
244	/* go through all of the boards looking for failed units. */
245	while (bnode != NULL) {
246		/* find failed chips */
247		pnode = find_failed_node(bnode->nodes);
248		if ((pnode != NULL) && !system_failed) {
249			system_failed = 1;
250			exit_code = 1;
251			if (print_flag == 0) {
252				return (exit_code);
253			}
254			log_printf("\n", 0);
255			log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
256			    "Replaceable Units (FRU) in System:\n"), 0);
257			log_printf("=========================="
258			    "====================\n", 0);
259		}
260
261		while (pnode != NULL) {
262			void *value;
263			char *name;		/* node name string */
264			char *type;		/* node type string */
265
266			value = get_prop_val(find_prop(pnode, "status"));
267			name = get_node_name(pnode);
268
269			/* sanity check of data retreived from PROM */
270			if ((value == NULL) || (name == NULL)) {
271				pnode = next_failed_node(pnode);
272				continue;
273			}
274
275
276			log_printf(dgettext(TEXT_DOMAIN, "%s unavailable :\n"),
277			    name, 0);
278
279			log_printf(dgettext(TEXT_DOMAIN, "\tPROM fault "
280			    "string: %s\n"), value, 0);
281
282			log_printf(dgettext(TEXT_DOMAIN, "\tFailed Field "
283			    "Replaceable Unit is "), 0);
284
285			/*
286			 * Determine whether FRU is CPU module, system
287			 * board, or SBus card.
288			 */
289			if ((name != NULL) && (strstr(name, "sbus"))) {
290
291				log_printf(dgettext(TEXT_DOMAIN, "SBus "
292				    "Card %d\n"), get_sbus_slot(pnode), 0);
293
294			} else if (((name = get_node_name(pnode)) !=
295			    NULL) && (strstr(name, "pci"))) {
296
297				log_printf(dgettext(TEXT_DOMAIN, "system "
298				    "board\n"), 0);
299
300			} else if (((name = get_node_name(pnode)) !=
301			    NULL) && (strstr(name, "ffb"))) {
302
303				log_printf(dgettext(TEXT_DOMAIN, "FFB "
304				    "Card %d\n"), tazmo_physical_slot(
305				    dev_find_node(bnode->nodes, "slot2dev"),
306				    pnode, -1, slot_str), 0);
307
308			} else if (((name = get_node_name(pnode->parent)) !=
309			    NULL) && (strstr(name, "pci"))) {
310
311				(void) tazmo_physical_slot(NULL,
312				    pnode->parent,
313				    get_pci_device(pnode),
314				    slot_str);
315				log_printf(dgettext(TEXT_DOMAIN, "PCI Card "
316				    "in %s\n"), slot_str, 0);
317
318			} else if (((type = get_node_type(pnode)) != NULL) &&
319			    (strstr(type, "cpu"))) {
320
321				log_printf(
322				    dgettext(TEXT_DOMAIN, "UltraSPARC "
323				    "module Module %d\n"),
324				    get_id(pnode));
325
326			} else if (((type = get_node_type(pnode)) != NULL) &&
327			    (strstr(type, "memory-module"))) {
328
329				fru = (char *)(get_prop_val(
330				    find_prop(pnode, "fru")));
331				sock_name = (char *)(get_prop_val(
332				    find_prop(pnode, "socket-name")));
333				log_printf(
334				    dgettext(TEXT_DOMAIN, "%s in "
335				    "socket %s\n"), fru,
336				    sock_name, 0);
337			}
338			pnode = next_failed_node(pnode);
339		}
340		bnode = bnode->next;
341	}
342
343	if (!system_failed) {
344		log_printf("\n", 0);
345		log_printf(dgettext(TEXT_DOMAIN, "No failures found "
346		    "in System\n"), 0);
347		log_printf("===========================\n", 0);
348	}
349
350	if (system_failed)
351		return (1);
352	else
353		return (0);
354}
355
356void
357display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
358{
359#ifdef lint
360	kstats = kstats;
361#endif
362	/* Display failed units */
363	(void) disp_fail_parts(tree);
364}
365
366
367void
368display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
369    struct system_kstat_data *kstats)
370{
371	/*
372	 * Now display the last powerfail time and the fatal hardware
373	 * reset information. We do this under a couple of conditions.
374	 * First if the user asks for it. The second is iof the user
375	 * told us to do logging, and we found a system failure.
376	 */
377	if (flag) {
378		/*
379		 * display time of latest powerfail. Not all systems
380		 * have this capability. For those that do not, this
381		 * is just a no-op.
382		 */
383		disp_powerfail(root);
384
385		(void) disp_envc_status(kstats);
386
387		tazjav_disp_asic_revs(tree);
388
389		platform_disp_prom_version(tree);
390	}
391	return;
392
393}
394
395/* ARGSUSED */
396void
397display_boardnum(int num)
398{
399	log_printf("SYS   ", 0);
400}
401
402
403
404/*
405 * display_pci
406 * Display all the PCI IO cards on this board.
407 */
408
409/* ARGSUSED */
410void
411display_pci(Board_node *board)
412{
413	struct io_card *card_list = NULL;
414	struct io_card card;
415	void *value;
416	Prom_node *pci;
417	Prom_node *card_node;
418
419	if (board == NULL)
420		return;
421
422	/* Initialize all the common information */
423	card.display = 1;
424	card.board = board->board_num;
425	(void) sprintf(card.bus_type, "PCI");
426
427	for (pci = dev_find_node(board->nodes, PCI_NAME); pci != NULL;
428	    pci = dev_next_node(pci, PCI_NAME)) {
429		char *name;
430		Prom_node *prev_parent = NULL;
431		int prev_device = -1;
432		int pci_pci_bridge = 0;
433
434		/*
435		 * If we have reached a pci-to-pci bridge node,
436		 * we are one level below the 'pci' nodes level
437		 * in the device tree. To get back to that level,
438		 * the search should continue with the sibling of
439		 * the parent or else the remaining 'pci' cards
440		 * will not show up in the output.
441		 */
442		if (find_prop(pci, "upa-portid") == NULL) {
443			if ((pci->parent->sibling != NULL) &&
444			    (strcmp(get_prop_val(
445			    find_prop(pci->parent->sibling,
446			    "name")), PCI_NAME) == 0))
447				pci = pci->parent->sibling;
448			else {
449				pci = pci->parent->sibling;
450				continue;
451			}
452		}
453
454		/* Skip all failed nodes for now */
455		if (node_failed(pci))
456			continue;
457
458		/* Fill in frequency */
459		value = get_prop_val(find_prop(pci, "clock-frequency"));
460		if (value == NULL)
461			card.freq = -1;
462		else
463			card.freq = ((*(int *)value) + 500000) / 1000000;
464
465		/* Walk through the PSYCHO children */
466		card_node = pci->child;
467		while (card_node != NULL) {
468			Prop *compat = NULL;
469
470			/* If it doesn't have a name, skip it */
471			name = (char *)get_prop_val(
472			    find_prop(card_node, "name"));
473			if (name == NULL) {
474				card_node = card_node->sibling;
475				continue;
476			}
477
478			/*
479			 * If this is a PCI bridge, then display its
480			 * children.
481			 */
482			if (strcmp(name, "pci") == 0) {
483				card_node = card_node->child;
484				pci_pci_bridge = 1;
485				continue;
486			}
487
488			/* Get the slot number for this card */
489			if (pci_pci_bridge) {
490				card.slot = tazmo_physical_slot(
491				    dev_find_node(board->nodes, "slot2dev"),
492				    pci,
493				    get_pci_to_pci_device(card_node->parent),
494				    card.slot_str);
495			} else
496				card.slot = tazmo_physical_slot(
497				    dev_find_node(board->nodes, "slot2dev"),
498				    pci,
499				    get_pci_device(card_node),
500				    card.slot_str);
501
502			/*
503			 * Check that duplicate devices are not reported
504			 * on Tazmo.
505			 */
506			if ((card_node->parent == prev_parent) &&
507			    (get_pci_device(card_node) == prev_device) &&
508			    (pci_pci_bridge == 0))
509				card.slot = -1;
510			prev_parent = card_node->parent;
511			prev_device = get_pci_device(card_node);
512
513
514			if (card.slot == -1 || strstr(name, "ebus")) {
515				card_node = card_node->sibling;
516				continue;
517			}
518
519			/* XXX - Don't know how to get status for PCI cards */
520			card.status[0] = '\0';
521
522			/* Get the model of this card */
523			value = get_prop_val(find_prop(card_node, "model"));
524			if (value == NULL)
525				card.model[0] = '\0';
526			else
527				(void) sprintf(card.model, "%s",
528				    (char *)value);
529
530			/*
531			 * Check if further processing is necessary to display
532			 * this card uniquely.
533			 */
534			distinguish_identical_io_cards(name, card_node, &card);
535
536
537			/*
538			 * If we haven't figured out the frequency yet,
539			 * try and get it from the card.
540			 */
541			value = get_prop_val(find_prop(pci, "clock-frequency"));
542			if (value != NULL && card.freq == -1)
543				card.freq = ((*(int *)value) + 500000)
544				    / 1000000;
545
546
547			value = get_prop_val(find_prop(card_node,
548			    "compatible"));
549
550			/*
551			 * On Tazmo, we would like to print out the last
552			 * string of the "compatible" property if it exists.
553			 * The IEEE 1275 spec. states that this last string
554			 * will be the classcode name.
555			 */
556			if (value != NULL) {
557				char *tval;
558				int index;
559				const int always = 1;
560
561				tval = (char *)value;
562				index = 0;
563				compat = find_prop(card_node, "compatible");
564				while (always) {
565					if ((strlen(tval) + 1) ==
566					    (compat->size - index))
567						break;
568					index += strlen(tval) + 1;
569					tval += strlen(tval) + 1;
570				}
571				value = (void *)tval;
572			}
573
574			if (value != NULL)
575				(void) sprintf(card.name, "%s-%s",
576				    (char *)name, (char *)value);
577			else
578				(void) sprintf(card.name, "%s",
579				    (char *)name);
580
581			if (card.freq != -1)
582				card_list = insert_io_card(card_list, &card);
583
584			/*
585			 * If we are done with the children of the pci bridge,
586			 * we must continue with the remaining siblings of
587			 * the pci-to-pci bridge.
588			 */
589			if ((card_node->sibling == NULL) && pci_pci_bridge) {
590				card_node = card_node->parent->sibling;
591				pci_pci_bridge = 0;
592			} else
593				card_node = card_node->sibling;
594		}
595	}
596
597	display_io_cards(card_list);
598	free_io_cards(card_list);
599}
600
601
602/*
603 * Print out all the io cards in the list.  Also print the column
604 * headers if told to do so.
605 */
606void
607display_io_cards(struct io_card *list)
608{
609	static int banner = 0; /* Have we printed the column headings? */
610	struct io_card *p;
611
612	if (list == NULL)
613		return;
614
615	if (banner == 0) {
616		log_printf("     Bus   Freq\n", 0);
617		log_printf("Brd  Type  MHz   Slot  "
618		    "Name                              "
619		    "Model", 0);
620		log_printf("\n", 0);
621		log_printf("---  ----  ----  ----  "
622		    "--------------------------------  "
623		    "----------------------", 0);
624		log_printf("\n", 0);
625		banner = 1;
626	}
627
628	for (p = list; p != NULL; p = p -> next) {
629		log_printf("SYS   ", p->board, 0);
630		log_printf("%-4s  ", p->bus_type, 0);
631		log_printf("%3d   ", p->freq, 0);
632		log_printf("%3d   ", p->slot, 0);
633		log_printf("%-32.32s", p->name, 0);
634		if (strlen(p->name) > 32)
635			log_printf("+ ", 0);
636		else
637			log_printf("  ", 0);
638		log_printf("%-22.22s", p->model, 0);
639		if (strlen(p->model) > 22)
640			log_printf("+", 0);
641		log_printf("\n", 0);
642	}
643}
644
645/*
646 * display_ffb
647 * Display all FFBs on this board.  It can either be in tabular format,
648 * or a more verbose format.
649 */
650void
651display_ffb(Board_node *board, int table)
652{
653	Prom_node *ffb;
654	void *value;
655	struct io_card *card_list = NULL;
656	struct io_card card;
657
658	if (board == NULL)
659		return;
660
661	/* Fill in common information */
662	card.display = 1;
663	card.board = board->board_num;
664	(void) sprintf(card.bus_type, "UPA");
665	card.freq = sys_clk;
666
667	for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL;
668	    ffb = dev_next_node(ffb, FFB_NAME)) {
669		if (table == 1) {
670			/* Print out in table format */
671
672			/* XXX - Get the slot number (hack) */
673			card.slot = tazmo_physical_slot(
674			    dev_find_node(board->nodes, "slot2dev"),
675			    ffb,
676			    -1,
677			    card.slot_str);
678
679			/* Find out if it's single or double buffered */
680			(void) sprintf(card.name, "FFB");
681			value = get_prop_val(find_prop(ffb, "board_type"));
682			if (value != NULL)
683				if ((*(int *)value) & FFB_B_BUFF)
684					(void) sprintf(card.name,
685					    "FFB, Double Buffered");
686				else
687					(void) sprintf(card.name,
688					    "FFB, Single Buffered");
689
690			/* Print model number */
691			card.model[0] = '\0';
692			value = get_prop_val(find_prop(ffb, "model"));
693			if (value != NULL)
694				(void) sprintf(card.model, "%s",
695				    (char *)value);
696
697			card_list = insert_io_card(card_list, &card);
698		} else {
699			/* print in long format */
700			char device[MAXSTRLEN];
701			int fd = -1;
702			struct dirent *direntp;
703			DIR *dirp;
704			union strap_un strap;
705			struct ffb_sys_info fsi;
706
707			/* Find the device node using upa address */
708			value = get_prop_val(find_prop(ffb, "upa-portid"));
709			if (value == NULL)
710				continue;
711
712			(void) sprintf(device, "%s@%x", FFB_NAME,
713			    *(int *)value);
714			if ((dirp = opendir("/devices")) == NULL)
715				continue;
716
717			while ((direntp = readdir(dirp)) != NULL) {
718				if (strstr(direntp->d_name, device) != NULL) {
719					(void) sprintf(device, "/devices/%s",
720					    direntp->d_name);
721					fd = open(device, O_RDWR, 0666);
722					break;
723				}
724			}
725			(void) closedir(dirp);
726
727			if (fd == -1)
728				continue;
729
730			if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
731				continue;
732
733			log_printf("FFB Hardware Configuration:\n", 0);
734			log_printf("-----------------------------------\n", 0);
735
736			strap.ffb_strap_bits = fsi.ffb_strap_bits;
737			log_printf("\tBoard rev: %d\n",
738			    (int)strap.fld.board_rev, 0);
739			log_printf("\tFBC version: "
740			    "0x%x\n", fsi.fbc_version, 0);
741			log_printf("\tDAC: %s\n",
742			    fmt_manf_id(fsi.dac_version, device), 0);
743			log_printf("\t3DRAM: %s\n",
744			    fmt_manf_id(fsi.fbram_version, device), 0);
745			log_printf("\n", 0);
746		}
747	}
748
749	display_io_cards(card_list);
750	free_io_cards(card_list);
751}
752
753/*
754 * This module does the reading and interpreting of javelin system
755 * kstats. These kstats are created by the environ drivers.
756 */
757void
758read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat,
759    struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep)
760{
761	kstat_ctl_t		*kc;
762	struct envctrltwo_kstat_data *ecp;
763	kstat_t			*ksp;
764
765	if ((kc = kstat_open()) == NULL) {
766		return;
767	}
768#ifdef lint
769	tree = tree;
770	bdp = bdp;
771	ep = ep;
772#endif
773
774	/* read the envctrltwo kstats */
775	ecp = &sys_kstat->envc_data;
776
777	/* Read the power supply kstats */
778	ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
779	    ENVCTRL_KSTAT_PSNAME2);
780
781	if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
782		(void) memcpy(ecp->ps_kstats, ksp->ks_data,
783		    ksp->ks_ndata * sizeof (envctrl_ps2_t));
784	} else {
785		sys_kstat->envctrltwo_kstat_ok = B_FALSE;
786		return;
787	}
788
789	ecp->num_ps_kstats = ksp->ks_ndata;
790
791	/* Read the fan status kstats */
792	ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
793	    ENVCTRL_KSTAT_FANSTAT);
794
795	if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
796		(void) memcpy(ecp->fan_kstats, ksp->ks_data,
797		    ksp->ks_ndata * sizeof (envctrl_fan_t));
798	} else {
799		sys_kstat->envctrltwo_kstat_ok = B_FALSE;
800		return;
801	}
802
803	ecp->num_fan_kstats = ksp->ks_ndata;
804
805	/* Read the enclosure kstats */
806	ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
807	    ENVCTRL_KSTAT_ENCL);
808
809	if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
810		(void) memcpy(ecp->encl_kstats, ksp->ks_data,
811		    ksp->ks_ndata * sizeof (envctrl_encl_t));
812	} else {
813		sys_kstat->envctrltwo_kstat_ok = B_FALSE;
814		return;
815	}
816
817	ecp->num_encl_kstats = ksp->ks_ndata;
818
819	/* Read the temperature kstats */
820	ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
821	    ENVCTRL_KSTAT_TEMPERATURE);
822
823	if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
824		(void) memcpy(ecp->temp_kstats, ksp->ks_data,
825		    ksp->ks_ndata * sizeof (envctrl_temp_t));
826	} else {
827		sys_kstat->envctrltwo_kstat_ok = B_FALSE;
828		return;
829	}
830
831	ecp->num_temp_kstats = ksp->ks_ndata;
832
833	/* Read the disk kstats */
834	ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
835	    ENVCTRL_KSTAT_DISK);
836
837	if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
838		(void) memcpy(ecp->disk_kstats, ksp->ks_data,
839		    ksp->ks_ndata * sizeof (envctrl_disk_t));
840	} else {
841		sys_kstat->envctrltwo_kstat_ok = B_FALSE;
842		return;
843	}
844
845	ecp->num_disk_kstats = ksp->ks_ndata;
846
847	sys_kstat->envctrltwo_kstat_ok = 1;
848	return;
849
850}
851
852/*
853 * Walk the PROM device tree and build the system tree and root tree.
854 * Nodes that have a board number property are placed in the board
855 * structures for easier processing later. Child nodes are placed
856 * under their parents. ffb (Fusion Frame Buffer) nodes are handled
857 * specially, because they do not contain board number properties.
858 * This was requested from OBP, but was not granted. So this code
859 * must parse the MID of the FFB to find the board#.
860 */
861Prom_node *
862walk(Sys_tree *tree, Prom_node *root, int id)
863{
864	register int curnode;
865	Prom_node *pnode;
866	char *name;
867	char *type;
868	char *model;
869	int board_node = 0;
870
871	/* allocate a node for this level */
872	if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
873	    NULL) {
874		perror("malloc");
875		exit(2);	/* program errors cause exit 2 */
876	}
877
878	/* assign parent Prom_node */
879	pnode->parent = root;
880	pnode->sibling = NULL;
881	pnode->child = NULL;
882
883	/* read properties for this node */
884	dump_node(pnode);
885
886	/*
887	 * Place a node in a 'board' if it has 'board'-ness. The definition
888	 * is that all nodes that are children of root should have a
889	 * board# property. But the PROM tree does not exactly follow
890	 * this. This is where we start hacking. The name 'ffb' can
891	 * change, so watch out for this.
892	 *
893	 * The UltraSPARC, sbus, pci and ffb nodes will exit in
894	 * the desktops and will not have board# properties. These
895	 * cases must be handled here.
896	 *
897	 * PCI to PCI bridges also have the name "pci", but with different
898	 * model property values.  They should not be put under 'board'.
899	 */
900	name = get_node_name(pnode);
901	type = get_node_type(pnode);
902	model = (char *)get_prop_val(find_prop(pnode, "model"));
903#ifdef DEBUG
904	if (name != NULL)
905		printf("name=%s ", name);
906	if (type != NULL)
907		printf("type=%s ", type);
908	if (model != NULL)
909		printf("model=%s", model);
910	printf("\n");
911
912	if (model == NULL)
913		model = "";
914#endif
915	if (type == NULL)
916		type = "";
917	if (name != NULL) {
918		if (has_board_num(pnode)) {
919			add_node(tree, pnode);
920			board_node = 1;
921#ifdef DEBUG
922			printf("ADDED BOARD name=%s type=%s model=%s\n",
923			    name, type, model);
924#endif
925		} else if ((strcmp(name, FFB_NAME)  == 0)		||
926		    (strcmp(type, "cpu") == 0)				||
927
928		    ((strcmp(name, "pci") == 0) && (model != NULL) &&
929		    (strcmp(model, "SUNW,psycho") == 0))		||
930
931		    ((strcmp(name, "pci") == 0) && (model != NULL) &&
932		    (strcmp(model, "SUNW,sabre") == 0))			||
933
934		    (strcmp(name, "counter-timer") == 0)		||
935		    (strcmp(name, "sbus") == 0)				||
936		    (strcmp(name, "memory") == 0)			||
937		    (strcmp(name, "mc") == 0)				||
938		    (strcmp(name, "associations") == 0)) {
939			add_node(tree, pnode);
940			board_node = 1;
941#ifdef DEBUG
942			printf("ADDED BOARD name=%s type=%s model=%s\n",
943			    name, type, model);
944#endif
945		}
946#ifdef DEBUG
947		else
948			printf("node not added: name=%s type=%s\n", name, type);
949#endif
950	}
951
952	if (curnode = child(id)) {
953		pnode->child = walk(tree, pnode, curnode);
954	}
955
956	if (curnode = next(id)) {
957		if (board_node) {
958			return (walk(tree, root, curnode));
959		} else {
960			pnode->sibling = walk(tree, root, curnode);
961		}
962	}
963
964	if (board_node) {
965		return (NULL);
966	} else {
967		return (pnode);
968	}
969}
970
971/*
972 * local functions
973 */
974
975/*
976 * disp_envc_status
977 *
978 * This routine displays the environmental status passed up from
979 * device drivers via kstats. The kstat names are defined in
980 * kernel header files included by this module.
981 * This is a Javelin specific environmental information display routine.
982 */
983static int
984disp_envc_status(struct system_kstat_data *sys_kstats)
985{
986	struct envctrltwo_kstat_data *ecp;
987	envctrl_ps2_t ps_ks;
988	envctrl_fan_t fans_ks;
989	envctrl_encl_t encl_ks;
990	envctrl_temp_t temp_ks;
991	envctrl_disk_t disk_ks;
992	char state[48];
993	uchar_t val, fsp_value;
994	uchar_t disk_pr, disk_fl;
995	int i;
996	int exit_code = 0;
997
998	if (sys_kstats->envctrltwo_kstat_ok == 0) {
999		log_printf("\n", 0);
1000		log_printf(dgettext(TEXT_DOMAIN, "Environmental information "
1001		    "is not available\n"), 0);
1002		log_printf(dgettext(TEXT_DOMAIN, "Environmental driver may "
1003		    "not be installed\n"), 0);
1004		log_printf("\n", 0);
1005		return (1);
1006	}
1007
1008	ecp = &sys_kstats->envc_data;
1009
1010	log_printf("\n", 0);
1011	log_printf("=========================", 0);
1012	log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0);
1013	log_printf("=========================", 0);
1014	log_printf("\n", 0);
1015	log_printf("\n", 0);
1016
1017	log_printf("System Temperatures (Celsius):\n", 0);
1018	log_printf("------------------------------\n", 0);
1019
1020	for (i = 0; i < ecp->num_temp_kstats; i++) {
1021		temp_ks = ecp->temp_kstats[i];
1022		log_printf("%10s    %d", temp_ks.label, temp_ks.value);
1023		if (temp_ks.value >= temp_ks.shutdown_threshold) {
1024			log_printf("    CRITICAL\n", 0);
1025			exit_code = 1;
1026		} else if (temp_ks.value >= temp_ks.warning_threshold) {
1027			log_printf("    WARNING\n", 0);
1028			exit_code = 1;
1029		} else if (temp_ks.value < temp_ks.min) {
1030			log_printf("    WARNING\n", 0);
1031			exit_code = 1;
1032		} else
1033			log_printf("\n", 0);
1034	}
1035
1036	log_printf("\n", 0);
1037	log_printf("=================================\n", 0);
1038	log_printf("\n", 0);
1039	encl_ks = ecp->encl_kstats[0];
1040	val = encl_ks.value & ENVCTRL_UE250_FSP_KEYMASK;
1041	fsp_value = encl_ks.value;
1042	switch (val) {
1043	case ENVCTRL_UE250_FSP_KEYOFF:
1044		(void) sprintf(state, "%s", "Off");
1045		break;
1046	case ENVCTRL_UE250_FSP_KEYON:
1047		(void) sprintf(state, "%s", "On");
1048		break;
1049	case ENVCTRL_UE250_FSP_KEYDIAG:
1050		(void) sprintf(state, "%s", "Diagnostic");
1051		break;
1052	case ENVCTRL_UE250_FSP_KEYLOCKED:
1053		(void) sprintf(state, "%s", "Secure");
1054		break;
1055	default:
1056		(void) sprintf(state, "%s", "Broken!");
1057		exit_code = 1;
1058		break;
1059	}
1060	log_printf("Front Status Panel:\n", 0);
1061	log_printf("-------------------\n", 0);
1062	log_printf("Keyswitch position is in %s mode.\n", state);
1063	log_printf("\n", 0);
1064	val = fsp_value & (ENVCTRL_UE250_FSP_DISK_ERR |
1065	    ENVCTRL_UE250_FSP_PS_ERR | ENVCTRL_UE250_FSP_TEMP_ERR |
1066	    ENVCTRL_UE250_FSP_GEN_ERR | ENVCTRL_UE250_FSP_ACTIVE);
1067	log_printf("System LED Status:  DISK ERROR      POWER  \n", 0);
1068	log_printf("                      [%3s]         [ ON]      \n",
1069	    val & ENVCTRL_UE250_FSP_DISK_ERR ? "ON" : "OFF");
1070	log_printf("                POWER SUPPLY ERROR  ACTIVITY \n", 0);
1071	log_printf("                      [%3s]         [%3s]      \n",
1072	    val & ENVCTRL_UE250_FSP_PS_ERR ? "ON" : "OFF",
1073	    val & ENVCTRL_UE250_FSP_ACTIVE ? "ON" : "OFF");
1074	log_printf("                    GENERAL ERROR   THERMAL ERROR  \n", 0);
1075	log_printf("                      [%3s]         [%3s]      \n",
1076	    val & ENVCTRL_UE250_FSP_GEN_ERR ? "ON" : "OFF",
1077	    val & ENVCTRL_UE250_FSP_TEMP_ERR ? "ON" : "OFF");
1078	if (val & (ENVCTRL_UE250_FSP_DISK_ERR | ENVCTRL_UE250_FSP_PS_ERR |
1079	    ENVCTRL_UE250_FSP_GEN_ERR | ENVCTRL_UE250_FSP_TEMP_ERR)) {
1080		exit_code = 1;
1081	}
1082
1083	log_printf("\n", 0);
1084	log_printf("=================================\n", 0);
1085	log_printf("\n", 0);
1086	disk_pr = disk_fl = 0;
1087	for (i = 0; i < ecp->num_disk_kstats; i++) {
1088		disk_ks = ecp->disk_kstats[i];
1089		if (disk_ks.slot == -1)
1090			continue;
1091		disk_pr |= 1 << disk_ks.slot;
1092		if (disk_ks.disk_ok == 0)
1093			disk_fl |= 1 << disk_ks.slot;
1094	}
1095
1096	log_printf("Disk LED Status:	OK = GREEN	ERROR = YELLOW\n", 0);
1097	log_printf("		DISK  5: %7s	DISK  3: %7s	DISK  1: %7s\n",
1098	    disk_pr & ENVCTRL_DISK_5 ?
1099	    disk_fl & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]" : "[EMPTY]",
1100	    disk_pr & ENVCTRL_DISK_3 ?
1101	    disk_fl & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]" : "[EMPTY]",
1102	    disk_pr & ENVCTRL_DISK_1 ?
1103	    disk_fl & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]" : "[EMPTY]");
1104	log_printf("		DISK  4: %7s	DISK  2: %7s	DISK  0: %7s\n",
1105	    disk_pr & ENVCTRL_DISK_4 ?
1106	    disk_fl & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]" : "[EMPTY]",
1107	    disk_pr & ENVCTRL_DISK_2 ?
1108	    disk_fl & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]" : "[EMPTY]",
1109	    disk_pr & ENVCTRL_DISK_0 ?
1110	    disk_fl & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]" : "[EMPTY]");
1111
1112	log_printf("\n", 0);
1113	log_printf("=================================\n", 0);
1114	log_printf("\n", 0);
1115	log_printf("Fan Bank :\n", 0);
1116	log_printf("----------\n", 0);
1117	log_printf("\n", 0);
1118
1119	fans_ks = ecp->fan_kstats[0];
1120	log_printf("Bank      Speed     Status\n", 0);
1121	log_printf("         (0-255)	\n", 0);
1122	log_printf("----      -----     ------\n", 0);
1123	if (fans_ks.fans_ok == B_TRUE)
1124		log_printf(" SYS     %5d        OK\n", fans_ks.fanspeed);
1125	else if (fans_ks.fans_ok != B_TRUE) {
1126		log_printf(" SYS     %5d      FAILED\n", fans_ks.fanspeed);
1127		exit_code = 1;
1128	}
1129
1130	log_printf("\n", 0);
1131	log_printf("=================================\n", 0);
1132	log_printf("\n", 0);
1133	log_printf("Power Supplies:\n", 0);
1134	log_printf("---------------\n", 0);
1135	log_printf("\n", 0);
1136	log_printf("Supply     Status\n", 0);
1137	log_printf("------     ------\n", 0);
1138
1139	for (i = 0; i < ecp->num_ps_kstats; i++) {
1140		ps_ks = ecp->ps_kstats[i];
1141		if (ps_ks.ps_ok == B_TRUE)
1142			(void) sprintf(state, "%s", "  OK  ");
1143		else if (ps_ks.ps_ok != B_TRUE) {
1144			(void) sprintf(state, "%s", "FAILED: DC "
1145			    "Power Failure");
1146			exit_code = 1;
1147		}
1148
1149		log_printf(" %2d        %s\n", ps_ks.slot, state);
1150	}
1151
1152	return (exit_code);
1153}
1154
1155void
1156tazjav_disp_asic_revs(Sys_tree *tree)
1157{
1158	Board_node *bnode;
1159	Prom_node *pnode;
1160	char *name;
1161	int *version;
1162	char *model;
1163
1164	/* Print the header */
1165	log_printf("\n", 0);
1166	log_printf("=========================", 0);
1167	log_printf(" HW Revisions ", 0);
1168	log_printf("=========================", 0);
1169	log_printf("\n", 0);
1170	log_printf("\n", 0);
1171
1172	bnode = tree->bd_list;
1173
1174	log_printf("ASIC Revisions:\n", 0);
1175	log_printf("---------------\n", 0);
1176
1177	/* Find sysio and print rev */
1178	for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL;
1179	    pnode = dev_next_node(pnode, "sbus")) {
1180		version = (int *)get_prop_val(find_prop(pnode, "version#"));
1181		name = get_prop_val(find_prop(pnode, "name"));
1182
1183		if ((version != NULL) && (name != NULL)) {
1184			log_printf("SBus: %s Rev %d\n", name, *version, 0);
1185		}
1186	}
1187
1188	/* Find Psycho and print rev */
1189	for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL;
1190	    pnode = dev_next_node(pnode, "pci")) {
1191		Prom_node *parsib = pnode->parent->sibling;
1192
1193		if (find_prop(pnode, "upa-portid") == NULL) {
1194			if ((parsib != NULL) &&
1195			    (strcmp(get_prop_val(
1196			    find_prop(parsib, "name")),
1197			    PCI_NAME) == 0))
1198				pnode = parsib;
1199			else {
1200				pnode = parsib;
1201				continue;
1202			}
1203		}
1204
1205		version = (int *)get_prop_val(find_prop(pnode, "version#"));
1206		name = get_prop_val(find_prop(pnode, "name"));
1207
1208		if ((version != NULL) && (name != NULL))
1209			if (get_pci_bus(pnode) == 0)
1210				log_printf("STP2223BGA: Rev %d\n", *version, 0);
1211	}
1212
1213	/* Find Cheerio and print rev */
1214	for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL;
1215	    pnode = dev_next_node(pnode, "ebus")) {
1216		version = (int *)get_prop_val(find_prop(pnode, "revision-id"));
1217		name = get_prop_val(find_prop(pnode, "name"));
1218
1219		if ((version != NULL) && (name != NULL))
1220			log_printf("STP2003QFP: Rev %d\n", *version, 0);
1221	}
1222
1223	/* Find System Controller and print rev */
1224	for (pnode = dev_find_node(bnode->nodes, "sc"); pnode != NULL;
1225	    pnode = dev_next_node(pnode, "sc")) {
1226		version = (int *)get_prop_val(find_prop(pnode, "version#"));
1227		model = (char *)get_prop_val(find_prop(pnode, "model"));
1228		name = get_prop_val(find_prop(pnode, "name"));
1229
1230		if ((version != NULL) && (name != NULL)) {
1231			if ((strcmp(model, "SUNW,sc-marvin") == 0))
1232				log_printf("STP2205BGA: Rev %d\n", *version, 0);
1233		}
1234	}
1235
1236	/* Find the FEPS and print rev */
1237	for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL;
1238	    pnode = dev_next_node(pnode, "SUNW,hme")) {
1239		version = (int *)get_prop_val(find_prop(pnode,	"hm-rev"));
1240		name = get_prop_val(find_prop(pnode, "name"));
1241
1242		if ((version != NULL) && (name != NULL)) {
1243			log_printf("FEPS: %s Rev ", name);
1244			if (*version == 0xa0) {
1245				log_printf("2.0\n", 0);
1246			} else if (*version == 0x20) {
1247				log_printf("2.1\n", 0);
1248			} else {
1249				log_printf("%x\n", *version, 0);
1250			}
1251		}
1252	}
1253	log_printf("\n", 0);
1254
1255	if (dev_find_node(bnode->nodes, FFB_NAME) != NULL) {
1256		display_ffb(bnode, 0);
1257	}
1258}
1259
1260
1261/*
1262 * Determine the physical PCI slot based on which Psycho is the parent
1263 * of the PCI card.
1264 */
1265static int
1266tazmo_physical_slot(Prom_node *slotd, Prom_node *parent, int device, char *str)
1267{
1268	int *upa_id = NULL;
1269	int *reg = NULL;
1270	int offset;
1271	char controller[MAXSTRLEN];
1272	char *name;
1273	Prop *prop;
1274	char *devpath_p;
1275	char slotx[16] = "";
1276	int *slot_names_mask;
1277	char *slot_names;
1278	int shift = 0;
1279	int slot;
1280	int slots, start_slot;
1281
1282	/*
1283	 * If slotd != NULL, then we must return the physical PCI slot
1284	 * number based on the information in the slot2dev associations
1285	 * node. This routine is called from display_pci() with slotd
1286	 * != NULL. If so, we return without obtaining the slot name.
1287	 * If slotd == NULL, we look for the slot name through the
1288	 * slot-names property in the bus node.
1289	 */
1290
1291	if (slotd != NULL) {
1292		(void) strcpy(str, "");
1293		if ((prop = find_prop(parent, "upa-portid")) != NULL)
1294			upa_id = (int *)(get_prop_val(prop));
1295		if ((prop = find_prop(parent, "reg")) != NULL)
1296			reg = (int *)(get_prop_val(prop));
1297		if ((prop = find_prop(parent, "name")) != NULL)
1298			name = (char *)(get_prop_val(prop));
1299		if ((upa_id == NULL) || (reg == NULL)) {
1300			return (-1);
1301		}
1302		offset = reg[1];
1303		if (strcmp(name, "pci") == 0) {
1304			(void) sprintf(controller, "/pci@%x,%x/*@%x,*",
1305			    *upa_id, offset, device);
1306			slots = 20;
1307		} else if (strcmp(name, "SUNW,ffb") == 0) {
1308			(void) sprintf(controller, "/*@%x,0", *upa_id);
1309			slots = 2;
1310		}
1311
1312		/*
1313		 * Javelin and future projects will use 0 based
1314		 * numbering for slots.
1315		 */
1316		start_slot = 0;
1317		slots = slots - 1;
1318		for (slot = start_slot; slot <= slots; slot++) {
1319			if (strcmp(name, "pci") == 0)
1320				(void) sprintf(slotx, "pci-slot#%d", slot);
1321			else if (strcmp(name, "SUNW,ffb") == 0)
1322				(void) sprintf(slotx, "graphics#%d", slot);
1323			if ((prop = find_prop(slotd, slotx)) != NULL)
1324				if ((devpath_p = (char *)(get_prop_val
1325				    (prop))) != NULL)
1326					if (strcmp(devpath_p, controller) == 0)
1327						return (slot);
1328		}
1329		return (-1);
1330	}
1331
1332	/*
1333	 * Get slot-names property from parent node.
1334	 * This property consists of a 32 bit mask indicating which
1335	 * devices are relevant to this bus node. Following are a
1336	 * number of strings depending on how many bits are set in the
1337	 * bit mask; the first string gives the label that is printed
1338	 * on the chassis for the smallest device number, and so on.
1339	 */
1340
1341	prop = find_prop(parent, "slot-names");
1342	if (prop == NULL) {
1343		(void) strcpy(str, "");
1344		return (-1);
1345	}
1346	slot_names_mask = (int *)(get_prop_val(prop));
1347	slot_names = (char *)slot_names_mask;
1348
1349	slot = 1;
1350	slot_names += 4;	/* Skip the 4 byte bitmask */
1351
1352	while (shift < 32) {
1353		/*
1354		 * Shift through the bitmask looking to see if the
1355		 * bit corresponding to "device" is set. If so, copy
1356		 * the correcsponding string to the provided pointer.
1357		 */
1358		if (*slot_names_mask & slot) {
1359			if (shift == device) {
1360				(void) strcpy(str, slot_names);
1361				return (0);
1362			}
1363			slot_names += strlen(slot_names)+1;
1364		}
1365		shift++;
1366		slot = slot << 1;
1367	}
1368	return (-1);
1369}
1370