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 * Littleneck Platform specific functions.
27 *
28 * called when :
29 * machine_type == MTYPE_LITTLENECK
30 *
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <kstat.h>
37 #include <string.h>
38 #include <assert.h>
39 #include <libintl.h>
40 #include <note.h>
41 #include <syslog.h>
42
43 #include <sys/openpromio.h>
44 #include <sys/sysmacros.h>
45
46 #include <pdevinfo.h>
47 #include <display.h>
48 #include <pdevinfo_sun4u.h>
49 #include <display_sun4u.h>
50 #include <libprtdiag.h>
51
52 #include <picl.h>
53 #include "workfile.c"
54
55 #define LNECK_MAX_PS 2
56 #define LNECK_MAX_DISKS 2
57 #define LNECK_MAX_FANS 1
58
59 #ifndef SCHIZO_COMPAT_PROP
60 #define SCHIZO_COMPAT_PROP "pci108e,8001"
61 #endif
62
63 /* Count of failed PSU's found */
64 int ps_failure = 0;
65
66 /*
67 * Ignore first entry into disp_envc_status()
68 * from libprtdiag/common/display_sun4u.c
69 */
70 int print_flag = 0;
71
72 /*
73 * these functions will overlay the symbol table of libprtdiag
74 * at runtime (workgroup server systems only)
75 */
76 int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
77 void display_cpu_devices(Sys_tree *tree);
78 void display_pci(Board_node *board);
79 void display_io_cards(struct io_card *list);
80 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
81 struct system_kstat_data *kstats);
82 void display_ffb(Board_node *board, int table);
83 void display_memoryconf(Sys_tree *tree);
84
85 /* local functions */
86 static int disp_envc_status(void);
87 static int lneck_env_print_temps(picl_nodehdl_t);
88 static int lneck_env_print_keyswitch(picl_nodehdl_t);
89 static int lneck_env_print_FSP_LEDS(picl_nodehdl_t);
90 static int lneck_env_print_disk(picl_nodehdl_t);
91 static int lneck_env_print_fans(picl_nodehdl_t);
92 static int lneck_env_print_ps(picl_nodehdl_t);
93
94 static void lneck_display_hw_revisions(Prom_node *root,
95 Board_node *bnode);
96 static void display_schizo_revisions(Board_node *bdlist);
97
98 /*
99 * Defining the error_check function in order to return the
100 * appropriate error code.
101 */
102 /*ARGSUSED0*/
103 int
error_check(Sys_tree * tree,struct system_kstat_data * kstats)104 error_check(Sys_tree *tree, struct system_kstat_data *kstats)
105 {
106 int exit_code = 0; /* init to all OK */
107 /* silently check for any types of machine errors */
108 print_flag = 0;
109 if (disp_fail_parts(tree) || disp_envc_status())
110 /* set exit_code to show failures */
111 exit_code = 1;
112
113 print_flag = 1;
114
115 return (exit_code);
116 }
117
118 void
display_cpu_devices(Sys_tree * tree)119 display_cpu_devices(Sys_tree *tree)
120 {
121 Board_node *bnode;
122
123 /*
124 * Display the table header for CPUs . Then display the CPU
125 * frequency, cache size, and processor revision of all cpus.
126 */
127 log_printf(dgettext(TEXT_DOMAIN,
128 "\n"
129 "========================= CPUs "
130 "==============================================="
131 "\n"
132 "\n"
133 " Run E$ CPU CPU \n"
134 "Brd CPU MHz MB Impl. Mask \n"
135 "--- --- ---- ---- ------- ---- \n"));
136
137 /* Now display all of the cpus on each board */
138 bnode = tree->bd_list;
139 while (bnode != NULL) {
140 display_cpus(bnode);
141 bnode = bnode->next;
142 }
143
144 log_printf("\n");
145 }
146
147
148 /*
149 * Display the CPUs present on this board.
150 */
151 void
display_cpus(Board_node * board)152 display_cpus(Board_node *board)
153 {
154 Prom_node *cpu;
155 char cpu_name[] = "cpu";
156
157 /*
158 * display the CPUs' operating frequency, cache size, impl. field
159 * and mask revision.
160 */
161
162 for (cpu = dev_find_type(board->nodes, cpu_name); cpu != NULL;
163 cpu = dev_next_type(cpu, cpu_name)) {
164 uint_t freq; /* CPU clock frequency */
165 int ecache_size; /* External cache size */
166 int *mid;
167 int *impl;
168 int *mask;
169
170 mid = (int *)get_prop_val(find_prop(cpu, "portid"));
171 freq = LNECK_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu));
172 ecache_size = get_ecache_size(cpu);
173 impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
174 mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
175
176 /* Do not display a failed CPU node */
177 if ((freq != 0) && (node_failed(cpu) == 0)) {
178 /* Board number */
179 switch (*mid) {
180 case 1:
181 log_printf(dgettext(TEXT_DOMAIN,
182 " B "));
183 break;
184 case 0:
185 log_printf(dgettext(TEXT_DOMAIN,
186 " A "));
187 break;
188 default:
189 log_printf(dgettext(TEXT_DOMAIN, "X "));
190 }
191
192 /* CPU MID */
193 log_printf("%2d ", *mid);
194
195 /* Module number */
196
197 /* Running frequency */
198 log_printf("%4u ", freq);
199
200 /* Ecache size */
201 if (ecache_size == 0)
202 log_printf("N/A ");
203 else
204 log_printf("%4.1f ",
205 (float)ecache_size / (float)(1<<20));
206
207 /* Implementation */
208 if (impl == NULL) {
209 log_printf(dgettext(TEXT_DOMAIN, "%6s "),
210 " N/A");
211 } else {
212 if (IS_CHEETAH(*impl))
213 log_printf("%-7s ", "US-III", 0);
214 else if (IS_CHEETAH_PLUS(*impl))
215 log_printf("%-7s ", "US-III+", 0);
216 else
217 log_printf("%-7x ", *impl, 0);
218 }
219
220 /* CPU Mask */
221 if (mask == NULL) {
222 log_printf(dgettext(TEXT_DOMAIN, " N/A "));
223 } else {
224 log_printf(dgettext(TEXT_DOMAIN, " %d.%d "),
225 (*mask >> 4) & 0xf, *mask & 0xf);
226 }
227
228 log_printf("\n");
229 }
230 }
231 }
232
233 void
display_memoryconf(Sys_tree * tree)234 display_memoryconf(Sys_tree *tree)
235 {
236 Board_node *bnode = tree->bd_list;
237
238 log_printf(dgettext(TEXT_DOMAIN,
239 "========================= Memory Configuration"
240 " ===============================\n"
241 "\n Logical Logical Logical "
242 "\n MC Bank Bank Bank DIMM "
243 "Interleave Interleaved"
244 "\n Brd ID num size Status Size "
245 "Factor with"
246 "\n---- --- ---- ------ ----------- ------ "
247 "---------- -----------"));
248
249 while (bnode != NULL) {
250 if (get_us3_mem_regs(bnode)) {
251 log_printf(dgettext(TEXT_DOMAIN,
252 "\nFailed to get memory information.\n"));
253 return;
254 }
255 bnode = bnode->next;
256 }
257
258 /* Display what we have found */
259 display_us3_banks();
260 }
261
262 /*ARGSUSED2*/
263 void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)264 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
265 struct system_kstat_data *kstats)
266 {
267 /*
268 * Now display the last powerfail time and the fatal hardware
269 * reset information. We do this under a couple of conditions.
270 * First if the user asks for it. The second is iof the user
271 * told us to do logging, and we found a system failure.
272 */
273
274 if (flag) {
275 /*
276 * display time of latest powerfail. Not all systems
277 * have this capability. For those that do not, this
278 * is just a no-op.
279 */
280 disp_powerfail(root);
281
282 (void) disp_envc_status();
283
284 /* Hardware revision function calls */
285 lneck_display_hw_revisions(root, tree->bd_list);
286 log_printf("\n");
287 }
288 return;
289
290 }
291
292 /*
293 * display_pci
294 * Display all the PCI IO cards on this board.
295 */
296 void
display_pci(Board_node * board)297 display_pci(Board_node *board)
298 {
299 struct io_card *card_list = NULL;
300 struct io_card card;
301 void *value;
302 Prom_node *pci;
303 Prom_node *card_node;
304
305 char *slot_name_arr[LNECK_MAX_SLOTS_PER_IO_BD] = {NULL};
306 int i;
307
308 if (board == NULL)
309 return;
310
311 memset(&card, 0, sizeof (struct io_card));
312 /* Initialize all the common information */
313 card.display = TRUE;
314 card.board = board->board_num;
315
316 /*
317 * Search for each pci instance, then find/display all nodes under
318 * each instance node found.
319 */
320 for (pci = dev_find_node_by_compat(board->nodes, SCHIZO_COMPAT_PROP);
321 pci != NULL;
322 pci = dev_next_node_by_compat(pci, SCHIZO_COMPAT_PROP)) {
323 (void) snprintf(card.bus_type, MAXSTRLEN,
324 dgettext(TEXT_DOMAIN, "PCI"));
325 /*
326 * Get slot-name properties from parent node and
327 * store them in an array.
328 */
329 value = (char *)get_prop_val(
330 find_prop(pci, "slot-names"));
331
332 if (value != NULL) {
333 /* array starts after first int */
334 slot_name_arr[0] = (char *)value + sizeof (int);
335 for (i = 1; i < LNECK_MAX_SLOTS_PER_IO_BD; i++) {
336 slot_name_arr[i] = (char *)slot_name_arr[i - 1]
337 + strlen(slot_name_arr[i - 1]) +1;
338 }
339 }
340 /*
341 * Search for Children of this node ie. Cards.
342 * Note: any of these cards can be a pci-bridge
343 * that itself has children. If we find a
344 * pci-bridge we need to handle it specially.
345 */
346 card_node = pci->child;
347 /* Generate the list of pci cards on pci instance: pci */
348 fill_pci_card_list(pci, card_node, &card, &card_list,
349 slot_name_arr);
350 } /* end-for */
351
352 display_io_cards(card_list);
353 free_io_cards(card_list);
354 log_printf("\n");
355 }
356
357 /*
358 * Print out all the io cards in the list. Also print the column
359 * headers if told to do so.
360 */
361 void
display_io_cards(struct io_card * list)362 display_io_cards(struct io_card *list)
363 {
364 static int banner = 0; /* Have we printed the column headings? */
365 struct io_card *p;
366
367 if (list == NULL) {
368 return;
369 }
370
371 if (banner == FALSE) {
372 log_printf(dgettext(TEXT_DOMAIN,
373 " Bus Max\n"
374 " IO Port Bus Freq Bus Dev,\n"
375 "Brd Type ID Side Slot MHz Freq Func State "
376 "Name "));
377 #ifdef DEBUG
378 log_printf(dgettext(TEXT_DOMAIN,
379 "Model Notes\n"));
380 #else
381 log_printf(dgettext(TEXT_DOMAIN, "Model\n"));
382 #endif
383 /* ---------Node Brd IO Port Bus Slot Bus Max Dev Stat */
384 log_printf(dgettext(TEXT_DOMAIN,
385 "---- ---- ---- ---- ---- ---- ---- ---- ----- "
386 "-------------------------------- "
387 #ifdef DEBUG
388 "---------------------- "
389 #endif
390 "----------------------\n"));
391 banner = TRUE;
392 }
393
394 for (p = list; p != NULL; p = p -> next) {
395 log_printf(dgettext(TEXT_DOMAIN, "I/O "));
396 log_printf(dgettext(TEXT_DOMAIN, "%-4s "), p->bus_type);
397 log_printf(dgettext(TEXT_DOMAIN, "%-3d "),
398 p->schizo_portid);
399 log_printf(dgettext(TEXT_DOMAIN, "%c "), p->pci_bus);
400 log_printf(dgettext(TEXT_DOMAIN, "%-1s "), p->slot_str);
401 log_printf(dgettext(TEXT_DOMAIN, "%-3d "), p->freq);
402 switch (p->pci_bus) {
403 case 'A':
404 log_printf(dgettext(TEXT_DOMAIN, " 66 "));
405 break;
406 case 'B':
407 log_printf(dgettext(TEXT_DOMAIN, " 33 "));
408 break;
409 default:
410 log_printf(dgettext(TEXT_DOMAIN, " - "));
411 break;
412 }
413
414 log_printf(dgettext(TEXT_DOMAIN, "%-1d,%-1d "),
415 p->dev_no, p->func_no);
416 log_printf(dgettext(TEXT_DOMAIN, "%-5s "), p->status);
417 log_printf(dgettext(TEXT_DOMAIN, "%-32.32s"), p->name);
418 if (strlen(p->name) > 32)
419 log_printf(dgettext(TEXT_DOMAIN, "+ "));
420 else
421 log_printf(dgettext(TEXT_DOMAIN, " "));
422 log_printf(dgettext(TEXT_DOMAIN, "%-22.22s"), p->model);
423 if (strlen(p->model) > 22)
424 log_printf(dgettext(TEXT_DOMAIN, "+"));
425 #ifdef DEBUG
426 log_printf("%s ", p->notes);
427 #endif
428 log_printf("\n");
429 }
430 }
431
432 /*
433 * display_ffb
434 *
435 * There are no FFB's on a Littleneck, however in the generic library,
436 * the display_ffb() function is implemented so we have to define an
437 * empty function here.
438 */
439 /*ARGSUSED0*/
440 void
display_ffb(Board_node * board,int table)441 display_ffb(Board_node *board, int table)
442 {}
443
444
445 /*
446 * local functions
447 */
448
449 /*
450 * disp_fail_parts
451 *
452 * Display the failed parts in the system. This function looks for
453 * the status property in all PROM nodes. On systems where
454 * the PROM does not support passing diagnostic information
455 * through the device tree, this routine will be silent.
456 */
457 int
disp_fail_parts(Sys_tree * tree)458 disp_fail_parts(Sys_tree *tree)
459 {
460 int exit_code = 0;
461 int system_failed = 0;
462 Board_node *bnode = tree->bd_list;
463 Prom_node *pnode;
464
465 /* go through all of the boards looking for failed units. */
466 while (bnode != NULL) {
467 /* find failed chips */
468 pnode = find_failed_node(bnode->nodes);
469 if ((pnode != NULL) && !system_failed) {
470 system_failed = 1;
471 exit_code = 1;
472 if (print_flag == 0) {
473 return (exit_code);
474 }
475 log_printf("\n");
476 log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
477 "Replaceable Units (FRU) in System:\n"));
478 log_printf("=========================="
479 "====================\n");
480 }
481 while (pnode != NULL) {
482 void *value;
483 char *name; /* node name string */
484 char *type; /* node type string */
485 char *board_type = NULL;
486
487 value = get_prop_val(find_prop(pnode, "status"));
488 name = get_node_name(pnode);
489
490 /* sanity check of data retrieved from PROM */
491 if ((value == NULL) || (name == NULL)) {
492 pnode = next_failed_node(pnode);
493 continue;
494 }
495
496 /* Find the board type of this board */
497 if (bnode->board_type == CPU_BOARD) {
498 board_type = "CPU";
499 } else {
500 board_type = "IO";
501 }
502
503 log_printf(dgettext(TEXT_DOMAIN, "%s unavailable "
504 "on %s Board #%d\n"), name, board_type,
505 bnode->board_num);
506
507 log_printf(dgettext(TEXT_DOMAIN,
508 "\tPROM fault string: %s\n"), value);
509
510 log_printf(dgettext(TEXT_DOMAIN,
511 "\tFailed Field Replaceable Unit is "));
512
513 /*
514 * Determine whether FRU is CPU module, system
515 * board, or SBus card.
516 */
517 if ((name != NULL) && (strstr(name, "sbus"))) {
518
519 log_printf(dgettext(TEXT_DOMAIN,
520 "SBus Card %d\n"),
521 get_sbus_slot(pnode));
522
523 } else if (((name = get_node_name(pnode->parent)) !=
524 NULL) && (strstr(name, "pci"))) {
525
526 log_printf(dgettext(TEXT_DOMAIN,
527 "PCI Card %d"),
528 get_pci_device(pnode));
529
530 } else if (((type = get_node_type(pnode)) != NULL) &&
531 (strstr(type, "cpu"))) {
532
533 log_printf(dgettext(TEXT_DOMAIN, "UltraSPARC "
534 "module Board %d Module %d\n"), 0,
535 get_id(pnode));
536
537 } else {
538 log_printf(dgettext(TEXT_DOMAIN,
539 "%s board %d\n"), board_type,
540 bnode->board_num);
541 }
542 pnode = next_failed_node(pnode);
543 }
544 bnode = bnode->next;
545 }
546
547 if (!system_failed) {
548 log_printf(dgettext(TEXT_DOMAIN,
549 "No failures found in System\n"));
550 log_printf("===========================\n\n");
551 return (0);
552 } else {
553 return (1);
554 }
555 }
556
557
558 /*
559 * disp_envc_status
560 *
561 * This routine displays the environmental status passed up from
562 * device drivers via the envlibobj.so library.
563 * This is a Littleneck specific environmental information display routine.
564 */
565 static int
disp_envc_status(void)566 disp_envc_status(void)
567 {
568 int err;
569 char *system = "SYSTEM";
570 picl_nodehdl_t system_node, root;
571
572 log_printf("\n");
573 log_printf(dgettext(TEXT_DOMAIN, "========================="
574 " Environmental Status =========================\n\n"));
575
576 err = picl_initialize();
577 if (err != PICL_SUCCESS) {
578 log_printf(dgettext(TEXT_DOMAIN,
579 "Cannot print environmental information\n"
580 "picl_initialize failed\n"
581 "%s\n"), picl_strerror(err));
582 }
583
584 if (err == PICL_SUCCESS) {
585 err = picl_get_root(&root);
586 err = find_child_device(root, system, &system_node);
587 if (err != PICL_SUCCESS) {
588 log_printf(dgettext(TEXT_DOMAIN,
589 "Cannot print environmental information\n"
590 "find_child_device for the SYSTEM node "
591 "failed\n"
592 "%s\n"), picl_strerror(err));
593 }
594
595 if ((err = lneck_env_print_temps(system_node)) !=
596 PICL_SUCCESS) {
597 log_printf(dgettext(TEXT_DOMAIN,
598 "Temperature Checking failed: %s\n"),
599 picl_strerror(err));
600 }
601 if ((err = lneck_env_print_keyswitch(system_node)) !=
602 PICL_SUCCESS) {
603 log_printf(dgettext(TEXT_DOMAIN,
604 "Keyswitch information checking failed: %s\n"),
605 picl_strerror(err));
606 }
607 if ((err = lneck_env_print_FSP_LEDS(system_node)) !=
608 PICL_SUCCESS) {
609 log_printf(dgettext(TEXT_DOMAIN,
610 "FSP LED information checking failed: %s\n"),
611 picl_strerror(err));
612 }
613 if ((err = lneck_env_print_disk(system_node)) !=
614 PICL_SUCCESS) {
615 log_printf(dgettext(TEXT_DOMAIN,
616 "Disk information checking failed: %s\n"),
617 picl_strerror(err));
618 }
619 if ((err = lneck_env_print_fans(system_node)) !=
620 PICL_SUCCESS) {
621 log_printf(dgettext(TEXT_DOMAIN,
622 "Fan information checking failed: %s\n"),
623 picl_strerror(err));
624 }
625 if ((err = lneck_env_print_ps(system_node)) !=
626 PICL_SUCCESS) {
627 log_printf(dgettext(TEXT_DOMAIN,
628 "Power Supply information checking failed: "
629 "%s\n"), picl_strerror(err));
630 } else if (ps_failure != 0)
631 err = PICL_FAILURE;
632 }
633 return (err);
634 }
635
636 int
lneck_env_print_ps(picl_nodehdl_t system_node)637 lneck_env_print_ps(picl_nodehdl_t system_node)
638 {
639 int i, err = 0;
640 int32_t number;
641 picl_nodehdl_t *ps;
642 picl_nodehdl_t ps_fail[2], ps_type[2];
643 char name[PICL_PROPNAMELEN_MAX];
644 boolean_t type;
645 char fault_state[PICL_PROPNAMELEN_MAX];
646
647 log_printf(dgettext(TEXT_DOMAIN,
648 "Power Supplies:\n"
649 "---------------\n"
650 "Supply Status PS Type\n"
651 "------ ------ ---------------\n"));
652 err = fill_device_array_from_id(system_node, "PSVC_PS", &number,
653 &ps);
654 if (err != PICL_SUCCESS) {
655 return (err);
656 }
657
658 for (i = 0; i < LNECK_MAX_PS; i++) {
659 err = picl_get_propval_by_name(ps[i], PICL_PROP_NAME, name,
660 PICL_PROPNAMELEN_MAX);
661 if (err == PICL_SUCCESS) {
662 log_printf(dgettext(TEXT_DOMAIN, "%6-s"), name);
663 } else continue;
664
665 err = picl_get_propval_by_name(ps[i], "FaultInformation",
666 fault_state, PICL_PROPNAMELEN_MAX);
667 if (err == PICL_SUCCESS) {
668 if ((strlen(fault_state) == 0) ||
669 (strcmp(fault_state, "NO_FAULT") == 0)) {
670 strcpy(fault_state, "OK");
671 } else
672 /*
673 * Bump up count if fault_state !OK
674 */
675 ps_failure++;
676
677 log_printf(dgettext(TEXT_DOMAIN, " [%-6s] "),
678 fault_state);
679 } else {
680 return (err);
681 }
682
683 err = fill_device_from_id(ps[i], "PSVC_DEV_FAULT_SENSOR",
684 &ps_fail[i]);
685 if (err != PICL_SUCCESS) {
686 return (err);
687 }
688
689 err = fill_device_from_id(ps[i], "PSVC_DEV_TYPE_SENSOR",
690 &ps_type[i]);
691 if (err != PICL_SUCCESS) {
692 return (err);
693 }
694 err = picl_get_propval_by_name(ps_type[i], "Gpio-value", &type,
695 sizeof (boolean_t));
696 if (err == PICL_SUCCESS) {
697 log_printf(dgettext(TEXT_DOMAIN, " [%13s]"),
698 type == 0 ? "Quahog/Razor" : "Sun-Fire-280R");
699 if (type == 0) {
700 log_printf(dgettext(TEXT_DOMAIN,
701 "WARNING: PS is of the wrong type\n"));
702 } else log_printf("\n");
703 } else {
704 return (err);
705 }
706
707 }
708
709 log_printf(dgettext(TEXT_DOMAIN,
710 "\n"
711 "================================="
712 "\n"
713 "\n"));
714
715 /*
716 * Do not display an error message just because PS1 is
717 * not present.
718 */
719 if (err == PICL_INVALIDHANDLE) {
720 err = PICL_SUCCESS;
721 }
722
723 return (err);
724 }
725
726 int
lneck_env_print_fans(picl_nodehdl_t system_node)727 lneck_env_print_fans(picl_nodehdl_t system_node) {
728 int i, err = 0;
729 int32_t number;
730 picl_nodehdl_t *fans;
731 picl_nodehdl_t fan_fault[1];
732 char fault_state[PICL_PROPNAMELEN_MAX];
733 char name[PICL_PROPNAMELEN_MAX];
734
735 err = fill_device_array_from_id(system_node, "PSVC_FAN", &number,
736 &fans);
737 if (err != PICL_SUCCESS) {
738 return (err);
739 }
740
741 log_printf(dgettext(TEXT_DOMAIN,
742 "\n"
743 "=================================\n"
744 "\n"
745 "Fan Bank :\n"
746 "----------\n"
747 "\n"
748 "Bank Status\n"
749 "---- -------\n"));
750
751 for (i = 0; i < LNECK_MAX_FANS; i++) {
752 err = picl_get_propval_by_name(fans[i], PICL_PROP_NAME, name,
753 PICL_PROPNAMELEN_MAX);
754 if (err == PICL_SUCCESS) {
755 log_printf(dgettext(TEXT_DOMAIN, "%16-s"), name);
756 } else continue;
757
758 err = fill_device_from_id(fans[i], "PSVC_DEV_FAULT_SENSOR",
759 &fan_fault[i]);
760 if (err != PICL_SUCCESS) {
761 return (err);
762 }
763
764 err = picl_get_propval_by_name(fans[i], "FaultInformation",
765 &fault_state, PICL_PROPNAMELEN_MAX);
766
767 if (err == PICL_SUCCESS) {
768 log_printf(dgettext(TEXT_DOMAIN, " [%3s]\n"),
769 fault_state);
770 } else {
771 return (err);
772 }
773 }
774 log_printf(dgettext(TEXT_DOMAIN,
775 "\n"
776 "================================="
777 "\n"
778 "\n"));
779
780 return (err);
781 }
782
783 int
lneck_env_print_disk(picl_nodehdl_t system_node)784 lneck_env_print_disk(picl_nodehdl_t system_node) {
785 int i, err = 0;
786 int32_t number;
787 picl_nodehdl_t *disks;
788 char fault_state[PICL_PROPNAMELEN_MAX];
789 char name[PICL_PROPNAMELEN_MAX];
790
791 err = fill_device_array_from_id(system_node, "PSVC_DISK", &number,
792 &disks);
793 if (err != PICL_SUCCESS) {
794 return (err);
795 }
796
797 log_printf(dgettext(TEXT_DOMAIN,
798 "Disk Status:\n"
799 " Presence Fault Value\n"
800 " -------- -----------\n"));
801
802 for (i = 0; i < LNECK_MAX_DISKS; i++) {
803 err = picl_get_propval_by_name(disks[i], PICL_PROP_NAME, name,
804 PICL_PROPNAMELEN_MAX);
805 switch (err) {
806 case PICL_SUCCESS:
807 log_printf(dgettext(TEXT_DOMAIN,
808 "DISK %2d: [PRESENT]"), i);
809 break;
810 case PICL_INVALIDHANDLE:
811 log_printf(dgettext(TEXT_DOMAIN,
812 "DISK %2d: [EMPTY ]\n"), i);
813 continue;
814 default:
815 return (err);
816 }
817 err = picl_get_propval_by_name(disks[i], "FaultInformation",
818 &fault_state, PICL_PROPNAMELEN_MAX);
819 if (err == PICL_SUCCESS) {
820 log_printf(dgettext(TEXT_DOMAIN, " [%3s]"),
821 fault_state);
822 } else {
823 if (err != PICL_INVALIDHANDLE)
824 return (err);
825 }
826 log_printf("\n");
827 }
828
829 if (err == PICL_INVALIDHANDLE) {
830 err = PICL_SUCCESS;
831 }
832
833 return (err);
834 }
835
836 int
lneck_env_print_FSP_LEDS(picl_nodehdl_t system_node)837 lneck_env_print_FSP_LEDS(picl_nodehdl_t system_node) {
838 int err;
839 int32_t number;
840 picl_nodehdl_t *fsp_led;
841 char fault_state[PICL_PROPNAMELEN_MAX];
842
843 err = fill_device_array_from_id(system_node, "PSVC_FSP_LED", &number,
844 &fsp_led);
845 if (err != PICL_SUCCESS) {
846 return (err);
847 }
848
849 log_printf(dgettext(TEXT_DOMAIN,
850 "System LED Status: POWER GEN FAULT\n"
851 " [ ON]"));
852 err = picl_get_propval_by_name(fsp_led[0], "State", &fault_state,
853 PICL_PROPNAMELEN_MAX);
854 if (err == PICL_SUCCESS) {
855 log_printf(" [%3s]", fault_state);
856 } else {
857 return (err);
858 }
859
860 log_printf(dgettext(TEXT_DOMAIN,
861 "\n"
862 "\n"
863 "================================="
864 "\n"
865 "\n"));
866
867 return (err);
868 }
869
870 int
lneck_env_print_keyswitch(picl_nodehdl_t system_node)871 lneck_env_print_keyswitch(picl_nodehdl_t system_node) {
872 int err = 0;
873 picl_nodehdl_t *keyswitch;
874 int32_t number;
875 char ks_pos[PICL_PROPNAMELEN_MAX];
876
877 err = fill_device_array_from_id(system_node, "PSVC_KEYSWITCH", &number,
878 &keyswitch);
879 if (err != PICL_SUCCESS) {
880 return (err);
881 }
882 err = picl_get_propval_by_name(keyswitch[0], "State", ks_pos,
883 PICL_PROPNAMELEN_MAX);
884 if (err != PICL_SUCCESS) {
885 return (err);
886 }
887
888 log_printf(dgettext(TEXT_DOMAIN,
889 "Front Status Panel:\n"
890 "-------------------\n"
891 "Keyswitch position: %s\n"), ks_pos);
892 log_printf("\n");
893
894 return (err);
895 }
896
897 int
lneck_env_print_temps(picl_nodehdl_t system_node)898 lneck_env_print_temps(picl_nodehdl_t system_node) {
899 int i, err = 0;
900 picl_nodehdl_t *system_ts_nodes;
901 int32_t temp, number;
902
903 err = fill_device_array_from_id(system_node, "PSVC_TS", &number,
904 &system_ts_nodes);
905 if (err != PICL_SUCCESS) {
906 return (err);
907 }
908
909
910 log_printf(dgettext(TEXT_DOMAIN,
911 "System Temperatures (Celsius):\n"
912 "------------------------------\n"
913 "cpu0 1 \n"
914 "---------\n"));
915
916 for (i = 0; i < 2; i++) {
917 err = picl_get_propval_by_name(system_ts_nodes[i],
918 "Temperature", &temp, sizeof (temp));
919 if (err == PICL_SUCCESS) {
920 log_printf(dgettext(TEXT_DOMAIN, " %02d"), temp);
921 } else {
922 if (err == PICL_INVALIDHANDLE) {
923 err = PICL_SUCCESS;
924 log_printf(dgettext(TEXT_DOMAIN, " xx"));
925 } else {
926 return (err);
927 }
928 }
929 }
930
931 log_printf("\n");
932 log_printf("\n");
933 log_printf(dgettext(TEXT_DOMAIN,
934 "=================================\n"));
935 log_printf("\n");
936
937 return (err);
938 }
939
940 static void
lneck_display_hw_revisions(Prom_node * root,Board_node * bdlist)941 lneck_display_hw_revisions(Prom_node *root, Board_node *bdlist)
942 {
943 Prom_node *pnode;
944 char *value;
945
946 log_printf(dgettext(TEXT_DOMAIN, "\n"
947 "========================= HW Revisions "
948 "=======================================\n\n"));
949
950 log_printf(dgettext(TEXT_DOMAIN,
951 "System PROM revisions:\n"
952 "----------------------\n"));
953
954 pnode = dev_find_node(root, "openprom");
955 if (pnode != NULL) {
956 value = (char *)get_prop_val(find_prop(pnode, "version"));
957 log_printf(value);
958 }
959
960 log_printf(dgettext(TEXT_DOMAIN, "\n\n"
961 "IO ASIC revisions:\n"
962 "------------------\n"
963 " Port\n"
964 "Model ID Status Version\n"
965 "-------- ---- ------ -------\n"));
966
967 display_schizo_revisions(bdlist);
968 }
969
970 static void
display_schizo_revisions(Board_node * bdlist)971 display_schizo_revisions(Board_node *bdlist)
972 {
973 Prom_node *pnode;
974 int *int_val;
975 int portid;
976 int prev_portid = -1;
977 char *status_a = NULL;
978 char *status_b = NULL;
979 int revision;
980 #ifdef DEBUG
981 uint32_t a_notes, b_notes;
982 #endif
983 int pci_bus;
984 Board_node *bnode;
985 bnode = bdlist;
986
987 while (bnode != NULL) {
988 /*
989 * search this board node for all Schizos
990 */
991
992 for (pnode = dev_find_node_by_compat(bnode->nodes,
993 SCHIZO_COMPAT_PROP); pnode != NULL;
994 pnode = dev_next_node_by_compat(pnode,
995 SCHIZO_COMPAT_PROP)) {
996
997 /*
998 * get the reg property to determine
999 * whether we are looking at side A or B
1000 */
1001
1002 int_val = (int *)get_prop_val
1003 (find_prop(pnode, "reg"));
1004 if (int_val != NULL) {
1005 int_val ++; /* second integer in array */
1006 pci_bus = ((*int_val) & 0x7f0000);
1007 }
1008
1009 /* get portid */
1010 int_val = (int *)get_prop_val
1011 (find_prop(pnode, "portid"));
1012 if (int_val == NULL)
1013 continue;
1014
1015 portid = *int_val;
1016
1017 /*
1018 * If this is a new portid and it is PCI bus B,
1019 * we skip onto the PCI bus A.
1020 */
1021 if ((portid != prev_portid) && (pci_bus == 0x700000)) {
1022 prev_portid = portid;
1023 /* status */
1024 status_b = (char *)get_prop_val
1025 (find_prop(pnode, "status"));
1026 #ifdef DEBUG
1027 b_notes = pci_bus;
1028 #endif
1029 continue; /* skip to the next schizo */
1030 }
1031
1032 /*
1033 * This must be side A of the same Schizo.
1034 * Gather all its props and display them.
1035 */
1036 #ifdef DEBUG
1037 a_notes = pci_bus;
1038 #endif
1039
1040 prev_portid = portid;
1041
1042 int_val = (int *)get_prop_val
1043 (find_prop(pnode, "version#"));
1044 if (int_val != NULL)
1045 revision = *int_val;
1046 else
1047 revision = -1;
1048
1049 status_a = (char *)get_prop_val(find_prop
1050 (pnode, "status"));
1051
1052 log_printf(dgettext(TEXT_DOMAIN, "Schizo "));
1053
1054 log_printf(dgettext(TEXT_DOMAIN, "%-3d "), portid, 0);
1055
1056
1057 log_printf((status_a == NULL && status_b == NULL) ?
1058 dgettext(TEXT_DOMAIN, " ok ") :
1059 dgettext(TEXT_DOMAIN, " fail "));
1060
1061 log_printf(dgettext(TEXT_DOMAIN, " %4d "),
1062 revision);
1063 #ifdef DEBUG
1064 log_printf(" 0x%x 0x%x", a_notes, b_notes);
1065 #endif
1066 log_printf("\n");
1067 }
1068 bnode = bnode->next;
1069 }
1070 }
1071