xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/javelin/common/javelin.c (revision 58e78d166bd2b5a9dda31250b8e8bad7c7548c0e)
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 
63 extern	int	print_flag;
64 
65 /*
66  * these functions will overlay the symbol table of libprtdiag
67  * at runtime (workgroup server systems only)
68  */
69 int	error_check(Sys_tree *tree, struct system_kstat_data *kstats);
70 void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
71 int	disp_fail_parts(Sys_tree *tree);
72 void	display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
73 void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
74 				struct system_kstat_data *kstats);
75 void	display_boardnum(int num);
76 void	display_pci(Board_node *);
77 void	display_io_cards(struct io_card *list);
78 void	display_ffb(Board_node *, int);
79 void	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 */
84 static	int disp_envc_status(struct system_kstat_data *);
85 static	void tazjav_disp_asic_revs(Sys_tree *);
86 static	int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *);
87 static	Prom_node *dev_next_node_sibling(Prom_node *root, char *name);
88 
89 
90 int
91 error_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 */
112 static Prom_node *
113 dev_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  */
131 void
132 display_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  */
231 int
232 disp_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 
356 void
357 display_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 
367 void
368 display_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 */
396 void
397 display_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 */
410 void
411 display_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  */
606 void
607 display_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  */
650 void
651 display_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  */
757 void
758 read_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  */
861 Prom_node *
862 walk(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  */
983 static int
984 disp_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 
1155 void
1156 tazjav_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  */
1265 static int
1266 tazmo_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