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 * Tazmo Platform specific functions.
28 *
29 * called when :
30 * machine_type == MTYPE_TAZMO
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_envctrl_status(Sys_tree *, struct system_kstat_data *);
86 static void check_disk_presence(Sys_tree *, int *, int *, int *);
87 static void modify_device_path(char *, char *);
88 static int disk_present(char *);
89 static void tazjav_disp_asic_revs(Sys_tree *);
90 static int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *);
91 static Prom_node *dev_next_node_sibling(Prom_node *root, char *name);
92
93
94 int
error_check(Sys_tree * tree,struct system_kstat_data * kstats)95 error_check(Sys_tree *tree, struct system_kstat_data *kstats)
96 {
97 int exit_code = 0; /* init to all OK */
98
99 #ifdef lint
100 kstats = kstats;
101 #endif
102 /*
103 * silently check for any types of machine errors
104 */
105 print_flag = 0;
106 if (disp_fail_parts(tree) || disp_envctrl_status(tree, kstats)) {
107 /* set exit_code to show failures */
108 exit_code = 1;
109 }
110 print_flag = 1;
111
112 return (exit_code);
113 }
114
115 /* Search for and return the node's sibling */
116 static Prom_node *
dev_next_node_sibling(Prom_node * root,char * name)117 dev_next_node_sibling(Prom_node *root, char *name)
118 {
119 if (root == NULL)
120 return (NULL);
121
122 /* look at your siblings */
123 if (dev_find_node(root->sibling, name) != NULL)
124 return (root->sibling);
125
126 return (NULL); /* not found */
127 }
128
129 /*
130 * This function displays memory configurations specific to Tazmo/Javelin.
131 * The PROM device tree is read to obtain this information.
132 * Some of the information obtained is memory interleave factor,
133 * DIMM sizes, DIMM socket names.
134 */
135 void
display_memoryconf(Sys_tree * tree)136 display_memoryconf(Sys_tree *tree)
137 {
138 Board_node *bnode;
139 Prom_node *memory;
140 Prom_node *bank;
141 Prom_node *dimm;
142 uint_t *preg;
143 uint_t interlv;
144 unsigned long size = 0;
145 int bank_count = 0;
146 char *sock_name;
147 char *status;
148 Prop *status_prop;
149 char interleave[8];
150 int total_size = 0;
151
152 log_printf("\n", 0);
153 log_printf("=========================", 0);
154 log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0);
155 log_printf("=========================", 0);
156 log_printf("\n", 0);
157 log_printf("\n", 0);
158 bnode = tree->bd_list;
159 memory = dev_find_node(bnode->nodes, "memory");
160 preg = (uint_t *)(get_prop_val(find_prop(memory, "interleave")));
161 if (preg) {
162 interlv = preg[4];
163 log_printf("Memory Interleave Factor = %d-way\n\n", interlv, 0);
164 }
165 log_printf(" Interlv. Socket Size\n", 0);
166 log_printf("Bank Group Name (MB) Status\n", 0);
167 log_printf("---- ----- ------ ---- ------\n", 0);
168
169 dimm = bnode->nodes;
170 for (bank = dev_find_node(bnode->nodes, "bank"); bank != NULL;
171 bank = dev_next_node(bank, "bank")) {
172 int bank_size = 0;
173 uint_t *reg_prop;
174
175 preg = (uint_t *)(get_prop_val(
176 find_prop(bank, "bank-interleave")));
177
178 reg_prop = (uint_t *)(get_prop_val(
179 find_prop(bank, "reg")));
180
181 /*
182 * Skip empty banks
183 */
184 if (((reg_prop[2]<<12) + (reg_prop[3]>>20)) == 0) {
185 bank_count++;
186 continue;
187 }
188
189 if (preg) {
190 interlv = preg[2];
191 (void) sprintf(interleave, " %d ", interlv);
192 bank_size = (preg[0]<<12) + (preg[1]>>20);
193 } else {
194 (void) sprintf(interleave, "%s", "none");
195 preg = (uint_t *)(get_prop_val(find_prop(bank, "reg")));
196 if (preg) {
197 bank_size = (preg[2]<<12) + (preg[3]>>20);
198 }
199 }
200 for (dimm = dev_find_node(bank, "dimm"); dimm != NULL;
201 dimm = dev_next_node_sibling(dimm, "dimm")) {
202 char dimm_status[16];
203
204 sock_name = (char *)(get_prop_val(
205 find_prop(dimm, "socket-name")));
206 preg = (uint_t *)(get_prop_val(find_prop(dimm, "reg")));
207 size = (preg[2]<<12) + (preg[3]>>20);
208 if ((status_prop = find_prop(dimm, "status")) == NULL) {
209 (void) sprintf(dimm_status, "%s", "OK");
210 } else {
211 status = (char *)(get_prop_val(status_prop));
212 (void) sprintf(dimm_status, "%s", status);
213 }
214 log_printf("%3d %5s %6s %4d %6s\n",
215 bank_count, interleave, sock_name,
216 size, dimm_status, 0);
217 }
218 total_size += bank_size;
219 bank_count++;
220 }
221 log_printf("\n", 0);
222 }
223
224 /*
225 * disp_fail_parts
226 *
227 * Display the failed parts in the system. This function looks for
228 * the status property in all PROM nodes. On systems where
229 * the PROM does not supports passing diagnostic information
230 * thruogh the device tree, this routine will be silent.
231 */
232 int
disp_fail_parts(Sys_tree * tree)233 disp_fail_parts(Sys_tree *tree)
234 {
235 int exit_code;
236 int system_failed = 0;
237 Board_node *bnode = tree->bd_list;
238 Prom_node *pnode;
239 char *fru;
240 char *sock_name;
241 char slot_str[MAXSTRLEN];
242
243 exit_code = 0;
244
245 /* go through all of the boards looking for failed units. */
246 while (bnode != NULL) {
247 /* find failed chips */
248 pnode = find_failed_node(bnode->nodes);
249 if ((pnode != NULL) && !system_failed) {
250 system_failed = 1;
251 exit_code = 1;
252 if (print_flag == 0) {
253 return (exit_code);
254 }
255 log_printf("\n", 0);
256 log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
257 "Replaceable Units (FRU) in System:\n"), 0);
258 log_printf("=========================="
259 "====================\n", 0);
260 }
261
262 while (pnode != NULL) {
263 void *value;
264 char *name; /* node name string */
265 char *type; /* node type string */
266
267 value = get_prop_val(find_prop(pnode, "status"));
268 name = get_node_name(pnode);
269
270 /* sanity check of data retreived from PROM */
271 if ((value == NULL) || (name == NULL)) {
272 pnode = next_failed_node(pnode);
273 continue;
274 }
275
276
277 log_printf(dgettext(TEXT_DOMAIN, "%s unavailable :\n"),
278 name, 0);
279
280 log_printf(dgettext(TEXT_DOMAIN,
281 "\tPROM fault string: %s\n"),
282 value, 0);
283
284 log_printf(dgettext(TEXT_DOMAIN,
285 "\tFailed Field 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,
300 "system board\n"), 0);
301
302 } else if (((name = get_node_name(pnode)) !=
303 NULL) && (strstr(name, "ffb"))) {
304
305 log_printf(dgettext(TEXT_DOMAIN,
306 "FFB Card %d\n"),
307 tazmo_physical_slot(
308 dev_find_node(bnode->nodes, "slot2dev"),
309 pnode, -1, slot_str), 0);
310
311 } else if (((name = get_node_name(pnode->parent)) !=
312 NULL) && (strstr(name, "pci"))) {
313
314 (void) tazmo_physical_slot(
315 NULL,
316 pnode->parent,
317 get_pci_device(pnode),
318 slot_str);
319 log_printf(dgettext(TEXT_DOMAIN,
320 "PCI Card in %s\n"), slot_str, 0);
321
322 } else if (((type = get_node_type(pnode)) != NULL) &&
323 (strstr(type, "cpu"))) {
324
325 log_printf(
326 dgettext(TEXT_DOMAIN,
327 "UltraSPARC module Module %d\n"),
328 get_id(pnode));
329
330 } else if (((type = get_node_type(pnode)) != NULL) &&
331 (strstr(type, "memory-module"))) {
332
333 fru = (char *)(get_prop_val(
334 find_prop(pnode, "fru")));
335 sock_name = (char *)(get_prop_val(
336 find_prop(pnode, "socket-name")));
337 log_printf(
338 dgettext(TEXT_DOMAIN,
339 "%s in socket %s\n"),
340 fru, sock_name, 0);
341 }
342 pnode = next_failed_node(pnode);
343 }
344 bnode = bnode->next;
345 }
346
347 if (!system_failed) {
348 log_printf("\n", 0);
349 log_printf(dgettext(TEXT_DOMAIN,
350 "No failures found in System\n"), 0);
351 log_printf("===========================\n", 0);
352 }
353
354 if (system_failed)
355 return (1);
356 else
357 return (0);
358 }
359
360 void
display_hp_fail_fault(Sys_tree * tree,struct system_kstat_data * kstats)361 display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
362 {
363 #ifdef lint
364 kstats = kstats;
365 #endif
366 /* Display failed units */
367 (void) disp_fail_parts(tree);
368 }
369
370
371 void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)372 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
373 struct system_kstat_data *kstats)
374 {
375 /*
376 * Now display the last powerfail time and the fatal hardware
377 * reset information. We do this under a couple of conditions.
378 * First if the user asks for it. The second is iof the user
379 * told us to do logging, and we found a system failure.
380 */
381 if (flag) {
382 /*
383 * display time of latest powerfail. Not all systems
384 * have this capability. For those that do not, this
385 * is just a no-op.
386 */
387 disp_powerfail(root);
388
389 (void) disp_envctrl_status(tree, kstats);
390
391 tazjav_disp_asic_revs(tree);
392
393 platform_disp_prom_version(tree);
394 }
395 return;
396
397 }
398
399 /* ARGSUSED */
400 void
display_boardnum(int num)401 display_boardnum(int num)
402 {
403 log_printf("SYS ", 0);
404 }
405
406
407
408 /*
409 * display_pci
410 * Display all the PCI IO cards on this board.
411 */
412
413 /* ARGSUSED */
414 void
display_pci(Board_node * board)415 display_pci(Board_node *board)
416 {
417 struct io_card *card_list = NULL;
418 struct io_card card;
419 void *value;
420 Prom_node *pci;
421 Prom_node *card_node;
422
423 if (board == NULL)
424 return;
425
426 /* Initialize all the common information */
427 card.display = 1;
428 card.board = board->board_num;
429 (void) sprintf(card.bus_type, "PCI");
430
431 for (pci = dev_find_node(board->nodes, PCI_NAME); pci != NULL;
432 pci = dev_next_node(pci, PCI_NAME)) {
433 char *name;
434 Prom_node *prev_parent = NULL;
435 int prev_device = -1;
436 int pci_pci_bridge = 0;
437
438 /*
439 * If we have reached a pci-to-pci bridge node,
440 * we are one level below the 'pci' nodes level
441 * in the device tree. To get back to that level,
442 * the search should continue with the sibling of
443 * the parent or else the remaining 'pci' cards
444 * will not show up in the output.
445 */
446 if (find_prop(pci, "upa-portid") == NULL) {
447 if ((pci->parent->sibling != NULL) &&
448 (strcmp(get_prop_val(
449 find_prop(pci->parent->sibling,
450 "name")), PCI_NAME) == 0))
451 pci = pci->parent->sibling;
452 else {
453 pci = pci->parent->sibling;
454 continue;
455 }
456 }
457
458 /* Skip all failed nodes for now */
459 if (node_failed(pci))
460 continue;
461
462 /* Fill in frequency */
463 value = get_prop_val(find_prop(pci, "clock-frequency"));
464 if (value == NULL)
465 card.freq = -1;
466 else
467 card.freq = ((*(int *)value) + 500000) / 1000000;
468
469 /* Walk through the PSYCHO children */
470 card_node = pci->child;
471 while (card_node != NULL) {
472 Prop *compat = NULL;
473
474 /* If it doesn't have a name, skip it */
475 name = (char *)get_prop_val(
476 find_prop(card_node, "name"));
477 if (name == NULL) {
478 card_node = card_node->sibling;
479 continue;
480 }
481
482 /*
483 * If this is a PCI bridge, then display its
484 * children.
485 */
486 if (strcmp(name, "pci") == 0) {
487 card_node = card_node->child;
488 pci_pci_bridge = 1;
489 continue;
490 }
491
492 /* Get the slot number for this card */
493 if (pci_pci_bridge) {
494 card.slot = tazmo_physical_slot(
495 dev_find_node(board->nodes, "slot2dev"),
496 pci,
497 get_pci_to_pci_device(card_node->parent),
498 card.slot_str);
499 } else
500 card.slot = tazmo_physical_slot(
501 dev_find_node(board->nodes, "slot2dev"),
502 pci,
503 get_pci_device(card_node),
504 card.slot_str);
505
506 /*
507 * Check that duplicate devices are not reported
508 * on Tazmo.
509 */
510 if ((card_node->parent == prev_parent) &&
511 (get_pci_device(card_node) == prev_device) &&
512 (pci_pci_bridge == 0))
513 card.slot = -1;
514 prev_parent = card_node->parent;
515 prev_device = get_pci_device(card_node);
516
517
518 if (card.slot == -1 || strstr(name, "ebus")) {
519 card_node = card_node->sibling;
520 continue;
521 }
522
523 /* XXX - Don't know how to get status for PCI cards */
524 card.status[0] = '\0';
525
526 /* Get the model of this card */
527 value = get_prop_val(find_prop(card_node, "model"));
528 if (value == NULL)
529 card.model[0] = '\0';
530 else
531 (void) sprintf(card.model, "%s",
532 (char *)value);
533
534 /*
535 * Check if further processing is necessary to display
536 * this card uniquely.
537 */
538 distinguish_identical_io_cards(name, card_node, &card);
539
540 /*
541 * If we haven't figured out the frequency yet,
542 * try and get it from the card.
543 */
544 value = get_prop_val(find_prop(pci, "clock-frequency"));
545 if (value != NULL && card.freq == -1)
546 card.freq = ((*(int *)value) + 500000)
547 / 1000000;
548
549
550 value = get_prop_val(find_prop(card_node,
551 "compatible"));
552
553 /*
554 * On Tazmo, we would like to print out the last
555 * string of the "compatible" property if it exists.
556 * The IEEE 1275 spec. states that this last string
557 * will be the classcode name.
558 */
559 if (value != NULL) {
560 char *tval;
561 int index;
562 const int always = 1;
563
564 tval = (char *)value;
565 index = 0;
566 compat = find_prop(card_node, "compatible");
567 while (always) {
568 if ((strlen(tval) + 1) ==
569 (compat->size - index))
570 break;
571 index += strlen(tval) + 1;
572 tval += strlen(tval) + 1;
573 }
574 value = (void *)tval;
575 }
576
577 if (value != NULL)
578 (void) sprintf(card.name, "%s-%s",
579 (char *)name, (char *)value);
580 else
581 (void) sprintf(card.name, "%s",
582 (char *)name);
583
584 if (card.freq != -1)
585 card_list = insert_io_card(card_list, &card);
586
587 /*
588 * If we are done with the children of the pci bridge,
589 * we must continue with the remaining siblings of
590 * the pci-to-pci bridge.
591 */
592 if ((card_node->sibling == NULL) && pci_pci_bridge) {
593 card_node = card_node->parent->sibling;
594 pci_pci_bridge = 0;
595 } else
596 card_node = card_node->sibling;
597 }
598 }
599
600 display_io_cards(card_list);
601 free_io_cards(card_list);
602 }
603
604
605 /*
606 * Print out all the io cards in the list. Also print the column
607 * headers if told to do so.
608 */
609 void
display_io_cards(struct io_card * list)610 display_io_cards(struct io_card *list)
611 {
612 static int banner = 0; /* Have we printed the column headings? */
613 struct io_card *p;
614
615 if (list == NULL)
616 return;
617
618 if (banner == 0) {
619 log_printf(" Bus Freq\n", 0);
620 log_printf("Brd Type MHz Slot "
621 "Name Model", 0);
622 log_printf("\n", 0);
623 log_printf("--- ---- ---- ---- "
624 "-------------------------------- "
625 "----------------------", 0);
626 log_printf("\n", 0);
627 banner = 1;
628 }
629
630 for (p = list; p != NULL; p = p -> next) {
631 log_printf("SYS ", p->board, 0);
632 log_printf("%-4s ", p->bus_type, 0);
633 log_printf("%3d ", p->freq, 0);
634 log_printf("%3d ", p->slot, 0);
635 log_printf("%-32.32s", p->name, 0);
636 if (strlen(p->name) > 32)
637 log_printf("+ ", 0);
638 else
639 log_printf(" ", 0);
640 log_printf("%-22.22s", p->model, 0);
641 if (strlen(p->model) > 22)
642 log_printf("+", 0);
643 log_printf("\n", 0);
644 }
645 }
646
647 /*
648 * display_ffb
649 * Display all FFBs on this board. It can either be in tabular format,
650 * or a more verbose format.
651 */
652 void
display_ffb(Board_node * board,int table)653 display_ffb(Board_node *board, int table)
654 {
655 Prom_node *ffb;
656 void *value;
657 struct io_card *card_list = NULL;
658 struct io_card card;
659
660 if (board == NULL)
661 return;
662
663 /* Fill in common information */
664 card.display = 1;
665 card.board = board->board_num;
666 (void) sprintf(card.bus_type, "UPA");
667 card.freq = sys_clk;
668
669 for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL;
670 ffb = dev_next_node(ffb, FFB_NAME)) {
671 if (table == 1) {
672 /* Print out in table format */
673
674 /* XXX - Get the slot number (hack) */
675 card.slot = tazmo_physical_slot(
676 dev_find_node(board->nodes, "slot2dev"),
677 ffb,
678 -1,
679 card.slot_str);
680
681 /* Find out if it's single or double buffered */
682 (void) sprintf(card.name, "FFB");
683 value = get_prop_val(find_prop(ffb, "board_type"));
684 if (value != NULL)
685 if ((*(int *)value) & FFB_B_BUFF)
686 (void) sprintf(card.name,
687 "FFB, Double Buffered");
688 else
689 (void) sprintf(card.name,
690 "FFB, Single Buffered");
691
692 /* Print model number */
693 card.model[0] = '\0';
694 value = get_prop_val(find_prop(ffb, "model"));
695 if (value != NULL)
696 (void) sprintf(card.model, "%s",
697 (char *)value);
698
699 card_list = insert_io_card(card_list, &card);
700 } else {
701 /* print in long format */
702 char device[MAXSTRLEN];
703 int fd = -1;
704 struct dirent *direntp;
705 DIR *dirp;
706 union strap_un strap;
707 struct ffb_sys_info fsi;
708
709 /* Find the device node using upa address */
710 value = get_prop_val(find_prop(ffb, "upa-portid"));
711 if (value == NULL)
712 continue;
713
714 (void) sprintf(device, "%s@%x", FFB_NAME,
715 *(int *)value);
716 if ((dirp = opendir("/devices")) == NULL)
717 continue;
718
719 while ((direntp = readdir(dirp)) != NULL) {
720 if (strstr(direntp->d_name, device) != NULL) {
721 (void) sprintf(device, "/devices/%s",
722 direntp->d_name);
723 fd = open(device, O_RDWR, 0666);
724 break;
725 }
726 }
727 (void) closedir(dirp);
728
729 if (fd == -1)
730 continue;
731
732 if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
733 continue;
734
735 log_printf("FFB Hardware Configuration:\n", 0);
736 log_printf("-----------------------------------\n", 0);
737
738 strap.ffb_strap_bits = fsi.ffb_strap_bits;
739 log_printf("\tBoard rev: %d\n",
740 (int)strap.fld.board_rev, 0);
741 log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
742 log_printf("\tDAC: %s\n",
743 fmt_manf_id(fsi.dac_version, device), 0);
744 log_printf("\t3DRAM: %s\n",
745 fmt_manf_id(fsi.fbram_version, device), 0);
746 log_printf("\n", 0);
747 }
748 }
749
750 display_io_cards(card_list);
751 free_io_cards(card_list);
752 }
753
754 /*
755 * This module does the reading and interpreting of tazmo system
756 * kstats. These kstats are created by the envctrl driver:
757 */
758 void
read_platform_kstats(Sys_tree * tree,struct system_kstat_data * sys_kstat,struct envctrl_kstat_data * ep)759 read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat,
760 struct envctrl_kstat_data *ep)
761 {
762 kstat_ctl_t *kc;
763 kstat_t *ksp;
764
765 if ((kc = kstat_open()) == NULL) {
766 return;
767 }
768
769 ep = &sys_kstat->env_data;
770
771 /* Read the power supply kstats */
772 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
773 ENVCTRL_KSTAT_PSNAME);
774
775 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
776 (void) memcpy(ep->ps_kstats, ksp->ks_data,
777 MAX_DEVS * sizeof (envctrl_ps_t));
778 } else {
779 sys_kstat->envctrl_kstat_ok = B_FALSE;
780 return;
781 }
782
783 /* Read the fan status kstats */
784 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
785 ENVCTRL_KSTAT_FANSTAT);
786
787 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
788 (void) memcpy(ep->fan_kstats, ksp->ks_data,
789 ksp->ks_ndata * sizeof (envctrl_fan_t));
790 } else {
791 sys_kstat->envctrl_kstat_ok = B_FALSE;
792 return;
793 }
794
795 /* Read the enclosure kstats */
796 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
797 ENVCTRL_KSTAT_ENCL);
798
799 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
800 (void) memcpy(ep->encl_kstats, ksp->ks_data,
801 ksp->ks_ndata * sizeof (envctrl_encl_t));
802 } else {
803 sys_kstat->envctrl_kstat_ok = B_FALSE;
804 return;
805 }
806
807 sys_kstat->envctrl_kstat_ok = B_TRUE;
808 }
809
810 /*
811 * Walk the PROM device tree and build the system tree and root tree.
812 * Nodes that have a board number property are placed in the board
813 * structures for easier processing later. Child nodes are placed
814 * under their parents. ffb (Fusion Frame Buffer) nodes are handled
815 * specially, because they do not contain board number properties.
816 * This was requested from OBP, but was not granted. So this code
817 * must parse the MID of the FFB to find the board#.
818 */
819 Prom_node *
walk(Sys_tree * tree,Prom_node * root,int id)820 walk(Sys_tree *tree, Prom_node *root, int id)
821 {
822 register int curnode;
823 Prom_node *pnode;
824 char *name;
825 char *type;
826 char *model;
827 int board_node = 0;
828
829 /* allocate a node for this level */
830 if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
831 NULL) {
832 perror("malloc");
833 exit(2); /* program errors cause exit 2 */
834 }
835
836 /* assign parent Prom_node */
837 pnode->parent = root;
838 pnode->sibling = NULL;
839 pnode->child = NULL;
840
841 /* read properties for this node */
842 dump_node(pnode);
843
844 /*
845 * Place a node in a 'board' if it has 'board'-ness. The definition
846 * is that all nodes that are children of root should have a
847 * board# property. But the PROM tree does not exactly follow
848 * this. This is where we start hacking. The name 'ffb' can
849 * change, so watch out for this.
850 *
851 * The UltraSPARC, sbus, pci and ffb nodes will exit in
852 * the desktops and will not have board# properties. These
853 * cases must be handled here.
854 *
855 * PCI to PCI bridges also have the name "pci", but with different
856 * model property values. They should not be put under 'board'.
857 */
858 name = get_node_name(pnode);
859 type = get_node_type(pnode);
860 model = (char *)get_prop_val(find_prop(pnode, "model"));
861 #ifdef DEBUG
862 if (name != NULL)
863 printf("name=%s ", name);
864 if (type != NULL)
865 printf("type=%s ", type);
866 if (model != NULL)
867 printf("model=%s", model);
868 printf("\n");
869
870 if (model == NULL)
871 model = "";
872 #endif
873 if (type == NULL)
874 type = "";
875 if (name != NULL) {
876 if (has_board_num(pnode)) {
877 add_node(tree, pnode);
878 board_node = 1;
879 #ifdef DEBUG
880 printf("ADDED BOARD name=%s type=%s model=%s\n",
881 name, type, model);
882 #endif
883 } else if ((strcmp(name, FFB_NAME) == 0) ||
884 (strcmp(type, "cpu") == 0) ||
885
886 ((strcmp(name, "pci") == 0) && (model != NULL) &&
887 (strcmp(model, "SUNW,psycho") == 0)) ||
888
889 ((strcmp(name, "pci") == 0) && (model != NULL) &&
890 (strcmp(model, "SUNW,sabre") == 0)) ||
891
892 (strcmp(name, "counter-timer") == 0) ||
893 (strcmp(name, "sbus") == 0) ||
894 (strcmp(name, "memory") == 0) ||
895 (strcmp(name, "mc") == 0) ||
896 (strcmp(name, "associations") == 0)) {
897 add_node(tree, pnode);
898 board_node = 1;
899 #ifdef DEBUG
900 printf("ADDED BOARD name=%s type=%s model=%s\n",
901 name, type, model);
902 #endif
903 }
904 #ifdef DEBUG
905 else
906 printf("node not added: name=%s type=%s\n", name, type);
907 #endif
908 }
909
910 if (curnode = child(id)) {
911 pnode->child = walk(tree, pnode, curnode);
912 }
913
914 if (curnode = next(id)) {
915 if (board_node) {
916 return (walk(tree, root, curnode));
917 } else {
918 pnode->sibling = walk(tree, root, curnode);
919 }
920 }
921
922 if (board_node) {
923 return (NULL);
924 } else {
925 return (pnode);
926 }
927 }
928
929 /*
930 * local functions
931 */
932
933 /*
934 * disp_envctrl_status
935 *
936 * This routine displays the environmental status passed up from
937 * device drivers via kstats. The kstat names are defined in
938 * kernel header files included by this module.
939 */
940 static int
disp_envctrl_status(Sys_tree * tree,struct system_kstat_data * sys_kstats)941 disp_envctrl_status(Sys_tree *tree, struct system_kstat_data *sys_kstats)
942 {
943 int exit_code = 0;
944 int possible_failure;
945 int i;
946 uchar_t val;
947 char fan_type[16];
948 char state[48];
949 char name[16];
950 envctrl_ps_t ps;
951 envctrl_fan_t fan;
952 envctrl_encl_t encl;
953 struct envctrl_kstat_data *ep;
954 uchar_t fsp_value;
955 int i4slot_backplane_value = -1;
956 int i8slot_backplane_value = -1;
957 int j8slot_backplane_value = -1;
958 static int first_8disk_bp = 0;
959 static int second_8disk_bp = 0;
960 static int first_4disk_bp = 0;
961
962 if (sys_kstats->envctrl_kstat_ok == 0) {
963 log_printf("\n", 0);
964 log_printf(dgettext(TEXT_DOMAIN, "Environmental information "
965 "is not available\n"), 0);
966 log_printf(dgettext(TEXT_DOMAIN, "Environmental driver may "
967 "not be installed\n"), 0);
968 log_printf("\n", 0);
969 return (1);
970 }
971
972 ep = &sys_kstats->env_data;
973
974 check_disk_presence(tree, &first_4disk_bp, &first_8disk_bp,
975 &second_8disk_bp);
976
977 log_printf("\n", 0);
978 log_printf("=========================", 0);
979 log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0);
980 log_printf("=========================", 0);
981 log_printf("\n", 0);
982 log_printf("\n", 0);
983
984 log_printf("System Temperatures (Celsius):\n", 0);
985 log_printf("------------------------------\n", 0);
986 for (i = 0; i < MAX_DEVS; i++) {
987 encl = ep->encl_kstats[i];
988 switch (encl.type) {
989 case ENVCTRL_ENCL_AMBTEMPR:
990 if (encl.instance == I2C_NODEV)
991 continue;
992 (void) sprintf(name, "%s", "AMBIENT");
993 log_printf("%s %d", name, encl.value);
994 if (encl.value > MAX_AMB_TEMP) {
995 log_printf(" WARNING\n", 0);
996 exit_code = 1;
997 } else
998 log_printf("\n", 0);
999 break;
1000 case ENVCTRL_ENCL_CPUTEMPR:
1001 if (encl.instance == I2C_NODEV)
1002 continue;
1003 (void) sprintf(name, "%s %d", "CPU", encl.instance);
1004 log_printf("%s %d", name, encl.value);
1005 if (encl.value > MAX_CPU_TEMP) {
1006 log_printf(" WARNING\n", 0);
1007 exit_code = 1;
1008 } else
1009 log_printf("\n", 0);
1010 break;
1011 case ENVCTRL_ENCL_FSP:
1012 if (encl.instance == I2C_NODEV)
1013 continue;
1014 val = encl.value & ENVCTRL_FSP_KEYMASK;
1015 fsp_value = encl.value;
1016 switch (val) {
1017 case ENVCTRL_FSP_KEYOFF:
1018 (void) sprintf(state, "%s", "Off");
1019 break;
1020 case ENVCTRL_FSP_KEYON:
1021 (void) sprintf(state, "%s", "On");
1022 break;
1023 case ENVCTRL_FSP_KEYDIAG:
1024 (void) sprintf(state, "%s", "Diagnostic");
1025 break;
1026 case ENVCTRL_FSP_KEYLOCKED:
1027 (void) sprintf(state, "%s", "Secure");
1028 break;
1029 default:
1030 (void) sprintf(state, "%s", "Broken!");
1031 exit_code = 1;
1032 break;
1033 }
1034 break;
1035 case ENVCTRL_ENCL_BACKPLANE4:
1036 case ENVCTRL_ENCL_BACKPLANE8:
1037 if (encl.instance == I2C_NODEV)
1038 continue;
1039 switch (encl.instance) {
1040 case 0:
1041 i4slot_backplane_value =
1042 encl.value & ENVCTRL_4SLOT_BACKPLANE;
1043 break;
1044 case 1:
1045 i8slot_backplane_value =
1046 encl.value & ENVCTRL_8SLOT_BACKPLANE;
1047 break;
1048 case 2:
1049 j8slot_backplane_value =
1050 encl.value & ENVCTRL_8SLOT_BACKPLANE;
1051 break;
1052 }
1053 default:
1054 break;
1055 }
1056 }
1057
1058 log_printf("=================================\n\n", 0);
1059 log_printf("Front Status Panel:\n", 0);
1060 log_printf("-------------------\n", 0);
1061 log_printf("Keyswitch position is in %s mode.\n", state);
1062 log_printf("\n", 0);
1063 val = fsp_value & (ENVCTRL_FSP_DISK_ERR | ENVCTRL_FSP_PS_ERR |
1064 ENVCTRL_FSP_TEMP_ERR | ENVCTRL_FSP_GEN_ERR |
1065 ENVCTRL_FSP_ACTIVE);
1066 log_printf("System LED Status: POWER GENERAL ERROR "
1067 " ACTIVITY\n", 0);
1068 log_printf(" [ ON] [%3s] "
1069 " [%3s]\n", val & ENVCTRL_FSP_GEN_ERR ? "ON" : "OFF",
1070 val & ENVCTRL_FSP_ACTIVE ? "ON" : "OFF");
1071 log_printf(" DISK ERROR "
1072 "THERMAL ERROR POWER SUPPLY ERROR\n", 0);
1073 log_printf(" [%3s] [%3s] "
1074 " [%3s]\n", val & ENVCTRL_FSP_DISK_ERR ? "ON" : "OFF",
1075 val & ENVCTRL_FSP_TEMP_ERR ? "ON" : "OFF",
1076 val & ENVCTRL_FSP_PS_ERR ? "ON" : "OFF");
1077 log_printf("\n", 0);
1078 /* record error conditions */
1079 if (val & (ENVCTRL_FSP_GEN_ERR | ENVCTRL_FSP_DISK_ERR |
1080 ENVCTRL_FSP_TEMP_ERR | ENVCTRL_FSP_PS_ERR)) {
1081 exit_code = 1;
1082 }
1083
1084
1085 log_printf("Disk LED Status: OK = GREEN ERROR = YELLOW\n", 0);
1086
1087 if (j8slot_backplane_value != -1) {
1088 log_printf(" DISK 18: %7s DISK 19: %7s\n",
1089 second_8disk_bp & ENVCTRL_DISK_6 ?
1090 j8slot_backplane_value & ENVCTRL_DISK_6 ? "[ERROR]" : "[OK]"
1091 : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_7 ?
1092 j8slot_backplane_value & ENVCTRL_DISK_7 ? "[ERROR]" : "[OK]"
1093 : "[EMPTY]");
1094 log_printf(" DISK 16: %7s DISK 17: %7s\n",
1095 second_8disk_bp & ENVCTRL_DISK_4 ?
1096 j8slot_backplane_value & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]"
1097 : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_5 ?
1098 j8slot_backplane_value & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]"
1099 : "[EMPTY]");
1100 log_printf(" DISK 14: %7s DISK 15: %7s\n",
1101 second_8disk_bp & ENVCTRL_DISK_2 ?
1102 j8slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]"
1103 : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_3 ?
1104 j8slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]"
1105 : "[EMPTY]");
1106 log_printf(" DISK 12: %7s DISK 13: %7s\n",
1107 second_8disk_bp & ENVCTRL_DISK_0 ?
1108 j8slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]"
1109 : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_1 ?
1110 j8slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]"
1111 : "[EMPTY]");
1112 }
1113 if (i8slot_backplane_value != -1) {
1114 log_printf(" DISK 10: %7s DISK 11: %7s\n",
1115 first_8disk_bp & ENVCTRL_DISK_6 ?
1116 i8slot_backplane_value & ENVCTRL_DISK_6 ? "[ERROR]" : "[OK]"
1117 : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_7 ?
1118 i8slot_backplane_value & ENVCTRL_DISK_7 ? "[ERROR]" : "[OK]"
1119 : "[EMPTY]");
1120 log_printf(" DISK 8: %7s DISK 9: %7s\n",
1121 first_8disk_bp & ENVCTRL_DISK_4 ?
1122 i8slot_backplane_value & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]"
1123 : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_5 ?
1124 i8slot_backplane_value & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]"
1125 : "[EMPTY]");
1126 log_printf(" DISK 6: %7s DISK 7: %7s\n",
1127 first_8disk_bp & ENVCTRL_DISK_2 ?
1128 i8slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]"
1129 : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_3 ?
1130 i8slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]"
1131 : "[EMPTY]");
1132 log_printf(" DISK 4: %7s DISK 5: %7s\n",
1133 first_8disk_bp & ENVCTRL_DISK_0 ?
1134 i8slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]"
1135 : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_1 ?
1136 i8slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]"
1137 : "[EMPTY]");
1138 }
1139 if (i4slot_backplane_value != -1) {
1140 log_printf(" DISK 2: %7s DISK 3: %7s\n",
1141 first_4disk_bp & ENVCTRL_DISK_2 ?
1142 i4slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]"
1143 : "[EMPTY]", first_4disk_bp & ENVCTRL_DISK_3 ?
1144 i4slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]"
1145 : "[EMPTY]");
1146 log_printf(" DISK 0: %7s DISK 1: %7s\n",
1147 first_4disk_bp & ENVCTRL_DISK_0 ?
1148 i4slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]"
1149 : "[EMPTY]", first_4disk_bp & ENVCTRL_DISK_1 ?
1150 i4slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]"
1151 : "[EMPTY]");
1152 }
1153
1154 log_printf("=================================\n", 0);
1155 log_printf("\n", 0);
1156
1157 log_printf("Fans:\n", 0);
1158 log_printf("-----\n", 0);
1159
1160 log_printf("Fan Bank Speed Status\n", 0);
1161 log_printf("-------- ----- ------\n", 0);
1162
1163 for (i = 0; i < MAX_DEVS; i++) {
1164 fan = ep->fan_kstats[i];
1165
1166 if (fan.instance == I2C_NODEV)
1167 continue;
1168
1169 switch (fan.type) {
1170 case ENVCTRL_FAN_TYPE_CPU:
1171 (void) sprintf(fan_type, "%s", "CPU");
1172 break;
1173 case ENVCTRL_FAN_TYPE_PS:
1174 (void) sprintf(fan_type, "%s", "PWR");
1175 break;
1176 case ENVCTRL_FAN_TYPE_AFB:
1177 (void) sprintf(fan_type, "%s", "AFB");
1178 break;
1179 }
1180 if (fan.fans_ok == B_TRUE) {
1181 (void) sprintf(state, "%s", " OK ");
1182 } else {
1183 (void) sprintf(state, "FAILED (FAN# %d)",
1184 fan.fanflt_num);
1185 /* we know fan.instance != I2C_NODEV */
1186 exit_code = 1;
1187 }
1188 if (fan.instance != I2C_NODEV)
1189 log_printf("%s %d %s\n", fan_type,
1190 fan.fanspeed, state);
1191 }
1192
1193
1194 log_printf("\n", 0);
1195
1196 log_printf("\n", 0);
1197 log_printf("Power Supplies:\n", 0);
1198 log_printf("---------------\n", 0);
1199 log_printf("Supply Rating Temp Status\n", 0);
1200 log_printf("------ ------ ---- ------\n", 0);
1201 for (i = 0; i < MAX_DEVS; i++) {
1202 ps = ep->ps_kstats[i];
1203 if (ps.curr_share_ok == B_TRUE &&
1204 ps.limit_ok == B_TRUE && ps.ps_ok == B_TRUE) {
1205 (void) sprintf(state, "%s", " OK ");
1206 possible_failure = 0;
1207 } else {
1208 if (ps.ps_ok != B_TRUE) {
1209 (void) sprintf(state, "%s",
1210 "FAILED: DC Power Failure");
1211 possible_failure = 1;
1212 } else if (ps.curr_share_ok != B_TRUE) {
1213 (void) sprintf(state, "%s",
1214 "WARNING: Current Share Imbalance");
1215 possible_failure = 1;
1216 } else if (ps.limit_ok != B_TRUE) {
1217 (void) sprintf(state, "%s",
1218 "WARNING: Current Overload");
1219 possible_failure = 1;
1220 }
1221 }
1222
1223 if (ps.instance != I2C_NODEV && ps.ps_rating != 0) {
1224 log_printf(" %2d %4d W %2d %s\n",
1225 ps.instance, ps.ps_rating, ps.ps_tempr, state);
1226 if (possible_failure)
1227 exit_code = 1;
1228 }
1229 }
1230
1231 return (exit_code);
1232 }
1233
1234 /*
1235 * This function will return a bitmask for each of the 4 disk backplane
1236 * and the two 8 disk backplanes. It creates this mask by first obtaining
1237 * the PROM path of the controller for each slot using the "slot2dev"
1238 * node in the PROM tree. It then modifies the PROM path to obtain a
1239 * physical device path to the controller. The presence of the controller
1240 * is determined by trying to open the controller device and reading
1241 * some information from the device. Currently only supported on Tazmo.
1242 */
1243 static void
check_disk_presence(Sys_tree * tree,int * i4disk,int * i8disk,int * j8disk)1244 check_disk_presence(Sys_tree *tree, int *i4disk, int *i8disk, int *j8disk)
1245 {
1246 Board_node *bnode;
1247 Prom_node *slot2disk = NULL;
1248 Prop *slotprop;
1249 char *devpath_p;
1250 char devpath[MAXSTRLEN];
1251 char slotx[16] = "";
1252 int slot;
1253 int slot_ptr = 0;
1254
1255 bnode = tree->bd_list;
1256 *i4disk = *i8disk, *j8disk = 0;
1257
1258 slot2disk = dev_find_node(bnode->nodes, "slot2disk");
1259
1260 for (slot = 0; slot < 20; slot++) {
1261 (void) sprintf(slotx, "slot#%d", slot);
1262 if ((slotprop = find_prop(slot2disk, slotx)) != NULL)
1263 if ((devpath_p = (char *)(get_prop_val(slotprop)))
1264 != NULL) {
1265 modify_device_path(devpath_p, devpath);
1266 if (disk_present(devpath)) {
1267 if (slot < 4)
1268 *i4disk |= 1 << slot_ptr;
1269 else if (slot < 12)
1270 *i8disk |= 1 << slot_ptr;
1271 else if (slot < 20)
1272 *j8disk |= 1 << slot_ptr;
1273 }
1274 }
1275 if ((slot == 3) || (slot == 11))
1276 slot_ptr = 0;
1277 else
1278 slot_ptr++;
1279 }
1280 }
1281
1282
1283
1284 /*
1285 * modify_device_path
1286 *
1287 * This function modifies a string from the slot2disk association
1288 * PROM node to a physical device path name. For example if the
1289 * slot2disk association value is "/pci@1f,4000/scsi@3/disk@1",
1290 * the equivalent physical device path will be
1291 * "/devices/pci@1f,4000/scsi@3/sd@1,0:c,raw".
1292 * We use this path to attempt to probe the disk to check for its
1293 * presence in the enclosure. We access the 'c' partition
1294 * which represents the entire disk.
1295 */
1296 static void
modify_device_path(char * oldpath,char * newpath)1297 modify_device_path(char *oldpath, char *newpath)
1298 {
1299 char *changeptr;
1300 long target;
1301 char targetstr[16];
1302
1303 (void) strcpy(newpath, "/devices");
1304 changeptr = strstr(oldpath, "disk@");
1305 /*
1306 * The assumption here is that nothing but the
1307 * target id follows the disk@ substring.
1308 */
1309 target = strtol(changeptr+5, NULL, 16);
1310 (void) strncat(newpath, oldpath, changeptr - oldpath);
1311 (void) sprintf(targetstr, "sd@%ld,0:c,raw", target);
1312 (void) strcat(newpath, targetstr);
1313 }
1314
1315 /*
1316 * Returns 0 if the device at devpath is not *physically* present. If it is,
1317 * then info on that device is placed in the dkinfop buffer, and 1 is returned.
1318 * Keep in mind that ioctl(DKIOCINFO)'s CDROMs owned by vold fail, so only
1319 * the dki_ctype field is set in that case.
1320 */
1321 static int
disk_present(char * devpath)1322 disk_present(char *devpath)
1323 {
1324 int search_file;
1325 struct stat stbuf;
1326 struct dk_cinfo dkinfo;
1327
1328 /*
1329 * Attempt to open the disk. If it fails, skip it.
1330 */
1331 if ((search_file = open(devpath, O_RDONLY | O_NDELAY)) < 0)
1332 return (0);
1333
1334 /*
1335 * Must be a character device
1336 */
1337 if (fstat(search_file, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
1338 (void) close(search_file);
1339 return (0);
1340 }
1341
1342 /*
1343 * Attempt to read the configuration info on the disk.
1344 * If it fails, we assume the disk's not there.
1345 * Note we must close the file for the disk before we
1346 * continue.
1347 */
1348 if (ioctl(search_file, DKIOCINFO, &dkinfo) < 0) {
1349 (void) close(search_file);
1350 return (0);
1351 }
1352 (void) close(search_file);
1353 return (1);
1354 }
1355
1356 void
tazjav_disp_asic_revs(Sys_tree * tree)1357 tazjav_disp_asic_revs(Sys_tree *tree)
1358 {
1359 Board_node *bnode;
1360 Prom_node *pnode;
1361 char *name;
1362 int *version;
1363 char *model;
1364
1365 /* Print the header */
1366 log_printf("\n", 0);
1367 log_printf("=========================", 0);
1368 log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0);
1369 log_printf("=========================", 0);
1370 log_printf("\n", 0);
1371 log_printf("\n", 0);
1372
1373 bnode = tree->bd_list;
1374
1375 log_printf("ASIC Revisions:\n", 0);
1376 log_printf("---------------\n", 0);
1377
1378 /* Find sysio and print rev */
1379 for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL;
1380 pnode = dev_next_node(pnode, "sbus")) {
1381 version = (int *)get_prop_val(find_prop(pnode, "version#"));
1382 name = get_prop_val(find_prop(pnode, "name"));
1383
1384 if ((version != NULL) && (name != NULL)) {
1385 log_printf("SBus: %s Rev %d\n",
1386 name, *version, 0);
1387 }
1388 }
1389
1390 /* Find Psycho and print rev */
1391 for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL;
1392 pnode = dev_next_node(pnode, "pci")) {
1393 Prom_node *parsib = pnode->parent->sibling;
1394
1395 if (find_prop(pnode, "upa-portid") == NULL) {
1396 if ((parsib != NULL) &&
1397 (strcmp(get_prop_val(
1398 find_prop(parsib, "name")),
1399 PCI_NAME) == 0))
1400 pnode = parsib;
1401 else {
1402 pnode = parsib;
1403 continue;
1404 }
1405 }
1406
1407 version = (int *)get_prop_val(find_prop(pnode, "version#"));
1408 name = get_prop_val(find_prop(pnode, "name"));
1409
1410 if ((version != NULL) && (name != NULL))
1411 if (get_pci_bus(pnode) == 0)
1412 log_printf("STP2223BGA: Rev %d\n", *version, 0);
1413 }
1414
1415 /* Find Cheerio and print rev */
1416 for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL;
1417 pnode = dev_next_node(pnode, "ebus")) {
1418 version = (int *)get_prop_val(find_prop(pnode, "revision-id"));
1419 name = get_prop_val(find_prop(pnode, "name"));
1420
1421 if ((version != NULL) && (name != NULL))
1422 log_printf("STP2003QFP: Rev %d\n", *version, 0);
1423 }
1424
1425 /* Find System Controller and print rev */
1426 for (pnode = dev_find_node(bnode->nodes, "sc"); pnode != NULL;
1427 pnode = dev_next_node(pnode, "sc")) {
1428 version = (int *)get_prop_val(find_prop(pnode, "version#"));
1429 model = (char *)get_prop_val(find_prop(pnode, "model"));
1430 name = get_prop_val(find_prop(pnode, "name"));
1431
1432 if ((version != NULL) && (name != NULL)) {
1433 if ((strcmp(model, "SUNW,sc-marvin") == 0))
1434 log_printf("STP2205BGA: Rev %d\n", *version, 0);
1435 }
1436 }
1437
1438 /* Find the FEPS and print rev */
1439 for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL;
1440 pnode = dev_next_node(pnode, "SUNW,hme")) {
1441 version = (int *)get_prop_val(find_prop(pnode, "hm-rev"));
1442 name = get_prop_val(find_prop(pnode, "name"));
1443
1444 if ((version != NULL) && (name != NULL)) {
1445 log_printf("FEPS: %s Rev ", name);
1446 if (*version == 0xa0) {
1447 log_printf("2.0\n", 0);
1448 } else if (*version == 0x20) {
1449 log_printf("2.1\n", 0);
1450 } else {
1451 log_printf("%x\n", *version, 0);
1452 }
1453 }
1454 }
1455 log_printf("\n", 0);
1456
1457 if (dev_find_node(bnode->nodes, FFB_NAME) != NULL) {
1458 display_ffb(bnode, 0);
1459 }
1460 }
1461
1462
1463 /*
1464 * Determine the physical PCI slot based on which Psycho is the parent
1465 * of the PCI card.
1466 */
1467 static int
tazmo_physical_slot(Prom_node * slotd,Prom_node * parent,int device,char * str)1468 tazmo_physical_slot(Prom_node *slotd, Prom_node *parent, int device, char *str)
1469 {
1470 int *upa_id = NULL;
1471 int *reg = NULL;
1472 int offset;
1473 char controller[MAXSTRLEN];
1474 char *name;
1475 Prop *prop;
1476 char *devpath_p;
1477 char slotx[16] = "";
1478 int *slot_names_mask;
1479 char *slot_names;
1480 int shift = 0;
1481 int slot;
1482 int slots, start_slot;
1483
1484 /*
1485 * If slotd != NULL, then we must return the physical PCI slot
1486 * number based on the information in the slot2dev associations
1487 * node. This routine is called from display_pci() with slotd
1488 * != NULL. If so, we return without obtaining the slot name.
1489 * If slotd == NULL, we look for the slot name through the
1490 * slot-names property in the bus node.
1491 */
1492
1493 if (slotd != NULL) {
1494 (void) strcpy(str, "");
1495 if ((prop = find_prop(parent, "upa-portid")) != NULL)
1496 upa_id = (int *)(get_prop_val(prop));
1497 if ((prop = find_prop(parent, "reg")) != NULL)
1498 reg = (int *)(get_prop_val(prop));
1499 if ((prop = find_prop(parent, "name")) != NULL)
1500 name = (char *)(get_prop_val(prop));
1501 if ((upa_id == NULL) || (reg == NULL)) {
1502 return (-1);
1503 }
1504 offset = reg[1];
1505 if (strcmp(name, "pci") == 0) {
1506 (void) sprintf(controller, "/pci@%x,%x/*@%x,*",
1507 *upa_id, offset, device);
1508 slots = 20;
1509 } else if (strcmp(name, "SUNW,ffb") == 0) {
1510 (void) sprintf(controller, "/*@%x,0", *upa_id);
1511 slots = 2;
1512 }
1513
1514 start_slot = 1;
1515 for (slot = start_slot; slot <= slots; slot++) {
1516 if (strcmp(name, "pci") == 0)
1517 (void) sprintf(slotx, "pci-slot#%d", slot);
1518 else if (strcmp(name, "SUNW,ffb") == 0)
1519 (void) sprintf(slotx, "graphics#%d", slot);
1520 if ((prop = find_prop(slotd, slotx)) != NULL)
1521 if ((devpath_p = (char *)(get_prop_val
1522 (prop))) != NULL)
1523 if (strcmp(devpath_p, controller) == 0)
1524 return (slot);
1525 }
1526 return (-1);
1527 }
1528
1529 /*
1530 * Get slot-names property from parent node.
1531 * This property consists of a 32 bit mask indicating which
1532 * devices are relevant to this bus node. Following are a
1533 * number of strings depending on how many bits are set in the
1534 * bit mask; the first string gives the label that is printed
1535 * on the chassis for the smallest device number, and so on.
1536 */
1537
1538 prop = find_prop(parent, "slot-names");
1539 if (prop == NULL) {
1540 (void) strcpy(str, "");
1541 return (-1);
1542 }
1543 slot_names_mask = (int *)(get_prop_val(prop));
1544 slot_names = (char *)slot_names_mask;
1545
1546 slot = 1;
1547 slot_names += 4; /* Skip the 4 byte bitmask */
1548
1549 while (shift < 32) {
1550 /*
1551 * Shift through the bitmask looking to see if the
1552 * bit corresponding to "device" is set. If so, copy
1553 * the correcsponding string to the provided pointer.
1554 */
1555 if (*slot_names_mask & slot) {
1556 if (shift == device) {
1557 (void) strcpy(str, slot_names);
1558 return (0);
1559 }
1560 slot_names += strlen(slot_names)+1;
1561 }
1562 shift++;
1563 slot = slot << 1;
1564 }
1565 return (-1);
1566 }
1567