1*1708Sstevel /*
2*1708Sstevel * CDDL HEADER START
3*1708Sstevel *
4*1708Sstevel * The contents of this file are subject to the terms of the
5*1708Sstevel * Common Development and Distribution License, Version 1.0 only
6*1708Sstevel * (the "License"). You may not use this file except in compliance
7*1708Sstevel * with the License.
8*1708Sstevel *
9*1708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*1708Sstevel * or http://www.opensolaris.org/os/licensing.
11*1708Sstevel * See the License for the specific language governing permissions
12*1708Sstevel * and limitations under the License.
13*1708Sstevel *
14*1708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
15*1708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*1708Sstevel * If applicable, add the following below this CDDL HEADER, with the
17*1708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
18*1708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
19*1708Sstevel *
20*1708Sstevel * CDDL HEADER END
21*1708Sstevel */
22*1708Sstevel /*
23*1708Sstevel * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24*1708Sstevel * Use is subject to license terms.
25*1708Sstevel *
26*1708Sstevel * Sunfire Platform specific functions.
27*1708Sstevel *
28*1708Sstevel * called when :
29*1708Sstevel * machine_type == MTYPE_SUNFIRE
30*1708Sstevel */
31*1708Sstevel
32*1708Sstevel #pragma ident "%Z%%M% %I% %E% SMI"
33*1708Sstevel
34*1708Sstevel #include <stdio.h>
35*1708Sstevel #include <stdlib.h>
36*1708Sstevel #include <unistd.h>
37*1708Sstevel #include <ctype.h>
38*1708Sstevel #include <string.h>
39*1708Sstevel #include <kvm.h>
40*1708Sstevel #include <varargs.h>
41*1708Sstevel #include <time.h>
42*1708Sstevel #include <dirent.h>
43*1708Sstevel #include <fcntl.h>
44*1708Sstevel #include <errno.h>
45*1708Sstevel #include <sys/param.h>
46*1708Sstevel #include <sys/stat.h>
47*1708Sstevel #include <sys/types.h>
48*1708Sstevel #include <sys/utsname.h>
49*1708Sstevel #include <sys/openpromio.h>
50*1708Sstevel #include <libintl.h>
51*1708Sstevel #include <syslog.h>
52*1708Sstevel #include <sys/dkio.h>
53*1708Sstevel #include "pdevinfo.h"
54*1708Sstevel #include "display.h"
55*1708Sstevel #include "pdevinfo_sun4u.h"
56*1708Sstevel #include "display_sun4u.h"
57*1708Sstevel #include "libprtdiag.h"
58*1708Sstevel
59*1708Sstevel #if !defined(TEXT_DOMAIN)
60*1708Sstevel #define TEXT_DOMAIN "SYS_TEST"
61*1708Sstevel #endif
62*1708Sstevel
63*1708Sstevel /* Macros for manipulating UPA IDs and board numbers on Sunfire. */
64*1708Sstevel #define bd_to_upa(bd) ((bd) << 1)
65*1708Sstevel #define upa_to_bd(upa) ((upa) >> 1)
66*1708Sstevel
67*1708Sstevel #define MAX_MSGS 64
68*1708Sstevel
69*1708Sstevel extern int print_flag;
70*1708Sstevel
71*1708Sstevel /*
72*1708Sstevel * these functions will overlay the symbol table of libprtdiag
73*1708Sstevel * at runtime (sunfire systems only)
74*1708Sstevel */
75*1708Sstevel int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
76*1708Sstevel void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
77*1708Sstevel int disp_fail_parts(Sys_tree *tree);
78*1708Sstevel void display_memorysize(Sys_tree *tree, struct system_kstat_data *kstats,
79*1708Sstevel struct grp_info *grps, struct mem_total *memory_total);
80*1708Sstevel void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
81*1708Sstevel void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
82*1708Sstevel struct system_kstat_data *kstats);
83*1708Sstevel void display_mid(int mid);
84*1708Sstevel void display_pci(Board_node *);
85*1708Sstevel void display_ffb(Board_node *, int);
86*1708Sstevel void add_node(Sys_tree *, Prom_node *);
87*1708Sstevel void resolve_board_types(Sys_tree *);
88*1708Sstevel
89*1708Sstevel /* local functions */
90*1708Sstevel static void build_mem_tables(Sys_tree *, struct system_kstat_data *,
91*1708Sstevel struct grp_info *);
92*1708Sstevel static void get_mem_total(struct mem_total *, struct grp_info *);
93*1708Sstevel static int disp_fault_list(Sys_tree *, struct system_kstat_data *);
94*1708Sstevel static int disp_err_log(struct system_kstat_data *);
95*1708Sstevel static int disp_env_status(struct system_kstat_data *);
96*1708Sstevel static int disp_keysw_and_leds(struct system_kstat_data *);
97*1708Sstevel static void sunfire_disp_prom_versions(Sys_tree *);
98*1708Sstevel static void erase_msgs(char **);
99*1708Sstevel static void display_msgs(char **msgs, int board);
100*1708Sstevel static void sunfire_disp_asic_revs(Sys_tree *, struct system_kstat_data *);
101*1708Sstevel static void display_hp_boards(struct system_kstat_data *);
102*1708Sstevel static int disp_parts(char **, u_longlong_t, int);
103*1708Sstevel /*
104*1708Sstevel * Error analysis routines. These routines decode data from specified
105*1708Sstevel * error registers. They are meant to be used for decoding the fatal
106*1708Sstevel * hardware reset data passed to the kernel by sun4u POST.
107*1708Sstevel */
108*1708Sstevel static int analyze_cpu(char **, int, u_longlong_t);
109*1708Sstevel static int analyze_ac(char **, u_longlong_t);
110*1708Sstevel static int analyze_dc(int, char **, u_longlong_t);
111*1708Sstevel
112*1708Sstevel #define RESERVED_STR "Reserved"
113*1708Sstevel
114*1708Sstevel #define MAX_PARTS 5
115*1708Sstevel #define MAX_FRUS 5
116*1708Sstevel
117*1708Sstevel #define MAXSTRLEN 256
118*1708Sstevel
119*1708Sstevel /* Define special bits */
120*1708Sstevel #define UPA_PORT_A 0x1
121*1708Sstevel #define UPA_PORT_B 0x2
122*1708Sstevel
123*1708Sstevel
124*1708Sstevel /*
125*1708Sstevel * These defines comne from async.h, but it does not get exported from
126*1708Sstevel * uts/sun4u/sys, so they must be redefined.
127*1708Sstevel */
128*1708Sstevel #define P_AFSR_ISAP 0x0000000040000000ULL /* incoming addr. parity err */
129*1708Sstevel #define P_AFSR_ETP 0x0000000020000000ULL /* ecache tag parity */
130*1708Sstevel #define P_AFSR_ETS 0x00000000000F0000ULL /* cache tag parity syndrome */
131*1708Sstevel #define ETS_SHIFT 16
132*1708Sstevel
133*1708Sstevel /* List of parts possible */
134*1708Sstevel #define RSVD_PART 1
135*1708Sstevel #define UPA_PART 2
136*1708Sstevel #define UPA_A_PART 3
137*1708Sstevel #define UPA_B_PART 4
138*1708Sstevel #define SOFTWARE_PART 5
139*1708Sstevel #define AC_PART 6
140*1708Sstevel #define AC_ANY_PART 7
141*1708Sstevel #define DTAG_PART 8
142*1708Sstevel #define DTAG_A_PART 9
143*1708Sstevel #define DTAG_B_PART 10
144*1708Sstevel #define FHC_PART 11
145*1708Sstevel #define BOARD_PART 12
146*1708Sstevel #define BOARD_ANY_PART 13
147*1708Sstevel #define BOARD_CONN_PART 14
148*1708Sstevel #define BACK_PIN_PART 15
149*1708Sstevel #define BACK_TERM_PART 16
150*1708Sstevel #define CPU_PART 17
151*1708Sstevel
152*1708Sstevel /* List of possible parts */
153*1708Sstevel static char *part_str[] = {
154*1708Sstevel "", /* 0, a placeholder for indexing */
155*1708Sstevel "", /* 1, reserved strings shouldn't be printed */
156*1708Sstevel "UPA devices", /* 2 */
157*1708Sstevel "UPA Port A device", /* 3 */
158*1708Sstevel "UPA Port B device", /* 4 */
159*1708Sstevel "Software error", /* 5 */
160*1708Sstevel "Address Controller", /* 6 */
161*1708Sstevel "Undetermined Address Controller in system", /* 7 */
162*1708Sstevel "Data Tags", /* 8 */
163*1708Sstevel "Data Tags for UPA Port A", /* 9 */
164*1708Sstevel "Data Tags for UPA Port B", /* 10 */
165*1708Sstevel "Firehose Controller", /* 11 */
166*1708Sstevel "This Board", /* 12 */
167*1708Sstevel "Undetermined Board in system", /* 13 */
168*1708Sstevel "Board Connector", /* 14 */
169*1708Sstevel "Centerplane pins ", /* 15 */
170*1708Sstevel "Centerplane terminators", /* 16 */
171*1708Sstevel "CPU", /* 17 */
172*1708Sstevel };
173*1708Sstevel
174*1708Sstevel /* Ecache parity error messages. Tells which bits are bad. */
175*1708Sstevel static char *ecache_parity[] = {
176*1708Sstevel "Bits 7:0 ",
177*1708Sstevel "Bits 15:8 ",
178*1708Sstevel "Bits 21:16 ",
179*1708Sstevel "Bits 24:22 "
180*1708Sstevel };
181*1708Sstevel
182*1708Sstevel
183*1708Sstevel struct ac_error {
184*1708Sstevel char *error;
185*1708Sstevel int part[MAX_PARTS];
186*1708Sstevel };
187*1708Sstevel
188*1708Sstevel typedef struct ac_error ac_err;
189*1708Sstevel
190*1708Sstevel /*
191*1708Sstevel * Hardware error register meanings, failed parts and FRUs. The
192*1708Sstevel * following strings are indexed for the bit positions of the
193*1708Sstevel * corresponding bits in the hardware. The code checks bit x of
194*1708Sstevel * the hardware error register and prints out string[x] if the bit
195*1708Sstevel * is turned on.
196*1708Sstevel *
197*1708Sstevel * This database of parts which are probably failed and which FRU's
198*1708Sstevel * to replace was based on knowledge of the Sunfire Programmers Spec.
199*1708Sstevel * and discussions with the hardware designers. The order of the part
200*1708Sstevel * lists and consequently the FRU lists are in the order of most
201*1708Sstevel * likely cause first.
202*1708Sstevel */
203*1708Sstevel static ac_err ac_errors[] = {
204*1708Sstevel { /* 0 */
205*1708Sstevel "UPA Port A Error",
206*1708Sstevel { UPA_A_PART, 0, 0, 0, 0 },
207*1708Sstevel },
208*1708Sstevel { /* 1 */
209*1708Sstevel "UPA Port B Error",
210*1708Sstevel { UPA_B_PART, 0, 0, 0, 0 },
211*1708Sstevel },
212*1708Sstevel { /* 2 */
213*1708Sstevel NULL,
214*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
215*1708Sstevel },
216*1708Sstevel { /* 3 */
217*1708Sstevel NULL,
218*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
219*1708Sstevel },
220*1708Sstevel { /* 4 */
221*1708Sstevel "UPA Interrupt to unmapped destination",
222*1708Sstevel { BOARD_PART, 0, 0, 0, 0 },
223*1708Sstevel },
224*1708Sstevel { /* 5 */
225*1708Sstevel "UPA Non-cacheable write to unmapped destination",
226*1708Sstevel { BOARD_PART, 0, 0, 0, 0 },
227*1708Sstevel },
228*1708Sstevel { /* 6 */
229*1708Sstevel "UPA Cacheable write to unmapped destination",
230*1708Sstevel { BOARD_PART, 0, 0, 0, 0 },
231*1708Sstevel },
232*1708Sstevel { /* 7 */
233*1708Sstevel "Illegal Write Received",
234*1708Sstevel { BOARD_PART, 0, 0, 0, 0 },
235*1708Sstevel },
236*1708Sstevel { /* 8 */
237*1708Sstevel "Local Writeback match with line in state S",
238*1708Sstevel { AC_PART, DTAG_PART, 0, 0, 0 },
239*1708Sstevel },
240*1708Sstevel { /* 9 */
241*1708Sstevel "Local Read match with valid line in Tags",
242*1708Sstevel { AC_PART, DTAG_PART, 0, 0, 0 },
243*1708Sstevel },
244*1708Sstevel { /* 10 */
245*1708Sstevel NULL,
246*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
247*1708Sstevel },
248*1708Sstevel { /* 11 */
249*1708Sstevel NULL,
250*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
251*1708Sstevel },
252*1708Sstevel { /* 12 */
253*1708Sstevel "Tag and Victim were valid during lookup",
254*1708Sstevel { AC_PART, DTAG_PART, 0, 0, 0 },
255*1708Sstevel },
256*1708Sstevel { /* 13 */
257*1708Sstevel "Local Writeback matches a victim in state S",
258*1708Sstevel { AC_PART, CPU_PART, 0, 0, 0 },
259*1708Sstevel },
260*1708Sstevel { /* 14 */
261*1708Sstevel "Local Read matches valid line in victim buffer",
262*1708Sstevel { AC_PART, CPU_PART, 0, 0, 0 },
263*1708Sstevel },
264*1708Sstevel { /* 15 */
265*1708Sstevel "Local Read victim bit set and victim is S state",
266*1708Sstevel { AC_PART, CPU_PART, 0, 0, 0 },
267*1708Sstevel },
268*1708Sstevel { /* 16 */
269*1708Sstevel "Local Read Victim bit set and Valid Victim Buffer",
270*1708Sstevel { AC_PART, CPU_PART, 0, 0, 0 },
271*1708Sstevel },
272*1708Sstevel { /* 17 */
273*1708Sstevel NULL,
274*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
275*1708Sstevel },
276*1708Sstevel { /* 18 */
277*1708Sstevel NULL,
278*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
279*1708Sstevel },
280*1708Sstevel { /* 19 */
281*1708Sstevel NULL,
282*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
283*1708Sstevel },
284*1708Sstevel { /* 20 */
285*1708Sstevel "UPA Transaction received in Sleep mode",
286*1708Sstevel { AC_PART, 0, 0, 0, 0 },
287*1708Sstevel },
288*1708Sstevel { /* 21 */
289*1708Sstevel "P_FERR error P_REPLY received from UPA Port",
290*1708Sstevel { CPU_PART, AC_PART, 0, 0, 0 },
291*1708Sstevel },
292*1708Sstevel { /* 22 */
293*1708Sstevel "Illegal P_REPLY received from UPA Port",
294*1708Sstevel { CPU_PART, AC_PART, 0, 0, 0 },
295*1708Sstevel },
296*1708Sstevel { /* 23 */
297*1708Sstevel NULL,
298*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
299*1708Sstevel },
300*1708Sstevel { /* 24 */
301*1708Sstevel "Timeout on a UPA Master Port",
302*1708Sstevel { AC_ANY_PART, BOARD_ANY_PART, 0, 0, 0 },
303*1708Sstevel },
304*1708Sstevel { /* 25 */
305*1708Sstevel NULL,
306*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
307*1708Sstevel },
308*1708Sstevel { /* 26 */
309*1708Sstevel NULL,
310*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
311*1708Sstevel },
312*1708Sstevel { /* 27 */
313*1708Sstevel NULL,
314*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
315*1708Sstevel },
316*1708Sstevel { /* 28 */
317*1708Sstevel "Coherent Transactions Queue Overflow Error",
318*1708Sstevel { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, AC_ANY_PART, 0 },
319*1708Sstevel },
320*1708Sstevel { /* 29 */
321*1708Sstevel "Non-cacheable Request Queue Overflow Error",
322*1708Sstevel { AC_PART, AC_ANY_PART, 0, 0, 0 },
323*1708Sstevel },
324*1708Sstevel { /* 30 */
325*1708Sstevel "Non-cacheable Reply Queue Overflow Error",
326*1708Sstevel { AC_PART, 0, 0, 0, 0 },
327*1708Sstevel },
328*1708Sstevel { /* 31 */
329*1708Sstevel "PREQ Queue Overflow Error",
330*1708Sstevel { CPU_PART, AC_PART, 0, 0, 0 },
331*1708Sstevel },
332*1708Sstevel { /* 32 */
333*1708Sstevel "Foreign DID CAM Overflow Error",
334*1708Sstevel { AC_PART, AC_ANY_PART, 0, 0, 0 },
335*1708Sstevel },
336*1708Sstevel { /* 33 */
337*1708Sstevel "FT->UPA Queue Overflow Error",
338*1708Sstevel { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, AC_ANY_PART, 0 },
339*1708Sstevel },
340*1708Sstevel { /* 34 */
341*1708Sstevel NULL,
342*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
343*1708Sstevel },
344*1708Sstevel { /* 35 */
345*1708Sstevel NULL,
346*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
347*1708Sstevel },
348*1708Sstevel { /* 36 */
349*1708Sstevel "UPA Port B Dtag Parity Error",
350*1708Sstevel { DTAG_B_PART, AC_PART, 0, 0, 0 },
351*1708Sstevel },
352*1708Sstevel { /* 37 */
353*1708Sstevel "UPA Port A Dtag Parity Error",
354*1708Sstevel { DTAG_A_PART, AC_PART, 0, 0, 0 },
355*1708Sstevel },
356*1708Sstevel { /* 38 */
357*1708Sstevel NULL,
358*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
359*1708Sstevel },
360*1708Sstevel { /* 39 */
361*1708Sstevel NULL,
362*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
363*1708Sstevel },
364*1708Sstevel { /* 40 */
365*1708Sstevel "UPA Bus Parity Error",
366*1708Sstevel { UPA_PART, AC_PART, 0, 0, 0 },
367*1708Sstevel },
368*1708Sstevel { /* 41 */
369*1708Sstevel "Data ID Line Mismatch",
370*1708Sstevel { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, 0, 0 },
371*1708Sstevel },
372*1708Sstevel { /* 42 */
373*1708Sstevel "Arbitration Line Mismatch",
374*1708Sstevel { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, 0, 0 },
375*1708Sstevel },
376*1708Sstevel { /* 43 */
377*1708Sstevel "Shared Line Parity Mismatch",
378*1708Sstevel { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, 0, 0 },
379*1708Sstevel },
380*1708Sstevel { /* 44 */
381*1708Sstevel "FireTruck Control Line Parity Error",
382*1708Sstevel { AC_PART, BACK_PIN_PART, 0, 0, 0 },
383*1708Sstevel },
384*1708Sstevel { /* 45 */
385*1708Sstevel "FireTruck Address Bus Parity Error",
386*1708Sstevel { AC_PART, BACK_PIN_PART, 0, 0, 0 },
387*1708Sstevel },
388*1708Sstevel { /* 46 */
389*1708Sstevel "Internal RAM Parity Error",
390*1708Sstevel { AC_PART, 0, 0, 0, 0 },
391*1708Sstevel },
392*1708Sstevel { /* 47 */
393*1708Sstevel NULL,
394*1708Sstevel { RSVD_PART, 0, 0, 0, 0 },
395*1708Sstevel },
396*1708Sstevel { /* 48 */
397*1708Sstevel "Internal Hardware Error",
398*1708Sstevel { AC_PART, 0, 0, 0, 0 },
399*1708Sstevel },
400*1708Sstevel { /* 49 */
401*1708Sstevel "FHC Communications Error",
402*1708Sstevel { FHC_PART, AC_PART, 0, 0, 0 },
403*1708Sstevel },
404*1708Sstevel /* Bits 50-63 are reserved in this implementation. */
405*1708Sstevel };
406*1708Sstevel
407*1708Sstevel
408*1708Sstevel #define MAX_BITS (sizeof (ac_errors)/ sizeof (ac_err))
409*1708Sstevel
410*1708Sstevel /*
411*1708Sstevel * There are only two error bits in the DC shadow chain that are
412*1708Sstevel * important. They indicate an overflow error and a parity error,
413*1708Sstevel * respectively. The other bits are not error bits and should not
414*1708Sstevel * be checked for.
415*1708Sstevel */
416*1708Sstevel #define DC_OVERFLOW 0x2
417*1708Sstevel #define DC_PARITY 0x4
418*1708Sstevel
419*1708Sstevel static char dc_overflow_txt[] = "Board %d DC %d Overflow Error";
420*1708Sstevel static char dc_parity_txt[] = "Board %d DC %d Parity Error";
421*1708Sstevel
422*1708Sstevel /* defines for the sysio */
423*1708Sstevel #define UPA_APERR 0x4
424*1708Sstevel
425*1708Sstevel int
error_check(Sys_tree * tree,struct system_kstat_data * kstats)426*1708Sstevel error_check(Sys_tree *tree, struct system_kstat_data *kstats)
427*1708Sstevel {
428*1708Sstevel int exit_code = 0; /* init to all OK */
429*1708Sstevel
430*1708Sstevel /*
431*1708Sstevel * silently check for any types of machine errors
432*1708Sstevel */
433*1708Sstevel print_flag = 0;
434*1708Sstevel if (disp_fail_parts(tree) || disp_fault_list(tree, kstats) ||
435*1708Sstevel disp_err_log(kstats) || disp_env_status(kstats)) {
436*1708Sstevel /* set exit_code to show failures */
437*1708Sstevel exit_code = 1;
438*1708Sstevel }
439*1708Sstevel print_flag = 1;
440*1708Sstevel
441*1708Sstevel return (exit_code);
442*1708Sstevel }
443*1708Sstevel
444*1708Sstevel /*
445*1708Sstevel * disp_fail_parts
446*1708Sstevel *
447*1708Sstevel * Display the failed parts in the system. This function looks for
448*1708Sstevel * the status property in all PROM nodes. On systems where
449*1708Sstevel * the PROM does not supports passing diagnostic information
450*1708Sstevel * thruogh the device tree, this routine will be silent.
451*1708Sstevel */
452*1708Sstevel int
disp_fail_parts(Sys_tree * tree)453*1708Sstevel disp_fail_parts(Sys_tree *tree)
454*1708Sstevel {
455*1708Sstevel int exit_code;
456*1708Sstevel int system_failed = 0;
457*1708Sstevel Board_node *bnode = tree->bd_list;
458*1708Sstevel Prom_node *pnode;
459*1708Sstevel
460*1708Sstevel exit_code = 0;
461*1708Sstevel
462*1708Sstevel /* go through all of the boards looking for failed units. */
463*1708Sstevel while (bnode != NULL) {
464*1708Sstevel /* find failed chips */
465*1708Sstevel pnode = find_failed_node(bnode->nodes);
466*1708Sstevel if ((pnode != NULL) && !system_failed) {
467*1708Sstevel system_failed = 1;
468*1708Sstevel exit_code = 1;
469*1708Sstevel if (print_flag == 0) {
470*1708Sstevel return (exit_code);
471*1708Sstevel }
472*1708Sstevel log_printf("\n", 0);
473*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
474*1708Sstevel "Failed Field Replaceable Units (FRU) "
475*1708Sstevel "in System:\n"), 0);
476*1708Sstevel log_printf("=========================="
477*1708Sstevel "====================\n", 0);
478*1708Sstevel }
479*1708Sstevel
480*1708Sstevel while (pnode != NULL) {
481*1708Sstevel void *value;
482*1708Sstevel char *name; /* node name string */
483*1708Sstevel char *type; /* node type string */
484*1708Sstevel char *board_type = NULL;
485*1708Sstevel
486*1708Sstevel value = get_prop_val(find_prop(pnode, "status"));
487*1708Sstevel name = get_node_name(pnode);
488*1708Sstevel
489*1708Sstevel /* sanity check of data retreived from PROM */
490*1708Sstevel if ((value == NULL) || (name == NULL)) {
491*1708Sstevel pnode = next_failed_node(pnode);
492*1708Sstevel continue;
493*1708Sstevel }
494*1708Sstevel
495*1708Sstevel /* Find the board type of this board */
496*1708Sstevel if (bnode->board_type == CPU_BOARD) {
497*1708Sstevel board_type = "CPU";
498*1708Sstevel } else {
499*1708Sstevel board_type = "IO";
500*1708Sstevel }
501*1708Sstevel
502*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
503*1708Sstevel "%s unavailable on %s Board #%d\n"),
504*1708Sstevel name, board_type, bnode->board_num, 0);
505*1708Sstevel
506*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
507*1708Sstevel "\tPROM fault string: %s\n"), value, 0);
508*1708Sstevel
509*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
510*1708Sstevel "\tFailed Field Replaceable Unit is "), 0);
511*1708Sstevel
512*1708Sstevel /*
513*1708Sstevel * Determine whether FRU is CPU module, system
514*1708Sstevel * board, or SBus card.
515*1708Sstevel */
516*1708Sstevel if ((name != NULL) && (strstr(name, "sbus"))) {
517*1708Sstevel
518*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
519*1708Sstevel "SBus Card %d\n"),
520*1708Sstevel get_sbus_slot(pnode), 0);
521*1708Sstevel
522*1708Sstevel } else if (((name = get_node_name(pnode->parent)) !=
523*1708Sstevel NULL) && (strstr(name, "pci"))) {
524*1708Sstevel
525*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
526*1708Sstevel "PCI Card %d"),
527*1708Sstevel get_pci_device(pnode), 0);
528*1708Sstevel
529*1708Sstevel } else if (((type = get_node_type(pnode)) != NULL) &&
530*1708Sstevel (strstr(type, "cpu"))) {
531*1708Sstevel
532*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
533*1708Sstevel "UltraSPARC module "
534*1708Sstevel "Board %d Module %d\n"),
535*1708Sstevel get_id(pnode) >> 1,
536*1708Sstevel get_id(pnode) & 0x1);
537*1708Sstevel
538*1708Sstevel } else {
539*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
540*1708Sstevel "%s board %d\n"), board_type,
541*1708Sstevel bnode->board_num, 0);
542*1708Sstevel }
543*1708Sstevel pnode = next_failed_node(pnode);
544*1708Sstevel }
545*1708Sstevel bnode = bnode->next;
546*1708Sstevel }
547*1708Sstevel
548*1708Sstevel if (!system_failed) {
549*1708Sstevel log_printf("\n", 0);
550*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
551*1708Sstevel "No failures found in System\n"), 0);
552*1708Sstevel log_printf("===========================\n", 0);
553*1708Sstevel }
554*1708Sstevel
555*1708Sstevel if (system_failed)
556*1708Sstevel return (1);
557*1708Sstevel else
558*1708Sstevel return (0);
559*1708Sstevel }
560*1708Sstevel
561*1708Sstevel void
display_memorysize(Sys_tree * tree,struct system_kstat_data * kstats,struct grp_info * grps,struct mem_total * memory_total)562*1708Sstevel display_memorysize(Sys_tree *tree, struct system_kstat_data *kstats,
563*1708Sstevel struct grp_info *grps, struct mem_total *memory_total) {
564*1708Sstevel
565*1708Sstevel /* Build the memory group tables and interleave data */
566*1708Sstevel build_mem_tables(tree, kstats, grps);
567*1708Sstevel
568*1708Sstevel /* display total usable installed memory */
569*1708Sstevel get_mem_total(memory_total, grps);
570*1708Sstevel (void) log_printf(dgettext(TEXT_DOMAIN,
571*1708Sstevel "Memory size: %4dMb\n"), memory_total->dram, 0);
572*1708Sstevel
573*1708Sstevel /* We display the NVSIMM size totals separately. */
574*1708Sstevel if (memory_total->nvsimm != 0) {
575*1708Sstevel (void) log_printf(dgettext(TEXT_DOMAIN,
576*1708Sstevel "NVSIMM size: %4dMb\n"), memory_total->nvsimm);
577*1708Sstevel }
578*1708Sstevel }
579*1708Sstevel
580*1708Sstevel /*
581*1708Sstevel * This routine displays the memory configuration for all boards in the
582*1708Sstevel * system.
583*1708Sstevel */
584*1708Sstevel void
display_memoryconf(Sys_tree * tree,struct grp_info * grps)585*1708Sstevel display_memoryconf(Sys_tree *tree, struct grp_info *grps)
586*1708Sstevel {
587*1708Sstevel int group;
588*1708Sstevel char *status_str[] = { "Unknown", " Empty ", " Failed", " Active",
589*1708Sstevel " Spare " };
590*1708Sstevel char *cond_str[] = { " Unknown ", " OK ", " Failing ",
591*1708Sstevel " Failed ", " Uninit. " };
592*1708Sstevel
593*1708Sstevel #ifdef lint
594*1708Sstevel tree = tree;
595*1708Sstevel #endif
596*1708Sstevel /* Print the header for the memory section. */
597*1708Sstevel log_printf("\n", 0);
598*1708Sstevel log_printf("=========================", 0);
599*1708Sstevel log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0);
600*1708Sstevel log_printf("=========================", 0);
601*1708Sstevel log_printf("\n", 0);
602*1708Sstevel log_printf("\n", 0);
603*1708Sstevel log_printf(" Intrlv. "
604*1708Sstevel "Intrlv.\n", 0);
605*1708Sstevel log_printf("Brd Bank MB Status Condition Speed Factor "
606*1708Sstevel " With\n", 0);
607*1708Sstevel log_printf("--- ----- ---- ------- ---------- ----- ------- "
608*1708Sstevel "-------\n", 0);
609*1708Sstevel
610*1708Sstevel /* Print the Memory groups information. */
611*1708Sstevel for (group = 0; group < MAX_GROUPS; group++) {
612*1708Sstevel struct grp *grp;
613*1708Sstevel
614*1708Sstevel grp = &grps->grp[group];
615*1708Sstevel
616*1708Sstevel /* If this board is not a CPU or MEM board, skip it. */
617*1708Sstevel if ((grp->type != MEM_BOARD) && (grp->type != CPU_BOARD)) {
618*1708Sstevel continue;
619*1708Sstevel }
620*1708Sstevel
621*1708Sstevel if (grp->valid) {
622*1708Sstevel log_printf("%2d ", grp->board, 0);
623*1708Sstevel log_printf(" %1d ", grp->group, 0);
624*1708Sstevel log_printf("%4d ", grp->size, 0);
625*1708Sstevel log_printf("%7s ", status_str[grp->status], 0);
626*1708Sstevel log_printf("%10s ", cond_str[grp->condition], 0);
627*1708Sstevel log_printf("%3dns ", grp->speed, 0);
628*1708Sstevel log_printf("%3d-way ", grp->factor, 0);
629*1708Sstevel if (grp->factor > 1) {
630*1708Sstevel log_printf("%4c", grp->groupid, 0);
631*1708Sstevel }
632*1708Sstevel log_printf("\n", 0);
633*1708Sstevel }
634*1708Sstevel }
635*1708Sstevel
636*1708Sstevel }
637*1708Sstevel
638*1708Sstevel
639*1708Sstevel void
display_hp_fail_fault(Sys_tree * tree,struct system_kstat_data * kstats)640*1708Sstevel display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
641*1708Sstevel {
642*1708Sstevel /* Display Hot plugged, disabled and failed boards */
643*1708Sstevel (void) display_hp_boards(kstats);
644*1708Sstevel
645*1708Sstevel /* Display failed units */
646*1708Sstevel (void) disp_fail_parts(tree);
647*1708Sstevel
648*1708Sstevel /* Display fault info */
649*1708Sstevel (void) disp_fault_list(tree, kstats);
650*1708Sstevel }
651*1708Sstevel
652*1708Sstevel void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)653*1708Sstevel display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
654*1708Sstevel struct system_kstat_data *kstats)
655*1708Sstevel {
656*1708Sstevel /*
657*1708Sstevel * Now display the last powerfail time and the fatal hardware
658*1708Sstevel * reset information. We do this under a couple of conditions.
659*1708Sstevel * First if the user asks for it. The second is iof the user
660*1708Sstevel * told us to do logging, and we found a system failure.
661*1708Sstevel */
662*1708Sstevel if (flag) {
663*1708Sstevel /*
664*1708Sstevel * display time of latest powerfail. Not all systems
665*1708Sstevel * have this capability. For those that do not, this
666*1708Sstevel * is just a no-op.
667*1708Sstevel */
668*1708Sstevel disp_powerfail(root);
669*1708Sstevel
670*1708Sstevel /* Display system environmental conditions. */
671*1708Sstevel (void) disp_env_status(kstats);
672*1708Sstevel
673*1708Sstevel /* Display ASIC Chip revs for all boards. */
674*1708Sstevel sunfire_disp_asic_revs(tree, kstats);
675*1708Sstevel
676*1708Sstevel /* Print the PROM revisions here */
677*1708Sstevel sunfire_disp_prom_versions(tree);
678*1708Sstevel
679*1708Sstevel /*
680*1708Sstevel * Display the latest system fatal hardware
681*1708Sstevel * error data, if any. The system holds this
682*1708Sstevel * data in SRAM, so it does not persist
683*1708Sstevel * across power-on resets.
684*1708Sstevel */
685*1708Sstevel (void) disp_err_log(kstats);
686*1708Sstevel }
687*1708Sstevel }
688*1708Sstevel
689*1708Sstevel void
display_mid(int mid)690*1708Sstevel display_mid(int mid)
691*1708Sstevel {
692*1708Sstevel log_printf(" %2d ", mid % 2, 0);
693*1708Sstevel }
694*1708Sstevel
695*1708Sstevel /*
696*1708Sstevel * display_pci
697*1708Sstevel * Call the generic psycho version of this function.
698*1708Sstevel */
699*1708Sstevel void
display_pci(Board_node * board)700*1708Sstevel display_pci(Board_node *board)
701*1708Sstevel {
702*1708Sstevel display_psycho_pci(board);
703*1708Sstevel }
704*1708Sstevel
705*1708Sstevel /*
706*1708Sstevel * display_ffb
707*1708Sstevel * Display all FFBs on this board. It can either be in tabular format,
708*1708Sstevel * or a more verbose format.
709*1708Sstevel */
710*1708Sstevel void
display_ffb(Board_node * board,int table)711*1708Sstevel display_ffb(Board_node *board, int table)
712*1708Sstevel {
713*1708Sstevel Prom_node *ffb;
714*1708Sstevel void *value;
715*1708Sstevel struct io_card *card_list = NULL;
716*1708Sstevel struct io_card card;
717*1708Sstevel
718*1708Sstevel if (board == NULL)
719*1708Sstevel return;
720*1708Sstevel
721*1708Sstevel /* Fill in common information */
722*1708Sstevel card.display = 1;
723*1708Sstevel card.board = board->board_num;
724*1708Sstevel (void) sprintf(card.bus_type, "UPA");
725*1708Sstevel card.freq = sys_clk;
726*1708Sstevel
727*1708Sstevel for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL;
728*1708Sstevel ffb = dev_next_node(ffb, FFB_NAME)) {
729*1708Sstevel if (table == 1) {
730*1708Sstevel /* Print out in table format */
731*1708Sstevel
732*1708Sstevel /* XXX - Get the slot number (hack) */
733*1708Sstevel card.slot = get_id(ffb);
734*1708Sstevel
735*1708Sstevel /* Find out if it's single or double buffered */
736*1708Sstevel (void) sprintf(card.name, "FFB");
737*1708Sstevel value = get_prop_val(find_prop(ffb, "board_type"));
738*1708Sstevel if (value != NULL)
739*1708Sstevel if ((*(int *)value) & FFB_B_BUFF)
740*1708Sstevel (void) sprintf(card.name, "FFB, "
741*1708Sstevel "Double Buffered");
742*1708Sstevel else
743*1708Sstevel (void) sprintf(card.name, "FFB, "
744*1708Sstevel "Single Buffered");
745*1708Sstevel
746*1708Sstevel /* Print model number */
747*1708Sstevel card.model[0] = '\0';
748*1708Sstevel value = get_prop_val(find_prop(ffb, "model"));
749*1708Sstevel if (value != NULL)
750*1708Sstevel (void) sprintf(card.model, "%s",
751*1708Sstevel (char *)value);
752*1708Sstevel
753*1708Sstevel card_list = insert_io_card(card_list, &card);
754*1708Sstevel } else {
755*1708Sstevel /* print in long format */
756*1708Sstevel char device[MAXSTRLEN];
757*1708Sstevel int fd = -1;
758*1708Sstevel struct dirent *direntp;
759*1708Sstevel DIR *dirp;
760*1708Sstevel union strap_un strap;
761*1708Sstevel struct ffb_sys_info fsi;
762*1708Sstevel
763*1708Sstevel /* Find the device node using upa address */
764*1708Sstevel value = get_prop_val(find_prop(ffb, "upa-portid"));
765*1708Sstevel if (value == NULL)
766*1708Sstevel continue;
767*1708Sstevel
768*1708Sstevel (void) sprintf(device, "%s@%x", FFB_NAME,
769*1708Sstevel *(int *)value);
770*1708Sstevel if ((dirp = opendir("/devices")) == NULL)
771*1708Sstevel continue;
772*1708Sstevel
773*1708Sstevel while ((direntp = readdir(dirp)) != NULL) {
774*1708Sstevel if (strstr(direntp->d_name, device) != NULL) {
775*1708Sstevel (void) sprintf(device, "/devices/%s",
776*1708Sstevel direntp->d_name);
777*1708Sstevel fd = open(device, O_RDWR, 0666);
778*1708Sstevel break;
779*1708Sstevel }
780*1708Sstevel }
781*1708Sstevel (void) closedir(dirp);
782*1708Sstevel
783*1708Sstevel if (fd == -1)
784*1708Sstevel continue;
785*1708Sstevel
786*1708Sstevel if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
787*1708Sstevel continue;
788*1708Sstevel
789*1708Sstevel log_printf("Board %d FFB Hardware Configuration:\n",
790*1708Sstevel board->board_num, 0);
791*1708Sstevel log_printf("-----------------------------------\n", 0);
792*1708Sstevel
793*1708Sstevel strap.ffb_strap_bits = fsi.ffb_strap_bits;
794*1708Sstevel log_printf("\tBoard rev: %d\n",
795*1708Sstevel (int)strap.fld.board_rev, 0);
796*1708Sstevel log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
797*1708Sstevel log_printf("\tDAC: %s\n",
798*1708Sstevel fmt_manf_id(fsi.dac_version, device), 0);
799*1708Sstevel log_printf("\t3DRAM: %s\n",
800*1708Sstevel fmt_manf_id(fsi.fbram_version, device), 0);
801*1708Sstevel log_printf("\n", 0);
802*1708Sstevel }
803*1708Sstevel }
804*1708Sstevel
805*1708Sstevel display_io_cards(card_list);
806*1708Sstevel free_io_cards(card_list);
807*1708Sstevel }
808*1708Sstevel
809*1708Sstevel /*
810*1708Sstevel * add_node
811*1708Sstevel *
812*1708Sstevel * This function adds a board node to the board structure where that
813*1708Sstevel * that node's physical component lives.
814*1708Sstevel */
815*1708Sstevel void
add_node(Sys_tree * root,Prom_node * pnode)816*1708Sstevel add_node(Sys_tree *root, Prom_node *pnode)
817*1708Sstevel {
818*1708Sstevel int board;
819*1708Sstevel Board_node *bnode;
820*1708Sstevel char *name = get_node_name(pnode);
821*1708Sstevel Prom_node *p;
822*1708Sstevel
823*1708Sstevel /* add this node to the Board list of the appropriate board */
824*1708Sstevel if ((board = get_board_num(pnode)) == -1) {
825*1708Sstevel void *value;
826*1708Sstevel
827*1708Sstevel /*
828*1708Sstevel * if it is a server, pci nodes and ffb nodes never have
829*1708Sstevel * board number properties and software can find the board
830*1708Sstevel * number from the reg property. It is derived from the
831*1708Sstevel * high word of the 'reg' property, which contains the
832*1708Sstevel * mid.
833*1708Sstevel */
834*1708Sstevel if ((name != NULL) &&
835*1708Sstevel ((strcmp(name, FFB_NAME) == 0) ||
836*1708Sstevel (strcmp(name, "pci") == 0) ||
837*1708Sstevel (strcmp(name, "counter-timer") == 0))) {
838*1708Sstevel /* extract the board number from the 'reg' prop. */
839*1708Sstevel if ((value = get_prop_val(find_prop(pnode,
840*1708Sstevel "reg"))) == NULL) {
841*1708Sstevel (void) printf("add_node() no reg property\n");
842*1708Sstevel exit(2);
843*1708Sstevel }
844*1708Sstevel board = (*(int *)value - 0x1c0) / 4;
845*1708Sstevel }
846*1708Sstevel }
847*1708Sstevel
848*1708Sstevel /* find the node with the same board number */
849*1708Sstevel if ((bnode = find_board(root, board)) == NULL) {
850*1708Sstevel bnode = insert_board(root, board);
851*1708Sstevel bnode->board_type = UNKNOWN_BOARD;
852*1708Sstevel }
853*1708Sstevel
854*1708Sstevel /* now attach this prom node to the board list */
855*1708Sstevel /* Insert this node at the end of the list */
856*1708Sstevel pnode->sibling = NULL;
857*1708Sstevel if (bnode->nodes == NULL)
858*1708Sstevel bnode->nodes = pnode;
859*1708Sstevel else {
860*1708Sstevel p = bnode->nodes;
861*1708Sstevel while (p->sibling != NULL)
862*1708Sstevel p = p->sibling;
863*1708Sstevel p->sibling = pnode;
864*1708Sstevel }
865*1708Sstevel
866*1708Sstevel }
867*1708Sstevel
868*1708Sstevel /*
869*1708Sstevel * Function resolve_board_types
870*1708Sstevel *
871*1708Sstevel * After the tree is walked and all the information is gathered, this
872*1708Sstevel * function is called to resolve the type of each board.
873*1708Sstevel */
874*1708Sstevel void
resolve_board_types(Sys_tree * tree)875*1708Sstevel resolve_board_types(Sys_tree *tree)
876*1708Sstevel {
877*1708Sstevel Board_node *bnode;
878*1708Sstevel Prom_node *pnode;
879*1708Sstevel char *type;
880*1708Sstevel
881*1708Sstevel bnode = tree->bd_list;
882*1708Sstevel while (bnode != NULL) {
883*1708Sstevel bnode->board_type = UNKNOWN_BOARD;
884*1708Sstevel
885*1708Sstevel pnode = dev_find_node(bnode->nodes, "fhc");
886*1708Sstevel type = get_prop_val(find_prop(pnode, "board-type"));
887*1708Sstevel if (type == NULL) {
888*1708Sstevel bnode = bnode->next;
889*1708Sstevel continue;
890*1708Sstevel }
891*1708Sstevel
892*1708Sstevel if (strcmp(type, CPU_BD_NAME) == 0) {
893*1708Sstevel bnode->board_type = CPU_BOARD;
894*1708Sstevel } else if (strcmp(type, MEM_BD_NAME) == 0) {
895*1708Sstevel bnode->board_type = MEM_BOARD;
896*1708Sstevel } else if (strcmp(type, DISK_BD_NAME) == 0) {
897*1708Sstevel bnode->board_type = DISK_BOARD;
898*1708Sstevel } else if (strcmp(type, IO_SBUS_FFB_BD_NAME) == 0) {
899*1708Sstevel bnode->board_type = IO_SBUS_FFB_BOARD;
900*1708Sstevel } else if (strcmp(type, IO_2SBUS_BD_NAME) == 0) {
901*1708Sstevel bnode->board_type = IO_2SBUS_BOARD;
902*1708Sstevel } else if (strcmp(type, IO_PCI_BD_NAME) == 0) {
903*1708Sstevel bnode->board_type = IO_PCI_BOARD;
904*1708Sstevel } else if (strcmp(type, IO_2SBUS_SOCPLUS_BD_NAME) == 0) {
905*1708Sstevel bnode->board_type = IO_2SBUS_SOCPLUS_BOARD;
906*1708Sstevel } else if (strcmp(type, IO_SBUS_FFB_SOCPLUS_BD_NAME) == 0) {
907*1708Sstevel bnode->board_type = IO_SBUS_FFB_SOCPLUS_BOARD;
908*1708Sstevel }
909*1708Sstevel
910*1708Sstevel bnode = bnode->next;
911*1708Sstevel }
912*1708Sstevel
913*1708Sstevel }
914*1708Sstevel
915*1708Sstevel /*
916*1708Sstevel * local functions
917*1708Sstevel */
918*1708Sstevel
919*1708Sstevel static void
sunfire_disp_prom_versions(Sys_tree * tree)920*1708Sstevel sunfire_disp_prom_versions(Sys_tree *tree)
921*1708Sstevel {
922*1708Sstevel Board_node *bnode;
923*1708Sstevel
924*1708Sstevel /* Display Prom revision header */
925*1708Sstevel log_printf("System Board PROM revisions:\n", 0);
926*1708Sstevel log_printf("----------------------------\n", 0);
927*1708Sstevel
928*1708Sstevel /* For each board, print the POST and OBP versions */
929*1708Sstevel for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) {
930*1708Sstevel Prom_node *flashprom; /* flashprom device node */
931*1708Sstevel
932*1708Sstevel /* find a flashprom node for this board */
933*1708Sstevel flashprom = dev_find_node(bnode->nodes, "flashprom");
934*1708Sstevel
935*1708Sstevel /* If no flashprom node found, continue */
936*1708Sstevel if (flashprom == NULL)
937*1708Sstevel continue;
938*1708Sstevel
939*1708Sstevel /* flashprom node found, display board# */
940*1708Sstevel log_printf("Board %2d: ", bnode->board_num, 0);
941*1708Sstevel
942*1708Sstevel disp_prom_version(flashprom);
943*1708Sstevel }
944*1708Sstevel }
945*1708Sstevel
946*1708Sstevel
947*1708Sstevel /*
948*1708Sstevel * functions that are only needed inside this library
949*1708Sstevel */
950*1708Sstevel
951*1708Sstevel /*
952*1708Sstevel * build_mem_tables
953*1708Sstevel *
954*1708Sstevel * This routine builds the memory table which tells how much memory
955*1708Sstevel * is present in each SIMM group of each board, what the interleave
956*1708Sstevel * factors are, and the group ID of the interleave group.
957*1708Sstevel *
958*1708Sstevel * The algorithms used are:
959*1708Sstevel * First fill in the sizes of groups.
960*1708Sstevel * Next build lists of all groups with same physical base.
961*1708Sstevel * From #of members in each list, interleave factor is
962*1708Sstevel * determined.
963*1708Sstevel * All members of a certain list get the same interleave
964*1708Sstevel * group ID.
965*1708Sstevel */
966*1708Sstevel static void
build_mem_tables(Sys_tree * tree,struct system_kstat_data * kstats,struct grp_info * grps)967*1708Sstevel build_mem_tables(Sys_tree *tree,
968*1708Sstevel struct system_kstat_data *kstats,
969*1708Sstevel struct grp_info *grps)
970*1708Sstevel {
971*1708Sstevel struct mem_inter inter_grps; /* temp structure for interleaves */
972*1708Sstevel struct inter_grp *intrp;
973*1708Sstevel int group;
974*1708Sstevel int i;
975*1708Sstevel
976*1708Sstevel /* initialize the interleave lists */
977*1708Sstevel for (i = 0, intrp = &inter_grps.i_grp[0]; i < MAX_GROUPS; i++,
978*1708Sstevel intrp++) {
979*1708Sstevel intrp->valid = 0;
980*1708Sstevel intrp->count = 0;
981*1708Sstevel intrp->groupid = '\0';
982*1708Sstevel intrp->base = 0;
983*1708Sstevel }
984*1708Sstevel
985*1708Sstevel for (group = 0; group < MAX_GROUPS; group++) {
986*1708Sstevel int found;
987*1708Sstevel int board;
988*1708Sstevel struct grp *grp;
989*1708Sstevel struct bd_kstat_data *bksp;
990*1708Sstevel uchar_t simm_reg;
991*1708Sstevel Board_node *bnode;
992*1708Sstevel
993*1708Sstevel board = group/2;
994*1708Sstevel bksp = &kstats->bd_ksp_list[board];
995*1708Sstevel grp = &grps->grp[group];
996*1708Sstevel grp->group = group % 2;
997*1708Sstevel
998*1708Sstevel /*
999*1708Sstevel * Copy the board type field into the group record.
1000*1708Sstevel */
1001*1708Sstevel if ((bnode = find_board(tree, board)) != NULL) {
1002*1708Sstevel grp->type = bnode->board_type;
1003*1708Sstevel } else {
1004*1708Sstevel grp->type = UNKNOWN_BOARD;
1005*1708Sstevel continue;
1006*1708Sstevel }
1007*1708Sstevel
1008*1708Sstevel /* Make sure we have kstats for this board */
1009*1708Sstevel if (bksp->ac_kstats_ok == 0) {
1010*1708Sstevel /* Mark this group as invalid and move to next one */
1011*1708Sstevel grp->valid = 0;
1012*1708Sstevel continue;
1013*1708Sstevel }
1014*1708Sstevel
1015*1708Sstevel /* Find the bank status property */
1016*1708Sstevel if (bksp->ac_memstat_ok) {
1017*1708Sstevel grp->status = bksp->mem_stat[grp->group].status;
1018*1708Sstevel grp->condition = bksp->mem_stat[grp->group].condition;
1019*1708Sstevel } else {
1020*1708Sstevel grp->status = StUnknown;
1021*1708Sstevel grp->condition = ConUnknown;
1022*1708Sstevel }
1023*1708Sstevel
1024*1708Sstevel switch (grp->status) {
1025*1708Sstevel case StBad:
1026*1708Sstevel case StActive:
1027*1708Sstevel case StSpare:
1028*1708Sstevel break;
1029*1708Sstevel default:
1030*1708Sstevel grp->status = StUnknown;
1031*1708Sstevel break;
1032*1708Sstevel }
1033*1708Sstevel
1034*1708Sstevel switch (grp->condition) {
1035*1708Sstevel case ConOK:
1036*1708Sstevel case ConFailing:
1037*1708Sstevel case ConFailed:
1038*1708Sstevel case ConTest:
1039*1708Sstevel case ConBad:
1040*1708Sstevel break;
1041*1708Sstevel default:
1042*1708Sstevel grp->condition = ConUnknown;
1043*1708Sstevel break;
1044*1708Sstevel }
1045*1708Sstevel
1046*1708Sstevel /* base the group size off of the simmstat kstat. */
1047*1708Sstevel if (bksp->simmstat_kstats_ok == 0) {
1048*1708Sstevel grp->valid = 0;
1049*1708Sstevel continue;
1050*1708Sstevel }
1051*1708Sstevel
1052*1708Sstevel /* Is it bank 0 or bank 1 */
1053*1708Sstevel if (grp->group == 0) {
1054*1708Sstevel simm_reg = bksp->simm_status[0];
1055*1708Sstevel } else {
1056*1708Sstevel simm_reg = bksp->simm_status[1];
1057*1708Sstevel }
1058*1708Sstevel
1059*1708Sstevel /* Now decode the size field. */
1060*1708Sstevel switch (simm_reg & 0x1f) {
1061*1708Sstevel case MEM_SIZE_64M:
1062*1708Sstevel grp->size = 64;
1063*1708Sstevel break;
1064*1708Sstevel case MEM_SIZE_256M:
1065*1708Sstevel grp->size = 256;
1066*1708Sstevel break;
1067*1708Sstevel case MEM_SIZE_1G:
1068*1708Sstevel grp->size = 1024;
1069*1708Sstevel break;
1070*1708Sstevel case MEM_SIZE_2G:
1071*1708Sstevel grp->size = 2048;
1072*1708Sstevel break;
1073*1708Sstevel default:
1074*1708Sstevel grp->valid = 0;
1075*1708Sstevel continue;
1076*1708Sstevel }
1077*1708Sstevel
1078*1708Sstevel /* Decode the speed field */
1079*1708Sstevel switch ((simm_reg & 0x60) >> 5) {
1080*1708Sstevel case MEM_SPEED_50ns:
1081*1708Sstevel grp->speed = 50;
1082*1708Sstevel break;
1083*1708Sstevel case MEM_SPEED_60ns:
1084*1708Sstevel grp->speed = 60;
1085*1708Sstevel break;
1086*1708Sstevel case MEM_SPEED_70ns:
1087*1708Sstevel grp->speed = 70;
1088*1708Sstevel break;
1089*1708Sstevel case MEM_SPEED_80ns:
1090*1708Sstevel grp->speed = 80;
1091*1708Sstevel break;
1092*1708Sstevel }
1093*1708Sstevel
1094*1708Sstevel grp->valid = 1;
1095*1708Sstevel grp->base = GRP_BASE(bksp->ac_memdecode[grp->group]);
1096*1708Sstevel grp->board = board;
1097*1708Sstevel if (grp->group == 0) {
1098*1708Sstevel grp->factor = INTLV0(bksp->ac_memctl);
1099*1708Sstevel } else { /* assume it is group 1 */
1100*1708Sstevel grp->factor = INTLV1(bksp->ac_memctl);
1101*1708Sstevel }
1102*1708Sstevel grp->groupid = '\0'; /* Not in a group yet */
1103*1708Sstevel
1104*1708Sstevel /*
1105*1708Sstevel * find the interleave list this group belongs on. If the
1106*1708Sstevel * interleave list corresponding to this base address is
1107*1708Sstevel * not found, then create a new one.
1108*1708Sstevel */
1109*1708Sstevel
1110*1708Sstevel i = 0;
1111*1708Sstevel intrp = &inter_grps.i_grp[0];
1112*1708Sstevel found = 0;
1113*1708Sstevel while ((i < MAX_GROUPS) && !found && (intrp->valid != 0)) {
1114*1708Sstevel if ((intrp->valid != 0) &&
1115*1708Sstevel (intrp->base == grp->base)) {
1116*1708Sstevel grp->groupid = intrp->groupid;
1117*1708Sstevel intrp->count++;
1118*1708Sstevel found = 1;
1119*1708Sstevel }
1120*1708Sstevel i++;
1121*1708Sstevel intrp++;
1122*1708Sstevel }
1123*1708Sstevel /*
1124*1708Sstevel * We did not find a matching base. So now i and intrp
1125*1708Sstevel * now point to the next interleave group in the list.
1126*1708Sstevel */
1127*1708Sstevel if (!found) {
1128*1708Sstevel intrp->count++;
1129*1708Sstevel intrp->valid = 1;
1130*1708Sstevel intrp->groupid = 'A' + (char)i;
1131*1708Sstevel intrp->base = grp->base;
1132*1708Sstevel grp->groupid = intrp->groupid;
1133*1708Sstevel }
1134*1708Sstevel }
1135*1708Sstevel }
1136*1708Sstevel
1137*1708Sstevel
1138*1708Sstevel static void
get_mem_total(struct mem_total * mem_total,struct grp_info * grps)1139*1708Sstevel get_mem_total(struct mem_total *mem_total, struct grp_info *grps)
1140*1708Sstevel {
1141*1708Sstevel struct grp *grp;
1142*1708Sstevel int i;
1143*1708Sstevel
1144*1708Sstevel /* Start with total of zero */
1145*1708Sstevel mem_total->dram = 0;
1146*1708Sstevel mem_total->nvsimm = 0;
1147*1708Sstevel
1148*1708Sstevel /* For now we ignore NVSIMMs. We might want to fix this later. */
1149*1708Sstevel for (i = 0, grp = &grps->grp[0]; i < MAX_GROUPS; i++, grp++) {
1150*1708Sstevel if (grp->valid == 1 && grp->status == StActive) {
1151*1708Sstevel mem_total->dram += grp->size;
1152*1708Sstevel }
1153*1708Sstevel }
1154*1708Sstevel }
1155*1708Sstevel
1156*1708Sstevel static int
disp_fault_list(Sys_tree * tree,struct system_kstat_data * kstats)1157*1708Sstevel disp_fault_list(Sys_tree *tree, struct system_kstat_data *kstats)
1158*1708Sstevel {
1159*1708Sstevel struct ft_list *ftp;
1160*1708Sstevel int i;
1161*1708Sstevel int result = 0;
1162*1708Sstevel time_t t;
1163*1708Sstevel
1164*1708Sstevel if (!kstats->ft_kstat_ok) {
1165*1708Sstevel return (result);
1166*1708Sstevel }
1167*1708Sstevel
1168*1708Sstevel for (i = 0, ftp = kstats->ft_array; i < kstats->nfaults; i++, ftp++) {
1169*1708Sstevel if (!result) {
1170*1708Sstevel log_printf("\n", 0);
1171*1708Sstevel log_printf("Detected System Faults\n", 0);
1172*1708Sstevel log_printf("======================\n", 0);
1173*1708Sstevel }
1174*1708Sstevel result = 1;
1175*1708Sstevel if (ftp->fclass == FT_BOARD) {
1176*1708Sstevel log_printf("Board %d fault: %s\n", ftp->unit,
1177*1708Sstevel ftp->msg, 0);
1178*1708Sstevel
1179*1708Sstevel /*
1180*1708Sstevel * If the fault on this board is PROM inherited, see
1181*1708Sstevel * if we can find some failed component information
1182*1708Sstevel * in the PROM device tree. The general solution
1183*1708Sstevel * would be to fix the fhc driver and have it put in
1184*1708Sstevel * more descriptive messages, but that's for another
1185*1708Sstevel * day.
1186*1708Sstevel */
1187*1708Sstevel
1188*1708Sstevel if (ftp->type == FT_PROM) {
1189*1708Sstevel Board_node *bn;
1190*1708Sstevel Prom_node *pn;
1191*1708Sstevel char *str;
1192*1708Sstevel
1193*1708Sstevel bn = find_board(tree, ftp->unit);
1194*1708Sstevel /*
1195*1708Sstevel * If any nodes under this board have a
1196*1708Sstevel * status containing "fail", print it out.
1197*1708Sstevel */
1198*1708Sstevel pn = find_failed_node(bn->nodes);
1199*1708Sstevel while (pn) {
1200*1708Sstevel str = get_prop_val(find_prop(pn,
1201*1708Sstevel "status"));
1202*1708Sstevel if (str != NULL) {
1203*1708Sstevel log_printf("Fault: %s\n", str,
1204*1708Sstevel 0);
1205*1708Sstevel }
1206*1708Sstevel
1207*1708Sstevel pn = next_failed_node(pn);
1208*1708Sstevel }
1209*1708Sstevel }
1210*1708Sstevel } else if ((ftp->type == FT_CORE_PS) || (ftp->type == FT_PPS)) {
1211*1708Sstevel log_printf("Unit %d %s failure\n", ftp->unit,
1212*1708Sstevel ftp->msg, 0);
1213*1708Sstevel } else if ((ftp->type == FT_OVERTEMP) &&
1214*1708Sstevel (ftp->fclass == FT_SYSTEM)) {
1215*1708Sstevel log_printf("Clock board %s\n", ftp->msg, 0);
1216*1708Sstevel } else {
1217*1708Sstevel log_printf("%s failure\n", ftp->msg, 0);
1218*1708Sstevel }
1219*1708Sstevel
1220*1708Sstevel t = (time_t)ftp->create_time;
1221*1708Sstevel log_printf("\tDetected %s",
1222*1708Sstevel asctime(localtime(&t)), 0);
1223*1708Sstevel }
1224*1708Sstevel
1225*1708Sstevel if (!result) {
1226*1708Sstevel log_printf("\n", 0);
1227*1708Sstevel log_printf("No System Faults found\n", 0);
1228*1708Sstevel log_printf("======================\n", 0);
1229*1708Sstevel }
1230*1708Sstevel
1231*1708Sstevel log_printf("\n", 0);
1232*1708Sstevel
1233*1708Sstevel return (result);
1234*1708Sstevel }
1235*1708Sstevel
1236*1708Sstevel
1237*1708Sstevel /*
1238*1708Sstevel * disp_err_log
1239*1708Sstevel *
1240*1708Sstevel * Display the fatal hardware reset system error logs. These logs are
1241*1708Sstevel * collected by POST and passed up through the kernel to userland.
1242*1708Sstevel * They will not necessarily be present in all systems. Their form
1243*1708Sstevel * might also be different in different systems.
1244*1708Sstevel *
1245*1708Sstevel * NOTE - We are comparing POST defined board types here. Do not confuse
1246*1708Sstevel * them with kernel board types. The structure being analyzed in this
1247*1708Sstevel * function is created by POST. All the defines for it are in reset_info.h,
1248*1708Sstevel * which was ported from POST header files.
1249*1708Sstevel */
1250*1708Sstevel static int
disp_err_log(struct system_kstat_data * kstats)1251*1708Sstevel disp_err_log(struct system_kstat_data *kstats)
1252*1708Sstevel {
1253*1708Sstevel int exit_code = 0;
1254*1708Sstevel int i;
1255*1708Sstevel struct reset_info *rst_info;
1256*1708Sstevel struct board_info *bdp;
1257*1708Sstevel char *err_msgs[MAX_MSGS]; /* holds all messages for a system board */
1258*1708Sstevel int msg_idx; /* current msg number */
1259*1708Sstevel int count; /* number added by last analyze call */
1260*1708Sstevel char **msgs;
1261*1708Sstevel
1262*1708Sstevel /* start by initializing the err_msgs array to all NULLs */
1263*1708Sstevel for (i = 0; i < MAX_MSGS; i++) {
1264*1708Sstevel err_msgs[i] = NULL;
1265*1708Sstevel }
1266*1708Sstevel
1267*1708Sstevel /* First check to see that the reset-info kstats are present. */
1268*1708Sstevel if (kstats->reset_kstats_ok == 0) {
1269*1708Sstevel return (exit_code);
1270*1708Sstevel }
1271*1708Sstevel
1272*1708Sstevel rst_info = &kstats->reset_info;
1273*1708Sstevel
1274*1708Sstevel /* Everything is OK, so print out time/date stamp first */
1275*1708Sstevel log_printf("\n", 0);
1276*1708Sstevel log_printf(
1277*1708Sstevel dgettext(TEXT_DOMAIN,
1278*1708Sstevel "Analysis of most recent Fatal Hardware Watchdog:\n"),
1279*1708Sstevel 0);
1280*1708Sstevel log_printf("======================================================\n",
1281*1708Sstevel 0);
1282*1708Sstevel log_printf("Log Date: %s\n",
1283*1708Sstevel get_time(&kstats->reset_info.tod_timestamp[0]), 0);
1284*1708Sstevel
1285*1708Sstevel /* initialize the vector and the message index. */
1286*1708Sstevel msgs = err_msgs;
1287*1708Sstevel msg_idx = 0;
1288*1708Sstevel
1289*1708Sstevel /* Loop Through all of the boards. */
1290*1708Sstevel bdp = &rst_info->bd_reset_info[0];
1291*1708Sstevel for (i = 0; i < MAX_BOARDS; i++, bdp++) {
1292*1708Sstevel
1293*1708Sstevel /* Is there data for this board? */
1294*1708Sstevel if ((bdp->board_desc & BD_STATE_MASK) == BD_NOT_PRESENT) {
1295*1708Sstevel continue;
1296*1708Sstevel }
1297*1708Sstevel
1298*1708Sstevel /* If it is a CPU Board, look for CPU data. */
1299*1708Sstevel if (BOARD_TYPE(bdp->board_desc) == CPU_TYPE) {
1300*1708Sstevel /* analyze CPU 0 if present */
1301*1708Sstevel if (bdp->board_desc & CPU0_OK) {
1302*1708Sstevel count = analyze_cpu(msgs, 0,
1303*1708Sstevel bdp->cpu[0].afsr);
1304*1708Sstevel msgs += count;
1305*1708Sstevel msg_idx += count;
1306*1708Sstevel }
1307*1708Sstevel
1308*1708Sstevel /* analyze CPU1 if present. */
1309*1708Sstevel if (bdp->board_desc & CPU1_OK) {
1310*1708Sstevel count = analyze_cpu(msgs, 1,
1311*1708Sstevel bdp->cpu[1].afsr);
1312*1708Sstevel msgs += count;
1313*1708Sstevel msg_idx += count;
1314*1708Sstevel }
1315*1708Sstevel }
1316*1708Sstevel
1317*1708Sstevel /* Always Analyze the AC and the DCs on a board. */
1318*1708Sstevel count = analyze_ac(msgs, bdp->ac_error_status);
1319*1708Sstevel msgs += count;
1320*1708Sstevel msg_idx += count;
1321*1708Sstevel
1322*1708Sstevel count = analyze_dc(i, msgs, bdp->dc_shadow_chain);
1323*1708Sstevel msgs += count;
1324*1708Sstevel msg_idx += count;
1325*1708Sstevel
1326*1708Sstevel if (msg_idx != 0)
1327*1708Sstevel display_msgs(err_msgs, i);
1328*1708Sstevel
1329*1708Sstevel erase_msgs(err_msgs);
1330*1708Sstevel
1331*1708Sstevel /* If any messages are logged, we have errors */
1332*1708Sstevel if (msg_idx != 0) {
1333*1708Sstevel exit_code = 1;
1334*1708Sstevel }
1335*1708Sstevel
1336*1708Sstevel /* reset the vector and the message index */
1337*1708Sstevel msg_idx = 0;
1338*1708Sstevel msgs = &err_msgs[0];
1339*1708Sstevel }
1340*1708Sstevel
1341*1708Sstevel return (exit_code);
1342*1708Sstevel }
1343*1708Sstevel
1344*1708Sstevel static void
erase_msgs(char ** msgs)1345*1708Sstevel erase_msgs(char **msgs)
1346*1708Sstevel {
1347*1708Sstevel int i;
1348*1708Sstevel
1349*1708Sstevel for (i = 0; (*msgs != NULL) && (i < MAX_MSGS); i++, msgs++) {
1350*1708Sstevel free(*msgs);
1351*1708Sstevel *msgs = NULL;
1352*1708Sstevel }
1353*1708Sstevel }
1354*1708Sstevel
1355*1708Sstevel
1356*1708Sstevel static void
display_msgs(char ** msgs,int board)1357*1708Sstevel display_msgs(char **msgs, int board)
1358*1708Sstevel {
1359*1708Sstevel int i;
1360*1708Sstevel
1361*1708Sstevel /* display the header for this board */
1362*1708Sstevel print_header(board);
1363*1708Sstevel
1364*1708Sstevel for (i = 0; (*msgs != NULL) && (i < MAX_MSGS); i++, msgs++) {
1365*1708Sstevel log_printf(*msgs, 0);
1366*1708Sstevel }
1367*1708Sstevel }
1368*1708Sstevel
1369*1708Sstevel
1370*1708Sstevel
1371*1708Sstevel /*
1372*1708Sstevel * disp_keysw_and_leds
1373*1708Sstevel *
1374*1708Sstevel * This routine displays the position of the keyswitch and the front panel
1375*1708Sstevel * system LEDs. The keyswitch can be in either normal, diagnostic, or
1376*1708Sstevel * secure position. The three front panel LEDs are of importance because
1377*1708Sstevel * the center LED indicates component failure on the system.
1378*1708Sstevel */
1379*1708Sstevel static int
disp_keysw_and_leds(struct system_kstat_data * kstats)1380*1708Sstevel disp_keysw_and_leds(struct system_kstat_data *kstats)
1381*1708Sstevel {
1382*1708Sstevel int board;
1383*1708Sstevel int diag_mode = 0;
1384*1708Sstevel int secure_mode = 0;
1385*1708Sstevel int result = 0;
1386*1708Sstevel
1387*1708Sstevel /* Check the first valid board to determeine the diag bit */
1388*1708Sstevel /* Find the first valid board */
1389*1708Sstevel for (board = 0; board < MAX_BOARDS; board++) {
1390*1708Sstevel if (kstats->bd_ksp_list[board].fhc_kstats_ok != 0) {
1391*1708Sstevel /* If this was successful, break out of loop */
1392*1708Sstevel if ((kstats->bd_ksp_list[board].fhc_bsr &
1393*1708Sstevel FHC_DIAG_MODE) == 0)
1394*1708Sstevel diag_mode = 1;
1395*1708Sstevel break;
1396*1708Sstevel }
1397*1708Sstevel }
1398*1708Sstevel
1399*1708Sstevel /*
1400*1708Sstevel * Check the register on the clock-board to determine the
1401*1708Sstevel * secure bit.
1402*1708Sstevel */
1403*1708Sstevel if (kstats->sys_kstats_ok) {
1404*1708Sstevel /* The secure bit is negative logic. */
1405*1708Sstevel if (kstats->keysw_status == KEY_SECURE) {
1406*1708Sstevel secure_mode = 1;
1407*1708Sstevel }
1408*1708Sstevel }
1409*1708Sstevel
1410*1708Sstevel /*
1411*1708Sstevel * The system cannot be in diag and secure mode. This is
1412*1708Sstevel * illegal.
1413*1708Sstevel */
1414*1708Sstevel if (secure_mode && diag_mode) {
1415*1708Sstevel result = 2;
1416*1708Sstevel return (result);
1417*1708Sstevel }
1418*1708Sstevel
1419*1708Sstevel /* Now print the keyswitch position. */
1420*1708Sstevel log_printf("Keyswitch position is in ", 0);
1421*1708Sstevel
1422*1708Sstevel if (diag_mode) {
1423*1708Sstevel log_printf("Diagnostic Mode\n");
1424*1708Sstevel } else if (secure_mode) {
1425*1708Sstevel log_printf("Secure Mode\n", 0);
1426*1708Sstevel } else {
1427*1708Sstevel log_printf("Normal Mode\n");
1428*1708Sstevel }
1429*1708Sstevel
1430*1708Sstevel /* display the redundant power status */
1431*1708Sstevel if (kstats->sys_kstats_ok) {
1432*1708Sstevel log_printf("System Power Status: ", 0);
1433*1708Sstevel
1434*1708Sstevel switch (kstats->power_state) {
1435*1708Sstevel case REDUNDANT:
1436*1708Sstevel log_printf("Redundant\n", 0);
1437*1708Sstevel break;
1438*1708Sstevel
1439*1708Sstevel case MINIMUM:
1440*1708Sstevel log_printf("Minimum Available\n", 0);
1441*1708Sstevel break;
1442*1708Sstevel
1443*1708Sstevel case BELOW_MINIMUM:
1444*1708Sstevel log_printf("Insufficient Power Available\n", 0);
1445*1708Sstevel break;
1446*1708Sstevel
1447*1708Sstevel default:
1448*1708Sstevel log_printf("Unknown\n", 0);
1449*1708Sstevel break;
1450*1708Sstevel }
1451*1708Sstevel }
1452*1708Sstevel
1453*1708Sstevel if (kstats->sys_kstats_ok) {
1454*1708Sstevel /*
1455*1708Sstevel * If the center LED is on, then we return a non-zero
1456*1708Sstevel * result.
1457*1708Sstevel */
1458*1708Sstevel log_printf("System LED Status: GREEN YELLOW "
1459*1708Sstevel "GREEN\n", 0);
1460*1708Sstevel if ((kstats->sysctrl & SYS_LED_MID) != 0) {
1461*1708Sstevel log_printf("WARNING ", 0);
1462*1708Sstevel } else {
1463*1708Sstevel log_printf("Normal ", 0);
1464*1708Sstevel }
1465*1708Sstevel
1466*1708Sstevel /*
1467*1708Sstevel * Left LED is negative logic, center and right LEDs
1468*1708Sstevel * are positive logic.
1469*1708Sstevel */
1470*1708Sstevel if ((kstats->sysctrl & SYS_LED_LEFT) == 0) {
1471*1708Sstevel log_printf("ON ", 0);
1472*1708Sstevel } else {
1473*1708Sstevel log_printf("OFF", 0);
1474*1708Sstevel }
1475*1708Sstevel
1476*1708Sstevel log_printf(" ", 0);
1477*1708Sstevel if ((kstats->sysctrl & SYS_LED_MID) != 0) {
1478*1708Sstevel log_printf("ON ", 0);
1479*1708Sstevel } else {
1480*1708Sstevel log_printf("OFF", 0);
1481*1708Sstevel }
1482*1708Sstevel
1483*1708Sstevel log_printf(" BLINKING", 0);
1484*1708Sstevel }
1485*1708Sstevel
1486*1708Sstevel log_printf("\n", 0);
1487*1708Sstevel return (result);
1488*1708Sstevel }
1489*1708Sstevel
1490*1708Sstevel /*
1491*1708Sstevel * disp_env_status
1492*1708Sstevel *
1493*1708Sstevel * This routine displays the environmental status passed up from
1494*1708Sstevel * device drivers via kstats. The kstat names are defined in
1495*1708Sstevel * kernel header files included by this module.
1496*1708Sstevel */
1497*1708Sstevel static int
disp_env_status(struct system_kstat_data * kstats)1498*1708Sstevel disp_env_status(struct system_kstat_data *kstats)
1499*1708Sstevel {
1500*1708Sstevel struct bd_kstat_data *bksp;
1501*1708Sstevel int exit_code = 0;
1502*1708Sstevel int i;
1503*1708Sstevel uchar_t curr_temp;
1504*1708Sstevel int is4slot = 0;
1505*1708Sstevel
1506*1708Sstevel /*
1507*1708Sstevel * Define some message arrays to make life simpler. These
1508*1708Sstevel * messages correspond to definitions in <sys/fhc.c> for
1509*1708Sstevel * temperature trend (enum temp_trend) and temperature state
1510*1708Sstevel * (enum temp_state).
1511*1708Sstevel */
1512*1708Sstevel static char *temp_trend_msg[] = { "unknown",
1513*1708Sstevel "rapidly falling",
1514*1708Sstevel "falling",
1515*1708Sstevel "stable",
1516*1708Sstevel "rising",
1517*1708Sstevel "rapidly rising",
1518*1708Sstevel "unknown (noisy)"
1519*1708Sstevel };
1520*1708Sstevel static char *temp_state_msg[] = { " OK ",
1521*1708Sstevel "WARNING ",
1522*1708Sstevel " DANGER "
1523*1708Sstevel };
1524*1708Sstevel
1525*1708Sstevel log_printf("\n", 0);
1526*1708Sstevel log_printf("=========================", 0);
1527*1708Sstevel log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0);
1528*1708Sstevel log_printf("=========================", 0);
1529*1708Sstevel log_printf("\n", 0);
1530*1708Sstevel
1531*1708Sstevel exit_code = disp_keysw_and_leds(kstats);
1532*1708Sstevel
1533*1708Sstevel if (!kstats->sys_kstats_ok) {
1534*1708Sstevel log_printf(dgettext(TEXT_DOMAIN,
1535*1708Sstevel "*** Error: Unavailable ***\n\n"));
1536*1708Sstevel return (1);
1537*1708Sstevel }
1538*1708Sstevel
1539*1708Sstevel /*
1540*1708Sstevel * for purposes within this routine,
1541*1708Sstevel * 5 slot behaves the same as a 4 slot
1542*1708Sstevel */
1543*1708Sstevel if (SYS_TYPE(kstats->sysstat1) == SYS_4_SLOT)
1544*1708Sstevel is4slot = 1;
1545*1708Sstevel
1546*1708Sstevel log_printf("\n", 0);
1547*1708Sstevel log_printf("\nFans:\n", 0);
1548*1708Sstevel log_printf("-----\n", 0);
1549*1708Sstevel
1550*1708Sstevel log_printf("Unit Status\n", 0);
1551*1708Sstevel log_printf("---- ------\n", 0);
1552*1708Sstevel
1553*1708Sstevel log_printf("%-4s ", is4slot ? "Disk" : "Rack", 0);
1554*1708Sstevel /* Check the status of the Rack Fans */
1555*1708Sstevel if ((kstats->fan_status & SYS_RACK_FANFAIL) == 0) {
1556*1708Sstevel log_printf("OK\n", 0);
1557*1708Sstevel } else {
1558*1708Sstevel log_printf("FAIL\n", 0);
1559*1708Sstevel exit_code = 1;
1560*1708Sstevel }
1561*1708Sstevel
1562*1708Sstevel if (!is4slot) {
1563*1708Sstevel /*
1564*1708Sstevel * keyswitch and ac box are on 8 & 16 slot only
1565*1708Sstevel */
1566*1708Sstevel /* Check the status of the Keyswitch Fan assembly. */
1567*1708Sstevel log_printf("%-4s ", "Key", 0);
1568*1708Sstevel if ((kstats->fan_status & SYS_KEYSW_FAN_OK) != 0) {
1569*1708Sstevel log_printf("OK\n", 0);
1570*1708Sstevel } else {
1571*1708Sstevel log_printf("FAIL\n", 0);
1572*1708Sstevel exit_code = 1;
1573*1708Sstevel }
1574*1708Sstevel
1575*1708Sstevel log_printf("%-4s ", "AC", 0);
1576*1708Sstevel if ((kstats->fan_status & SYS_AC_FAN_OK) != 0) {
1577*1708Sstevel log_printf("OK\n", 0);
1578*1708Sstevel } else {
1579*1708Sstevel log_printf("FAIL\n", 0);
1580*1708Sstevel exit_code = 1;
1581*1708Sstevel }
1582*1708Sstevel } else {
1583*1708Sstevel /*
1584*1708Sstevel * peripheral fan is on 4 slot only
1585*1708Sstevel * XXX might want to indicate transient states too
1586*1708Sstevel */
1587*1708Sstevel if (kstats->psstat_kstat_ok) {
1588*1708Sstevel if (kstats->ps_shadow[SYS_P_FAN_INDEX] == PS_OK) {
1589*1708Sstevel log_printf("PPS OK\n", 0);
1590*1708Sstevel } else if (kstats->ps_shadow[SYS_P_FAN_INDEX] ==
1591*1708Sstevel PS_FAIL) {
1592*1708Sstevel log_printf("PPS FAIL\n", 0);
1593*1708Sstevel exit_code = 1;
1594*1708Sstevel }
1595*1708Sstevel }
1596*1708Sstevel }
1597*1708Sstevel
1598*1708Sstevel log_printf("\n", 0);
1599*1708Sstevel
1600*1708Sstevel
1601*1708Sstevel log_printf("System Temperatures (Celsius):\n", 0);
1602*1708Sstevel log_printf("------------------------------\n", 0);
1603*1708Sstevel log_printf("Brd State Current Min Max Trend\n", 0);
1604*1708Sstevel log_printf("--- ------- ------- --- --- -----\n", 0);
1605*1708Sstevel
1606*1708Sstevel for (i = 0, bksp = &kstats->bd_ksp_list[0]; i < MAX_BOARDS;
1607*1708Sstevel i++, bksp++) {
1608*1708Sstevel
1609*1708Sstevel /* Make sure we have kstats for this board first */
1610*1708Sstevel if (!bksp->temp_kstat_ok) {
1611*1708Sstevel continue;
1612*1708Sstevel }
1613*1708Sstevel log_printf("%2d ", i, 0);
1614*1708Sstevel
1615*1708Sstevel /* Print the current state of the temperature */
1616*1708Sstevel log_printf("%s", temp_state_msg[bksp->tempstat.state], 0);
1617*1708Sstevel /* Set exit code for WARNING and DANGER */
1618*1708Sstevel if (bksp->tempstat.state != 0)
1619*1708Sstevel exit_code = 1;
1620*1708Sstevel
1621*1708Sstevel /* Print the current temperature */
1622*1708Sstevel curr_temp = bksp->tempstat.l1[bksp->tempstat.index % L1_SZ];
1623*1708Sstevel log_printf(" %2d ", curr_temp, 0);
1624*1708Sstevel
1625*1708Sstevel /* Print the minimum recorded temperature */
1626*1708Sstevel log_printf(" %2d ", bksp->tempstat.min, 0);
1627*1708Sstevel
1628*1708Sstevel /* Print the maximum recorded temperature */
1629*1708Sstevel log_printf(" %2d ", bksp->tempstat.max, 0);
1630*1708Sstevel
1631*1708Sstevel /* Print the current trend in temperature (if available) */
1632*1708Sstevel if (bksp->tempstat.version < 2)
1633*1708Sstevel log_printf("unknown\n", 0);
1634*1708Sstevel else
1635*1708Sstevel log_printf("%s\n", temp_trend_msg[bksp->tempstat.trend], 0);
1636*1708Sstevel }
1637*1708Sstevel if (kstats->temp_kstat_ok) {
1638*1708Sstevel log_printf("CLK ", 0);
1639*1708Sstevel
1640*1708Sstevel /* Print the current state of the temperature */
1641*1708Sstevel log_printf("%s", temp_state_msg[kstats->tempstat.state], 0);
1642*1708Sstevel /* Set exit code for WARNING or DANGER */
1643*1708Sstevel if (kstats->tempstat.state != 0)
1644*1708Sstevel exit_code = 1;
1645*1708Sstevel
1646*1708Sstevel /* Print the current temperature */
1647*1708Sstevel curr_temp = kstats->tempstat.l1[kstats->tempstat.index % L1_SZ];
1648*1708Sstevel log_printf(" %2d ", curr_temp, 0);
1649*1708Sstevel
1650*1708Sstevel /* Print the minimum recorded temperature */
1651*1708Sstevel log_printf(" %2d ", kstats->tempstat.min, 0);
1652*1708Sstevel
1653*1708Sstevel /* Print the maximum recorded temperature */
1654*1708Sstevel log_printf(" %2d ", kstats->tempstat.max, 0);
1655*1708Sstevel
1656*1708Sstevel /* Print the current trend in temperature (if available) */
1657*1708Sstevel if (kstats->tempstat.version < 2)
1658*1708Sstevel log_printf("unknown\n\n", 0);
1659*1708Sstevel else
1660*1708Sstevel log_printf("%s\n\n",
1661*1708Sstevel temp_trend_msg[kstats->tempstat.trend], 0);
1662*1708Sstevel } else {
1663*1708Sstevel log_printf("\n");
1664*1708Sstevel }
1665*1708Sstevel
1666*1708Sstevel log_printf("\n", 0);
1667*1708Sstevel log_printf("Power Supplies:\n", 0);
1668*1708Sstevel log_printf("---------------\n", 0);
1669*1708Sstevel log_printf("Supply Status\n", 0);
1670*1708Sstevel log_printf("--------- ------\n", 0);
1671*1708Sstevel if (kstats->psstat_kstat_ok) {
1672*1708Sstevel for (i = 0; i < SYS_PS_COUNT; i++) {
1673*1708Sstevel char *ps, *state;
1674*1708Sstevel
1675*1708Sstevel /* skip core power supplies that are not present */
1676*1708Sstevel if (i <= SYS_PPS0_INDEX && kstats->ps_shadow[i] ==
1677*1708Sstevel PS_OUT)
1678*1708Sstevel continue;
1679*1708Sstevel
1680*1708Sstevel /* Display the unit Number */
1681*1708Sstevel switch (i) {
1682*1708Sstevel case 0: ps = "0"; break;
1683*1708Sstevel case 1: ps = "1"; break;
1684*1708Sstevel case 2: ps = "2"; break;
1685*1708Sstevel case 3: ps = "3"; break;
1686*1708Sstevel case 4: ps = "4"; break;
1687*1708Sstevel case 5: ps = "5"; break;
1688*1708Sstevel case 6: ps = "6"; break;
1689*1708Sstevel case 7: ps = is4slot ? "2nd PPS" : "7"; break;
1690*1708Sstevel
1691*1708Sstevel case SYS_PPS0_INDEX: ps = "PPS"; break;
1692*1708Sstevel case SYS_CLK_33_INDEX: ps = " System 3.3v"; break;
1693*1708Sstevel case SYS_CLK_50_INDEX: ps = " System 5.0v"; break;
1694*1708Sstevel case SYS_V5_P_INDEX: ps = " Peripheral 5.0v"; break;
1695*1708Sstevel case SYS_V12_P_INDEX: ps = " Peripheral 12v"; break;
1696*1708Sstevel case SYS_V5_AUX_INDEX: ps = " Auxiliary 5.0v"; break;
1697*1708Sstevel case SYS_V5_P_PCH_INDEX: ps =
1698*1708Sstevel " Peripheral 5.0v precharge";
1699*1708Sstevel break;
1700*1708Sstevel case SYS_V12_P_PCH_INDEX: ps =
1701*1708Sstevel " Peripheral 12v precharge";
1702*1708Sstevel break;
1703*1708Sstevel case SYS_V3_PCH_INDEX: ps =
1704*1708Sstevel " System 3.3v precharge"; break;
1705*1708Sstevel case SYS_V5_PCH_INDEX: ps =
1706*1708Sstevel " System 5.0v precharge"; break;
1707*1708Sstevel
1708*1708Sstevel /* skip the peripheral fan here */
1709*1708Sstevel case SYS_P_FAN_INDEX:
1710*1708Sstevel continue;
1711*1708Sstevel }
1712*1708Sstevel
1713*1708Sstevel /* what is the state? */
1714*1708Sstevel switch (kstats->ps_shadow[i]) {
1715*1708Sstevel case PS_OK:
1716*1708Sstevel state = "OK";
1717*1708Sstevel break;
1718*1708Sstevel
1719*1708Sstevel case PS_FAIL:
1720*1708Sstevel state = "FAIL";
1721*1708Sstevel exit_code = 1;
1722*1708Sstevel break;
1723*1708Sstevel
1724*1708Sstevel /* XXX is this an exit_code condition? */
1725*1708Sstevel case PS_OUT:
1726*1708Sstevel state = "PPS Out";
1727*1708Sstevel exit_code = 1;
1728*1708Sstevel break;
1729*1708Sstevel
1730*1708Sstevel case PS_UNKNOWN:
1731*1708Sstevel state = "Unknown";
1732*1708Sstevel break;
1733*1708Sstevel
1734*1708Sstevel default:
1735*1708Sstevel state = "Illegal State";
1736*1708Sstevel break;
1737*1708Sstevel }
1738*1708Sstevel
1739*1708Sstevel log_printf("%-32s %s\n", ps, state, 0);
1740*1708Sstevel }
1741*1708Sstevel }
1742*1708Sstevel
1743*1708Sstevel /* Check status of the system AC Power Source */
1744*1708Sstevel log_printf("%-32s ", "AC Power", 0);
1745*1708Sstevel if ((kstats->sysstat2 & SYS_AC_FAIL) == 0) {
1746*1708Sstevel log_printf("OK\n", 0);
1747*1708Sstevel } else {
1748*1708Sstevel log_printf("failed\n", 0);
1749*1708Sstevel exit_code = 1;
1750*1708Sstevel }
1751*1708Sstevel log_printf("\n", 0);
1752*1708Sstevel
1753*1708Sstevel return (exit_code);
1754*1708Sstevel }
1755*1708Sstevel
1756*1708Sstevel
1757*1708Sstevel /*
1758*1708Sstevel * Many of the ASICs present in fusion machines have implementation and
1759*1708Sstevel * version numbers stored in the OBP device tree. These codes are displayed
1760*1708Sstevel * in this routine in an effort to aid Engineering and Field service
1761*1708Sstevel * in detecting old ASICs which may have bugs in them.
1762*1708Sstevel */
1763*1708Sstevel static void
sunfire_disp_asic_revs(Sys_tree * tree,struct system_kstat_data * kstats)1764*1708Sstevel sunfire_disp_asic_revs(Sys_tree *tree, struct system_kstat_data *kstats)
1765*1708Sstevel {
1766*1708Sstevel Board_node *bnode;
1767*1708Sstevel Prom_node *pnode;
1768*1708Sstevel int isplusbrd;
1769*1708Sstevel char *board_str[] = { "Uninitialized", "Unknown", "CPU",
1770*1708Sstevel "Memory", "Dual-SBus", "UPA-SBus",
1771*1708Sstevel "Dual-PCI", "Disk", "Clock",
1772*1708Sstevel "Dual-SBus-SOC+", "UPA-SBus-SOC+"};
1773*1708Sstevel
1774*1708Sstevel /* Print the header */
1775*1708Sstevel log_printf("\n", 0);
1776*1708Sstevel log_printf("=========================", 0);
1777*1708Sstevel log_printf(" HW Revisions ", 0);
1778*1708Sstevel log_printf("=========================", 0);
1779*1708Sstevel log_printf("\n", 0);
1780*1708Sstevel log_printf("\n", 0);
1781*1708Sstevel
1782*1708Sstevel /* Else this is a Sunfire or campfire */
1783*1708Sstevel log_printf("ASIC Revisions:\n", 0);
1784*1708Sstevel log_printf("---------------\n", 0);
1785*1708Sstevel
1786*1708Sstevel /* Display Firetruck ASIC Revisions first */
1787*1708Sstevel log_printf("Brd FHC AC SBus0 SBus1 PCI0 PCI1 FEPS", 0);
1788*1708Sstevel log_printf(" Board Type Attributes", 0);
1789*1708Sstevel log_printf("\n", 0);
1790*1708Sstevel log_printf("--- --- -- ----- ----- ---- ---- ----", 0);
1791*1708Sstevel log_printf(" ---------- ----------", 0);
1792*1708Sstevel log_printf("\n", 0);
1793*1708Sstevel
1794*1708Sstevel /*
1795*1708Sstevel * Display all of the FHC, AC, and chip revisions for the entire
1796*1708Sstevel * machine. The AC anf FHC chip revs are available from the device
1797*1708Sstevel * tree that was read out of the PROM, but the DC chip revs will be
1798*1708Sstevel * read via a kstat. The interfaces for this are not completely
1799*1708Sstevel * available at this time.
1800*1708Sstevel */
1801*1708Sstevel bnode = tree->bd_list;
1802*1708Sstevel while (bnode != NULL) {
1803*1708Sstevel int *version;
1804*1708Sstevel int upa = bd_to_upa(bnode->board_num);
1805*1708Sstevel
1806*1708Sstevel /* Display the header with the board number */
1807*1708Sstevel log_printf("%2d ", bnode->board_num, 0);
1808*1708Sstevel
1809*1708Sstevel /* display the FHC version */
1810*1708Sstevel if ((pnode = dev_find_node(bnode->nodes, "fhc")) == NULL) {
1811*1708Sstevel log_printf(" ", 0);
1812*1708Sstevel } else {
1813*1708Sstevel if ((version = (int *)get_prop_val(find_prop(pnode,
1814*1708Sstevel "version#"))) == NULL) {
1815*1708Sstevel log_printf(" ", 0);
1816*1708Sstevel } else {
1817*1708Sstevel log_printf(" %d ", *version, 0);
1818*1708Sstevel }
1819*1708Sstevel }
1820*1708Sstevel
1821*1708Sstevel /* display the AC version */
1822*1708Sstevel if ((pnode = dev_find_node(bnode->nodes, "ac")) == NULL) {
1823*1708Sstevel log_printf(" ", 0);
1824*1708Sstevel } else {
1825*1708Sstevel if ((version = (int *)get_prop_val(find_prop(pnode,
1826*1708Sstevel "version#"))) == NULL) {
1827*1708Sstevel log_printf(" ", 0);
1828*1708Sstevel } else {
1829*1708Sstevel log_printf(" %d ", *version, 0);
1830*1708Sstevel }
1831*1708Sstevel }
1832*1708Sstevel
1833*1708Sstevel /* Find sysio 0 on board and print rev */
1834*1708Sstevel if ((pnode = find_device(bnode, upa, "sbus")) == NULL) {
1835*1708Sstevel log_printf(" ", 0);
1836*1708Sstevel } else {
1837*1708Sstevel if ((version = (int *)get_prop_val(find_prop(pnode,
1838*1708Sstevel "version#"))) == NULL) {
1839*1708Sstevel log_printf(" ", 0);
1840*1708Sstevel } else {
1841*1708Sstevel log_printf(" %d ", *version, 0);
1842*1708Sstevel }
1843*1708Sstevel }
1844*1708Sstevel
1845*1708Sstevel /* Find sysio 1 on board and print rev */
1846*1708Sstevel if ((pnode = find_device(bnode, upa+1, "sbus")) == NULL) {
1847*1708Sstevel log_printf(" ", 0);
1848*1708Sstevel } else {
1849*1708Sstevel if ((version = (int *)get_prop_val(find_prop(pnode,
1850*1708Sstevel "version#"))) == NULL) {
1851*1708Sstevel log_printf(" ", 0);
1852*1708Sstevel } else {
1853*1708Sstevel log_printf(" %d ", *version, 0);
1854*1708Sstevel }
1855*1708Sstevel }
1856*1708Sstevel
1857*1708Sstevel /* Find Psycho 0 on board and print rev */
1858*1708Sstevel if ((pnode = find_device(bnode, upa, "pci")) == NULL) {
1859*1708Sstevel log_printf(" ", 0);
1860*1708Sstevel } else {
1861*1708Sstevel if ((version = (int *)get_prop_val(find_prop(pnode,
1862*1708Sstevel "version#"))) == NULL) {
1863*1708Sstevel log_printf(" ", 0);
1864*1708Sstevel } else {
1865*1708Sstevel log_printf(" %d ", *version, 0);
1866*1708Sstevel }
1867*1708Sstevel }
1868*1708Sstevel
1869*1708Sstevel /* Find Psycho 1 on board and print rev */
1870*1708Sstevel if ((pnode = find_device(bnode, upa+1, "pci")) == NULL) {
1871*1708Sstevel log_printf(" ", 0);
1872*1708Sstevel } else {
1873*1708Sstevel if ((version = (int *)get_prop_val(find_prop(pnode,
1874*1708Sstevel "version#"))) == NULL) {
1875*1708Sstevel log_printf(" ", 0);
1876*1708Sstevel } else {
1877*1708Sstevel log_printf(" %d ", *version, 0);
1878*1708Sstevel }
1879*1708Sstevel }
1880*1708Sstevel
1881*1708Sstevel /* Find the FEPS on board and print rev */
1882*1708Sstevel if ((pnode = dev_find_node(bnode->nodes, "SUNW,hme")) != NULL) {
1883*1708Sstevel if ((version = (int *)get_prop_val(find_prop(pnode,
1884*1708Sstevel "hm-rev"))) != NULL) {
1885*1708Sstevel if (*version == 0xa0) {
1886*1708Sstevel log_printf(" 2.0 ", 0);
1887*1708Sstevel } else if (*version == 0x20) {
1888*1708Sstevel log_printf(" 2.1 ", 0);
1889*1708Sstevel } else {
1890*1708Sstevel log_printf(" %2x ", *version, 0);
1891*1708Sstevel }
1892*1708Sstevel }
1893*1708Sstevel } else
1894*1708Sstevel log_printf(" ", 0);
1895*1708Sstevel
1896*1708Sstevel /* print out the board type */
1897*1708Sstevel isplusbrd = ISPLUSBRD(kstats->bd_ksp_list
1898*1708Sstevel [bnode->board_num].fhc_bsr);
1899*1708Sstevel
1900*1708Sstevel log_printf("%-16s", board_str[bnode->board_type], 0);
1901*1708Sstevel if (isplusbrd)
1902*1708Sstevel log_printf("100MHz Capable", 0);
1903*1708Sstevel else
1904*1708Sstevel log_printf("84MHz Capable", 0);
1905*1708Sstevel
1906*1708Sstevel log_printf("\n", 0);
1907*1708Sstevel bnode = bnode->next;
1908*1708Sstevel }
1909*1708Sstevel log_printf("\n", 0);
1910*1708Sstevel
1911*1708Sstevel /* Now display the FFB board component revisions */
1912*1708Sstevel for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) {
1913*1708Sstevel display_ffb(bnode, 0);
1914*1708Sstevel }
1915*1708Sstevel }
1916*1708Sstevel
1917*1708Sstevel static void
display_hp_boards(struct system_kstat_data * kstats)1918*1708Sstevel display_hp_boards(struct system_kstat_data *kstats)
1919*1708Sstevel {
1920*1708Sstevel int i;
1921*1708Sstevel int j;
1922*1708Sstevel int hp_found = 0;
1923*1708Sstevel struct hp_info *hp;
1924*1708Sstevel char *state;
1925*1708Sstevel
1926*1708Sstevel for (i = 0, hp = &kstats->hp_info[0]; i < MAX_BOARDS; i++, hp++) {
1927*1708Sstevel if (!hp->kstat_ok) {
1928*1708Sstevel continue;
1929*1708Sstevel }
1930*1708Sstevel
1931*1708Sstevel hp_found = 1;
1932*1708Sstevel }
1933*1708Sstevel
1934*1708Sstevel /* return if there are no hotplug boards in the system. */
1935*1708Sstevel if (!hp_found) {
1936*1708Sstevel return;
1937*1708Sstevel }
1938*1708Sstevel
1939*1708Sstevel if (hp_found != 0) {
1940*1708Sstevel log_printf("\n", 0);
1941*1708Sstevel log_printf("Detached Boards\n", 0);
1942*1708Sstevel log_printf("===============\n", 0);
1943*1708Sstevel log_printf(" Slot State Type Info\n", 0);
1944*1708Sstevel log_printf(" ---- --------- ------ ----"
1945*1708Sstevel "-------------------------------------\n", 0);
1946*1708Sstevel }
1947*1708Sstevel
1948*1708Sstevel /* Display all detached boards */
1949*1708Sstevel for (i = 0, hp = &kstats->hp_info[0]; i < MAX_BOARDS; i++, hp++) {
1950*1708Sstevel struct cpu_info *cpu;
1951*1708Sstevel
1952*1708Sstevel if (hp->kstat_ok == 0) {
1953*1708Sstevel continue;
1954*1708Sstevel }
1955*1708Sstevel
1956*1708Sstevel
1957*1708Sstevel switch (hp->bd_info.state) {
1958*1708Sstevel case UNKNOWN_STATE:
1959*1708Sstevel state = "unknown";
1960*1708Sstevel break;
1961*1708Sstevel
1962*1708Sstevel case ACTIVE_STATE:
1963*1708Sstevel state = "active";
1964*1708Sstevel break;
1965*1708Sstevel
1966*1708Sstevel case LOWPOWER_STATE:
1967*1708Sstevel state = "low-power";
1968*1708Sstevel break;
1969*1708Sstevel
1970*1708Sstevel case HOTPLUG_STATE:
1971*1708Sstevel state = "hot-plug";
1972*1708Sstevel break;
1973*1708Sstevel
1974*1708Sstevel case DISABLED_STATE:
1975*1708Sstevel state = "disabled";
1976*1708Sstevel break;
1977*1708Sstevel
1978*1708Sstevel case FAILED_STATE:
1979*1708Sstevel state = "failed";
1980*1708Sstevel break;
1981*1708Sstevel
1982*1708Sstevel default:
1983*1708Sstevel state = "unknown";
1984*1708Sstevel break;
1985*1708Sstevel }
1986*1708Sstevel
1987*1708Sstevel log_printf(" %2d %9s ", i, state, 0);
1988*1708Sstevel
1989*1708Sstevel switch (hp->bd_info.type) {
1990*1708Sstevel case MEM_BOARD:
1991*1708Sstevel log_printf("%-14s ", MEM_BD_NAME, 0);
1992*1708Sstevel break;
1993*1708Sstevel
1994*1708Sstevel case CPU_BOARD:
1995*1708Sstevel log_printf("%-14s ", CPU_BD_NAME, 0);
1996*1708Sstevel
1997*1708Sstevel /* Cannot display CPU info for disabled boards */
1998*1708Sstevel if ((hp->bd_info.state == DISABLED_STATE) ||
1999*1708Sstevel (hp->bd_info.state == FAILED_STATE)) {
2000*1708Sstevel break;
2001*1708Sstevel }
2002*1708Sstevel
2003*1708Sstevel /* Display both CPUs if present */
2004*1708Sstevel cpu = &hp->bd_info.bd.cpu[0];
2005*1708Sstevel for (j = 0; j < 2; j++, cpu++) {
2006*1708Sstevel log_printf("CPU %d: ", j, 0);
2007*1708Sstevel /* Print the rated speed of the CPU. */
2008*1708Sstevel if (cpu->cpu_speed > 1) {
2009*1708Sstevel log_printf("%3d MHz", cpu->cpu_speed,
2010*1708Sstevel 0);
2011*1708Sstevel } else {
2012*1708Sstevel log_printf("no CPU ", 0);
2013*1708Sstevel continue;
2014*1708Sstevel }
2015*1708Sstevel
2016*1708Sstevel /* Display the size of the cache */
2017*1708Sstevel if (cpu->cache_size != 0) {
2018*1708Sstevel log_printf(" %0.1fM ",
2019*1708Sstevel (float)cpu->cache_size /
2020*1708Sstevel (float)(1024*1024), 0);
2021*1708Sstevel } else {
2022*1708Sstevel log_printf(" ", 0);
2023*1708Sstevel }
2024*1708Sstevel }
2025*1708Sstevel break;
2026*1708Sstevel
2027*1708Sstevel case IO_2SBUS_BOARD:
2028*1708Sstevel log_printf("%-14s ", IO_2SBUS_BD_NAME, 0);
2029*1708Sstevel break;
2030*1708Sstevel
2031*1708Sstevel case IO_2SBUS_SOCPLUS_BOARD:
2032*1708Sstevel log_printf("%-14s ", IO_2SBUS_SOCPLUS_BD_NAME, 0);
2033*1708Sstevel break;
2034*1708Sstevel
2035*1708Sstevel case IO_SBUS_FFB_BOARD:
2036*1708Sstevel log_printf("%-14s ", IO_SBUS_FFB_BD_NAME, 0);
2037*1708Sstevel switch (hp->bd_info.bd.io2.ffb_size) {
2038*1708Sstevel case FFB_SINGLE:
2039*1708Sstevel log_printf("Single buffered FFB", 0);
2040*1708Sstevel break;
2041*1708Sstevel
2042*1708Sstevel case FFB_DOUBLE:
2043*1708Sstevel log_printf("Double buffered FFB", 0);
2044*1708Sstevel break;
2045*1708Sstevel
2046*1708Sstevel case FFB_NOT_FOUND:
2047*1708Sstevel log_printf("No FFB installed", 0);
2048*1708Sstevel break;
2049*1708Sstevel
2050*1708Sstevel default:
2051*1708Sstevel log_printf("Illegal FFB size", 0);
2052*1708Sstevel break;
2053*1708Sstevel }
2054*1708Sstevel break;
2055*1708Sstevel
2056*1708Sstevel case IO_SBUS_FFB_SOCPLUS_BOARD:
2057*1708Sstevel log_printf("%-14s ", IO_SBUS_FFB_SOCPLUS_BD_NAME, 0);
2058*1708Sstevel switch (hp->bd_info.bd.io2.ffb_size) {
2059*1708Sstevel case FFB_SINGLE:
2060*1708Sstevel log_printf("Single buffered FFB", 0);
2061*1708Sstevel break;
2062*1708Sstevel
2063*1708Sstevel case FFB_DOUBLE:
2064*1708Sstevel log_printf("Double buffered FFB", 0);
2065*1708Sstevel break;
2066*1708Sstevel
2067*1708Sstevel case FFB_NOT_FOUND:
2068*1708Sstevel log_printf("No FFB installed", 0);
2069*1708Sstevel break;
2070*1708Sstevel
2071*1708Sstevel default:
2072*1708Sstevel log_printf("Illegal FFB size", 0);
2073*1708Sstevel break;
2074*1708Sstevel }
2075*1708Sstevel break;
2076*1708Sstevel
2077*1708Sstevel case IO_PCI_BOARD:
2078*1708Sstevel log_printf("%-14s ", IO_PCI_BD_NAME, 0);
2079*1708Sstevel break;
2080*1708Sstevel
2081*1708Sstevel case DISK_BOARD:
2082*1708Sstevel log_printf("%-14s ", "disk", 0);
2083*1708Sstevel for (j = 0; j < 2; j++) {
2084*1708Sstevel log_printf("Disk %d:", j, 0);
2085*1708Sstevel if (hp->bd_info.bd.dsk.disk_pres[j]) {
2086*1708Sstevel log_printf(" Target: %2d ",
2087*1708Sstevel hp->bd_info.bd.dsk.disk_id[j],
2088*1708Sstevel 0);
2089*1708Sstevel } else {
2090*1708Sstevel log_printf(" no disk ", 0);
2091*1708Sstevel }
2092*1708Sstevel }
2093*1708Sstevel break;
2094*1708Sstevel
2095*1708Sstevel case UNKNOWN_BOARD:
2096*1708Sstevel case UNINIT_BOARD:
2097*1708Sstevel default:
2098*1708Sstevel log_printf("UNKNOWN ", 0);
2099*1708Sstevel break;
2100*1708Sstevel }
2101*1708Sstevel log_printf("\n");
2102*1708Sstevel }
2103*1708Sstevel }
2104*1708Sstevel
2105*1708Sstevel /*
2106*1708Sstevel * Analysis functions:
2107*1708Sstevel *
2108*1708Sstevel * Most of the Fatal error data analyzed from error registers is not
2109*1708Sstevel * very complicated. This is because the FRUs for errors detected by
2110*1708Sstevel * most parts is either a CPU module, a FFB, or the system board
2111*1708Sstevel * itself.
2112*1708Sstevel * The analysis of the Address Controller errors is the most complicated.
2113*1708Sstevel * These errors can be caused by other boards as well as the local board.
2114*1708Sstevel */
2115*1708Sstevel
2116*1708Sstevel /*
2117*1708Sstevel * analyze_cpu
2118*1708Sstevel *
2119*1708Sstevel * Analyze the CPU MFSR passed in and determine what type of fatal
2120*1708Sstevel * hardware errors occurred at the time of the crash. This function
2121*1708Sstevel * returns a pointer to a string to the calling routine.
2122*1708Sstevel */
2123*1708Sstevel static int
analyze_cpu(char ** msgs,int cpu_id,u_longlong_t afsr)2124*1708Sstevel analyze_cpu(char **msgs, int cpu_id, u_longlong_t afsr)
2125*1708Sstevel {
2126*1708Sstevel int count = 0;
2127*1708Sstevel int i;
2128*1708Sstevel int syndrome;
2129*1708Sstevel char msgbuf[MAXSTRLEN];
2130*1708Sstevel
2131*1708Sstevel if (msgs == NULL) {
2132*1708Sstevel return (count);
2133*1708Sstevel }
2134*1708Sstevel
2135*1708Sstevel if (afsr & P_AFSR_ETP) {
2136*1708Sstevel (void) sprintf(msgbuf, "CPU %d Ecache Tag Parity Error, ",
2137*1708Sstevel cpu_id);
2138*1708Sstevel
2139*1708Sstevel /* extract syndrome for afsr */
2140*1708Sstevel syndrome = (afsr & P_AFSR_ETS) >> ETS_SHIFT;
2141*1708Sstevel
2142*1708Sstevel /* now concat the parity syndrome msg */
2143*1708Sstevel for (i = 0; i < 4; i++) {
2144*1708Sstevel if ((0x1 << i) & syndrome) {
2145*1708Sstevel (void) strcat(msgbuf, ecache_parity[i]);
2146*1708Sstevel }
2147*1708Sstevel }
2148*1708Sstevel (void) strcat(msgbuf, "\n");
2149*1708Sstevel *msgs++ = strdup(msgbuf);
2150*1708Sstevel count++;
2151*1708Sstevel }
2152*1708Sstevel
2153*1708Sstevel if (afsr & P_AFSR_ISAP) {
2154*1708Sstevel (void) sprintf(msgbuf,
2155*1708Sstevel "CPU %d Incoming System Address Parity Error\n",
2156*1708Sstevel cpu_id);
2157*1708Sstevel *msgs++ = strdup(msgbuf);
2158*1708Sstevel count++;
2159*1708Sstevel }
2160*1708Sstevel
2161*1708Sstevel return (count);
2162*1708Sstevel }
2163*1708Sstevel
2164*1708Sstevel /*
2165*1708Sstevel * analyze_ac
2166*1708Sstevel *
2167*1708Sstevel * This function checks the AC error register passed in and checks
2168*1708Sstevel * for any errors that occured during the fatal hardware reset.
2169*1708Sstevel */
2170*1708Sstevel static int
analyze_ac(char ** msgs,u_longlong_t ac_error)2171*1708Sstevel analyze_ac(char **msgs, u_longlong_t ac_error)
2172*1708Sstevel {
2173*1708Sstevel int i;
2174*1708Sstevel int count = 0;
2175*1708Sstevel char msgbuf[MAXSTRLEN];
2176*1708Sstevel int tmp_cnt;
2177*1708Sstevel
2178*1708Sstevel if (msgs == NULL) {
2179*1708Sstevel return (count);
2180*1708Sstevel }
2181*1708Sstevel
2182*1708Sstevel for (i = 2; i < MAX_BITS; i++) {
2183*1708Sstevel if ((((u_longlong_t)0x1 << i) & ac_error) != 0) {
2184*1708Sstevel if (ac_errors[i].error != NULL) {
2185*1708Sstevel (void) sprintf(msgbuf, "AC: %s\n",
2186*1708Sstevel ac_errors[i].error);
2187*1708Sstevel *msgs++ = strdup(msgbuf);
2188*1708Sstevel count++;
2189*1708Sstevel
2190*1708Sstevel /* display the part that might cause this */
2191*1708Sstevel tmp_cnt = disp_parts(msgs, ac_error, i);
2192*1708Sstevel count += tmp_cnt;
2193*1708Sstevel msgs += tmp_cnt;
2194*1708Sstevel }
2195*1708Sstevel }
2196*1708Sstevel }
2197*1708Sstevel
2198*1708Sstevel return (count);
2199*1708Sstevel }
2200*1708Sstevel
2201*1708Sstevel /*
2202*1708Sstevel * analyze_dc
2203*1708Sstevel *
2204*1708Sstevel * This routine checks the DC shdow chain and tries to determine
2205*1708Sstevel * what type of error might have caused the fatal hardware reset
2206*1708Sstevel * error.
2207*1708Sstevel */
2208*1708Sstevel static int
analyze_dc(int board,char ** msgs,u_longlong_t dc_error)2209*1708Sstevel analyze_dc(int board, char **msgs, u_longlong_t dc_error)
2210*1708Sstevel {
2211*1708Sstevel int i;
2212*1708Sstevel int count = 0;
2213*1708Sstevel char msgbuf[MAXSTRLEN];
2214*1708Sstevel
2215*1708Sstevel if (msgs == NULL) {
2216*1708Sstevel return (count);
2217*1708Sstevel }
2218*1708Sstevel
2219*1708Sstevel /*
2220*1708Sstevel * The DC scan data is contained in 8 bytes, one byte per
2221*1708Sstevel * DC. There are 8 DCs on a system board.
2222*1708Sstevel */
2223*1708Sstevel
2224*1708Sstevel for (i = 0; i < 8; i++) {
2225*1708Sstevel if (dc_error & DC_OVERFLOW) {
2226*1708Sstevel (void) sprintf(msgbuf, dc_overflow_txt, board, i);
2227*1708Sstevel *msgs++ = strdup(msgbuf);
2228*1708Sstevel count++;
2229*1708Sstevel }
2230*1708Sstevel
2231*1708Sstevel if (dc_error & DC_PARITY) {
2232*1708Sstevel (void) sprintf(msgbuf, dc_parity_txt, board, i);
2233*1708Sstevel *msgs++ = strdup(msgbuf);
2234*1708Sstevel count++;
2235*1708Sstevel }
2236*1708Sstevel dc_error = dc_error >> 8; /* shift over to next byte */
2237*1708Sstevel }
2238*1708Sstevel
2239*1708Sstevel return (count);
2240*1708Sstevel }
2241*1708Sstevel
2242*1708Sstevel static int
disp_parts(char ** msgs,u_longlong_t ac_error,int type)2243*1708Sstevel disp_parts(char **msgs, u_longlong_t ac_error, int type)
2244*1708Sstevel {
2245*1708Sstevel int count = 0;
2246*1708Sstevel int part;
2247*1708Sstevel char msgbuf[MAXSTRLEN];
2248*1708Sstevel int i;
2249*1708Sstevel
2250*1708Sstevel if (msgs == NULL) {
2251*1708Sstevel return (count);
2252*1708Sstevel }
2253*1708Sstevel
2254*1708Sstevel (void) sprintf(msgbuf, "\tThe error could be caused by:\n");
2255*1708Sstevel *msgs++ = strdup(msgbuf);
2256*1708Sstevel count++;
2257*1708Sstevel
2258*1708Sstevel for (i = 0; (i < MAX_FRUS) && ac_errors[type].part[i]; i++) {
2259*1708Sstevel part = ac_errors[type].part[i];
2260*1708Sstevel
2261*1708Sstevel if (part == UPA_PART) {
2262*1708Sstevel if (ac_error & UPA_PORT_A) {
2263*1708Sstevel part = UPA_A_PART;
2264*1708Sstevel } else if (ac_error & UPA_PORT_B) {
2265*1708Sstevel part = UPA_B_PART;
2266*1708Sstevel }
2267*1708Sstevel }
2268*1708Sstevel
2269*1708Sstevel if (part == DTAG_PART) {
2270*1708Sstevel if (ac_error & UPA_PORT_A) {
2271*1708Sstevel part = DTAG_A_PART;
2272*1708Sstevel } else if (ac_error & UPA_PORT_B) {
2273*1708Sstevel part = DTAG_B_PART;
2274*1708Sstevel }
2275*1708Sstevel }
2276*1708Sstevel
2277*1708Sstevel (void) sprintf(msgbuf, "\t\t%s\n", part_str[part]);
2278*1708Sstevel
2279*1708Sstevel *msgs++ = strdup(msgbuf);
2280*1708Sstevel count++;
2281*1708Sstevel }
2282*1708Sstevel
2283*1708Sstevel return (count);
2284*1708Sstevel }
2285