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