make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / arch / alpha / kernel / err_common.c
1 /*
2  *      linux/arch/alpha/kernel/err_common.c
3  *
4  *      Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
5  *
6  *      Error handling code supporting Alpha systems
7  */
8
9 #include <linux/init.h>
10 #include <linux/pci.h>
11 #include <linux/sched.h>
12
13 #include <asm/io.h>
14 #include <asm/hwrpb.h>
15 #include <asm/smp.h>
16
17 #include "err_impl.h"
18 #include "proto.h"
19
20 /*
21  * err_print_prefix -- error handling print routines should prefix
22  * all prints with this
23  */
24 char *err_print_prefix = KERN_NOTICE;
25
26 /*
27  * Forward references
28  */
29 static void el_print_timestamp(union el_timestamp);
30 static void el_process_subpackets(struct el_subpacket *, int);
31
32 \f
33 /*
34  * Generic
35  */
36 void
37 mchk_dump_mem(void *data, size_t length, char **annotation)
38 {
39         unsigned long *ldata = data;
40         size_t i;
41         
42         for (i = 0; (i * sizeof(*ldata)) < length; i++) {
43                 if (annotation && !annotation[i]) 
44                         annotation = NULL;
45                 printk("%s    %08x: %016lx    %s\n",
46                        err_print_prefix,
47                        (unsigned)(i * sizeof(*ldata)), ldata[i],
48                        annotation ? annotation[i] : "");
49         }
50 }
51
52 void
53 mchk_dump_logout_frame(struct el_common *mchk_header)
54 {
55         printk("%s  -- Frame Header --\n"
56                  "    Frame Size:   %d (0x%x) bytes\n"
57                  "    Flags:        %s%s\n"
58                  "    MCHK Code:    0x%x\n"
59                  "    Frame Rev:    %d\n"
60                  "    Proc Offset:  0x%08x\n"
61                  "    Sys Offset:   0x%08x\n"
62                  "  -- Processor Region --\n",
63                err_print_prefix, 
64                mchk_header->size, mchk_header->size,
65                mchk_header->retry ? "RETRY " : "", 
66                  mchk_header->err2 ? "SECOND_ERR " : "",
67                mchk_header->code,
68                mchk_header->frame_rev,
69                mchk_header->proc_offset,
70                mchk_header->sys_offset);
71
72         mchk_dump_mem((void *)
73                       ((unsigned long)mchk_header + mchk_header->proc_offset),
74                       mchk_header->sys_offset - mchk_header->proc_offset,
75                       NULL);
76         
77         printk("%s  -- System Region --\n", err_print_prefix);
78         mchk_dump_mem((void *)
79                       ((unsigned long)mchk_header + mchk_header->sys_offset),
80                       mchk_header->size - mchk_header->sys_offset,
81                       NULL);
82         printk("%s  -- End of Frame --\n", err_print_prefix);
83 }
84
85 \f
86 /*
87  * EV7 generic
88  */
89 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV7)
90
91 void
92 ev7_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
93 {
94         /*
95          * Sync the processor
96          */
97         mb();
98         draina();
99
100         /*
101          * Parse the logout frame without printing first. If the only error(s)
102          * found are have a disposition of "dismiss", then just dismiss them
103          * and don't print any message
104          */
105         printk("%sEV7 MACHINE CHECK vector %lx\n", err_print_prefix, vector);
106
107         /* 
108          * Release the logout frame 
109          */
110         wrmces(0x7);
111         mb();
112 }
113
114 struct ev7_pal_subpacket {
115         union {
116                 struct {
117                         u32 mchk_code;
118                         u32 subpacket_count;
119                         u64 whami;
120                         u64 rbox_whami;
121                         u64 rbox_int;
122                         u64 exc_addr;
123                         union el_timestamp timestamp;
124                         u64 halt_code;
125                         u64 reserved;
126                 } logout;
127         } by_type;
128 };
129
130 static char *el_ev7_processor_subpacket_annotation[] = {
131         "Subpacket Header",     "I_STAT",       "DC_STAT",
132         "C_ADDR",               "C_SYNDROME_1", "C_SYNDROME_0",
133         "C_STAT",               "C_STS",        "MM_STAT",
134         "EXC_ADDR",             "IER_CM",       "ISUM",
135         "PAL_BASE",             "I_CTL",        "PROCESS_CONTEXT",
136         "CBOX_CTL",             "CBOX_STP_CTL", "CBOX_ACC_CTL",
137         "CBOX_LCL_SET",         "CBOX_GLB_SET", "BBOX_CTL",
138         "BBOX_ERR_STS",         "BBOX_ERR_IDX", "CBOX_DDP_ERR_STS",
139         "BBOX_DAT_RMP",         NULL
140 };
141
142 static char *el_ev7_zbox_subpacket_annotation[] = {
143         "Subpacket Header",     
144         "ZBOX(0): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
145         "ZBOX(0): DRAM_ERROR_CTL    / DRAM_ERR_STATUS_3",
146         "ZBOX(0): DIFT_TIMEOUT      / DRAM_ERR_ADR",
147         "ZBOX(0): FRC_ERR_ADR       / DRAM_MAPPER_CTL",
148         "ZBOX(0): reserved          / DIFT_ERR_STATUS",
149         "ZBOX(1): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
150         "ZBOX(1): DRAM_ERROR_CTL    / DRAM_ERR_STATUS_3",
151         "ZBOX(1): DIFT_TIMEOUT      / DRAM_ERR_ADR",
152         "ZBOX(1): FRC_ERR_ADR       / DRAM_MAPPER_CTL",
153         "ZBOX(1): reserved          / DIFT_ERR_STATUS",
154         "CBOX_CTL",             "CBOX_STP_CTL",
155         "ZBOX(0)_ERROR_PA",     "ZBOX(1)_ERROR_PA",
156         "ZBOX(0)_ORED_SYNDROME","ZBOX(1)_ORED_SYNDROME",
157         NULL
158 };
159
160 static char *el_ev7_rbox_subpacket_annotation[] = {
161         "Subpacket Header",     "RBOX_CFG",     "RBOX_N_CFG",
162         "RBOX_S_CFG",           "RBOX_E_CFG",   "RBOX_W_CFG",
163         "RBOX_N_ERR",           "RBOX_S_ERR",   "RBOX_E_ERR",
164         "RBOX_W_ERR",           "RBOX_IO_CFG",  "RBOX_IO_ERR",
165         "RBOX_L_ERR",           "RBOX_WHOAMI",  "RBOX_IMASL",
166         "RBOX_INTQ",            "RBOX_INT",     NULL
167 };
168
169 static char *el_ev7_io_subpacket_annotation[] = {
170         "Subpacket Header",     "IO_ASIC_REV",  "IO_SYS_REV",
171         "IO7_UPH",              "HPI_CTL",      "CRD_CTL",
172         "HEI_CTL",              "PO7_ERROR_SUM","PO7_UNCRR_SYM",
173         "PO7_CRRCT_SYM",        "PO7_UGBGE_SYM","PO7_ERR_PKT0",
174         "PO7_ERR_PKT1",         "reserved",     "reserved",
175         "PO0_ERR_SUM",          "PO0_TLB_ERR",  "PO0_SPL_COMPLT",
176         "PO0_TRANS_SUM",        "PO0_FIRST_ERR","PO0_MULT_ERR",
177         "DM CSR PH",            "DM CSR PH",    "DM CSR PH",
178         "DM CSR PH",            "reserved",
179         "PO1_ERR_SUM",          "PO1_TLB_ERR",  "PO1_SPL_COMPLT",
180         "PO1_TRANS_SUM",        "PO1_FIRST_ERR","PO1_MULT_ERR",
181         "DM CSR PH",            "DM CSR PH",    "DM CSR PH",
182         "DM CSR PH",            "reserved",
183         "PO2_ERR_SUM",          "PO2_TLB_ERR",  "PO2_SPL_COMPLT",
184         "PO2_TRANS_SUM",        "PO2_FIRST_ERR","PO2_MULT_ERR",
185         "DM CSR PH",            "DM CSR PH",    "DM CSR PH",
186         "DM CSR PH",            "reserved",
187         "PO3_ERR_SUM",          "PO3_TLB_ERR",  "PO3_SPL_COMPLT",
188         "PO3_TRANS_SUM",        "PO3_FIRST_ERR","PO3_MULT_ERR",
189         "DM CSR PH",            "DM CSR PH",    "DM CSR PH",
190         "DM CSR PH",            "reserved",     
191         NULL
192 };
193         
194 static struct el_subpacket_annotation el_ev7_pal_annotations[] = {
195         SUBPACKET_ANNOTATION(EL_CLASS__PAL,
196                              EL_TYPE__PAL__EV7_PROCESSOR,
197                              1,
198                              "EV7 Processor Subpacket",
199                              el_ev7_processor_subpacket_annotation),
200         SUBPACKET_ANNOTATION(EL_CLASS__PAL,
201                              EL_TYPE__PAL__EV7_ZBOX,
202                              1,
203                              "EV7 ZBOX Subpacket",
204                              el_ev7_zbox_subpacket_annotation),
205         SUBPACKET_ANNOTATION(EL_CLASS__PAL,
206                              EL_TYPE__PAL__EV7_RBOX,
207                              1,
208                              "EV7 RBOX Subpacket",
209                              el_ev7_rbox_subpacket_annotation),
210         SUBPACKET_ANNOTATION(EL_CLASS__PAL,
211                              EL_TYPE__PAL__EV7_IO,
212                              1,
213                              "EV7 IO Subpacket",
214                              el_ev7_io_subpacket_annotation)
215 };
216
217 static struct el_subpacket *
218 ev7_process_pal_subpacket(struct el_subpacket *header)
219 {
220         struct ev7_pal_subpacket *packet;
221
222         if (header->class != EL_CLASS__PAL) {
223                 printk("%s  ** Unexpected header CLASS %d TYPE %d, aborting\n",
224                        err_print_prefix,
225                        header->class, header->type);
226                 return NULL;
227         }
228
229         packet = (struct ev7_pal_subpacket *)header->by_type.raw.data_start;
230
231         switch(header->type) {
232         case EL_TYPE__PAL__LOGOUT_FRAME:
233                 printk("%s*** MCHK occurred on LPID %ld (RBOX %lx)\n",
234                        err_print_prefix,
235                        packet->by_type.logout.whami, 
236                        packet->by_type.logout.rbox_whami);
237                 el_print_timestamp(packet->by_type.logout.timestamp);
238                 printk("%s  EXC_ADDR: %016lx\n"
239                          "  HALT_CODE: %lx\n", 
240                        err_print_prefix,
241                        packet->by_type.logout.exc_addr,
242                        packet->by_type.logout.halt_code);
243                 el_process_subpackets(header,
244                                       packet->by_type.logout.subpacket_count);
245                 break;
246         default:
247                 printk("%s  ** PAL TYPE %d SUBPACKET\n", 
248                        err_print_prefix,
249                        header->type);
250                 el_annotate_subpacket(header);
251                 break;
252         }
253         
254         return (struct el_subpacket *)((unsigned long)header + header->length);
255 }
256
257 struct el_subpacket_handler ev7_pal_subpacket_handler =
258         SUBPACKET_HANDLER_INIT(EL_CLASS__PAL, ev7_process_pal_subpacket);
259
260 void 
261 ev7_register_error_handlers(void)
262 {
263         int i;
264
265         for(i = 0;
266             i<sizeof(el_ev7_pal_annotations)/sizeof(el_ev7_pal_annotations[1]);
267             i++) {
268                 cdl_register_subpacket_annotation(&el_ev7_pal_annotations[i]);
269         }       
270         cdl_register_subpacket_handler(&ev7_pal_subpacket_handler);
271 }
272
273 #endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_EV7 */
274
275 \f
276 /*
277  * EV6 generic
278  */
279
280 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV6)
281
282 static int
283 ev6_parse_ibox(u64 i_stat, int print)
284 {
285         int status = MCHK_DISPOSITION_REPORT;
286
287 #define EV6__I_STAT__PAR        (1UL << 29)
288 #define EV6__I_STAT__ERRMASK    (EV6__I_STAT__PAR)
289
290         if (!(i_stat & EV6__I_STAT__ERRMASK))
291                 return MCHK_DISPOSITION_UNKNOWN_ERROR;
292
293         if (!print)
294                 return status;
295
296         if (i_stat & EV6__I_STAT__PAR)
297                 printk("%s    Icache parity error\n", err_print_prefix);
298
299         return status;
300 }
301
302 static int
303 ev6_parse_mbox(u64 mm_stat, u64 d_stat, u64 c_stat, int print)
304 {
305         int status = MCHK_DISPOSITION_REPORT;
306
307 #define EV6__MM_STAT__DC_TAG_PERR       (1UL << 10)
308 #define EV6__MM_STAT__ERRMASK           (EV6__MM_STAT__DC_TAG_PERR)
309 #define EV6__D_STAT__TPERR_P0           (1UL << 0)
310 #define EV6__D_STAT__TPERR_P1           (1UL << 1)
311 #define EV6__D_STAT__ECC_ERR_ST         (1UL << 2)
312 #define EV6__D_STAT__ECC_ERR_LD         (1UL << 3)
313 #define EV6__D_STAT__SEO                (1UL << 4)
314 #define EV6__D_STAT__ERRMASK            (EV6__D_STAT__TPERR_P0 |        \
315                                          EV6__D_STAT__TPERR_P1 |        \
316                                          EV6__D_STAT__ECC_ERR_ST |      \
317                                          EV6__D_STAT__ECC_ERR_LD |      \
318                                          EV6__D_STAT__SEO)
319
320         if (!(d_stat & EV6__D_STAT__ERRMASK) && 
321             !(mm_stat & EV6__MM_STAT__ERRMASK))
322                 return MCHK_DISPOSITION_UNKNOWN_ERROR;
323
324         if (!print)
325                 return status;
326
327         if (mm_stat & EV6__MM_STAT__DC_TAG_PERR)
328                 printk("%s    Dcache tag parity error on probe\n",
329                        err_print_prefix);
330         if (d_stat & EV6__D_STAT__TPERR_P0)
331                 printk("%s    Dcache tag parity error - pipe 0\n",
332                        err_print_prefix);
333         if (d_stat & EV6__D_STAT__TPERR_P1)
334                 printk("%s    Dcache tag parity error - pipe 1\n",
335                        err_print_prefix);
336         if (d_stat & EV6__D_STAT__ECC_ERR_ST)
337                 printk("%s    ECC error occurred on a store\n", 
338                        err_print_prefix);
339         if (d_stat & EV6__D_STAT__ECC_ERR_LD)
340                 printk("%s    ECC error occurred on a %s load\n",
341                        err_print_prefix,
342                        c_stat ? "" : "speculative ");
343         if (d_stat & EV6__D_STAT__SEO)
344                 printk("%s    Dcache second error\n", err_print_prefix);
345
346         return status;
347 }
348
349 static int
350 ev6_parse_cbox(u64 c_addr, u64 c1_syn, u64 c2_syn, 
351                u64 c_stat, u64 c_sts, int print)
352 {
353         char *sourcename[] = { "UNKNOWN", "UNKNOWN", "UNKNOWN",
354                                "MEMORY", "BCACHE", "DCACHE", 
355                                "BCACHE PROBE", "BCACHE PROBE" };
356         char *streamname[] = { "D", "I" };
357         char *bitsname[] = { "SINGLE", "DOUBLE" };
358         int status = MCHK_DISPOSITION_REPORT;
359         int source = -1, stream = -1, bits = -1;
360
361 #define EV6__C_STAT__BC_PERR            (0x01)
362 #define EV6__C_STAT__DC_PERR            (0x02)
363 #define EV6__C_STAT__DSTREAM_MEM_ERR    (0x03)
364 #define EV6__C_STAT__DSTREAM_BC_ERR     (0x04)
365 #define EV6__C_STAT__DSTREAM_DC_ERR     (0x05)
366 #define EV6__C_STAT__PROBE_BC_ERR0      (0x06)  /* both 6 and 7 indicate... */
367 #define EV6__C_STAT__PROBE_BC_ERR1      (0x07)  /* ...probe bc error.       */
368 #define EV6__C_STAT__ISTREAM_MEM_ERR    (0x0B)
369 #define EV6__C_STAT__ISTREAM_BC_ERR     (0x0C)
370 #define EV6__C_STAT__DSTREAM_MEM_DBL    (0x13)
371 #define EV6__C_STAT__DSTREAM_BC_DBL     (0x14)
372 #define EV6__C_STAT__ISTREAM_MEM_DBL    (0x1B)
373 #define EV6__C_STAT__ISTREAM_BC_DBL     (0x1C)
374 #define EV6__C_STAT__SOURCE_MEMORY      (0x03)
375 #define EV6__C_STAT__SOURCE_BCACHE      (0x04)
376 #define EV6__C_STAT__SOURCE__S          (0)
377 #define EV6__C_STAT__SOURCE__M          (0x07)
378 #define EV6__C_STAT__ISTREAM__S         (3)
379 #define EV6__C_STAT__ISTREAM__M         (0x01)
380 #define EV6__C_STAT__DOUBLE__S          (4)
381 #define EV6__C_STAT__DOUBLE__M          (0x01)
382 #define EV6__C_STAT__ERRMASK            (0x1F)
383 #define EV6__C_STS__SHARED              (1 << 0)
384 #define EV6__C_STS__DIRTY               (1 << 1)
385 #define EV6__C_STS__VALID               (1 << 2)
386 #define EV6__C_STS__PARITY              (1 << 3)
387
388         if (!(c_stat & EV6__C_STAT__ERRMASK))
389                 return MCHK_DISPOSITION_UNKNOWN_ERROR;
390
391         if (!print)
392                 return status;
393
394         source = EXTRACT(c_stat, EV6__C_STAT__SOURCE);
395         stream = EXTRACT(c_stat, EV6__C_STAT__ISTREAM);
396         bits = EXTRACT(c_stat, EV6__C_STAT__DOUBLE);
397
398         if (c_stat & EV6__C_STAT__BC_PERR) {
399                 printk("%s    Bcache tag parity error\n", err_print_prefix);
400                 source = -1;
401         }
402
403         if (c_stat & EV6__C_STAT__DC_PERR) {
404                 printk("%s    Dcache tag parity error\n", err_print_prefix);
405                 source = -1;
406         }
407
408         if (c_stat == EV6__C_STAT__PROBE_BC_ERR0 ||
409             c_stat == EV6__C_STAT__PROBE_BC_ERR1) {
410                 printk("%s    Bcache single-bit error on a probe hit\n",
411                        err_print_prefix);
412                 source = -1;
413         }
414
415         if (source != -1) 
416                 printk("%s    %s-STREAM %s-BIT ECC error from %s\n",
417                        err_print_prefix,
418                        streamname[stream], bitsname[bits], sourcename[source]);
419
420         printk("%s    Address: 0x%016lx\n"
421                  "    Syndrome[upper.lower]: %02lx.%02lx\n", 
422                err_print_prefix,
423                c_addr,
424                c2_syn, c1_syn);
425
426         if (source == EV6__C_STAT__SOURCE_MEMORY ||
427             source == EV6__C_STAT__SOURCE_BCACHE) 
428                 printk("%s    Block status: %s%s%s%s\n",
429                        err_print_prefix,
430                        (c_sts & EV6__C_STS__SHARED) ? "SHARED " : "",
431                        (c_sts & EV6__C_STS__DIRTY)  ? "DIRTY "  : "",
432                        (c_sts & EV6__C_STS__VALID)  ? "VALID "  : "",
433                        (c_sts & EV6__C_STS__PARITY) ? "PARITY " : "");
434                 
435         return status;
436 }
437
438 int
439 ev6_process_logout_frame(struct el_common *mchk_header, int print)
440 {
441         struct el_common_EV6_mcheck *ev6mchk = 
442                 (struct el_common_EV6_mcheck *)mchk_header;
443         int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
444
445         status |= ev6_parse_ibox(ev6mchk->I_STAT, print);
446         status |= ev6_parse_mbox(ev6mchk->MM_STAT, ev6mchk->DC_STAT, 
447                                  ev6mchk->C_STAT, print);
448         status |= ev6_parse_cbox(ev6mchk->C_ADDR, ev6mchk->DC1_SYNDROME,
449                                  ev6mchk->DC0_SYNDROME, ev6mchk->C_STAT,
450                                  ev6mchk->C_STS, print);
451
452         if (!print)
453                 return status;
454
455         if (status != MCHK_DISPOSITION_DISMISS) {
456                 char *saved_err_prefix = err_print_prefix;
457
458                 /*
459                  * Dump some additional information from the frame
460                  */
461                 printk("%s    EXC_ADDR: 0x%016lx   IER_CM: 0x%016lx"
462                             "   ISUM: 0x%016lx\n"
463                          "    PAL_BASE: 0x%016lx   I_CTL:  0x%016lx"
464                             "   PCTX: 0x%016lx\n",
465                        err_print_prefix,
466                        ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM,
467                        ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX);
468
469                 if (status == MCHK_DISPOSITION_UNKNOWN_ERROR) {
470                         printk("%s    UNKNOWN error, frame follows:\n",
471                                err_print_prefix);
472                 } else {
473                         /* had decode -- downgrade print level for frame */
474                         err_print_prefix = KERN_NOTICE;
475                 }
476
477                 mchk_dump_logout_frame(mchk_header);
478
479                 err_print_prefix = saved_err_prefix;
480         }
481
482         return status;
483 }
484
485 void
486 ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
487 {
488         struct el_common *mchk_header = (struct el_common *)la_ptr;
489
490         /*
491          * Sync the processor
492          */
493         mb();
494         draina();
495
496         /*
497          * Parse the logout frame without printing first. If the only error(s)
498          * found are have a disposition of "dismiss", then just dismiss them
499          * and don't print any message
500          */
501         if (ev6_process_logout_frame(mchk_header, 0) != 
502             MCHK_DISPOSITION_DISMISS) {
503                 char *saved_err_prefix = err_print_prefix;
504                 err_print_prefix = KERN_CRIT;
505
506                 /*
507                  * Either a nondismissable error was detected or no
508                  * recognized error was detected  in the logout frame 
509                  * -- report the error in either case
510                  */
511                 printk("%s*CPU %s Error (Vector 0x%x) reported on CPU %d:\n", 
512                        err_print_prefix,
513                        (vector == SCB_Q_PROCERR)?"Correctable":"Uncorrectable",
514                        (unsigned int)vector, (int)smp_processor_id());
515                 
516                 ev6_process_logout_frame(mchk_header, 1);
517                 dik_show_regs(regs, NULL);
518
519                 err_print_prefix = saved_err_prefix;
520         }
521
522         /* 
523          * Release the logout frame 
524          */
525         wrmces(0x7);
526         mb();
527 }
528
529 #endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_EV6 */
530
531 \f
532 /*
533  * Console Data Log
534  */
535 /* Data */
536 static struct el_subpacket_handler *subpacket_handler_list = NULL;
537 static struct el_subpacket_annotation *subpacket_annotation_list = NULL;
538
539 static void
540 el_print_timestamp(union el_timestamp timestamp)
541 {
542         if (timestamp.as_int)
543                 printk("%s  TIMESTAMP: %d/%d/%02d %d:%02d:%0d\n", 
544                        err_print_prefix,
545                        timestamp.b.month, timestamp.b.day,
546                        timestamp.b.year, timestamp.b.hour,
547                        timestamp.b.minute, timestamp.b.second);
548 }
549
550 static struct el_subpacket *
551 el_process_header_subpacket(struct el_subpacket *header)
552 {
553         union el_timestamp timestamp;
554         char *name = "UNKNOWN EVENT";
555         int packet_count = 0;
556         int length = 0;
557
558         if (header->class != EL_CLASS__HEADER) {
559                 printk("%s** Unexpected header CLASS %d TYPE %d, aborting\n",
560                        err_print_prefix,
561                        header->class, header->type);
562                 return NULL;
563         }
564
565         switch(header->type) {
566         case EL_TYPE__HEADER__SYSTEM_ERROR_FRAME:
567                 name = "SYSTEM ERROR";
568                 length = header->by_type.sys_err.frame_length;
569                 packet_count = 
570                         header->by_type.sys_err.frame_packet_count;
571                 timestamp.as_int = 0;
572                 break;
573         case EL_TYPE__HEADER__SYSTEM_EVENT_FRAME:
574                 name = "SYSTEM EVENT";
575                 length = header->by_type.sys_event.frame_length;
576                 packet_count = 
577                         header->by_type.sys_event.frame_packet_count;
578                 timestamp = header->by_type.sys_event.timestamp;
579                 break;
580         case EL_TYPE__HEADER__HALT_FRAME:
581                 name = "ERROR HALT";
582                 length = header->by_type.err_halt.frame_length;
583                 packet_count = 
584                         header->by_type.err_halt.frame_packet_count;
585                 timestamp = header->by_type.err_halt.timestamp;
586                 break;
587         case EL_TYPE__HEADER__LOGOUT_FRAME:
588                 name = "LOGOUT FRAME";
589                 length = header->by_type.logout_header.frame_length;
590                 packet_count = 1;
591                 timestamp.as_int = 0;
592                 break;
593         default: /* Unknown */
594                 printk("%s** Unknown header - CLASS %d TYPE %d, aborting\n",
595                        err_print_prefix,
596                        header->class, header->type);
597                 return NULL;            
598         }
599
600         printk("%s*** %s:\n"
601                  "  CLASS %d, TYPE %d\n", 
602                err_print_prefix,
603                name,
604                header->class, header->type);
605         el_print_timestamp(timestamp);
606         
607         /*
608          * Process the subpackets
609          */
610         el_process_subpackets(header, packet_count);
611
612         /* return the next header */
613         header = (struct el_subpacket *)
614                 ((unsigned long)header + header->length + length);
615         return header;
616 }
617
618 static void
619 el_process_subpackets(struct el_subpacket *header, int packet_count)
620 {
621         struct el_subpacket *subpacket;
622         int i;
623
624         subpacket = (struct el_subpacket *)
625                 ((unsigned long)header + header->length);
626
627         for (i = 0; subpacket && i < packet_count; i++) {
628                 printk("%sPROCESSING SUBPACKET %d\n", err_print_prefix, i);
629                 subpacket = el_process_subpacket(subpacket);
630         }
631 }
632
633 static struct el_subpacket *
634 el_process_subpacket_reg(struct el_subpacket *header)
635 {
636         struct el_subpacket *next = NULL;
637         struct el_subpacket_handler *h = subpacket_handler_list;
638
639         for (; h && h->class != header->class; h = h->next);
640         if (h) next = h->handler(header);
641
642         return next;
643 }
644
645 struct el_subpacket *
646 el_process_subpacket(struct el_subpacket *header)
647 {
648         struct el_subpacket *next = NULL;
649
650         switch(header->class) {
651         case EL_CLASS__TERMINATION:
652                 /* Termination packet, there are no more */
653                 break;
654         case EL_CLASS__HEADER: 
655                 next = el_process_header_subpacket(header);
656                 break;
657         default:
658                 if (NULL == (next = el_process_subpacket_reg(header))) {
659                         printk("%s** Unexpected header CLASS %d TYPE %d"
660                                " -- aborting.\n",
661                                err_print_prefix,
662                                header->class, header->type);
663                 }
664                 break;
665         }
666
667         return next;
668 }
669
670 void 
671 el_annotate_subpacket(struct el_subpacket *header)
672 {
673         struct el_subpacket_annotation *a;
674         char **annotation = NULL;
675
676         for (a = subpacket_annotation_list; a; a = a->next) {
677                 if (a->class == header->class &&
678                     a->type == header->type &&
679                     a->revision == header->revision) {
680                         /*
681                          * We found the annotation
682                          */
683                         annotation = a->annotation;
684                         printk("%s  %s\n", err_print_prefix, a->description);
685                         break;
686                 }
687         }
688
689         mchk_dump_mem(header, header->length, annotation);
690 }
691
692 static void __init
693 cdl_process_console_data_log(int cpu, struct percpu_struct *pcpu)
694 {
695         struct el_subpacket *header = (struct el_subpacket *)
696                 (IDENT_ADDR | pcpu->console_data_log_pa);
697         int err;
698
699         printk("%s******* CONSOLE DATA LOG FOR CPU %d. *******\n"
700                  "*** Error(s) were logged on a previous boot\n",
701                err_print_prefix, cpu);
702         
703         for (err = 0; header && (header->class != EL_CLASS__TERMINATION); err++)
704                 header = el_process_subpacket(header);
705
706         /* let the console know it's ok to clear the error(s) at restart */
707         pcpu->console_data_log_pa = 0;
708
709         printk("%s*** %d total error(s) logged\n"
710                  "**** END OF CONSOLE DATA LOG FOR CPU %d ****\n", 
711                err_print_prefix, err, cpu);
712 }
713
714 void __init
715 cdl_check_console_data_log(void)
716 {
717         struct percpu_struct *pcpu;
718         unsigned long cpu;
719
720         for (cpu = 0; cpu < hwrpb->nr_processors; cpu++) {
721                 pcpu = (struct percpu_struct *)
722                         ((unsigned long)hwrpb + hwrpb->processor_offset 
723                          + cpu * hwrpb->processor_size);
724                 if (pcpu->console_data_log_pa)
725                         cdl_process_console_data_log(cpu, pcpu);
726         }
727
728 }
729
730 int __init
731 cdl_register_subpacket_annotation(struct el_subpacket_annotation *new)
732 {
733         struct el_subpacket_annotation *a = subpacket_annotation_list;
734
735         if (a == NULL) subpacket_annotation_list = new;
736         else {
737                 for (; a->next != NULL; a = a->next) {
738                         if ((a->class == new->class && a->type == new->type) ||
739                             a == new) {
740                                 printk("Attempted to re-register "
741                                        "subpacket annotation\n");
742                                 return -EINVAL;
743                         }
744                 }
745                 a->next = new;
746         }
747         new->next = NULL;
748
749         return 0;
750 }
751
752 int __init
753 cdl_register_subpacket_handler(struct el_subpacket_handler *new)
754 {
755         struct el_subpacket_handler *h = subpacket_handler_list;
756
757         if (h == NULL) subpacket_handler_list = new;
758         else {
759                 for (; h->next != NULL; h = h->next) {
760                         if (h->class == new->class || h == new) {
761                                 printk("Attempted to re-register "
762                                        "subpacket handler\n");
763                                 return -EINVAL;
764                         }
765                 }
766                 h->next = new;
767         }
768         new->next = NULL;
769
770         return 0;
771 }
772