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