xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/daktari/common/daktari.c (revision fd6d41c5025e9fb45a115fc82d86e9983d1e9fd6)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Daktari Platform specific functions.
28  *
29  * 	called when :
30  *      machine_type ==  MTYPE_DAKTARI
31  *
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <kstat.h>
40 #include <string.h>
41 #include <assert.h>
42 #include <libintl.h>
43 #include <note.h>
44 
45 #include <sys/openpromio.h>
46 #include <sys/sysmacros.h>
47 #include <sys/daktari.h>
48 
49 #include <pdevinfo.h>
50 #include <display.h>
51 #include <pdevinfo_sun4u.h>
52 #include <display_sun4u.h>
53 #include <libprtdiag.h>
54 
55 #include <picl.h>
56 #include "workfile.c"
57 
58 #if !defined(TEXT_DOMAIN)
59 #define	TEXT_DOMAIN	"SYS_TEST"
60 #endif
61 
62 #define	DAK_MAX_SLOTS_PER_IO_BD		9
63 #define	DAK_MAX_DISKS			12
64 #define	DAK_MAX_FSP_LEDS		2
65 #define	DAK_MAX_PS			3
66 #define	DAK_MAX_PS_VOLTAGE_SENSORS	4
67 #define	DAK_MAX_PS_FAULT_SENSORS	3
68 #define	DAK_MAX_FANS			10
69 #ifndef SCHIZO_COMPAT_PROP
70 #define	SCHIZO_COMPAT_PROP		"pci108e,8001"
71 #endif
72 
73 #define	MULTIPLE_BITS_SET(x)		((x)&((x)-1))
74 
75 extern	int	print_flag;
76 
77 /*
78  * these functions will overlay the symbol table of libprtdiag
79  * at runtime (workgroup server systems only)
80  */
81 void	display_cpu_devices(Sys_tree *tree);
82 void	display_cpus(Board_node *board);
83 void	display_pci(Board_node *board);
84 void	display_io_cards(struct io_card *list);
85 void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
86 				struct system_kstat_data *kstats);
87 void	display_ffb(Board_node *board, int table);
88 void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
89 
90 /* local functions */
91 static	int disp_envc_status(void);
92 static	int dak_env_print_temps(picl_nodehdl_t);
93 static	int dak_env_print_keyswitch(picl_nodehdl_t);
94 static	int dak_env_print_FSP_LEDS(picl_nodehdl_t);
95 static	int dak_env_print_disk(picl_nodehdl_t);
96 static	int dak_env_print_fans(picl_nodehdl_t);
97 static	int dak_env_print_ps(picl_nodehdl_t);
98 
99 static void dak_display_hw_revisions(Prom_node *root,
100 					Board_node *bnode);
101 static void display_schizo_revisions(Board_node *bdlist);
102 
103 
104 /*
105  * Defining the error_check function in order to return the
106  * appropriate error code.
107  */
108 /*ARGSUSED0*/
109 int
110 error_check(Sys_tree *tree, struct system_kstat_data *kstats)
111 {
112 	int exit_code = 0;	/* init to all OK */
113 	/*
114 	 * silently check for any types of machine errors
115 	 */
116 	print_flag = 0;
117 	if (disp_fail_parts(tree)) {
118 		/* set exit_code to show failures */
119 		exit_code = 1;
120 	}
121 	print_flag = 1;
122 
123 	return (exit_code);
124 }
125 
126 /*
127  * disp_fail_parts
128  *
129  * Display the failed parts in the system. This function looks for
130  * the status property in all PROM nodes. On systems where
131  * the PROM does not support passing diagnostic information
132  * through the device tree, this routine will be silent.
133  */
134 int
135 disp_fail_parts(Sys_tree *tree)
136 {
137 	int exit_code = 0;
138 	int system_failed = 0;
139 	Board_node *bnode = tree->bd_list;
140 	Prom_node *pnode;
141 
142 	/* go through all of the boards looking for failed units. */
143 	while (bnode != NULL) {
144 		/* find failed chips */
145 		pnode = find_failed_node(bnode->nodes);
146 		if ((pnode != NULL) && !system_failed) {
147 			system_failed = 1;
148 			exit_code = 1;
149 			if (print_flag == 0) {
150 				return (exit_code);
151 			}
152 			log_printf("\n");
153 			log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
154 			    "Replaceable Units (FRU) in System:\n"));
155 			log_printf("=========================="
156 			    "====================\n");
157 		}
158 		while (pnode != NULL) {
159 			void *value;
160 			char *name;		/* node name string */
161 			char *type;		/* node type string */
162 			char *board_type = NULL;
163 
164 			value = get_prop_val(find_prop(pnode, "status"));
165 			name = get_node_name(pnode);
166 
167 			/* sanity check of data retrieved from PROM */
168 			if ((value == NULL) || (name == NULL)) {
169 				pnode = next_failed_node(pnode);
170 				continue;
171 			}
172 
173 			/* Find the board type of this board */
174 			if (bnode->board_type == CPU_BOARD) {
175 				board_type = "CPU";
176 			} else {
177 				board_type = "IO";
178 			}
179 
180 			log_printf(dgettext(TEXT_DOMAIN, "%s unavailable "
181 			    "on %s Board #%d\n"), name, board_type,
182 			    bnode->board_num);
183 
184 			log_printf(dgettext(TEXT_DOMAIN,
185 			    "\tPROM fault string: %s\n"), value);
186 
187 			log_printf(dgettext(TEXT_DOMAIN,
188 			    "\tFailed Field Replaceable Unit is "));
189 
190 			/*
191 			 * Determine whether FRU is CPU module, system
192 			 * board, or SBus card.
193 			 */
194 			if ((name != NULL) && (strstr(name, "sbus"))) {
195 
196 				log_printf(dgettext(TEXT_DOMAIN,
197 				    "SBus Card %d\n"),
198 				    get_sbus_slot(pnode));
199 
200 			} else if (((name = get_node_name(pnode->parent)) !=
201 			    NULL) && (strstr(name, "pci"))) {
202 
203 				log_printf(dgettext(TEXT_DOMAIN,
204 				    "PCI Card %d"),
205 				    get_pci_device(pnode));
206 
207 			} else if (((type = get_node_type(pnode)) != NULL) &&
208 			    (strstr(type, "cpu"))) {
209 
210 				log_printf(dgettext(TEXT_DOMAIN, "UltraSPARC "
211 				    "module Board %d Module %d\n"), 0,
212 				    get_id(pnode));
213 
214 			} else {
215 				log_printf(dgettext(TEXT_DOMAIN,
216 				    "%s board %d\n"), board_type,
217 				    bnode->board_num);
218 			}
219 			pnode = next_failed_node(pnode);
220 		}
221 		bnode = bnode->next;
222 	}
223 
224 	if (!system_failed) {
225 		log_printf(dgettext(TEXT_DOMAIN,
226 		    "No failures found in System\n"));
227 		log_printf("===========================\n\n");
228 	}
229 
230 	if (system_failed)
231 		return (1);
232 	else
233 		return (0);
234 }
235 
236 /*ARGSUSED*/
237 void
238 display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
239 {
240 	/* Display failed units */
241 	(void) disp_fail_parts(tree);
242 }
243 
244 /*ARGSUSED*/
245 void
246 display_memoryconf(Sys_tree *tree, struct grp_info *grps)
247 {
248 	Board_node	*bnode = tree->bd_list;
249 
250 	log_printf(dgettext(TEXT_DOMAIN,
251 	    "========================= Memory Configuration"
252 	    " ===============================\n"
253 	    "\n           Logical  Logical"
254 	    "  Logical "
255 	    "\n      MC   Bank     Bank     Bank"
256 	    "         DIMM    Interleave  Interleaved"
257 	    "\n Brd  ID   num      size     "
258 	    "Status       Size    "
259 	    "Factor      with"
260 	    "\n----  ---  ----     ------   "
261 	    "-----------  ------  "
262 	    "----------  -----------"));
263 
264 	while (bnode != NULL) {
265 		if (get_us3_mem_regs(bnode)) {
266 			log_printf(dgettext(TEXT_DOMAIN,
267 			    "\nFailed to get memory information.\n"));
268 			return;
269 		}
270 		bnode = bnode->next;
271 	}
272 
273 	/* Display what we have found */
274 	display_us3_banks();
275 }
276 
277 void
278 display_cpu_devices(Sys_tree *tree)
279 {
280 	Board_node *bnode;
281 
282 	/*
283 	 * Display the table header for CPUs . Then display the CPU
284 	 * frequency, cache size, and processor revision of all cpus.
285 	 */
286 	log_printf(dgettext(TEXT_DOMAIN,
287 	    "\n"
288 	    "========================="
289 	    " CPUs "
290 	    "==============================================="
291 	    "\n"
292 	    "\n"
293 	    "           Run   E$  CPU    CPU  \n"
294 	    "Brd  CPU   MHz   MB Impl.   Mask \n"
295 	    "--- ----- ---- ---- ------- ---- \n"));
296 
297 	/* Now display all of the cpus on each board */
298 	bnode = tree->bd_list;
299 	if (bnode == NULL) {
300 		log_printf(dgettext(TEXT_DOMAIN,
301 		    "CPU Board list was NULL\n"));
302 	}
303 	while (bnode != NULL) {
304 		display_cpus(bnode);
305 		bnode = bnode->next;
306 	}
307 
308 	log_printf("\n");
309 }
310 
311 /*
312  * Display the CPUs present on this board.
313  */
314 void
315 display_cpus(Board_node *board)
316 {
317 	Prom_node 	*cpu;
318 	uint_t freq;	 /* CPU clock frequency */
319 	int ecache_size; /* External cache size */
320 	int *l3_shares;
321 	int *mid;
322 	int *impl;
323 	int *mask;
324 	int *coreid;
325 	char fru_prev = 'X'; /* Valid frus are 'A','B','C','D' */
326 	int mid_prev;
327 	int ecache_size_prev = 0;
328 	char fru_name;
329 
330 	/*
331 	 * display the CPUs' operating frequency, cache size, impl. field
332 	 * and mask revision.
333 	 */
334 	for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
335 	    cpu = dev_next_type(cpu, "cpu")) {
336 
337 		mid = (int *)get_prop_val(find_prop(cpu, "portid"));
338 		if (mid == NULL)
339 			mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
340 		freq = DAK_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu));
341 		ecache_size = get_ecache_size(cpu);
342 		impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
343 		mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
344 		l3_shares = (int *)get_prop_val(find_prop(cpu,
345 		    "l3-cache-sharing"));
346 
347 		/* Do not display a failed CPU node */
348 		if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
349 			continue;
350 
351 		/* Board number */
352 		fru_name = (char)('A' + DAK_GETSLOT(*mid));
353 
354 		if (CPU_IMPL_IS_CMP(*impl)) {
355 			coreid = (int *)get_prop_val(find_prop(cpu, "reg"));
356 			if (coreid == NULL) {
357 				continue;
358 			}
359 			if ((fru_prev == 'X') ||
360 			    ((fru_prev != 'X') &&
361 			    (fru_name != fru_prev))) {
362 				fru_prev = fru_name;
363 				mid_prev = *mid;
364 				ecache_size_prev = ecache_size;
365 				continue;
366 			} else {
367 				/*
368 				 * Some CMP chips have a split E$,
369 				 * so the size for both cores is added
370 				 * together to get the total size for
371 				 * the chip.
372 				 *
373 				 * Still, other CMP chips have E$ (L3)
374 				 * which is logically shared, so the
375 				 * total size is equal to the core size.
376 				 */
377 				if ((l3_shares == NULL) ||
378 				    ((l3_shares != NULL) &&
379 				    MULTIPLE_BITS_SET(*l3_shares))) {
380 					ecache_size += ecache_size_prev;
381 				}
382 				ecache_size_prev = 0;
383 				fru_prev = 'X';
384 			}
385 		}
386 
387 		log_printf("%2c", fru_name);
388 
389 		/* CPU Module ID */
390 		if (CPU_IMPL_IS_CMP(*impl)) {
391 			log_printf("%3d,%3d", mid_prev, *mid, 0);
392 		} else
393 			log_printf("    %d  ", *mid);
394 
395 		/* Running frequency */
396 		log_printf(" %4u ", freq);
397 
398 		/* Ecache size */
399 		if (ecache_size == 0)
400 			log_printf(dgettext(TEXT_DOMAIN, "%3s  "),
401 			    "N/A");
402 		else
403 			log_printf("%4.1f ",
404 			    (float)ecache_size / (float)(1<<20));
405 
406 		/* Implementation */
407 		if (impl == NULL) {
408 			log_printf(dgettext(TEXT_DOMAIN, "%s    "),
409 			"N/A");
410 		} else {
411 			if (IS_CHEETAH(*impl))
412 				log_printf("%7s", "US-III ", 0);
413 			else if (IS_CHEETAH_PLUS(*impl))
414 				log_printf("%7s", "US-III+", 0);
415 			else if (IS_JAGUAR(*impl))
416 				log_printf("%7s", "US-IV  ", 0);
417 			else if (IS_PANTHER(*impl))
418 				log_printf("%7s", "US-IV+ ", 0);
419 			else
420 				log_printf("%-7x", *impl, 0);
421 		}
422 
423 		/* CPU Mask */
424 		if (mask == NULL) {
425 			log_printf(dgettext(TEXT_DOMAIN, " %3s   "),
426 			"N/A");
427 		} else {
428 			log_printf(dgettext(TEXT_DOMAIN, " %2d.%d"),
429 			    (*mask >> 4) & 0xf, *mask & 0xf);
430 		}
431 
432 		log_printf("\n");
433 	}
434 }
435 
436 /*
437  * display_pci
438  * Display all the PCI IO cards on this board.
439  */
440 void
441 display_pci(Board_node *board)
442 {
443 	struct io_card	*card_list = NULL;
444 	struct io_card	card;
445 	void		*value;
446 	Prom_node	*pci;
447 	Prom_node	*card_node;
448 	char		*slot_name_arr[DAK_MAX_SLOTS_PER_IO_BD] = {NULL};
449 	int		i;
450 #ifdef DEBUG
451 	int		slot_name_bits;
452 #endif
453 
454 	if (board == NULL)
455 		return;
456 
457 	memset(&card, 0, sizeof (struct io_card));
458 	/* Initialize all the common information */
459 	card.display = TRUE;
460 	card.board = board->board_num;
461 
462 	/*
463 	 * Search for each pci instance, then find/display all nodes under
464 	 * each instance node found.
465 	 */
466 	for (pci = dev_find_node_by_compat(board->nodes, SCHIZO_COMPAT_PROP);
467 	    pci != NULL;
468 	    pci = dev_next_node_by_compat(pci, SCHIZO_COMPAT_PROP)) {
469 		(void) snprintf(card.bus_type, MAXSTRLEN,
470 		    dgettext(TEXT_DOMAIN, "PCI"));
471 		/*
472 		 * Get slot-name properties from parent node and
473 		 * store them in an array.
474 		 */
475 		value = (char *)get_prop_val(
476 		    find_prop(pci, "slot-names"));
477 
478 		if (value != NULL) {
479 #ifdef DEBUG
480 			/* save the 4 byte bitmask */
481 			slot_name_bits = *(int *)value;
482 #endif
483 
484 			/* array starts after first int */
485 			slot_name_arr[0] = (char *)value + sizeof (int);
486 			for (i = 1; i < DAK_MAX_SLOTS_PER_IO_BD; i++) {
487 				slot_name_arr[i] = (char *)slot_name_arr[i - 1]
488 				    + strlen(slot_name_arr[i - 1]) +1;
489 			}
490 		}
491 		/*
492 		 * Search for Children of this node ie. Cards.
493 		 * Note: any of these cards can be a pci-bridge
494 		 *	that itself has children. If we find a
495 		 *	pci-bridge we need to handle it specially.
496 		 */
497 		card_node = pci->child;
498 		/* Generate the list of pci cards on pci instance: pci */
499 		fill_pci_card_list(pci, card_node, &card, &card_list,
500 		    slot_name_arr);
501 	} /* end-for */
502 
503 	display_io_cards(card_list);
504 	free_io_cards(card_list);
505 	log_printf("\n");
506 }
507 
508 /*
509  * Print out all the io cards in the list.  Also print the column
510  * headers if told to do so.
511  */
512 void
513 display_io_cards(struct io_card *list)
514 {
515 	static int banner = 0; /* Have we printed the column headings? */
516 	struct io_card *p;
517 
518 	if (list == NULL)
519 		return;
520 
521 	if (banner == FALSE) {
522 		log_printf(dgettext(TEXT_DOMAIN,
523 		    "                         Bus  Max\n"
524 		    "     IO   Port Bus       Freq Bus  Dev,"
525 		    "\n"
526 		    "Brd  Type  ID  Side Slot MHz  Freq "
527 		    "Func State Name                              "
528 		    "Model\n"
529 		/* ---------Brd  IO   Port Bus  Slot Bus  Max  Dev  Stat */
530 		    "---- ---- ---- ---- ---- ---- ---- ----"
531 		    " ----- "
532 		    "--------------------------------  "
533 		    "----------------------\n"));
534 		banner = TRUE;
535 	}
536 
537 	for (p = list; p != NULL; p = p -> next) {
538 		log_printf(dgettext(TEXT_DOMAIN, "I/O  "));
539 		log_printf("%-4s  ", p->bus_type);
540 		log_printf("%-3d  ", p->schizo_portid);
541 		log_printf("%c    ", p->pci_bus);
542 		log_printf("%-1s    ", p->slot_str);
543 		log_printf("%-3d ", p->freq);
544 		switch (p->pci_bus) {
545 		case 'A':
546 			log_printf(dgettext(TEXT_DOMAIN, " 66  "));
547 			break;
548 		case 'B':
549 			log_printf(dgettext(TEXT_DOMAIN, " 33  "));
550 			break;
551 		default:
552 			log_printf(dgettext(TEXT_DOMAIN, "  -  "));
553 			break;
554 		}
555 
556 		log_printf("%-1d,%-1d  ", p->dev_no, p->func_no);
557 		log_printf("%-5s ", p->status);
558 		log_printf("%-32.32s", p->name);
559 		if (strlen(p->name) > 32)
560 			log_printf(dgettext(TEXT_DOMAIN, "+ "));
561 		else
562 			log_printf(dgettext(TEXT_DOMAIN, "  "));
563 		log_printf("%-22.22s", p->model);
564 		if (strlen(p->model) > 22)
565 			log_printf(dgettext(TEXT_DOMAIN, "+"));
566 
567 #ifdef DEBUG
568 		log_printf(dgettext(TEXT_DOMAIN, "%s  "), p->notes);
569 #endif
570 		log_printf("\n");
571 	}
572 }
573 
574 /*
575  * display_ffb
576  *
577  * There are no FFB's on a Daktari, however in the generic library,
578  * the display_ffb() function is implemented so we have to define an
579  * empty function here.
580  */
581 /* ARGSUSED */
582 void
583 display_ffb(Board_node *board, int table)
584 {}
585 
586 
587 /*
588  * ----------------------------------------------------------------------------
589  */
590 
591 /* ARGSUSED */
592 void
593 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
594 	struct system_kstat_data *kstats)
595 {
596 	/* NOTE(ARGUNUSED(kstats)) */
597 	/*
598 	 * Now display the last powerfail time and the fatal hardware
599 	 * reset information. We do this under a couple of conditions.
600 	 * First if the user asks for it. The second is if the user
601 	 * told us to do logging, and we found a system failure.
602 	 */
603 	if (flag) {
604 		/*
605 		 * display time of latest powerfail. Not all systems
606 		 * have this capability. For those that do not, this
607 		 * is just a no-op.
608 		 */
609 		disp_powerfail(root);
610 
611 		(void) disp_envc_status();
612 
613 		/* platform_disp_prom_version(tree); */
614 		dak_display_hw_revisions(root, tree->bd_list);
615 	}
616 }
617 
618 /*
619  * local functions
620  */
621 
622 /*
623  * disp_envc_status
624  *
625  * This routine displays the environmental status passed up from
626  * device drivers via the envlibobj.so library.
627  * This is a Daktari specific environmental information display routine.
628  */
629 int
630 disp_envc_status()
631 {
632 	int err;
633 	char *system = "SYSTEM";
634 	picl_nodehdl_t system_node, root;
635 
636 	err = picl_initialize();
637 	if (err != PICL_SUCCESS) {
638 		log_printf(dgettext(TEXT_DOMAIN,
639 		    "picl_initialize failed\n"
640 		    "%s\nCannot display environmental status\n"),
641 		    picl_strerror(err));
642 		return (err);
643 	}
644 	err = picl_get_root(&root);
645 	err = find_child_device(root, system, &system_node);
646 	if (err != PICL_SUCCESS) {
647 		log_printf(dgettext(TEXT_DOMAIN,
648 		    "picl_get_node_by_path for the SYSTEM node "
649 		    "failed\n"
650 		    "%s\nCannot display environmental status\n"),
651 		    picl_strerror(err));
652 		return (err);
653 	}
654 
655 	log_printf(dgettext(TEXT_DOMAIN,
656 	    "\n"
657 	    "========================= "
658 	    "Environmental Status "
659 	    "========================="
660 	    "\n"
661 	    "\n"));
662 
663 	dak_env_print_temps(system_node);
664 	dak_env_print_keyswitch(system_node);
665 	dak_env_print_FSP_LEDS(system_node);
666 	dak_env_print_disk(system_node);
667 	dak_env_print_fans(system_node);
668 	dak_env_print_ps(system_node);
669 
670 	(void) picl_shutdown();
671 	return (0);
672 }
673 
674 int
675 dak_env_print_ps(picl_nodehdl_t system_node)
676 {
677 	int		i, r, fail, err = 0;
678 	int		low_warn_flag = 0;
679 	int32_t		number;
680 	char		name[PICL_PROPNAMELEN_MAX];
681 	picl_nodehdl_t	*ps;
682 	picl_nodehdl_t	*ps_fail[DAK_MAX_PS_FAULT_SENSORS];
683 	picl_nodehdl_t	*ps_I_sensor[DAK_MAX_PS_VOLTAGE_SENSORS];
684 	int32_t		volts[DAK_MAX_PS_VOLTAGE_SENSORS];
685 	int32_t		lo_warn[DAK_MAX_PS_VOLTAGE_SENSORS];
686 	char		fault_state
687 	    [DAK_MAX_PS_FAULT_SENSORS][PICL_PROPNAMELEN_MAX];
688 	char		ps_state[PICL_PROPNAMELEN_MAX];
689 	/* Printing out the Power Supply Heading information */
690 	log_printf(dgettext(TEXT_DOMAIN,
691 	    "Power Supplies:\n"
692 	    "---------------\n"
693 	    "                                                    "
694 	    "Current Drain:\n"
695 	    "Supply     Status     Fan Fail  Temp Fail  CS Fail  "
696 	    "3.3V   5V   12V   48V\n"
697 	    "------  ------------  --------  ---------  "
698 	    "-------  ----   --   ---   ---\n"));
699 
700 	err = fill_device_array_from_id(system_node, "PSVC_PS", &number,
701 	    &ps);
702 	if (err != PICL_SUCCESS) {
703 		log_printf(dgettext(TEXT_DOMAIN,
704 		    "failed in fill_device_array_from_id for PS\n"
705 		    "%s\n"), picl_strerror(err));
706 		return (err);
707 	}
708 	/* Printing out the Power Supply Status information */
709 	for (i = 0; i < DAK_MAX_PS; i++) {
710 		/*
711 		 * Re initialize the fail variable so that if
712 		 * one power supply fails, they don't all do also.
713 		 */
714 		fail = 0;
715 
716 		err = picl_get_propval_by_name(ps[i], PICL_PROP_NAME, name,
717 		    PICL_PROPNAMELEN_MAX);
718 		if (err != PICL_SUCCESS) {
719 			continue;
720 		}
721 		err = picl_get_propval_by_name(ps[i], "State", ps_state,
722 		    PICL_PROPNAMELEN_MAX);
723 		if (err != PICL_SUCCESS) {
724 			log_printf(dgettext(TEXT_DOMAIN,
725 			    "Error getting ps[%d]'s state: %s"),
726 			    i, picl_strerror(err));
727 		}
728 
729 		err = fill_device_array_from_id(ps[i], "PSVC_DEV_FAULT_SENSOR",
730 		    &number, &ps_fail[i]);
731 
732 		if (err != PICL_SUCCESS) {
733 			log_printf(dgettext(TEXT_DOMAIN,
734 			    "failed to get present PS fault sensors\n"
735 			    "%s\n"), picl_strerror(err));
736 			return (err);
737 		}
738 
739 		err = fill_device_array_from_id(ps[i], "PSVC_PS_I_SENSOR",
740 		    &number, &ps_I_sensor[i]);
741 
742 		if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
743 			log_printf(dgettext(TEXT_DOMAIN,
744 			    "failed to get present PS I sensors\n"
745 			    "%s\n"), picl_strerror(err));
746 		}
747 
748 		log_printf("%s", name);
749 
750 		/*
751 		 * If the AC cord is unplugged, then the power supply
752 		 * sensors will have unreliable values.  In this case,
753 		 * skip to the next power supply.
754 		 */
755 		if (strcmp(ps_state, "HOTPLUGGED") == 0) {
756 			log_printf(dgettext(TEXT_DOMAIN,
757 			    "      UNPLUGGED\n"));
758 			continue;
759 		}
760 
761 		for (r = 0; r < DAK_MAX_PS_FAULT_SENSORS; r++) {
762 			err = picl_get_propval_by_name(ps_fail[i][r], "State",
763 			    fault_state[r], PICL_PROPNAMELEN_MAX);
764 			if (err == PICL_SUCCESS) {
765 				fail =
766 				    strcmp(fault_state[r], "OFF")
767 				    + fail;
768 			} else {
769 				log_printf(dgettext(TEXT_DOMAIN,
770 				    "picl_get_propval_by_name for ps "
771 				    "fault state failed\n"
772 				    "%s\n"), picl_strerror(err));
773 				return (err);
774 			}
775 		}
776 		for (r = 0; r < DAK_MAX_PS_VOLTAGE_SENSORS; r++) {
777 			err = picl_get_propval_by_name(ps_I_sensor[i][r],
778 			    "AtoDSensorValue", &volts[r],
779 			    sizeof (int32_t));
780 			if (err != PICL_SUCCESS) {
781 				log_printf(dgettext(TEXT_DOMAIN,
782 				    "failed to get A to D sensor "
783 				    "value\n%s\n"), picl_strerror(err));
784 				return (err);
785 			}
786 			err = picl_get_propval_by_name(ps_I_sensor[i][r],
787 			    "LowWarningThreshold", &lo_warn[r],
788 			    sizeof (int32_t));
789 			if (err != PICL_SUCCESS) {
790 				log_printf(dgettext(TEXT_DOMAIN,
791 				    "failed to get low warning threshold "
792 				    "value\n%s\n"), picl_strerror(err));
793 				return (err);
794 			}
795 			if (volts[r] <= lo_warn[r])
796 				low_warn_flag++;
797 		}
798 
799 		if (fail != 0 || low_warn_flag != 0) {
800 			log_printf(dgettext(TEXT_DOMAIN,
801 			    "      FAIL      "));
802 		} else {
803 			log_printf(dgettext(TEXT_DOMAIN, "      GOOD      "));
804 		}
805 
806 		if (fail != 0) {
807 			for (r = 0; r < DAK_MAX_PS_FAULT_SENSORS; r++) {
808 				log_printf(dgettext(TEXT_DOMAIN, "      %-4s"),
809 				    fault_state[r]);
810 			}
811 		} else {
812 			for (r = 0; r < DAK_MAX_PS_FAULT_SENSORS; r++) {
813 				log_printf(dgettext(TEXT_DOMAIN, "          "));
814 			}
815 		}
816 		for (r = 0; r < DAK_MAX_PS_VOLTAGE_SENSORS; r++) {
817 			log_printf(dgettext(TEXT_DOMAIN, "    %2d"), volts[r]);
818 		}
819 		log_printf("\n");
820 	}
821 	log_printf("\n");
822 	return (err);
823 }
824 
825 int
826 dak_env_print_fans(picl_nodehdl_t system_node)
827 {
828 	int		i, err = 0;
829 	int32_t		number, fan_speed;
830 	picl_nodehdl_t	*fans;
831 	char		name[PICL_PROPNAMELEN_MAX];
832 	char		enabled[PICL_PROPNAMELEN_MAX];
833 
834 	err = fill_device_array_from_id(system_node, "PSVC_FAN", &number,
835 	    &fans);
836 	if (err != PICL_SUCCESS) {
837 		log_printf(dgettext(TEXT_DOMAIN,
838 		    "failed in fill_device_array_from_id "
839 		    "for FAN\n"
840 		    "%s\n"), picl_strerror(err));
841 		return (err);
842 	}
843 
844 	log_printf("\n");
845 	log_printf(dgettext(TEXT_DOMAIN,
846 	    "=================================\n"));
847 	log_printf("\n");
848 	log_printf(dgettext(TEXT_DOMAIN, "Fan Bank :\n"));
849 	log_printf(dgettext(TEXT_DOMAIN, "----------\n"));
850 	log_printf("\n");
851 	log_printf(dgettext(TEXT_DOMAIN, "Bank                        Speed "
852 	    "        Status        Fan State\n"));
853 	log_printf(dgettext(TEXT_DOMAIN, "                           ( RPMS )"
854 	    "	\n"));
855 	log_printf(dgettext(TEXT_DOMAIN, "----                       --------"
856 	    "      ---------      ---------\n"));
857 
858 
859 	for (i = 0; i < DAK_MAX_FANS; i++) {
860 		char fan_state[PICL_PROPNAMELEN_MAX];
861 		fan_speed = 0;
862 		err = picl_get_propval_by_name(fans[i], PICL_PROP_NAME, name,
863 		    PICL_PROPNAMELEN_MAX);
864 		if (err == PICL_SUCCESS) {
865 			log_printf(dgettext(TEXT_DOMAIN, "%16-s"), name);
866 		} else {
867 			continue;
868 		}
869 
870 		err = picl_get_propval_by_name(fans[i], "Fan-speed",
871 		    &fan_speed, sizeof (int32_t));
872 		if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
873 			log_printf(dgettext(TEXT_DOMAIN,
874 			    "failed in picl_get_propval_by_name for "
875 			    "fan speed\n"
876 			    "%s\n"), picl_strerror(err));
877 			return (err);
878 		}
879 
880 		if ((strcmp(name, "CPU0_PRIM_FAN") != 0) &&
881 		    (strcmp(name, "CPU1_PRIM_FAN") != 0)) {
882 			err = picl_get_propval_by_name(fans[i], "Fan-switch",
883 			    enabled, PICL_PROPNAMELEN_MAX);
884 			if ((err != PICL_SUCCESS) &&
885 			    (err != PICL_INVALIDHANDLE)) {
886 				log_printf(dgettext(TEXT_DOMAIN,
887 				    "failed in picl_get_propval_by_name for"
888 				    " fan enabled/disabled\n"
889 				    "%s\n"), picl_strerror(err));
890 				return (err);
891 			}
892 			/*
893 			 * Display the fan's speed and whether or not
894 			 * it's enabled.
895 			 */
896 			if (strcmp(enabled, "ON") == 0) {
897 				log_printf(dgettext(TEXT_DOMAIN,
898 				    "\t     %4d        [ENABLED]"),
899 				    fan_speed);
900 			} else {
901 				log_printf(dgettext(TEXT_DOMAIN,
902 				    "\t        0        [DISABLED]"));
903 			}
904 
905 		} else {
906 			/* Display the fan's speed */
907 			log_printf(dgettext(TEXT_DOMAIN, "\t     %4d"),
908 			    fan_speed);
909 			log_printf(dgettext(TEXT_DOMAIN,
910 			    "        [ENABLED]"));
911 		}
912 
913 		err = picl_get_propval_by_name(fans[i], "State", fan_state,
914 		    PICL_PROPNAMELEN_MAX);
915 		if (err != PICL_SUCCESS) {
916 			log_printf(dgettext(TEXT_DOMAIN,
917 			    "picl_get_propval_by_name failed: %s"),
918 			    picl_strerror(err));
919 			return (err);
920 		}
921 		log_printf(dgettext(TEXT_DOMAIN, "\t    %s\n"), fan_state);
922 	}
923 	log_printf("\n");
924 	log_printf(dgettext(TEXT_DOMAIN,
925 	    "=================================\n"));
926 	log_printf("\n");
927 
928 	return (err);
929 }
930 
931 int
932 dak_env_print_disk(picl_nodehdl_t system_node)
933 {
934 	int		i, err;
935 	int32_t		number;
936 	picl_nodehdl_t	*disks;
937 	picl_nodehdl_t	disk_slots[DAK_MAX_DISKS];
938 	picl_nodehdl_t	disk_fault_leds[DAK_MAX_DISKS];
939 	picl_nodehdl_t	disk_remove_leds[DAK_MAX_DISKS];
940 	char		led_state[PICL_PROPNAMELEN_MAX];
941 	char		name[PICL_PROPNAMELEN_MAX];
942 
943 	err = fill_device_array_from_id(system_node, "PSVC_DISK", &number,
944 	    &disks);
945 	if (err != PICL_SUCCESS) {
946 		log_printf(dgettext(TEXT_DOMAIN,
947 		    "failed in fill_device_array_from_id for "
948 		    "DISK\n"
949 		    "%s\n"), picl_strerror(err));
950 		return (err);
951 	}
952 
953 	log_printf(dgettext(TEXT_DOMAIN,
954 	    "Disk Status:\n"
955 	    "	  Presence	Fault LED	Remove LED\n"));
956 
957 	for (i = 0; i < DAK_MAX_DISKS; i++) {
958 		err = picl_get_propval_by_name(disks[i], PICL_PROP_NAME, name,
959 		    PICL_PROPNAMELEN_MAX);
960 		switch (err) {
961 		case PICL_SUCCESS:
962 			log_printf(dgettext(TEXT_DOMAIN, "DISK  %2d: [%7s]"),
963 			    i, "PRESENT");
964 			break;
965 		case PICL_INVALIDHANDLE:
966 			log_printf(dgettext(TEXT_DOMAIN, "DISK  %2d: [%7s]"),
967 			    i, "EMPTY");
968 			log_printf("\n");
969 			continue;
970 		default:
971 			log_printf(dgettext(TEXT_DOMAIN,
972 			    "Failed picl_get_propval_by_name for "
973 			    "disk %d with %s\n"), i, picl_strerror(err));
974 			return (err);
975 		}
976 
977 		err = fill_device_from_id(disks[i], "PSVC_PARENT",
978 		    &(disk_slots[i]));
979 		switch (err) {
980 		case PICL_SUCCESS:
981 			break;
982 		case PICL_INVALIDHANDLE:
983 			continue;
984 		default:
985 			log_printf(dgettext(TEXT_DOMAIN,
986 			    "failed in fill_device_from_id for disk "
987 			    "slot\n"
988 			    "%s\n"), picl_strerror(err));
989 			return (err);
990 		}
991 
992 		err = fill_device_from_id(disk_slots[i], "PSVC_SLOT_FAULT_LED",
993 		    &disk_fault_leds[i]);
994 		if (err != PICL_SUCCESS) {
995 			log_printf(dgettext(TEXT_DOMAIN,
996 			    "failed in fill_device_from_id for disk slot "
997 			    "fault led\n"
998 			    "%s\n"), picl_strerror(err));
999 			return (err);
1000 		}
1001 		err = picl_get_propval_by_name(disk_fault_leds[i],
1002 		    "State", led_state, PICL_PROPNAMELEN_MAX);
1003 		if (err == PICL_SUCCESS) {
1004 			log_printf(dgettext(TEXT_DOMAIN, "	   [%3s]"),
1005 			    led_state);
1006 		} else {
1007 			log_printf(dgettext(TEXT_DOMAIN,
1008 			    "picl_get_propval_by_name for fault led_state"
1009 			    " failed\n"
1010 			    "%s\n"), picl_strerror(err));
1011 			return (err);
1012 		}
1013 		err = fill_device_from_id(disk_slots[i], "PSVC_SLOT_REMOVE_LED",
1014 		    &disk_remove_leds[i]);
1015 		if (err != PICL_SUCCESS) {
1016 			log_printf(dgettext(TEXT_DOMAIN,
1017 			    "failed in fill_device_from_id for disk slot "
1018 			    "remove led\n"
1019 			    "%s\n"), picl_strerror(err));
1020 			return (err);
1021 		}
1022 
1023 		err = picl_get_propval_by_name(disk_remove_leds[i],
1024 		    "State", led_state, PICL_PROPNAMELEN_MAX);
1025 		if (err == PICL_SUCCESS) {
1026 			log_printf(dgettext(TEXT_DOMAIN,
1027 			    "	   [%3s]"), led_state);
1028 		} else {
1029 			log_printf(dgettext(TEXT_DOMAIN,
1030 			    "picl_get_propval_by_name for remove"
1031 			    " led_state failed\n"
1032 			    "%s\n"), picl_strerror(err));
1033 			return (err);
1034 		}
1035 		log_printf("\n");
1036 	}
1037 	return (err);
1038 }
1039 
1040 int
1041 dak_env_print_FSP_LEDS(picl_nodehdl_t system_node)
1042 {
1043 	int		i, err = 0;
1044 	int32_t		number;
1045 	picl_nodehdl_t	*fsp_leds;
1046 	char		led_state[PICL_PROPNAMELEN_MAX];
1047 
1048 	err = fill_device_array_from_id(system_node, "PSVC_FSP_LED", &number,
1049 	    &fsp_leds);
1050 	if (err != PICL_SUCCESS) {
1051 		log_printf(dgettext(TEXT_DOMAIN,
1052 		    "failed in fill_device_array_from_id for "
1053 		    "FSP_LED\n"
1054 		    "%s\n"), picl_strerror(err));
1055 		return (err);
1056 	}
1057 
1058 	log_printf(dgettext(TEXT_DOMAIN,
1059 	    "System LED Status:\n"
1060 	    "                   GEN FAULT                REMOVE\n"));
1061 	for (i = 0; i < DAK_MAX_FSP_LEDS; i++) {
1062 		err = picl_get_propval_by_name(fsp_leds[i], "State",
1063 		    led_state, PICL_PROPNAMELEN_MAX);
1064 		if (err != PICL_SUCCESS) {
1065 			log_printf(dgettext(TEXT_DOMAIN,
1066 			    "picl_get_propval_by_name for led_state"
1067 			    " failed\n"
1068 			    "%s\n"), picl_strerror(err));
1069 			return (err);
1070 		}
1071 
1072 		log_printf(dgettext(TEXT_DOMAIN,
1073 		    "                    [%3s]"), led_state);
1074 	}
1075 	log_printf("\n\n");
1076 	log_printf(dgettext(TEXT_DOMAIN,
1077 	    "                   DISK FAULT               "));
1078 	log_printf(dgettext(TEXT_DOMAIN, "POWER FAULT\n"));
1079 	for (i = 2; i < 4; i++) {
1080 		err = picl_get_propval_by_name(fsp_leds[i], "State",
1081 		    led_state, PICL_PROPNAMELEN_MAX);
1082 		if (err != PICL_SUCCESS) {
1083 			log_printf(dgettext(TEXT_DOMAIN,
1084 			    "picl_get_propval_by_name for led_state"
1085 			    " failed\n"
1086 			    "%s\n"), picl_strerror(err));
1087 			return (err);
1088 		}
1089 		log_printf(dgettext(TEXT_DOMAIN, "                    [%3s]"),
1090 		    led_state);
1091 	}
1092 	log_printf("\n\n");
1093 	log_printf(dgettext(TEXT_DOMAIN,
1094 	    "                   LEFT THERMAL FAULT       "
1095 	    "RIGHT THERMAL FAULT\n"));
1096 	for (i = 4; i < 6; i++) {
1097 		err = picl_get_propval_by_name(fsp_leds[i], "State",
1098 		    led_state, PICL_PROPNAMELEN_MAX);
1099 		if (err != PICL_SUCCESS) {
1100 			log_printf(dgettext(TEXT_DOMAIN,
1101 			    "picl_get_propval_by_name for led_state "
1102 			    "failed\n"
1103 			    "%s\n"), picl_strerror(err));
1104 			return (err);
1105 		}
1106 		log_printf(dgettext(TEXT_DOMAIN, "                    [%3s]"),
1107 		    led_state);
1108 	}
1109 	log_printf("\n\n");
1110 	log_printf(dgettext(TEXT_DOMAIN,
1111 	    "                   LEFT DOOR                "
1112 	    "RIGHT DOOR\n"));
1113 	for (i = 6; i < 8; i++) {
1114 		err = picl_get_propval_by_name(fsp_leds[i], "State",
1115 		    led_state, PICL_PROPNAMELEN_MAX);
1116 		if (err != PICL_SUCCESS) {
1117 			log_printf(dgettext(TEXT_DOMAIN,
1118 			    "picl_get_propval_by_name for led_state"
1119 			    " failed\n"
1120 			    "%s\n"), picl_strerror(err));
1121 			return (err);
1122 		}
1123 		log_printf(dgettext(TEXT_DOMAIN, "                    [%3s]"),
1124 		    led_state);
1125 	}
1126 	log_printf("\n\n");
1127 	log_printf(dgettext(TEXT_DOMAIN,
1128 	    "=================================\n"));
1129 	log_printf("\n");
1130 
1131 	return (err);
1132 }
1133 
1134 int
1135 dak_env_print_keyswitch(picl_nodehdl_t system_node)
1136 {
1137 	int 		err = 0;
1138 	picl_nodehdl_t *keyswitch;
1139 	int32_t		number;
1140 	char		ks_pos[PICL_PROPNAMELEN_MAX];
1141 
1142 	err = fill_device_array_from_id(system_node, "PSVC_KEYSWITCH", &number,
1143 	    &keyswitch);
1144 	if (err != PICL_SUCCESS) {
1145 		log_printf(dgettext(TEXT_DOMAIN,
1146 		    "failed in fill_device_array_from_id for "
1147 		    "	PSVC_KEYSWITCH\n"
1148 		    "%s\n"), picl_strerror(err));
1149 		return (err);
1150 	}
1151 
1152 	err = picl_get_propval_by_name(keyswitch[0], "State", ks_pos,
1153 	    PICL_PROPNAMELEN_MAX);
1154 	if (err != PICL_SUCCESS) {
1155 		log_printf(dgettext(TEXT_DOMAIN,
1156 		    "picl_get_propval_by_name for keyswitch state "
1157 		    "failed\n"
1158 		    "%s\n"), picl_strerror(err));
1159 		return (err);
1160 	}
1161 
1162 	log_printf(dgettext(TEXT_DOMAIN,
1163 	    "Front Status Panel:\n"
1164 	    "-------------------\n"
1165 	    "Keyswitch position: "
1166 	    "%s\n"), ks_pos);
1167 	log_printf("\n");
1168 
1169 	return (err);
1170 }
1171 
1172 int
1173 dak_env_print_temps(picl_nodehdl_t system_node)
1174 {
1175 	int		i;
1176 	int		err;
1177 	picl_nodehdl_t	*system_ts_nodes;
1178 	int32_t		temp;
1179 	int32_t		number;
1180 	char		label[PICL_PROPNAMELEN_MAX];
1181 	char		state[PICL_PROPNAMELEN_MAX];
1182 	char		*p;
1183 
1184 	err = fill_device_array_from_id(system_node, "PSVC_TS", &number,
1185 	    &system_ts_nodes);
1186 	if (err != PICL_SUCCESS) {
1187 		return (err);
1188 	}
1189 
1190 	log_printf(dgettext(TEXT_DOMAIN,
1191 	    "System Temperatures (Celsius):\n"
1192 	    "-------------------------------\n"
1193 	    "Device\t\tTemperature\tStatus\n"
1194 	    "---------------------------------------\n"));
1195 
1196 	for (i = 0; i < number; i++) {
1197 		err = picl_get_propval_by_name(system_ts_nodes[i],
1198 		    "State", state, sizeof (state));
1199 		if (err != PICL_SUCCESS) {
1200 			if (err == PICL_INVALIDHANDLE) {
1201 				strcpy(state, "n/a");
1202 			} else {
1203 				log_printf("%s\n", picl_strerror(err));
1204 				return (err);
1205 			}
1206 		}
1207 		err = picl_get_propval_by_name(system_ts_nodes[i],
1208 		    PICL_PROP_NAME, label, PICL_PROPNAMELEN_MAX);
1209 		if (err != PICL_SUCCESS) {
1210 			if (err == PICL_INVALIDHANDLE)
1211 				/* This FRU isn't present. Skip it. */
1212 				continue;
1213 			log_printf("%s\n", picl_strerror(err));
1214 			return (err);
1215 		}
1216 
1217 		/*
1218 		 * The names in the tree are like "CPU0_DIE_TEMPERATURE_SENSOR".
1219 		 * All we want to print is up to the first underscore.
1220 		 */
1221 		p = strchr(label, '_');
1222 		if (p != NULL)
1223 			*p = '\0';
1224 
1225 		err = picl_get_propval_by_name(system_ts_nodes[i],
1226 		    "Temperature", &temp, sizeof (temp));
1227 		if (err != PICL_SUCCESS) {
1228 			log_printf("%s\n", picl_strerror(err));
1229 			return (err);
1230 		}
1231 		log_printf("%s\t\t%3d\t\t%s\n", label, temp, state);
1232 	}
1233 
1234 	log_printf(dgettext(TEXT_DOMAIN,
1235 	    "\n=================================\n\n"));
1236 
1237 	return (PICL_SUCCESS);
1238 }
1239 
1240 static void
1241 dak_display_hw_revisions(Prom_node *root, Board_node *bdlist)
1242 {
1243 	Prom_node	*pnode;
1244 	char		*value;
1245 
1246 	log_printf(dgettext(TEXT_DOMAIN, "\n"
1247 	    "========================= HW Revisions "
1248 	    "=======================================\n\n"));
1249 
1250 	log_printf(dgettext(TEXT_DOMAIN,
1251 	    "System PROM revisions:\n"
1252 	    "----------------------\n"));
1253 
1254 	pnode = dev_find_node(root, "openprom");
1255 	if (pnode != NULL) {
1256 		value = (char *)get_prop_val(find_prop(pnode, "version"));
1257 		log_printf(value);
1258 	}
1259 
1260 	log_printf(dgettext(TEXT_DOMAIN, "\n\n"
1261 	    "IO ASIC revisions:\n"
1262 	    "------------------\n"
1263 	    "         Port\n"
1264 	    "Model     ID  Status Version\n"
1265 	    "-------- ---- ------ -------\n"));
1266 
1267 	display_schizo_revisions(bdlist);
1268 }
1269 
1270 static void
1271 display_schizo_revisions(Board_node *bdlist)
1272 {
1273 	Prom_node	*pnode;
1274 	int		*int_val;
1275 	int		portid;
1276 	int		prev_portid = -1;
1277 	char		*status_a = NULL;
1278 	char		*status_b = NULL;
1279 	int		revision;
1280 #ifdef DEBUG
1281 	uint32_t	a_notes, b_notes;
1282 #endif
1283 	int		pci_bus;
1284 	Board_node	*bnode;
1285 	bnode = bdlist;
1286 
1287 	while (bnode != NULL) {
1288 		/*
1289 		 * search this board node for all Schizos
1290 		 */
1291 		for (pnode = dev_find_node_by_compat(bnode->nodes,
1292 		    SCHIZO_COMPAT_PROP); pnode != NULL;
1293 		    pnode = dev_next_node_by_compat(pnode,
1294 		    SCHIZO_COMPAT_PROP)) {
1295 
1296 			/*
1297 			 * get the reg property to determine
1298 			 * whether we are looking at side A or B
1299 			 */
1300 			int_val = (int *)get_prop_val
1301 			    (find_prop(pnode, "reg"));
1302 			if (int_val != NULL) {
1303 				int_val ++; /* second integer in array */
1304 				pci_bus = ((*int_val) & 0x7f0000);
1305 			}
1306 
1307 			/* get portid */
1308 			int_val = (int *)get_prop_val
1309 			    (find_prop(pnode, "portid"));
1310 			if (int_val == NULL)
1311 				continue;
1312 
1313 			portid = *int_val;
1314 
1315 			/*
1316 			 * If this is a new portid and it is PCI bus B,
1317 			 * we skip onto the PCI bus A.
1318 			 */
1319 			if ((portid != prev_portid) && (pci_bus == 0x700000)) {
1320 				prev_portid = portid;
1321 				/* status */
1322 				status_b = (char *)get_prop_val
1323 				    (find_prop(pnode, "status"));
1324 #ifdef DEBUG
1325 				b_notes = pci_bus;
1326 #endif
1327 				continue; /* skip to the next schizo */
1328 			}
1329 
1330 			/*
1331 			 * This must be side A of the same Schizo.
1332 			 * Gather all its props and display them.
1333 			 */
1334 #ifdef DEBUG
1335 			a_notes = pci_bus;
1336 #endif
1337 
1338 			prev_portid = portid;
1339 
1340 			int_val = (int *)get_prop_val
1341 			    (find_prop(pnode, "version#"));
1342 			if (int_val != NULL)
1343 				revision = *int_val;
1344 			else
1345 				revision = -1;
1346 
1347 			status_a = (char *)get_prop_val(find_prop
1348 			    (pnode, "status"));
1349 
1350 			log_printf(dgettext(TEXT_DOMAIN, "Schizo    "));
1351 
1352 			log_printf(dgettext(TEXT_DOMAIN, "%-3d "), portid, 0);
1353 
1354 
1355 			log_printf((status_a == NULL && status_b == NULL) ?
1356 			    dgettext(TEXT_DOMAIN, "  ok  ") :
1357 			    dgettext(TEXT_DOMAIN, " fail "));
1358 
1359 			log_printf(dgettext(TEXT_DOMAIN, " %4d   "),
1360 			    revision);
1361 #ifdef DEBUG
1362 			log_printf(" 0x%x 0x%x", a_notes, b_notes);
1363 #endif
1364 			log_printf("\n");
1365 		}
1366 		bnode = bnode->next;
1367 	}
1368 }
1369