xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/javelin/common/javelin.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
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 
64 extern	int	print_flag;
65 
66 /*
67  * these functions will overlay the symbol table of libprtdiag
68  * at runtime (workgroup server systems only)
69  */
70 int	error_check(Sys_tree *tree, struct system_kstat_data *kstats);
71 void	display_memoryconf(Sys_tree *tree);
72 int	disp_fail_parts(Sys_tree *tree);
73 void	display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
74 void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
75 				struct system_kstat_data *kstats);
76 void	display_boardnum(int num);
77 void	display_pci(Board_node *);
78 void	display_io_cards(struct io_card *list);
79 void	display_ffb(Board_node *, int);
80 void	read_platform_kstats(Sys_tree *tree,
81 		struct system_kstat_data *sys_kstat,
82 	        struct envctrl_kstat_data *ep);
83 
84 /* local functions */
85 static	int disp_envc_status(struct system_kstat_data *);
86 static	void tazjav_disp_asic_revs(Sys_tree *);
87 static	int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *);
88 static	Prom_node *dev_next_node_sibling(Prom_node *root, char *name);
89 
90 
91 int
92 error_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 */
113 static Prom_node *
114 dev_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  */
132 void
133 display_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  */
229 int
230 disp_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 
354 void
355 display_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 
365 void
366 display_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 */
394 void
395 display_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 */
408 void
409 display_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  */
604 void
605 display_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  */
648 void
649 display_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  */
755 void
756 read_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  */
854 Prom_node *
855 walk(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  */
976 static int
977 disp_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 
1148 void
1149 tazjav_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  */
1258 static int
1259 tazmo_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