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