1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2020 Peter Tribble.
26 *
27 * Javelin Platform specific functions.
28 *
29 * called when :
30 * machine_type == MTYPE_JAVELIN
31 *
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <ctype.h>
38 #include <string.h>
39 #include <kvm.h>
40 #include <varargs.h>
41 #include <errno.h>
42 #include <time.h>
43 #include <dirent.h>
44 #include <fcntl.h>
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 #include <sys/utsname.h>
49 #include <sys/openpromio.h>
50 #include <kstat.h>
51 #include <libintl.h>
52 #include <syslog.h>
53 #include <sys/dkio.h>
54 #include "pdevinfo.h"
55 #include "display.h"
56 #include "pdevinfo_sun4u.h"
57 #include "display_sun4u.h"
58 #include "libprtdiag.h"
59
60 #if !defined(TEXT_DOMAIN)
61 #define TEXT_DOMAIN "SYS_TEST"
62 #endif
63
64 extern int print_flag;
65
66 /*
67 * these functions will overlay the symbol table of libprtdiag
68 * at runtime (workgroup server systems only)
69 */
70 int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
71 void display_memoryconf(Sys_tree *tree);
72 int disp_fail_parts(Sys_tree *tree);
73 void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
74 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
75 struct system_kstat_data *kstats);
76 void display_boardnum(int num);
77 void display_pci(Board_node *);
78 void display_io_cards(struct io_card *list);
79 void display_ffb(Board_node *, int);
80 void read_platform_kstats(Sys_tree *tree,
81 struct system_kstat_data *sys_kstat,
82 struct envctrl_kstat_data *ep);
83
84 /* local functions */
85 static int disp_envc_status(struct system_kstat_data *);
86 static void tazjav_disp_asic_revs(Sys_tree *);
87 static int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *);
88 static Prom_node *dev_next_node_sibling(Prom_node *root, char *name);
89
90
91 int
error_check(Sys_tree * tree,struct system_kstat_data * kstats)92 error_check(Sys_tree *tree, struct system_kstat_data *kstats)
93 {
94 int exit_code = 0; /* init to all OK */
95
96 #ifdef lint
97 kstats = kstats;
98 #endif
99 /*
100 * silently check for any types of machine errors
101 */
102 print_flag = 0;
103 if (disp_fail_parts(tree) || disp_envc_status(kstats)) {
104 /* set exit_code to show failures */
105 exit_code = 1;
106 }
107 print_flag = 1;
108
109 return (exit_code);
110 }
111
112 /* Search for and return the node's sibling */
113 static Prom_node *
dev_next_node_sibling(Prom_node * root,char * name)114 dev_next_node_sibling(Prom_node *root, char *name)
115 {
116 if (root == NULL)
117 return (NULL);
118
119 /* look at your siblings */
120 if (dev_find_node(root->sibling, name) != NULL)
121 return (root->sibling);
122
123 return (NULL); /* not found */
124 }
125
126 /*
127 * This function displays memory configurations specific to Tazmo/Javelin.
128 * The PROM device tree is read to obtain this information.
129 * Some of the information obtained is memory interleave factor,
130 * DIMM sizes, DIMM socket names.
131 */
132 void
display_memoryconf(Sys_tree * tree)133 display_memoryconf(Sys_tree *tree)
134 {
135 Board_node *bnode;
136 Prom_node *memory;
137 Prom_node *bank;
138 Prom_node *dimm;
139 uint_t *preg;
140 uint_t interlv;
141 unsigned long size = 0;
142 int bank_count = 0;
143 char *sock_name;
144 char *status;
145 Prop *status_prop;
146 char interleave[8];
147 int total_size = 0;
148
149 log_printf("\n", 0);
150 log_printf("=========================", 0);
151 log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0);
152 log_printf("=========================", 0);
153 log_printf("\n", 0);
154 log_printf("\n", 0);
155 bnode = tree->bd_list;
156 memory = dev_find_node(bnode->nodes, "memory");
157 preg = (uint_t *)(get_prop_val(find_prop(memory, "interleave")));
158 if (preg) {
159 interlv = preg[4];
160 log_printf("Memory Interleave Factor = %d-way\n\n", interlv, 0);
161 }
162 log_printf(" Interlv. Socket Size\n", 0);
163 log_printf("Bank Group Name (MB) Status\n", 0);
164 log_printf("---- ----- ------ ---- ------\n", 0);
165
166 dimm = bnode->nodes;
167 for (bank = dev_find_node(bnode->nodes, "bank"); bank != NULL;
168 bank = dev_next_node(bank, "bank")) {
169 int bank_size = 0;
170 uint_t *reg_prop;
171
172 preg = (uint_t *)(get_prop_val(
173 find_prop(bank, "bank-interleave")));
174
175 reg_prop = (uint_t *)(get_prop_val(
176 find_prop(bank, "reg")));
177
178 /*
179 * Skip empty banks
180 */
181 if (((reg_prop[2]<<12) + (reg_prop[3]>>20)) == 0) {
182 bank_count++;
183 continue;
184 }
185
186 if (preg) {
187 interlv = preg[2];
188 (void) sprintf(interleave, " %d ", interlv);
189 bank_size = (preg[0]<<12) + (preg[1]>>20);
190 } else {
191 (void) sprintf(interleave, "%s", "none");
192 preg = (uint_t *)(get_prop_val(find_prop(bank, "reg")));
193 if (preg) {
194 bank_size = (preg[2]<<12) + (preg[3]>>20);
195 }
196 }
197 for (dimm = dev_find_node(bank, "dimm"); dimm != NULL;
198 dimm = dev_next_node_sibling(dimm, "dimm")) {
199 char dimm_status[16];
200
201 sock_name = (char *)(get_prop_val(
202 find_prop(dimm, "socket-name")));
203 preg = (uint_t *)(get_prop_val(find_prop(dimm, "reg")));
204 size = (preg[2]<<12) + (preg[3]>>20);
205 if ((status_prop = find_prop(dimm, "status")) == NULL) {
206 (void) sprintf(dimm_status, "%s", "OK");
207 } else {
208 status = (char *)(get_prop_val(status_prop));
209 (void) sprintf(dimm_status, "%s", status);
210 }
211 log_printf("%3d %5s %6s %4d %6s\n",
212 bank_count, interleave, sock_name,
213 size, dimm_status, 0);
214 }
215 total_size += bank_size;
216 bank_count++;
217 }
218 log_printf("\n", 0);
219 }
220
221 /*
222 * disp_fail_parts
223 *
224 * Display the failed parts in the system. This function looks for
225 * the status property in all PROM nodes. On systems where
226 * the PROM does not supports passing diagnostic information
227 * thruogh the device tree, this routine will be silent.
228 */
229 int
disp_fail_parts(Sys_tree * tree)230 disp_fail_parts(Sys_tree *tree)
231 {
232 int exit_code;
233 int system_failed = 0;
234 Board_node *bnode = tree->bd_list;
235 Prom_node *pnode;
236 char *fru;
237 char *sock_name;
238 char slot_str[MAXSTRLEN];
239
240 exit_code = 0;
241
242 /* go through all of the boards looking for failed units. */
243 while (bnode != NULL) {
244 /* find failed chips */
245 pnode = find_failed_node(bnode->nodes);
246 if ((pnode != NULL) && !system_failed) {
247 system_failed = 1;
248 exit_code = 1;
249 if (print_flag == 0) {
250 return (exit_code);
251 }
252 log_printf("\n", 0);
253 log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
254 "Replaceable Units (FRU) in System:\n"), 0);
255 log_printf("=========================="
256 "====================\n", 0);
257 }
258
259 while (pnode != NULL) {
260 void *value;
261 char *name; /* node name string */
262 char *type; /* node type string */
263
264 value = get_prop_val(find_prop(pnode, "status"));
265 name = get_node_name(pnode);
266
267 /* sanity check of data retreived from PROM */
268 if ((value == NULL) || (name == NULL)) {
269 pnode = next_failed_node(pnode);
270 continue;
271 }
272
273
274 log_printf(dgettext(TEXT_DOMAIN, "%s unavailable :\n"),
275 name, 0);
276
277 log_printf(dgettext(TEXT_DOMAIN, "\tPROM fault "
278 "string: %s\n"), value, 0);
279
280 log_printf(dgettext(TEXT_DOMAIN, "\tFailed Field "
281 "Replaceable Unit is "), 0);
282
283 /*
284 * Determine whether FRU is CPU module, system
285 * board, or SBus card.
286 */
287 if ((name != NULL) && (strstr(name, "sbus"))) {
288
289 log_printf(dgettext(TEXT_DOMAIN, "SBus "
290 "Card %d\n"), get_sbus_slot(pnode), 0);
291
292 } else if (((name = get_node_name(pnode)) !=
293 NULL) && (strstr(name, "pci"))) {
294
295 log_printf(dgettext(TEXT_DOMAIN, "system "
296 "board\n"), 0);
297
298 } else if (((name = get_node_name(pnode)) !=
299 NULL) && (strstr(name, "ffb"))) {
300
301 log_printf(dgettext(TEXT_DOMAIN, "FFB "
302 "Card %d\n"), tazmo_physical_slot(
303 dev_find_node(bnode->nodes, "slot2dev"),
304 pnode, -1, slot_str), 0);
305
306 } else if (((name = get_node_name(pnode->parent)) !=
307 NULL) && (strstr(name, "pci"))) {
308
309 (void) tazmo_physical_slot(NULL,
310 pnode->parent,
311 get_pci_device(pnode),
312 slot_str);
313 log_printf(dgettext(TEXT_DOMAIN, "PCI Card "
314 "in %s\n"), slot_str, 0);
315
316 } else if (((type = get_node_type(pnode)) != NULL) &&
317 (strstr(type, "cpu"))) {
318
319 log_printf(
320 dgettext(TEXT_DOMAIN, "UltraSPARC "
321 "module Module %d\n"),
322 get_id(pnode));
323
324 } else if (((type = get_node_type(pnode)) != NULL) &&
325 (strstr(type, "memory-module"))) {
326
327 fru = (char *)(get_prop_val(
328 find_prop(pnode, "fru")));
329 sock_name = (char *)(get_prop_val(
330 find_prop(pnode, "socket-name")));
331 log_printf(
332 dgettext(TEXT_DOMAIN, "%s in "
333 "socket %s\n"), fru,
334 sock_name, 0);
335 }
336 pnode = next_failed_node(pnode);
337 }
338 bnode = bnode->next;
339 }
340
341 if (!system_failed) {
342 log_printf("\n", 0);
343 log_printf(dgettext(TEXT_DOMAIN, "No failures found "
344 "in System\n"), 0);
345 log_printf("===========================\n", 0);
346 }
347
348 if (system_failed)
349 return (1);
350 else
351 return (0);
352 }
353
354 void
display_hp_fail_fault(Sys_tree * tree,struct system_kstat_data * kstats)355 display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
356 {
357 #ifdef lint
358 kstats = kstats;
359 #endif
360 /* Display failed units */
361 (void) disp_fail_parts(tree);
362 }
363
364
365 void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)366 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
367 struct system_kstat_data *kstats)
368 {
369 /*
370 * Now display the last powerfail time and the fatal hardware
371 * reset information. We do this under a couple of conditions.
372 * First if the user asks for it. The second is iof the user
373 * told us to do logging, and we found a system failure.
374 */
375 if (flag) {
376 /*
377 * display time of latest powerfail. Not all systems
378 * have this capability. For those that do not, this
379 * is just a no-op.
380 */
381 disp_powerfail(root);
382
383 (void) disp_envc_status(kstats);
384
385 tazjav_disp_asic_revs(tree);
386
387 platform_disp_prom_version(tree);
388 }
389 return;
390
391 }
392
393 /* ARGSUSED */
394 void
display_boardnum(int num)395 display_boardnum(int num)
396 {
397 log_printf("SYS ", 0);
398 }
399
400
401
402 /*
403 * display_pci
404 * Display all the PCI IO cards on this board.
405 */
406
407 /* ARGSUSED */
408 void
display_pci(Board_node * board)409 display_pci(Board_node *board)
410 {
411 struct io_card *card_list = NULL;
412 struct io_card card;
413 void *value;
414 Prom_node *pci;
415 Prom_node *card_node;
416
417 if (board == NULL)
418 return;
419
420 /* Initialize all the common information */
421 card.display = 1;
422 card.board = board->board_num;
423 (void) sprintf(card.bus_type, "PCI");
424
425 for (pci = dev_find_node(board->nodes, PCI_NAME); pci != NULL;
426 pci = dev_next_node(pci, PCI_NAME)) {
427 char *name;
428 Prom_node *prev_parent = NULL;
429 int prev_device = -1;
430 int pci_pci_bridge = 0;
431
432 /*
433 * If we have reached a pci-to-pci bridge node,
434 * we are one level below the 'pci' nodes level
435 * in the device tree. To get back to that level,
436 * the search should continue with the sibling of
437 * the parent or else the remaining 'pci' cards
438 * will not show up in the output.
439 */
440 if (find_prop(pci, "upa-portid") == NULL) {
441 if ((pci->parent->sibling != NULL) &&
442 (strcmp(get_prop_val(
443 find_prop(pci->parent->sibling,
444 "name")), PCI_NAME) == 0))
445 pci = pci->parent->sibling;
446 else {
447 pci = pci->parent->sibling;
448 continue;
449 }
450 }
451
452 /* Skip all failed nodes for now */
453 if (node_failed(pci))
454 continue;
455
456 /* Fill in frequency */
457 value = get_prop_val(find_prop(pci, "clock-frequency"));
458 if (value == NULL)
459 card.freq = -1;
460 else
461 card.freq = ((*(int *)value) + 500000) / 1000000;
462
463 /* Walk through the PSYCHO children */
464 card_node = pci->child;
465 while (card_node != NULL) {
466 Prop *compat = NULL;
467
468 /* If it doesn't have a name, skip it */
469 name = (char *)get_prop_val(
470 find_prop(card_node, "name"));
471 if (name == NULL) {
472 card_node = card_node->sibling;
473 continue;
474 }
475
476 /*
477 * If this is a PCI bridge, then display its
478 * children.
479 */
480 if (strcmp(name, "pci") == 0) {
481 card_node = card_node->child;
482 pci_pci_bridge = 1;
483 continue;
484 }
485
486 /* Get the slot number for this card */
487 if (pci_pci_bridge) {
488 card.slot = tazmo_physical_slot(
489 dev_find_node(board->nodes, "slot2dev"),
490 pci,
491 get_pci_to_pci_device(card_node->parent),
492 card.slot_str);
493 } else
494 card.slot = tazmo_physical_slot(
495 dev_find_node(board->nodes, "slot2dev"),
496 pci,
497 get_pci_device(card_node),
498 card.slot_str);
499
500 /*
501 * Check that duplicate devices are not reported
502 * on Tazmo.
503 */
504 if ((card_node->parent == prev_parent) &&
505 (get_pci_device(card_node) == prev_device) &&
506 (pci_pci_bridge == 0))
507 card.slot = -1;
508 prev_parent = card_node->parent;
509 prev_device = get_pci_device(card_node);
510
511
512 if (card.slot == -1 || strstr(name, "ebus")) {
513 card_node = card_node->sibling;
514 continue;
515 }
516
517 /* XXX - Don't know how to get status for PCI cards */
518 card.status[0] = '\0';
519
520 /* Get the model of this card */
521 value = get_prop_val(find_prop(card_node, "model"));
522 if (value == NULL)
523 card.model[0] = '\0';
524 else
525 (void) sprintf(card.model, "%s",
526 (char *)value);
527
528 /*
529 * Check if further processing is necessary to display
530 * this card uniquely.
531 */
532 distinguish_identical_io_cards(name, card_node, &card);
533
534
535 /*
536 * If we haven't figured out the frequency yet,
537 * try and get it from the card.
538 */
539 value = get_prop_val(find_prop(pci, "clock-frequency"));
540 if (value != NULL && card.freq == -1)
541 card.freq = ((*(int *)value) + 500000)
542 / 1000000;
543
544
545 value = get_prop_val(find_prop(card_node,
546 "compatible"));
547
548 /*
549 * On Tazmo, we would like to print out the last
550 * string of the "compatible" property if it exists.
551 * The IEEE 1275 spec. states that this last string
552 * will be the classcode name.
553 */
554 if (value != NULL) {
555 char *tval;
556 int index;
557 const int always = 1;
558
559 tval = (char *)value;
560 index = 0;
561 compat = find_prop(card_node, "compatible");
562 while (always) {
563 if ((strlen(tval) + 1) ==
564 (compat->size - index))
565 break;
566 index += strlen(tval) + 1;
567 tval += strlen(tval) + 1;
568 }
569 value = (void *)tval;
570 }
571
572 if (value != NULL)
573 (void) sprintf(card.name, "%s-%s",
574 (char *)name, (char *)value);
575 else
576 (void) sprintf(card.name, "%s",
577 (char *)name);
578
579 if (card.freq != -1)
580 card_list = insert_io_card(card_list, &card);
581
582 /*
583 * If we are done with the children of the pci bridge,
584 * we must continue with the remaining siblings of
585 * the pci-to-pci bridge.
586 */
587 if ((card_node->sibling == NULL) && pci_pci_bridge) {
588 card_node = card_node->parent->sibling;
589 pci_pci_bridge = 0;
590 } else
591 card_node = card_node->sibling;
592 }
593 }
594
595 display_io_cards(card_list);
596 free_io_cards(card_list);
597 }
598
599
600 /*
601 * Print out all the io cards in the list. Also print the column
602 * headers if told to do so.
603 */
604 void
display_io_cards(struct io_card * list)605 display_io_cards(struct io_card *list)
606 {
607 static int banner = 0; /* Have we printed the column headings? */
608 struct io_card *p;
609
610 if (list == NULL)
611 return;
612
613 if (banner == 0) {
614 log_printf(" Bus Freq\n", 0);
615 log_printf("Brd Type MHz Slot "
616 "Name "
617 "Model", 0);
618 log_printf("\n", 0);
619 log_printf("--- ---- ---- ---- "
620 "-------------------------------- "
621 "----------------------", 0);
622 log_printf("\n", 0);
623 banner = 1;
624 }
625
626 for (p = list; p != NULL; p = p -> next) {
627 log_printf("SYS ", p->board, 0);
628 log_printf("%-4s ", p->bus_type, 0);
629 log_printf("%3d ", p->freq, 0);
630 log_printf("%3d ", p->slot, 0);
631 log_printf("%-32.32s", p->name, 0);
632 if (strlen(p->name) > 32)
633 log_printf("+ ", 0);
634 else
635 log_printf(" ", 0);
636 log_printf("%-22.22s", p->model, 0);
637 if (strlen(p->model) > 22)
638 log_printf("+", 0);
639 log_printf("\n", 0);
640 }
641 }
642
643 /*
644 * display_ffb
645 * Display all FFBs on this board. It can either be in tabular format,
646 * or a more verbose format.
647 */
648 void
display_ffb(Board_node * board,int table)649 display_ffb(Board_node *board, int table)
650 {
651 Prom_node *ffb;
652 void *value;
653 struct io_card *card_list = NULL;
654 struct io_card card;
655
656 if (board == NULL)
657 return;
658
659 /* Fill in common information */
660 card.display = 1;
661 card.board = board->board_num;
662 (void) sprintf(card.bus_type, "UPA");
663 card.freq = sys_clk;
664
665 for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL;
666 ffb = dev_next_node(ffb, FFB_NAME)) {
667 if (table == 1) {
668 /* Print out in table format */
669
670 /* XXX - Get the slot number (hack) */
671 card.slot = tazmo_physical_slot(
672 dev_find_node(board->nodes, "slot2dev"),
673 ffb,
674 -1,
675 card.slot_str);
676
677 /* Find out if it's single or double buffered */
678 (void) sprintf(card.name, "FFB");
679 value = get_prop_val(find_prop(ffb, "board_type"));
680 if (value != NULL)
681 if ((*(int *)value) & FFB_B_BUFF)
682 (void) sprintf(card.name,
683 "FFB, Double Buffered");
684 else
685 (void) sprintf(card.name,
686 "FFB, Single Buffered");
687
688 /* Print model number */
689 card.model[0] = '\0';
690 value = get_prop_val(find_prop(ffb, "model"));
691 if (value != NULL)
692 (void) sprintf(card.model, "%s",
693 (char *)value);
694
695 card_list = insert_io_card(card_list, &card);
696 } else {
697 /* print in long format */
698 char device[MAXSTRLEN];
699 int fd = -1;
700 struct dirent *direntp;
701 DIR *dirp;
702 union strap_un strap;
703 struct ffb_sys_info fsi;
704
705 /* Find the device node using upa address */
706 value = get_prop_val(find_prop(ffb, "upa-portid"));
707 if (value == NULL)
708 continue;
709
710 (void) sprintf(device, "%s@%x", FFB_NAME,
711 *(int *)value);
712 if ((dirp = opendir("/devices")) == NULL)
713 continue;
714
715 while ((direntp = readdir(dirp)) != NULL) {
716 if (strstr(direntp->d_name, device) != NULL) {
717 (void) sprintf(device, "/devices/%s",
718 direntp->d_name);
719 fd = open(device, O_RDWR, 0666);
720 break;
721 }
722 }
723 (void) closedir(dirp);
724
725 if (fd == -1)
726 continue;
727
728 if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
729 continue;
730
731 log_printf("FFB Hardware Configuration:\n", 0);
732 log_printf("-----------------------------------\n", 0);
733
734 strap.ffb_strap_bits = fsi.ffb_strap_bits;
735 log_printf("\tBoard rev: %d\n",
736 (int)strap.fld.board_rev, 0);
737 log_printf("\tFBC version: "
738 "0x%x\n", fsi.fbc_version, 0);
739 log_printf("\tDAC: %s\n",
740 fmt_manf_id(fsi.dac_version, device), 0);
741 log_printf("\t3DRAM: %s\n",
742 fmt_manf_id(fsi.fbram_version, device), 0);
743 log_printf("\n", 0);
744 }
745 }
746
747 display_io_cards(card_list);
748 free_io_cards(card_list);
749 }
750
751 /*
752 * This module does the reading and interpreting of javelin system
753 * kstats. These kstats are created by the envctrl drivers.
754 */
755 void
read_platform_kstats(Sys_tree * tree,struct system_kstat_data * sys_kstat,struct envctrl_kstat_data * ep)756 read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat,
757 struct envctrl_kstat_data *ep)
758 {
759 kstat_ctl_t *kc;
760 struct envctrltwo_kstat_data *ecp;
761 kstat_t *ksp;
762
763 if ((kc = kstat_open()) == NULL) {
764 return;
765 }
766
767 /* read the envctrltwo kstats */
768 ecp = &sys_kstat->envc_data;
769
770 /* Read the power supply kstats */
771 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
772 ENVCTRL_KSTAT_PSNAME2);
773
774 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
775 (void) memcpy(ecp->ps_kstats, ksp->ks_data,
776 ksp->ks_ndata * sizeof (envctrl_ps2_t));
777 } else {
778 sys_kstat->envctrltwo_kstat_ok = B_FALSE;
779 return;
780 }
781
782 ecp->num_ps_kstats = ksp->ks_ndata;
783
784 /* Read the fan status kstats */
785 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
786 ENVCTRL_KSTAT_FANSTAT);
787
788 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
789 (void) memcpy(ecp->fan_kstats, ksp->ks_data,
790 ksp->ks_ndata * sizeof (envctrl_fan_t));
791 } else {
792 sys_kstat->envctrltwo_kstat_ok = B_FALSE;
793 return;
794 }
795
796 ecp->num_fan_kstats = ksp->ks_ndata;
797
798 /* Read the enclosure kstats */
799 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
800 ENVCTRL_KSTAT_ENCL);
801
802 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
803 (void) memcpy(ecp->encl_kstats, ksp->ks_data,
804 ksp->ks_ndata * sizeof (envctrl_encl_t));
805 } else {
806 sys_kstat->envctrltwo_kstat_ok = B_FALSE;
807 return;
808 }
809
810 ecp->num_encl_kstats = ksp->ks_ndata;
811
812 /* Read the temperature kstats */
813 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
814 ENVCTRL_KSTAT_TEMPERATURE);
815
816 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
817 (void) memcpy(ecp->temp_kstats, ksp->ks_data,
818 ksp->ks_ndata * sizeof (envctrl_temp_t));
819 } else {
820 sys_kstat->envctrltwo_kstat_ok = B_FALSE;
821 return;
822 }
823
824 ecp->num_temp_kstats = ksp->ks_ndata;
825
826 /* Read the disk kstats */
827 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
828 ENVCTRL_KSTAT_DISK);
829
830 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
831 (void) memcpy(ecp->disk_kstats, ksp->ks_data,
832 ksp->ks_ndata * sizeof (envctrl_disk_t));
833 } else {
834 sys_kstat->envctrltwo_kstat_ok = B_FALSE;
835 return;
836 }
837
838 ecp->num_disk_kstats = ksp->ks_ndata;
839
840 sys_kstat->envctrltwo_kstat_ok = 1;
841 return;
842
843 }
844
845 /*
846 * Walk the PROM device tree and build the system tree and root tree.
847 * Nodes that have a board number property are placed in the board
848 * structures for easier processing later. Child nodes are placed
849 * under their parents. ffb (Fusion Frame Buffer) nodes are handled
850 * specially, because they do not contain board number properties.
851 * This was requested from OBP, but was not granted. So this code
852 * must parse the MID of the FFB to find the board#.
853 */
854 Prom_node *
walk(Sys_tree * tree,Prom_node * root,int id)855 walk(Sys_tree *tree, Prom_node *root, int id)
856 {
857 register int curnode;
858 Prom_node *pnode;
859 char *name;
860 char *type;
861 char *model;
862 int board_node = 0;
863
864 /* allocate a node for this level */
865 if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
866 NULL) {
867 perror("malloc");
868 exit(2); /* program errors cause exit 2 */
869 }
870
871 /* assign parent Prom_node */
872 pnode->parent = root;
873 pnode->sibling = NULL;
874 pnode->child = NULL;
875
876 /* read properties for this node */
877 dump_node(pnode);
878
879 /*
880 * Place a node in a 'board' if it has 'board'-ness. The definition
881 * is that all nodes that are children of root should have a
882 * board# property. But the PROM tree does not exactly follow
883 * this. This is where we start hacking. The name 'ffb' can
884 * change, so watch out for this.
885 *
886 * The UltraSPARC, sbus, pci and ffb nodes will exit in
887 * the desktops and will not have board# properties. These
888 * cases must be handled here.
889 *
890 * PCI to PCI bridges also have the name "pci", but with different
891 * model property values. They should not be put under 'board'.
892 */
893 name = get_node_name(pnode);
894 type = get_node_type(pnode);
895 model = (char *)get_prop_val(find_prop(pnode, "model"));
896 #ifdef DEBUG
897 if (name != NULL)
898 printf("name=%s ", name);
899 if (type != NULL)
900 printf("type=%s ", type);
901 if (model != NULL)
902 printf("model=%s", model);
903 printf("\n");
904
905 if (model == NULL)
906 model = "";
907 #endif
908 if (type == NULL)
909 type = "";
910 if (name != NULL) {
911 if (has_board_num(pnode)) {
912 add_node(tree, pnode);
913 board_node = 1;
914 #ifdef DEBUG
915 printf("ADDED BOARD name=%s type=%s model=%s\n",
916 name, type, model);
917 #endif
918 } else if ((strcmp(name, FFB_NAME) == 0) ||
919 (strcmp(type, "cpu") == 0) ||
920
921 ((strcmp(name, "pci") == 0) && (model != NULL) &&
922 (strcmp(model, "SUNW,psycho") == 0)) ||
923
924 ((strcmp(name, "pci") == 0) && (model != NULL) &&
925 (strcmp(model, "SUNW,sabre") == 0)) ||
926
927 (strcmp(name, "counter-timer") == 0) ||
928 (strcmp(name, "sbus") == 0) ||
929 (strcmp(name, "memory") == 0) ||
930 (strcmp(name, "mc") == 0) ||
931 (strcmp(name, "associations") == 0)) {
932 add_node(tree, pnode);
933 board_node = 1;
934 #ifdef DEBUG
935 printf("ADDED BOARD name=%s type=%s model=%s\n",
936 name, type, model);
937 #endif
938 }
939 #ifdef DEBUG
940 else
941 printf("node not added: name=%s type=%s\n", name, type);
942 #endif
943 }
944
945 if (curnode = child(id)) {
946 pnode->child = walk(tree, pnode, curnode);
947 }
948
949 if (curnode = next(id)) {
950 if (board_node) {
951 return (walk(tree, root, curnode));
952 } else {
953 pnode->sibling = walk(tree, root, curnode);
954 }
955 }
956
957 if (board_node) {
958 return (NULL);
959 } else {
960 return (pnode);
961 }
962 }
963
964 /*
965 * local functions
966 */
967
968 /*
969 * disp_envc_status
970 *
971 * This routine displays the environmental status passed up from
972 * device drivers via kstats. The kstat names are defined in
973 * kernel header files included by this module.
974 * This is a Javelin specific environmental information display routine.
975 */
976 static int
disp_envc_status(struct system_kstat_data * sys_kstats)977 disp_envc_status(struct system_kstat_data *sys_kstats)
978 {
979 struct envctrltwo_kstat_data *ecp;
980 envctrl_ps2_t ps_ks;
981 envctrl_fan_t fans_ks;
982 envctrl_encl_t encl_ks;
983 envctrl_temp_t temp_ks;
984 envctrl_disk_t disk_ks;
985 char state[48];
986 uchar_t val, fsp_value;
987 uchar_t disk_pr, disk_fl;
988 int i;
989 int exit_code = 0;
990
991 if (sys_kstats->envctrltwo_kstat_ok == 0) {
992 log_printf("\n", 0);
993 log_printf(dgettext(TEXT_DOMAIN, "Environmental information "
994 "is not available\n"), 0);
995 log_printf(dgettext(TEXT_DOMAIN, "Environmental driver may "
996 "not be installed\n"), 0);
997 log_printf("\n", 0);
998 return (1);
999 }
1000
1001 ecp = &sys_kstats->envc_data;
1002
1003 log_printf("\n", 0);
1004 log_printf("=========================", 0);
1005 log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0);
1006 log_printf("=========================", 0);
1007 log_printf("\n", 0);
1008 log_printf("\n", 0);
1009
1010 log_printf("System Temperatures (Celsius):\n", 0);
1011 log_printf("------------------------------\n", 0);
1012
1013 for (i = 0; i < ecp->num_temp_kstats; i++) {
1014 temp_ks = ecp->temp_kstats[i];
1015 log_printf("%10s %d", temp_ks.label, temp_ks.value);
1016 if (temp_ks.value >= temp_ks.shutdown_threshold) {
1017 log_printf(" CRITICAL\n", 0);
1018 exit_code = 1;
1019 } else if (temp_ks.value >= temp_ks.warning_threshold) {
1020 log_printf(" WARNING\n", 0);
1021 exit_code = 1;
1022 } else if (temp_ks.value < temp_ks.min) {
1023 log_printf(" WARNING\n", 0);
1024 exit_code = 1;
1025 } else
1026 log_printf("\n", 0);
1027 }
1028
1029 log_printf("\n", 0);
1030 log_printf("=================================\n", 0);
1031 log_printf("\n", 0);
1032 encl_ks = ecp->encl_kstats[0];
1033 val = encl_ks.value & ENVCTRL_UE250_FSP_KEYMASK;
1034 fsp_value = encl_ks.value;
1035 switch (val) {
1036 case ENVCTRL_UE250_FSP_KEYOFF:
1037 (void) sprintf(state, "%s", "Off");
1038 break;
1039 case ENVCTRL_UE250_FSP_KEYON:
1040 (void) sprintf(state, "%s", "On");
1041 break;
1042 case ENVCTRL_UE250_FSP_KEYDIAG:
1043 (void) sprintf(state, "%s", "Diagnostic");
1044 break;
1045 case ENVCTRL_UE250_FSP_KEYLOCKED:
1046 (void) sprintf(state, "%s", "Secure");
1047 break;
1048 default:
1049 (void) sprintf(state, "%s", "Broken!");
1050 exit_code = 1;
1051 break;
1052 }
1053 log_printf("Front Status Panel:\n", 0);
1054 log_printf("-------------------\n", 0);
1055 log_printf("Keyswitch position is in %s mode.\n", state);
1056 log_printf("\n", 0);
1057 val = fsp_value & (ENVCTRL_UE250_FSP_DISK_ERR |
1058 ENVCTRL_UE250_FSP_PS_ERR | ENVCTRL_UE250_FSP_TEMP_ERR |
1059 ENVCTRL_UE250_FSP_GEN_ERR | ENVCTRL_UE250_FSP_ACTIVE);
1060 log_printf("System LED Status: DISK ERROR POWER \n", 0);
1061 log_printf(" [%3s] [ ON] \n",
1062 val & ENVCTRL_UE250_FSP_DISK_ERR ? "ON" : "OFF");
1063 log_printf(" POWER SUPPLY ERROR ACTIVITY \n", 0);
1064 log_printf(" [%3s] [%3s] \n",
1065 val & ENVCTRL_UE250_FSP_PS_ERR ? "ON" : "OFF",
1066 val & ENVCTRL_UE250_FSP_ACTIVE ? "ON" : "OFF");
1067 log_printf(" GENERAL ERROR THERMAL ERROR \n", 0);
1068 log_printf(" [%3s] [%3s] \n",
1069 val & ENVCTRL_UE250_FSP_GEN_ERR ? "ON" : "OFF",
1070 val & ENVCTRL_UE250_FSP_TEMP_ERR ? "ON" : "OFF");
1071 if (val & (ENVCTRL_UE250_FSP_DISK_ERR | ENVCTRL_UE250_FSP_PS_ERR |
1072 ENVCTRL_UE250_FSP_GEN_ERR | ENVCTRL_UE250_FSP_TEMP_ERR)) {
1073 exit_code = 1;
1074 }
1075
1076 log_printf("\n", 0);
1077 log_printf("=================================\n", 0);
1078 log_printf("\n", 0);
1079 disk_pr = disk_fl = 0;
1080 for (i = 0; i < ecp->num_disk_kstats; i++) {
1081 disk_ks = ecp->disk_kstats[i];
1082 if (disk_ks.slot == -1)
1083 continue;
1084 disk_pr |= 1 << disk_ks.slot;
1085 if (disk_ks.disk_ok == 0)
1086 disk_fl |= 1 << disk_ks.slot;
1087 }
1088
1089 log_printf("Disk LED Status: OK = GREEN ERROR = YELLOW\n", 0);
1090 log_printf(" DISK 5: %7s DISK 3: %7s DISK 1: %7s\n",
1091 disk_pr & ENVCTRL_DISK_5 ?
1092 disk_fl & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]" : "[EMPTY]",
1093 disk_pr & ENVCTRL_DISK_3 ?
1094 disk_fl & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]" : "[EMPTY]",
1095 disk_pr & ENVCTRL_DISK_1 ?
1096 disk_fl & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]" : "[EMPTY]");
1097 log_printf(" DISK 4: %7s DISK 2: %7s DISK 0: %7s\n",
1098 disk_pr & ENVCTRL_DISK_4 ?
1099 disk_fl & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]" : "[EMPTY]",
1100 disk_pr & ENVCTRL_DISK_2 ?
1101 disk_fl & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]" : "[EMPTY]",
1102 disk_pr & ENVCTRL_DISK_0 ?
1103 disk_fl & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]" : "[EMPTY]");
1104
1105 log_printf("\n", 0);
1106 log_printf("=================================\n", 0);
1107 log_printf("\n", 0);
1108 log_printf("Fan Bank :\n", 0);
1109 log_printf("----------\n", 0);
1110 log_printf("\n", 0);
1111
1112 fans_ks = ecp->fan_kstats[0];
1113 log_printf("Bank Speed Status\n", 0);
1114 log_printf(" (0-255) \n", 0);
1115 log_printf("---- ----- ------\n", 0);
1116 if (fans_ks.fans_ok == B_TRUE)
1117 log_printf(" SYS %5d OK\n", fans_ks.fanspeed);
1118 else if (fans_ks.fans_ok != B_TRUE) {
1119 log_printf(" SYS %5d FAILED\n", fans_ks.fanspeed);
1120 exit_code = 1;
1121 }
1122
1123 log_printf("\n", 0);
1124 log_printf("=================================\n", 0);
1125 log_printf("\n", 0);
1126 log_printf("Power Supplies:\n", 0);
1127 log_printf("---------------\n", 0);
1128 log_printf("\n", 0);
1129 log_printf("Supply Status\n", 0);
1130 log_printf("------ ------\n", 0);
1131
1132 for (i = 0; i < ecp->num_ps_kstats; i++) {
1133 ps_ks = ecp->ps_kstats[i];
1134 if (ps_ks.ps_ok == B_TRUE)
1135 (void) sprintf(state, "%s", " OK ");
1136 else if (ps_ks.ps_ok != B_TRUE) {
1137 (void) sprintf(state, "%s", "FAILED: DC "
1138 "Power Failure");
1139 exit_code = 1;
1140 }
1141
1142 log_printf(" %2d %s\n", ps_ks.slot, state);
1143 }
1144
1145 return (exit_code);
1146 }
1147
1148 void
tazjav_disp_asic_revs(Sys_tree * tree)1149 tazjav_disp_asic_revs(Sys_tree *tree)
1150 {
1151 Board_node *bnode;
1152 Prom_node *pnode;
1153 char *name;
1154 int *version;
1155 char *model;
1156
1157 /* Print the header */
1158 log_printf("\n", 0);
1159 log_printf("=========================", 0);
1160 log_printf(" HW Revisions ", 0);
1161 log_printf("=========================", 0);
1162 log_printf("\n", 0);
1163 log_printf("\n", 0);
1164
1165 bnode = tree->bd_list;
1166
1167 log_printf("ASIC Revisions:\n", 0);
1168 log_printf("---------------\n", 0);
1169
1170 /* Find sysio and print rev */
1171 for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL;
1172 pnode = dev_next_node(pnode, "sbus")) {
1173 version = (int *)get_prop_val(find_prop(pnode, "version#"));
1174 name = get_prop_val(find_prop(pnode, "name"));
1175
1176 if ((version != NULL) && (name != NULL)) {
1177 log_printf("SBus: %s Rev %d\n", name, *version, 0);
1178 }
1179 }
1180
1181 /* Find Psycho and print rev */
1182 for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL;
1183 pnode = dev_next_node(pnode, "pci")) {
1184 Prom_node *parsib = pnode->parent->sibling;
1185
1186 if (find_prop(pnode, "upa-portid") == NULL) {
1187 if ((parsib != NULL) &&
1188 (strcmp(get_prop_val(
1189 find_prop(parsib, "name")),
1190 PCI_NAME) == 0))
1191 pnode = parsib;
1192 else {
1193 pnode = parsib;
1194 continue;
1195 }
1196 }
1197
1198 version = (int *)get_prop_val(find_prop(pnode, "version#"));
1199 name = get_prop_val(find_prop(pnode, "name"));
1200
1201 if ((version != NULL) && (name != NULL))
1202 if (get_pci_bus(pnode) == 0)
1203 log_printf("STP2223BGA: Rev %d\n", *version, 0);
1204 }
1205
1206 /* Find Cheerio and print rev */
1207 for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL;
1208 pnode = dev_next_node(pnode, "ebus")) {
1209 version = (int *)get_prop_val(find_prop(pnode, "revision-id"));
1210 name = get_prop_val(find_prop(pnode, "name"));
1211
1212 if ((version != NULL) && (name != NULL))
1213 log_printf("STP2003QFP: Rev %d\n", *version, 0);
1214 }
1215
1216 /* Find System Controller and print rev */
1217 for (pnode = dev_find_node(bnode->nodes, "sc"); pnode != NULL;
1218 pnode = dev_next_node(pnode, "sc")) {
1219 version = (int *)get_prop_val(find_prop(pnode, "version#"));
1220 model = (char *)get_prop_val(find_prop(pnode, "model"));
1221 name = get_prop_val(find_prop(pnode, "name"));
1222
1223 if ((version != NULL) && (name != NULL)) {
1224 if ((strcmp(model, "SUNW,sc-marvin") == 0))
1225 log_printf("STP2205BGA: Rev %d\n", *version, 0);
1226 }
1227 }
1228
1229 /* Find the FEPS and print rev */
1230 for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL;
1231 pnode = dev_next_node(pnode, "SUNW,hme")) {
1232 version = (int *)get_prop_val(find_prop(pnode, "hm-rev"));
1233 name = get_prop_val(find_prop(pnode, "name"));
1234
1235 if ((version != NULL) && (name != NULL)) {
1236 log_printf("FEPS: %s Rev ", name);
1237 if (*version == 0xa0) {
1238 log_printf("2.0\n", 0);
1239 } else if (*version == 0x20) {
1240 log_printf("2.1\n", 0);
1241 } else {
1242 log_printf("%x\n", *version, 0);
1243 }
1244 }
1245 }
1246 log_printf("\n", 0);
1247
1248 if (dev_find_node(bnode->nodes, FFB_NAME) != NULL) {
1249 display_ffb(bnode, 0);
1250 }
1251 }
1252
1253
1254 /*
1255 * Determine the physical PCI slot based on which Psycho is the parent
1256 * of the PCI card.
1257 */
1258 static int
tazmo_physical_slot(Prom_node * slotd,Prom_node * parent,int device,char * str)1259 tazmo_physical_slot(Prom_node *slotd, Prom_node *parent, int device, char *str)
1260 {
1261 int *upa_id = NULL;
1262 int *reg = NULL;
1263 int offset;
1264 char controller[MAXSTRLEN];
1265 char *name;
1266 Prop *prop;
1267 char *devpath_p;
1268 char slotx[16] = "";
1269 int *slot_names_mask;
1270 char *slot_names;
1271 int shift = 0;
1272 int slot;
1273 int slots, start_slot;
1274
1275 /*
1276 * If slotd != NULL, then we must return the physical PCI slot
1277 * number based on the information in the slot2dev associations
1278 * node. This routine is called from display_pci() with slotd
1279 * != NULL. If so, we return without obtaining the slot name.
1280 * If slotd == NULL, we look for the slot name through the
1281 * slot-names property in the bus node.
1282 */
1283
1284 if (slotd != NULL) {
1285 (void) strcpy(str, "");
1286 if ((prop = find_prop(parent, "upa-portid")) != NULL)
1287 upa_id = (int *)(get_prop_val(prop));
1288 if ((prop = find_prop(parent, "reg")) != NULL)
1289 reg = (int *)(get_prop_val(prop));
1290 if ((prop = find_prop(parent, "name")) != NULL)
1291 name = (char *)(get_prop_val(prop));
1292 if ((upa_id == NULL) || (reg == NULL)) {
1293 return (-1);
1294 }
1295 offset = reg[1];
1296 if (strcmp(name, "pci") == 0) {
1297 (void) sprintf(controller, "/pci@%x,%x/*@%x,*",
1298 *upa_id, offset, device);
1299 slots = 20;
1300 } else if (strcmp(name, "SUNW,ffb") == 0) {
1301 (void) sprintf(controller, "/*@%x,0", *upa_id);
1302 slots = 2;
1303 }
1304
1305 /*
1306 * Javelin and future projects will use 0 based
1307 * numbering for slots.
1308 */
1309 start_slot = 0;
1310 slots = slots - 1;
1311 for (slot = start_slot; slot <= slots; slot++) {
1312 if (strcmp(name, "pci") == 0)
1313 (void) sprintf(slotx, "pci-slot#%d", slot);
1314 else if (strcmp(name, "SUNW,ffb") == 0)
1315 (void) sprintf(slotx, "graphics#%d", slot);
1316 if ((prop = find_prop(slotd, slotx)) != NULL)
1317 if ((devpath_p = (char *)(get_prop_val
1318 (prop))) != NULL)
1319 if (strcmp(devpath_p, controller) == 0)
1320 return (slot);
1321 }
1322 return (-1);
1323 }
1324
1325 /*
1326 * Get slot-names property from parent node.
1327 * This property consists of a 32 bit mask indicating which
1328 * devices are relevant to this bus node. Following are a
1329 * number of strings depending on how many bits are set in the
1330 * bit mask; the first string gives the label that is printed
1331 * on the chassis for the smallest device number, and so on.
1332 */
1333
1334 prop = find_prop(parent, "slot-names");
1335 if (prop == NULL) {
1336 (void) strcpy(str, "");
1337 return (-1);
1338 }
1339 slot_names_mask = (int *)(get_prop_val(prop));
1340 slot_names = (char *)slot_names_mask;
1341
1342 slot = 1;
1343 slot_names += 4; /* Skip the 4 byte bitmask */
1344
1345 while (shift < 32) {
1346 /*
1347 * Shift through the bitmask looking to see if the
1348 * bit corresponding to "device" is set. If so, copy
1349 * the correcsponding string to the provided pointer.
1350 */
1351 if (*slot_names_mask & slot) {
1352 if (shift == device) {
1353 (void) strcpy(str, slot_names);
1354 return (0);
1355 }
1356 slot_names += strlen(slot_names)+1;
1357 }
1358 shift++;
1359 slot = slot << 1;
1360 }
1361 return (-1);
1362 }
1363