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 *
29 * Cherrystone platform-specific functions
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
51 #include <picl.h>
52
53 #include <sys/cheetahregs.h>
54 #include <sys/cherrystone.h>
55 #include "workfile.c"
56
57 #define SCHIZO_COMPAT_PROP "pci108e,8001"
58
59 #define MULTIPLE_BITS_SET(x) ((x)&((x)-1))
60
61 #define MAX_PS 2
62 #define MAX_PS_SENSORS 3
63 #define MAX_DISKS 2
64 #define MAX_FANS 5
65 #define NUM_PCI_SLOTS 5
66
67 /*
68 * these functions will overlay the symbol table of libprtdiag
69 * at runtime (workgroup server systems only)
70 */
71 void display_cpu_devices(Sys_tree *tree);
72 void display_pci(Board_node *board);
73 void display_io_cards(struct io_card *list);
74 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
75 struct system_kstat_data *kstats);
76 void display_ffb(Board_node *board, int table);
77 void display_memoryconf(Sys_tree *tree);
78
79 /* local functions */
80 static void disp_envc_status(void);
81 static int print_temps(picl_nodehdl_t);
82 static int print_keyswitch(picl_nodehdl_t);
83 static int print_FSP_LEDS(picl_nodehdl_t);
84 static int print_disk(picl_nodehdl_t);
85 static int print_fans(picl_nodehdl_t);
86 static int print_ps(picl_nodehdl_t);
87
88 static void display_hw_revisions(Prom_node *root,
89 Board_node *bnode);
90 static void display_schizo_revisions(Board_node *bdlist);
91
92
93 void
display_cpu_devices(Sys_tree * tree)94 display_cpu_devices(Sys_tree *tree)
95 {
96 Board_node *bnode;
97
98 log_printf(dgettext(TEXT_DOMAIN,
99 "\n========================= CPUs "
100 "===============================================\n\n"
101 " Run E$ CPU CPU \n"
102 "Brd CPU MHz MB Impl. Mask \n"
103 "--- ----- ---- ---- ------- ---- \n"));
104
105 bnode = tree->bd_list;
106 while (bnode != NULL) {
107 display_cpus(bnode);
108 bnode = bnode->next;
109 }
110
111 log_printf("\n");
112 }
113 void
display_cpus(Board_node * board)114 display_cpus(Board_node *board)
115 {
116 Prom_node *cpu;
117 uint_t freq;
118 int ecache_size;
119 int *l3_shares;
120 int *mid;
121 int *impl;
122 int *mask;
123 int *coreid;
124 char fru_prev = 'X'; /* Valid frus are 'A','B' */
125 int mid_prev;
126 int ecache_size_prev = 0;
127 char fru_name;
128
129 /*
130 * display the CPUs' operating frequency, cache size, impl. field
131 * and mask revision.
132 */
133
134 for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
135 cpu = dev_next_type(cpu, "cpu")) {
136
137 mid = (int *)get_prop_val(find_prop(cpu, "portid"));
138 if (mid == NULL)
139 mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
140 freq = HZ_TO_MHZ(get_cpu_freq(cpu));
141 ecache_size = get_ecache_size(cpu);
142 impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
143 mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
144 l3_shares =
145 (int *)get_prop_val(find_prop(cpu, "l3-cache-sharing"));
146
147 /* Do not display a failed CPU node */
148 if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
149 continue;
150
151 fru_name = CHERRYSTONE_GETSLOT_LABEL(*mid);
152 if (CPU_IMPL_IS_CMP(*impl)) {
153 coreid = (int *)get_prop_val(find_prop(cpu, "reg"));
154 if (coreid == NULL) {
155 continue;
156 }
157 if ((fru_prev == 'X') ||
158 ((fru_prev != 'X') &&
159 (fru_name != fru_prev))) {
160 fru_prev = fru_name;
161 mid_prev = *mid;
162 ecache_size_prev = ecache_size;
163 continue;
164 } else {
165 /*
166 * Some CMP chips have a split E$,
167 * so the size for both cores is added
168 * together to get the total size for
169 * the chip.
170 *
171 * Still, other CMP chips have E$ (L3)
172 * which is logically shared, so the
173 * total size is equal to the core size.
174 */
175 if ((l3_shares == NULL) ||
176 ((l3_shares != NULL) &&
177 MULTIPLE_BITS_SET(*l3_shares))) {
178 ecache_size += ecache_size_prev;
179 }
180 ecache_size_prev = 0;
181 fru_prev = 'X';
182 }
183 }
184
185 log_printf(" %c", fru_name);
186
187 /* CPU Module ID */
188 if (CPU_IMPL_IS_CMP(*impl)) {
189 log_printf("%3d,%3d ", mid_prev, *mid, 0);
190 } else
191 log_printf(" %2d ", *mid);
192
193 /* Running frequency */
194 log_printf("%4u", freq);
195
196 if (ecache_size == 0)
197 log_printf(" N/A ");
198 else
199 log_printf(" %4.1f ",
200 (float)ecache_size / (float)(1<<20));
201 /* Implementation */
202 if (impl == NULL) {
203 log_printf(dgettext(TEXT_DOMAIN, " N/A "));
204 } else {
205 if (IS_CHEETAH(*impl))
206 log_printf(dgettext(TEXT_DOMAIN,
207 "US-III "));
208 else if (IS_CHEETAH_PLUS(*impl))
209 log_printf(dgettext(TEXT_DOMAIN,
210 "US-III+ "));
211 else if (IS_JAGUAR(*impl))
212 log_printf(dgettext(TEXT_DOMAIN,
213 "US-IV "));
214 else if (IS_PANTHER(*impl))
215 log_printf(dgettext(TEXT_DOMAIN,
216 "US-IV+ "));
217 else
218 log_printf("%-6x ", *impl);
219 }
220
221 /* CPU Mask */
222 if (mask == NULL) {
223 log_printf(dgettext(TEXT_DOMAIN, " N/A\n"));
224 } else {
225 log_printf(dgettext(TEXT_DOMAIN, " %d.%d\n"),
226 (*mask >> 4) & 0xf, *mask & 0xf);
227 }
228 }
229 }
230
231 void
display_memoryconf(Sys_tree * tree)232 display_memoryconf(Sys_tree *tree)
233 {
234 Board_node *bnode = tree->bd_list;
235
236 log_printf(dgettext(TEXT_DOMAIN,
237 "========================= Memory Configuration"
238 " ===============================\n\n"
239 " Logical Logical Logical\n"
240 " MC Bank Bank Bank DIMM "
241 "Interleave Interleaved\n"
242 "Brd ID num size Status Size "
243 "Factor with\n"
244 "--- --- ---- ------ ----------- ------ "
245 "---------- -----------"));
246
247 while (bnode != NULL) {
248 if (get_us3_mem_regs(bnode)) {
249 log_printf(dgettext(TEXT_DOMAIN,
250 "\nFailed to get memory information.\n"));
251 return;
252 }
253 bnode = bnode->next;
254 }
255
256 /* Display what we have found */
257 display_us3_banks();
258 }
259
260 /*ARGSUSED3*/
261 void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)262 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
263 struct system_kstat_data *kstats)
264 {
265 /*
266 * Now display the last powerfail time and the fatal hardware
267 * reset information. We do this under a couple of conditions.
268 * First if the user asks for it. The second is if the user
269 * told us to do logging, and we found a system failure.
270 */
271
272 if (flag) {
273 /*
274 * display time of latest powerfail. Not all systems
275 * have this capability. For those that do not, this
276 * is just a no-op.
277 */
278 disp_powerfail(root);
279
280 disp_envc_status();
281
282 display_hw_revisions(root, tree->bd_list);
283 }
284 return;
285
286 }
287
288 /*
289 * display_pci
290 * Display all the PCI IO cards on this board.
291 */
292 void
display_pci(Board_node * board)293 display_pci(Board_node *board)
294 {
295 struct io_card *card_list = NULL;
296 struct io_card card;
297 void *value;
298 Prom_node *pci;
299 Prom_node *card_node;
300 static int banner = FALSE;
301
302 char *slot_name_arr[NUM_PCI_SLOTS];
303 int i;
304
305 if (board == NULL)
306 return;
307
308 (void) memset(&card, 0, sizeof (struct io_card));
309 /* Initialize all the common information */
310 card.display = TRUE;
311 card.board = board->board_num;
312
313 /*
314 * Search for each pci instance, then find/display all nodes under
315 * each instance node found.
316 */
317 for (pci = dev_find_node_by_compat(board->nodes, SCHIZO_COMPAT_PROP);
318 pci != NULL;
319 pci = dev_next_node_by_compat(pci, SCHIZO_COMPAT_PROP)) {
320 (void) snprintf(card.bus_type, MAXSTRLEN,
321 dgettext(TEXT_DOMAIN, "PCI"));
322 /*
323 * Get slot-name properties from parent node and
324 * store them in an array.
325 */
326 value = (char *)get_prop_val(
327 find_prop(pci, "slot-names"));
328
329 if (value != NULL) {
330 /* array starts after first int */
331 slot_name_arr[0] = (char *)value + sizeof (int);
332 for (i = 1; i < NUM_PCI_SLOTS; i++) {
333 slot_name_arr[i] = (char *)slot_name_arr[i - 1]
334 + strlen(slot_name_arr[i - 1]) +1;
335 }
336 }
337 /*
338 * Search for Children of this node ie. Cards.
339 * Note: any of these cards can be a pci-bridge
340 * that itself has children. If we find a
341 * pci-bridge we need to handle it specially.
342 */
343 card_node = pci->child;
344 /* Generate the list of pci cards on pci instance: pci */
345 fill_pci_card_list(pci, card_node, &card, &card_list,
346 slot_name_arr);
347 } /* end-for */
348
349 if (!banner && card_list != NULL) {
350 log_printf(dgettext(TEXT_DOMAIN,
351 " Bus Max\n"
352 " IO Port Bus Freq Bus Dev,\n"
353 "Type ID Side Slot MHz Freq Func State "
354 "Name Model"
355 #ifdef DEBUG
356 " Notes"
357 #endif
358 "\n"
359 "---- ---- ---- ---- ---- ---- ---- ----- "
360 "-------------------------------- "
361 #ifdef DEBUG
362 "---------------------- "
363 #endif
364 "----------------------\n"));
365 banner = TRUE;
366 }
367
368 display_io_cards(card_list);
369 free_io_cards(card_list);
370 }
371
372 /*
373 * Print out all the io cards in the list. Also print the column
374 * headers if told to do so.
375 */
376 void
display_io_cards(struct io_card * list)377 display_io_cards(struct io_card *list)
378 {
379 struct io_card *p;
380
381 for (p = list; p != NULL; p = p -> next) {
382 log_printf(dgettext(TEXT_DOMAIN,
383 "%-4s %-3d %c %-1s %-3d"),
384 p->bus_type, p->schizo_portid, p->pci_bus,
385 p->slot_str, p->freq);
386
387 switch (p->pci_bus) {
388 case 'A':
389 log_printf(dgettext(TEXT_DOMAIN, " 66 "));
390 break;
391 case 'B':
392 log_printf(dgettext(TEXT_DOMAIN, " 33 "));
393 break;
394 default:
395 assert(0);
396 break;
397 }
398
399 log_printf(dgettext(TEXT_DOMAIN,
400 "%-1d,%-1d %-5s %-32.32s"),
401 p->dev_no, p->func_no, p->status, p->name);
402 if (strlen(p->name) > 32)
403 log_printf(dgettext(TEXT_DOMAIN, "+ "));
404 else
405 log_printf(dgettext(TEXT_DOMAIN, " "));
406 log_printf(dgettext(TEXT_DOMAIN, "%-22.22s"), p->model);
407 if (strlen(p->model) > 22)
408 log_printf(dgettext(TEXT_DOMAIN, "+"));
409 #ifdef DEBUG
410 log_printf("%s", p->notes);
411 #endif
412 log_printf("\n");
413 }
414 }
415
416 /*ARGSUSED*/
417 void
display_ffb(Board_node * board,int table)418 display_ffb(Board_node *board, int table)
419 {
420 /* NOP, since there are no FFB's on this platform. */
421 }
422
423
424 /*
425 * local functions
426 */
427
428
429 static void
disp_envc_status()430 disp_envc_status()
431 {
432 int err;
433 char *system = "SYSTEM";
434 picl_nodehdl_t system_node, root;
435
436 log_printf(dgettext(TEXT_DOMAIN,
437 "\n"
438 "========================= Environmental Status "
439 "=========================\n\n"));
440
441 err = picl_initialize();
442 if (err != PICL_SUCCESS) {
443 exit_code = PD_INTERNAL_FAILURE;
444 goto err_out;
445 }
446 err = picl_get_root(&root);
447 if (err != PICL_SUCCESS) {
448 exit_code = PD_INTERNAL_FAILURE;
449 goto err_out;
450 }
451 err = find_child_device(root, system, &system_node);
452 if (err != PICL_SUCCESS) {
453 exit_code = PD_INTERNAL_FAILURE;
454 goto err_out;
455 }
456
457 err = print_temps(system_node);
458 err |= print_keyswitch(system_node);
459 err |= print_FSP_LEDS(system_node);
460 err |= print_disk(system_node);
461 err |= print_fans(system_node);
462 err |= print_ps(system_node);
463
464 if (err != PICL_SUCCESS)
465 goto err_out;
466
467 return;
468
469 err_out:
470 log_printf(dgettext(TEXT_DOMAIN,
471 "\nEnvironmental reporting error: %s\n"),
472 picl_strerror(err));
473 }
474
475 static int
print_ps(picl_nodehdl_t system_node)476 print_ps(picl_nodehdl_t system_node)
477 {
478 int i, j, err = 0;
479 int32_t number;
480 picl_nodehdl_t *ps;
481 picl_nodehdl_t *ps_fail_sensor;
482 char name[PICL_PROPNAMELEN_MAX];
483 char fault_state[PICL_PROPNAMELEN_MAX];
484
485 log_printf(dgettext(TEXT_DOMAIN, "\n\n"
486 "Power Supplies:\n"
487 "---------------\n"
488 "\n"
489 "Supply Status Fault Fan Fail Temp Fail\n"
490 "------ ------------ -------- --------- ---------\n"));
491
492 err = fill_device_array_from_id(system_node, "PSVC_PS", &number, &ps);
493 if (err != PICL_SUCCESS) {
494 return (err);
495 }
496
497 for (i = 0; i < MAX_PS; i++) {
498 err = picl_get_propval_by_name(ps[i], PICL_PROP_NAME, name,
499 PICL_PROPNAMELEN_MAX);
500 if (err != PICL_SUCCESS)
501 continue;
502
503 log_printf(dgettext(TEXT_DOMAIN, "%6-s"), name);
504 err = picl_get_propval_by_name(ps[i], "FaultInformation",
505 fault_state, PICL_PROPNAMELEN_MAX);
506 if (err != PICL_SUCCESS) {
507 free(ps);
508 return (err);
509 }
510 log_printf(dgettext(TEXT_DOMAIN, " [%-12s]"), fault_state);
511 if (strcmp(fault_state, "NO AC POWER") == 0) {
512 log_printf("\n");
513 continue;
514 }
515
516 err = fill_device_array_from_id(ps[i], "PSVC_DEV_FAULT_SENSOR",
517 &number, &ps_fail_sensor);
518
519 if (err != PICL_SUCCESS) {
520 free(ps);
521 return (err);
522 }
523 log_printf(" ");
524 for (j = 0; j < MAX_PS_SENSORS; j++) {
525 err = picl_get_propval_by_name(ps_fail_sensor[j],
526 "State", fault_state, PICL_PROPNAMELEN_MAX);
527 if (err != PICL_SUCCESS) {
528 if (err == PICL_FAILURE) {
529 break;
530 }
531 free(ps);
532 free(ps_fail_sensor);
533 return (err);
534 }
535 log_printf(dgettext(TEXT_DOMAIN, "%-10s"), fault_state);
536 }
537 log_printf("\n");
538 free(ps_fail_sensor);
539 }
540
541 log_printf(dgettext(TEXT_DOMAIN,
542 "\n=================================\n\n"));
543
544 free(ps);
545 return (PICL_SUCCESS);
546 }
547
548 static int
print_fans(picl_nodehdl_t system_node)549 print_fans(picl_nodehdl_t system_node)
550 {
551 int i, err;
552 int32_t number;
553 picl_nodehdl_t *fans;
554 picl_nodehdl_t phdl;
555 char prop[PICL_PROPNAMELEN_MAX];
556 char parent[PICL_PROPNAMELEN_MAX];
557 int32_t rpm;
558
559 err = fill_device_array_from_id(system_node, "PSVC_FAN", &number,
560 &fans);
561 if (err != PICL_SUCCESS) {
562 return (err);
563 }
564
565 log_printf(dgettext(TEXT_DOMAIN,
566 "\n=================================\n\n"
567 "Fan Status:\n"
568 "-----------\n\n"
569 "Fan Tray Fan RPM Status\n"
570 "----------- ---- ----- ----------\n"));
571
572 for (i = 0; i < MAX_FANS; i++) {
573 err = picl_get_propval_by_name(fans[i], PICL_PROP_NAME, prop,
574 PICL_PROPNAMELEN_MAX);
575 if (err != PICL_SUCCESS)
576 continue;
577
578 err = fill_device_from_id(fans[i], "PSVC_PARENT", &phdl);
579 if (err != PICL_SUCCESS)
580 continue;
581 err = picl_get_propval_by_name(phdl, PICL_PROP_NAME, parent,
582 PICL_PROPNAMELEN_MAX);
583 if (err != PICL_SUCCESS)
584 continue;
585
586 log_printf(dgettext(TEXT_DOMAIN, "%-16s"), parent);
587
588
589 log_printf(dgettext(TEXT_DOMAIN, "%-16s"), prop);
590
591 err = picl_get_propval_by_name(fans[i], "Fan-speed",
592 &rpm, sizeof (rpm));
593 if (err != PICL_SUCCESS) {
594 free(fans);
595 return (err);
596 }
597 log_printf(dgettext(TEXT_DOMAIN, "%5d "), rpm);
598
599 err = picl_get_propval_by_name(fans[i], "FaultInformation",
600 prop, PICL_PROPNAMELEN_MAX);
601 if (err != PICL_SUCCESS) {
602 free(fans);
603 return (err);
604 }
605 log_printf(dgettext(TEXT_DOMAIN, " [%s]\n"), prop);
606 }
607 log_printf(dgettext(TEXT_DOMAIN,
608 "\n=================================\n\n"));
609 free(fans);
610 return (PICL_SUCCESS);
611 }
612
613 static int
print_disk(picl_nodehdl_t system_node)614 print_disk(picl_nodehdl_t system_node)
615 {
616 int i, err;
617 int32_t number;
618 picl_nodehdl_t *disks;
619 char state[PICL_PROPNAMELEN_MAX];
620
621 err = fill_device_array_from_id(system_node, "PSVC_DISK", &number,
622 &disks);
623 if (err != PICL_SUCCESS) {
624 return (err);
625 }
626
627 log_printf(dgettext(TEXT_DOMAIN,
628 "Disk Status:\n"
629 "------------\n"));
630 for (i = 0; i < MAX_DISKS; i++) {
631 err = picl_get_propval_by_name(disks[i], "FaultInformation",
632 state, PICL_PROPNAMELEN_MAX);
633
634 switch (err) {
635 case PICL_SUCCESS:
636 log_printf(dgettext(TEXT_DOMAIN,
637 "DISK %d: [%3s]\n"), i, state);
638 break;
639 case PICL_INVALIDHANDLE:
640 log_printf(dgettext(TEXT_DOMAIN,
641 "DISK %d: [ NOT PRESENT ]\n"), i);
642 break;
643 default:
644 free(disks);
645 return (err);
646 }
647 }
648 free(disks);
649 return (PICL_SUCCESS);
650 }
651
652 static int
print_FSP_LEDS(picl_nodehdl_t system_node)653 print_FSP_LEDS(picl_nodehdl_t system_node)
654 {
655 int err;
656 int32_t number;
657 picl_nodehdl_t *fsp_led;
658 char fault_state[PICL_PROPNAMELEN_MAX];
659 char locate_state[PICL_PROPNAMELEN_MAX];
660
661 err = fill_device_array_from_id(system_node, "PSVC_FSP_LED", &number,
662 &fsp_led);
663 if (err != PICL_SUCCESS) {
664 return (err);
665 }
666
667 assert(number == 2);
668 err = picl_get_propval_by_name(fsp_led[0], "State", &fault_state,
669 PICL_PROPNAMELEN_MAX);
670 if (err != PICL_SUCCESS) {
671 free(fsp_led);
672 return (err);
673 }
674
675 if (strcmp(fault_state, PSVC_LED_ON) == 0)
676 exit_code = PD_SYSTEM_FAILURE;
677
678 err = picl_get_propval_by_name(fsp_led[1], "State", &locate_state,
679 PICL_PROPNAMELEN_MAX);
680 if (err != PICL_SUCCESS) {
681 free(fsp_led);
682 return (err);
683 }
684
685 log_printf(dgettext(TEXT_DOMAIN,
686 "System LED Status:\n\n"
687 " LOCATOR FAULT POWER\n"
688 " ------- ------- -------\n"
689 " [%3s] [%3s] [ ON]"),
690 locate_state, fault_state);
691
692 log_printf(dgettext(TEXT_DOMAIN,
693 "\n\n=================================\n\n"));
694 free(fsp_led);
695 return (err);
696 }
697
698 static int
print_keyswitch(picl_nodehdl_t system_node)699 print_keyswitch(picl_nodehdl_t system_node)
700 {
701 int err;
702 picl_nodehdl_t *keyswitch;
703 int32_t number;
704 char ks_pos[PICL_PROPNAMELEN_MAX];
705
706 err = fill_device_array_from_id(system_node, "PSVC_KEYSWITCH", &number,
707 &keyswitch);
708 if (err != PICL_SUCCESS) {
709 return (err);
710 }
711 err = picl_get_propval_by_name(keyswitch[0], "State", ks_pos,
712 PICL_PROPNAMELEN_MAX);
713 if (err != PICL_SUCCESS) {
714 free(keyswitch);
715 return (err);
716 }
717
718 log_printf(dgettext(TEXT_DOMAIN,
719 "Front Status Panel:\n"
720 "-------------------\n"
721 "Keyswitch position: %s\n\n"), ks_pos);
722 free(keyswitch);
723 return (err);
724 }
725
726 static int
print_temps(picl_nodehdl_t system_node)727 print_temps(picl_nodehdl_t system_node)
728 {
729 int i;
730 int err;
731 picl_nodehdl_t *system_ts_nodes;
732 int32_t temp;
733 int32_t number;
734 char label[PICL_PROPNAMELEN_MAX];
735 char state[PICL_PROPNAMELEN_MAX];
736 char *p;
737
738 err = fill_device_array_from_id(system_node, "PSVC_TS", &number,
739 &system_ts_nodes);
740 if (err != PICL_SUCCESS) {
741 return (err);
742 }
743
744 log_printf(dgettext(TEXT_DOMAIN,
745 "System Temperatures (Celsius):\n"
746 "-------------------------------\n"
747 "Device\t\tTemperature\tStatus\n"
748 "---------------------------------------\n"));
749
750 for (i = 0; i < number; i++) {
751 err = picl_get_propval_by_name(system_ts_nodes[i],
752 "State", state, sizeof (state));
753 if (err != PICL_SUCCESS) {
754 if (err == PICL_INVALIDHANDLE) {
755 (void) strcpy(state, "n/a");
756 } else {
757 free(system_ts_nodes);
758 return (err);
759 }
760 }
761 err = picl_get_propval_by_name(system_ts_nodes[i],
762 PICL_PROP_NAME, label, PICL_PROPNAMELEN_MAX);
763 if (err != PICL_SUCCESS) {
764 if (err == PICL_INVALIDHANDLE)
765 /* This FRU isn't present. Skip it. */
766 continue;
767 free(system_ts_nodes);
768 return (err);
769 }
770
771 /*
772 * The names in the tree are like "CPU0_DIE_TEMPERATURE_SENSOR".
773 * All we want to print is up to the first underscore.
774 */
775 p = strchr(label, '_');
776 if (p != NULL)
777 *p = '\0';
778
779 err = picl_get_propval_by_name(system_ts_nodes[i],
780 "Temperature", &temp, sizeof (temp));
781 if (err != PICL_SUCCESS) {
782 free(system_ts_nodes);
783 return (err);
784 }
785 log_printf("%s\t\t%3d\t\t%s\n", label, temp, state);
786 }
787
788 log_printf(dgettext(TEXT_DOMAIN,
789 "\n=================================\n\n"));
790
791 free(system_ts_nodes);
792 return (PICL_SUCCESS);
793 }
794
795 static void
display_hw_revisions(Prom_node * root,Board_node * bdlist)796 display_hw_revisions(Prom_node *root, Board_node *bdlist)
797 {
798 Prom_node *pnode;
799 char *value;
800
801 log_printf(dgettext(TEXT_DOMAIN, "\n"
802 "========================= HW Revisions "
803 "=======================================\n\n"));
804
805 log_printf(dgettext(TEXT_DOMAIN,
806 "System PROM revisions:\n"
807 "----------------------\n"));
808
809 pnode = dev_find_node(root, "openprom");
810 if (pnode != NULL) {
811 value = (char *)get_prop_val(find_prop(pnode, "version"));
812 log_printf(value);
813 }
814
815 log_printf(dgettext(TEXT_DOMAIN, "\n\n"
816 "IO ASIC revisions:\n"
817 "------------------\n"
818 " Port\n"
819 "Model ID Status Version\n"
820 "-------- ---- ------ -------\n"));
821
822 display_schizo_revisions(bdlist);
823 }
824
825
826 static void
display_schizo_revisions(Board_node * bdlist)827 display_schizo_revisions(Board_node *bdlist)
828 {
829 Prom_node *pnode;
830 int *int_val;
831 int portid;
832 int prev_portid = -1;
833 char *status_a = NULL;
834 char *status_b = NULL;
835 int revision;
836 #ifdef DEBUG
837 uint32_t a_notes, b_notes;
838 #endif
839 int pci_bus;
840 Board_node *bnode;
841 bnode = bdlist;
842
843 while (bnode != NULL) {
844 /*
845 * search this board node for all Schizos
846 */
847
848 for (pnode = dev_find_node_by_compat(bnode->nodes,
849 SCHIZO_COMPAT_PROP); pnode != NULL;
850 pnode = dev_next_node_by_compat(pnode,
851 SCHIZO_COMPAT_PROP)) {
852
853 /*
854 * get the reg property to determine
855 * whether we are looking at side A or B
856 */
857
858 int_val = (int *)get_prop_val
859 (find_prop(pnode, "reg"));
860 if (int_val != NULL) {
861 int_val ++; /* second integer in array */
862 pci_bus = ((*int_val) & 0x7f0000);
863 }
864
865 /* get portid */
866 int_val = (int *)get_prop_val
867 (find_prop(pnode, "portid"));
868 if (int_val == NULL)
869 continue;
870
871 portid = *int_val;
872
873 /*
874 * If this is a new portid and it is PCI bus B,
875 * we skip onto the PCI bus A.
876 */
877 if ((portid != prev_portid) && (pci_bus == 0x700000)) {
878 prev_portid = portid;
879 /* status */
880 status_b = (char *)get_prop_val
881 (find_prop(pnode, "status"));
882 #ifdef DEBUG
883 b_notes = pci_bus;
884 #endif
885 continue; /* skip to the next schizo */
886 }
887
888 /*
889 * This must be side A of the same Schizo.
890 * Gather all its props and display them.
891 */
892 #ifdef DEBUG
893 a_notes = pci_bus;
894 #endif
895
896 prev_portid = portid;
897
898 int_val = (int *)get_prop_val
899 (find_prop(pnode, "version#"));
900 if (int_val != NULL)
901 revision = *int_val;
902 else
903 revision = -1;
904
905 status_a = (char *)get_prop_val(find_prop
906 (pnode, "status"));
907
908 log_printf(dgettext(TEXT_DOMAIN, "Schizo "));
909
910 log_printf(dgettext(TEXT_DOMAIN, "%-3d "), portid, 0);
911
912
913 log_printf((status_a == NULL && status_b == NULL) ?
914 dgettext(TEXT_DOMAIN, " ok ") :
915 dgettext(TEXT_DOMAIN, " fail "));
916
917 log_printf(dgettext(TEXT_DOMAIN, " %4d "),
918 revision);
919 #ifdef DEBUG
920 log_printf(" 0x%x 0x%x", a_notes, b_notes);
921 #endif
922 log_printf("\n");
923 }
924 bnode = bnode->next;
925 }
926 }
927