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