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