Merge branch 'release-2.6.27' of git://git.kernel.org/pub/scm/linux/kernel/git/ak...
[linux-2.6] / arch / ia64 / kernel / mca_drv.c
1 /*
2  * File:        mca_drv.c
3  * Purpose:     Generic MCA handling layer
4  *
5  * Copyright (C) 2004 FUJITSU LIMITED
6  * Copyright (C) 2004 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
7  * Copyright (C) 2005 Silicon Graphics, Inc
8  * Copyright (C) 2005 Keith Owens <kaos@sgi.com>
9  * Copyright (C) 2006 Russ Anderson <rja@sgi.com>
10  */
11 #include <linux/types.h>
12 #include <linux/init.h>
13 #include <linux/sched.h>
14 #include <linux/interrupt.h>
15 #include <linux/irq.h>
16 #include <linux/kallsyms.h>
17 #include <linux/bootmem.h>
18 #include <linux/acpi.h>
19 #include <linux/timer.h>
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/smp.h>
23 #include <linux/workqueue.h>
24 #include <linux/mm.h>
25
26 #include <asm/delay.h>
27 #include <asm/machvec.h>
28 #include <asm/page.h>
29 #include <asm/ptrace.h>
30 #include <asm/system.h>
31 #include <asm/sal.h>
32 #include <asm/mca.h>
33
34 #include <asm/irq.h>
35 #include <asm/hw_irq.h>
36
37 #include "mca_drv.h"
38
39 /* max size of SAL error record (default) */
40 static int sal_rec_max = 10000;
41
42 /* from mca_drv_asm.S */
43 extern void *mca_handler_bhhook(void);
44
45 static DEFINE_SPINLOCK(mca_bh_lock);
46
47 typedef enum {
48         MCA_IS_LOCAL  = 0,
49         MCA_IS_GLOBAL = 1
50 } mca_type_t;
51
52 #define MAX_PAGE_ISOLATE 1024
53
54 static struct page *page_isolate[MAX_PAGE_ISOLATE];
55 static int num_page_isolate = 0;
56
57 typedef enum {
58         ISOLATE_NG,
59         ISOLATE_OK,
60         ISOLATE_NONE
61 } isolate_status_t;
62
63 typedef enum {
64         MCA_NOT_RECOVERED = 0,
65         MCA_RECOVERED     = 1
66 } recovery_status_t;
67
68 /*
69  *  This pool keeps pointers to the section part of SAL error record
70  */
71 static struct {
72         slidx_list_t *buffer; /* section pointer list pool */
73         int          cur_idx; /* Current index of section pointer list pool */
74         int          max_idx; /* Maximum index of section pointer list pool */
75 } slidx_pool;
76
77 static int
78 fatal_mca(const char *fmt, ...)
79 {
80         va_list args;
81         char buf[256];
82
83         va_start(args, fmt);
84         vsnprintf(buf, sizeof(buf), fmt, args);
85         va_end(args);
86         ia64_mca_printk(KERN_ALERT "MCA: %s\n", buf);
87
88         return MCA_NOT_RECOVERED;
89 }
90
91 static int
92 mca_recovered(const char *fmt, ...)
93 {
94         va_list args;
95         char buf[256];
96
97         va_start(args, fmt);
98         vsnprintf(buf, sizeof(buf), fmt, args);
99         va_end(args);
100         ia64_mca_printk(KERN_INFO "MCA: %s\n", buf);
101
102         return MCA_RECOVERED;
103 }
104
105 /**
106  * mca_page_isolate - isolate a poisoned page in order not to use it later
107  * @paddr:      poisoned memory location
108  *
109  * Return value:
110  *      one of isolate_status_t, ISOLATE_OK/NG/NONE.
111  */
112
113 static isolate_status_t
114 mca_page_isolate(unsigned long paddr)
115 {
116         int i;
117         struct page *p;
118
119         /* whether physical address is valid or not */
120         if (!ia64_phys_addr_valid(paddr))
121                 return ISOLATE_NONE;
122
123         if (!pfn_valid(paddr >> PAGE_SHIFT))
124                 return ISOLATE_NONE;
125
126         /* convert physical address to physical page number */
127         p = pfn_to_page(paddr>>PAGE_SHIFT);
128
129         /* check whether a page number have been already registered or not */
130         for (i = 0; i < num_page_isolate; i++)
131                 if (page_isolate[i] == p)
132                         return ISOLATE_OK; /* already listed */
133
134         /* limitation check */
135         if (num_page_isolate == MAX_PAGE_ISOLATE)
136                 return ISOLATE_NG;
137
138         /* kick pages having attribute 'SLAB' or 'Reserved' */
139         if (PageSlab(p) || PageReserved(p))
140                 return ISOLATE_NG;
141
142         /* add attribute 'Reserved' and register the page */
143         get_page(p);
144         SetPageReserved(p);
145         page_isolate[num_page_isolate++] = p;
146
147         return ISOLATE_OK;
148 }
149
150 /**
151  * mca_hanlder_bh - Kill the process which occurred memory read error
152  * @paddr:      poisoned address received from MCA Handler
153  */
154
155 void
156 mca_handler_bh(unsigned long paddr, void *iip, unsigned long ipsr)
157 {
158         ia64_mlogbuf_dump();
159         printk(KERN_ERR "OS_MCA: process [cpu %d, pid: %d, uid: %d, "
160                 "iip: %p, psr: 0x%lx,paddr: 0x%lx](%s) encounters MCA.\n",
161                 raw_smp_processor_id(), current->pid, current->uid,
162                 iip, ipsr, paddr, current->comm);
163
164         spin_lock(&mca_bh_lock);
165         switch (mca_page_isolate(paddr)) {
166         case ISOLATE_OK:
167                 printk(KERN_DEBUG "Page isolation: ( %lx ) success.\n", paddr);
168                 break;
169         case ISOLATE_NG:
170                 printk(KERN_CRIT "Page isolation: ( %lx ) failure.\n", paddr);
171                 break;
172         default:
173                 break;
174         }
175         spin_unlock(&mca_bh_lock);
176
177         /* This process is about to be killed itself */
178         do_exit(SIGKILL);
179 }
180
181 /**
182  * mca_make_peidx - Make index of processor error section
183  * @slpi:       pointer to record of processor error section
184  * @peidx:      pointer to index of processor error section
185  */
186
187 static void
188 mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx)
189 {
190         /*
191          * calculate the start address of
192          *   "struct cpuid_info" and "sal_processor_static_info_t".
193          */
194         u64 total_check_num = slpi->valid.num_cache_check
195                                 + slpi->valid.num_tlb_check
196                                 + slpi->valid.num_bus_check
197                                 + slpi->valid.num_reg_file_check
198                                 + slpi->valid.num_ms_check;
199         u64 head_size = sizeof(sal_log_mod_error_info_t) * total_check_num
200                         + sizeof(sal_log_processor_info_t);
201         u64 mid_size  = slpi->valid.cpuid_info * sizeof(struct sal_cpuid_info);
202
203         peidx_head(peidx)   = slpi;
204         peidx_mid(peidx)    = (struct sal_cpuid_info *)
205                 (slpi->valid.cpuid_info ? ((char*)slpi + head_size) : NULL);
206         peidx_bottom(peidx) = (sal_processor_static_info_t *)
207                 (slpi->valid.psi_static_struct ?
208                         ((char*)slpi + head_size + mid_size) : NULL);
209 }
210
211 /**
212  * mca_make_slidx -  Make index of SAL error record
213  * @buffer:     pointer to SAL error record
214  * @slidx:      pointer to index of SAL error record
215  *
216  * Return value:
217  *      1 if record has platform error / 0 if not
218  */
219 #define LOG_INDEX_ADD_SECT_PTR(sect, ptr) \
220         {slidx_list_t *hl = &slidx_pool.buffer[slidx_pool.cur_idx]; \
221         hl->hdr = ptr; \
222         list_add(&hl->list, &(sect)); \
223         slidx_pool.cur_idx = (slidx_pool.cur_idx + 1)%slidx_pool.max_idx; }
224
225 static int
226 mca_make_slidx(void *buffer, slidx_table_t *slidx)
227 {
228         int platform_err = 0;
229         int record_len = ((sal_log_record_header_t*)buffer)->len;
230         u32 ercd_pos;
231         int sects;
232         sal_log_section_hdr_t *sp;
233
234         /*
235          * Initialize index referring current record
236          */
237         INIT_LIST_HEAD(&(slidx->proc_err));
238         INIT_LIST_HEAD(&(slidx->mem_dev_err));
239         INIT_LIST_HEAD(&(slidx->sel_dev_err));
240         INIT_LIST_HEAD(&(slidx->pci_bus_err));
241         INIT_LIST_HEAD(&(slidx->smbios_dev_err));
242         INIT_LIST_HEAD(&(slidx->pci_comp_err));
243         INIT_LIST_HEAD(&(slidx->plat_specific_err));
244         INIT_LIST_HEAD(&(slidx->host_ctlr_err));
245         INIT_LIST_HEAD(&(slidx->plat_bus_err));
246         INIT_LIST_HEAD(&(slidx->unsupported));
247
248         /*
249          * Extract a Record Header
250          */
251         slidx->header = buffer;
252
253         /*
254          * Extract each section records
255          * (arranged from "int ia64_log_platform_info_print()")
256          */
257         for (ercd_pos = sizeof(sal_log_record_header_t), sects = 0;
258                 ercd_pos < record_len; ercd_pos += sp->len, sects++) {
259                 sp = (sal_log_section_hdr_t *)((char*)buffer + ercd_pos);
260                 if (!efi_guidcmp(sp->guid, SAL_PROC_DEV_ERR_SECT_GUID)) {
261                         LOG_INDEX_ADD_SECT_PTR(slidx->proc_err, sp);
262                 } else if (!efi_guidcmp(sp->guid,
263                                 SAL_PLAT_MEM_DEV_ERR_SECT_GUID)) {
264                         platform_err = 1;
265                         LOG_INDEX_ADD_SECT_PTR(slidx->mem_dev_err, sp);
266                 } else if (!efi_guidcmp(sp->guid,
267                                 SAL_PLAT_SEL_DEV_ERR_SECT_GUID)) {
268                         platform_err = 1;
269                         LOG_INDEX_ADD_SECT_PTR(slidx->sel_dev_err, sp);
270                 } else if (!efi_guidcmp(sp->guid,
271                                 SAL_PLAT_PCI_BUS_ERR_SECT_GUID)) {
272                         platform_err = 1;
273                         LOG_INDEX_ADD_SECT_PTR(slidx->pci_bus_err, sp);
274                 } else if (!efi_guidcmp(sp->guid,
275                                 SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID)) {
276                         platform_err = 1;
277                         LOG_INDEX_ADD_SECT_PTR(slidx->smbios_dev_err, sp);
278                 } else if (!efi_guidcmp(sp->guid,
279                                 SAL_PLAT_PCI_COMP_ERR_SECT_GUID)) {
280                         platform_err = 1;
281                         LOG_INDEX_ADD_SECT_PTR(slidx->pci_comp_err, sp);
282                 } else if (!efi_guidcmp(sp->guid,
283                                 SAL_PLAT_SPECIFIC_ERR_SECT_GUID)) {
284                         platform_err = 1;
285                         LOG_INDEX_ADD_SECT_PTR(slidx->plat_specific_err, sp);
286                 } else if (!efi_guidcmp(sp->guid,
287                                 SAL_PLAT_HOST_CTLR_ERR_SECT_GUID)) {
288                         platform_err = 1;
289                         LOG_INDEX_ADD_SECT_PTR(slidx->host_ctlr_err, sp);
290                 } else if (!efi_guidcmp(sp->guid,
291                                 SAL_PLAT_BUS_ERR_SECT_GUID)) {
292                         platform_err = 1;
293                         LOG_INDEX_ADD_SECT_PTR(slidx->plat_bus_err, sp);
294                 } else {
295                         LOG_INDEX_ADD_SECT_PTR(slidx->unsupported, sp);
296                 }
297         }
298         slidx->n_sections = sects;
299
300         return platform_err;
301 }
302
303 /**
304  * init_record_index_pools - Initialize pool of lists for SAL record index
305  *
306  * Return value:
307  *      0 on Success / -ENOMEM on Failure
308  */
309 static int
310 init_record_index_pools(void)
311 {
312         int i;
313         int rec_max_size;  /* Maximum size of SAL error records */
314         int sect_min_size; /* Minimum size of SAL error sections */
315         /* minimum size table of each section */
316         static int sal_log_sect_min_sizes[] = {
317                 sizeof(sal_log_processor_info_t)
318                 + sizeof(sal_processor_static_info_t),
319                 sizeof(sal_log_mem_dev_err_info_t),
320                 sizeof(sal_log_sel_dev_err_info_t),
321                 sizeof(sal_log_pci_bus_err_info_t),
322                 sizeof(sal_log_smbios_dev_err_info_t),
323                 sizeof(sal_log_pci_comp_err_info_t),
324                 sizeof(sal_log_plat_specific_err_info_t),
325                 sizeof(sal_log_host_ctlr_err_info_t),
326                 sizeof(sal_log_plat_bus_err_info_t),
327         };
328
329         /*
330          * MCA handler cannot allocate new memory on flight,
331          * so we preallocate enough memory to handle a SAL record.
332          *
333          * Initialize a handling set of slidx_pool:
334          *   1. Pick up the max size of SAL error records
335          *   2. Pick up the min size of SAL error sections
336          *   3. Allocate the pool as enough to 2 SAL records
337          *     (now we can estimate the maxinum of section in a record.)
338          */
339
340         /* - 1 - */
341         rec_max_size = sal_rec_max;
342
343         /* - 2 - */
344         sect_min_size = sal_log_sect_min_sizes[0];
345         for (i = 1; i < sizeof sal_log_sect_min_sizes/sizeof(size_t); i++)
346                 if (sect_min_size > sal_log_sect_min_sizes[i])
347                         sect_min_size = sal_log_sect_min_sizes[i];
348
349         /* - 3 - */
350         slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1;
351         slidx_pool.buffer = (slidx_list_t *)
352                 kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL);
353
354         return slidx_pool.buffer ? 0 : -ENOMEM;
355 }
356
357
358 /*****************************************************************************
359  * Recovery functions                                                        *
360  *****************************************************************************/
361
362 /**
363  * is_mca_global - Check whether this MCA is global or not
364  * @peidx:      pointer of index of processor error section
365  * @pbci:       pointer to pal_bus_check_info_t
366  * @sos:        pointer to hand off struct between SAL and OS
367  *
368  * Return value:
369  *      MCA_IS_LOCAL / MCA_IS_GLOBAL
370  */
371
372 static mca_type_t
373 is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci,
374               struct ia64_sal_os_state *sos)
375 {
376         pal_processor_state_info_t *psp =
377                 (pal_processor_state_info_t*)peidx_psp(peidx);
378
379         /*
380          * PAL can request a rendezvous, if the MCA has a global scope.
381          * If "rz_always" flag is set, SAL requests MCA rendezvous
382          * in spite of global MCA.
383          * Therefore it is local MCA when rendezvous has not been requested.
384          * Failed to rendezvous, the system must be down.
385          */
386         switch (sos->rv_rc) {
387                 case -1: /* SAL rendezvous unsuccessful */
388                         return MCA_IS_GLOBAL;
389                 case  0: /* SAL rendezvous not required */
390                         return MCA_IS_LOCAL;
391                 case  1: /* SAL rendezvous successful int */
392                 case  2: /* SAL rendezvous successful int with init */
393                 default:
394                         break;
395         }
396
397         /*
398          * If One or more Cache/TLB/Reg_File/Uarch_Check is here,
399          * it would be a local MCA. (i.e. processor internal error)
400          */
401         if (psp->tc || psp->cc || psp->rc || psp->uc)
402                 return MCA_IS_LOCAL;
403         
404         /*
405          * Bus_Check structure with Bus_Check.ib (internal bus error) flag set
406          * would be a global MCA. (e.g. a system bus address parity error)
407          */
408         if (!pbci || pbci->ib)
409                 return MCA_IS_GLOBAL;
410
411         /*
412          * Bus_Check structure with Bus_Check.eb (external bus error) flag set
413          * could be either a local MCA or a global MCA.
414          *
415          * Referring Bus_Check.bsi:
416          *   0: Unknown/unclassified
417          *   1: BERR#
418          *   2: BINIT#
419          *   3: Hard Fail
420          * (FIXME: Are these SGI specific or generic bsi values?)
421          */
422         if (pbci->eb)
423                 switch (pbci->bsi) {
424                         case 0:
425                                 /* e.g. a load from poisoned memory */
426                                 return MCA_IS_LOCAL;
427                         case 1:
428                         case 2:
429                         case 3:
430                                 return MCA_IS_GLOBAL;
431                 }
432
433         return MCA_IS_GLOBAL;
434 }
435
436 /**
437  * get_target_identifier - Get the valid Cache or Bus check target identifier.
438  * @peidx:      pointer of index of processor error section
439  *
440  * Return value:
441  *      target address on Success / 0 on Failure
442  */
443 static u64
444 get_target_identifier(peidx_table_t *peidx)
445 {
446         u64 target_address = 0;
447         sal_log_mod_error_info_t *smei;
448         pal_cache_check_info_t *pcci;
449         int i, level = 9;
450
451         /*
452          * Look through the cache checks for a valid target identifier
453          * If more than one valid target identifier, return the one
454          * with the lowest cache level.
455          */
456         for (i = 0; i < peidx_cache_check_num(peidx); i++) {
457                 smei = (sal_log_mod_error_info_t *)peidx_cache_check(peidx, i);
458                 if (smei->valid.target_identifier && smei->target_identifier) {
459                         pcci = (pal_cache_check_info_t *)&(smei->check_info);
460                         if (!target_address || (pcci->level < level)) {
461                                 target_address = smei->target_identifier;
462                                 level = pcci->level;
463                                 continue;
464                         }
465                 }
466         }
467         if (target_address)
468                 return target_address;
469
470         /*
471          * Look at the bus check for a valid target identifier
472          */
473         smei = peidx_bus_check(peidx, 0);
474         if (smei && smei->valid.target_identifier)
475                 return smei->target_identifier;
476
477         return 0;
478 }
479
480 /**
481  * recover_from_read_error - Try to recover the errors which type are "read"s.
482  * @slidx:      pointer of index of SAL error record
483  * @peidx:      pointer of index of processor error section
484  * @pbci:       pointer of pal_bus_check_info
485  * @sos:        pointer to hand off struct between SAL and OS
486  *
487  * Return value:
488  *      1 on Success / 0 on Failure
489  */
490
491 static int
492 recover_from_read_error(slidx_table_t *slidx,
493                         peidx_table_t *peidx, pal_bus_check_info_t *pbci,
494                         struct ia64_sal_os_state *sos)
495 {
496         u64 target_identifier;
497         pal_min_state_area_t *pmsa;
498         struct ia64_psr *psr1, *psr2;
499         ia64_fptr_t *mca_hdlr_bh = (ia64_fptr_t*)mca_handler_bhhook;
500
501         /* Is target address valid? */
502         target_identifier = get_target_identifier(peidx);
503         if (!target_identifier)
504                 return fatal_mca("target address not valid");
505
506         /*
507          * cpu read or memory-mapped io read
508          *
509          *    offending process  affected process  OS MCA do
510          *     kernel mode        kernel mode       down system
511          *     kernel mode        user   mode       kill the process
512          *     user   mode        kernel mode       down system (*)
513          *     user   mode        user   mode       kill the process
514          *
515          * (*) You could terminate offending user-mode process
516          *    if (pbci->pv && pbci->pl != 0) *and* if you sure
517          *    the process not have any locks of kernel.
518          */
519
520         /* Is minstate valid? */
521         if (!peidx_bottom(peidx) || !(peidx_bottom(peidx)->valid.minstate))
522                 return fatal_mca("minstate not valid");
523         psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr);
524         psr2 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_xpsr);
525
526         /*
527          *  Check the privilege level of interrupted context.
528          *   If it is user-mode, then terminate affected process.
529          */
530
531         pmsa = sos->pal_min_state;
532         if (psr1->cpl != 0 ||
533            ((psr2->cpl != 0) && mca_recover_range(pmsa->pmsa_iip))) {
534                 /*
535                  *  setup for resume to bottom half of MCA,
536                  * "mca_handler_bhhook"
537                  */
538                 /* pass to bhhook as argument (gr8, ...) */
539                 pmsa->pmsa_gr[8-1] = target_identifier;
540                 pmsa->pmsa_gr[9-1] = pmsa->pmsa_iip;
541                 pmsa->pmsa_gr[10-1] = pmsa->pmsa_ipsr;
542                 /* set interrupted return address (but no use) */
543                 pmsa->pmsa_br0 = pmsa->pmsa_iip;
544                 /* change resume address to bottom half */
545                 pmsa->pmsa_iip = mca_hdlr_bh->fp;
546                 pmsa->pmsa_gr[1-1] = mca_hdlr_bh->gp;
547                 /* set cpl with kernel mode */
548                 psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr;
549                 psr2->cpl = 0;
550                 psr2->ri  = 0;
551                 psr2->bn  = 1;
552                 psr2->i  = 0;
553
554                 return mca_recovered("user memory corruption. "
555                                 "kill affected process - recovered.");
556         }
557
558         return fatal_mca("kernel context not recovered, iip 0x%lx\n",
559                          pmsa->pmsa_iip);
560 }
561
562 /**
563  * recover_from_platform_error - Recover from platform error.
564  * @slidx:      pointer of index of SAL error record
565  * @peidx:      pointer of index of processor error section
566  * @pbci:       pointer of pal_bus_check_info
567  * @sos:        pointer to hand off struct between SAL and OS
568  *
569  * Return value:
570  *      1 on Success / 0 on Failure
571  */
572
573 static int
574 recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx,
575                             pal_bus_check_info_t *pbci,
576                             struct ia64_sal_os_state *sos)
577 {
578         int status = 0;
579         pal_processor_state_info_t *psp =
580                 (pal_processor_state_info_t*)peidx_psp(peidx);
581
582         if (psp->bc && pbci->eb && pbci->bsi == 0) {
583                 switch(pbci->type) {
584                 case 1: /* partial read */
585                 case 3: /* full line(cpu) read */
586                 case 9: /* I/O space read */
587                         status = recover_from_read_error(slidx, peidx, pbci,
588                                                          sos);
589                         break;
590                 case 0: /* unknown */
591                 case 2: /* partial write */
592                 case 4: /* full line write */
593                 case 5: /* implicit or explicit write-back operation */
594                 case 6: /* snoop probe */
595                 case 7: /* incoming or outgoing ptc.g */
596                 case 8: /* write coalescing transactions */
597                 case 10: /* I/O space write */
598                 case 11: /* inter-processor interrupt message(IPI) */
599                 case 12: /* interrupt acknowledge or
600                                 external task priority cycle */
601                 default:
602                         break;
603                 }
604         } else if (psp->cc && !psp->bc) {       /* Cache error */
605                 status = recover_from_read_error(slidx, peidx, pbci, sos);
606         }
607
608         return status;
609 }
610
611 /*
612  * recover_from_tlb_check
613  * @peidx:      pointer of index of processor error section
614  *
615  * Return value:
616  *      1 on Success / 0 on Failure
617  */
618 static int
619 recover_from_tlb_check(peidx_table_t *peidx)
620 {
621         sal_log_mod_error_info_t *smei;
622         pal_tlb_check_info_t *ptci;
623
624         smei = (sal_log_mod_error_info_t *)peidx_tlb_check(peidx, 0);
625         ptci = (pal_tlb_check_info_t *)&(smei->check_info);
626
627         /*
628          * Look for signature of a duplicate TLB DTC entry, which is
629          * a SW bug and always fatal.
630          */
631         if (ptci->op == PAL_TLB_CHECK_OP_PURGE
632             && !(ptci->itr || ptci->dtc || ptci->itc))
633                 return fatal_mca("Duplicate TLB entry");
634
635         return mca_recovered("TLB check recovered");
636 }
637
638 /**
639  * recover_from_processor_error
640  * @platform:   whether there are some platform error section or not
641  * @slidx:      pointer of index of SAL error record
642  * @peidx:      pointer of index of processor error section
643  * @pbci:       pointer of pal_bus_check_info
644  * @sos:        pointer to hand off struct between SAL and OS
645  *
646  * Return value:
647  *      1 on Success / 0 on Failure
648  */
649
650 static int
651 recover_from_processor_error(int platform, slidx_table_t *slidx,
652                              peidx_table_t *peidx, pal_bus_check_info_t *pbci,
653                              struct ia64_sal_os_state *sos)
654 {
655         pal_processor_state_info_t *psp =
656                 (pal_processor_state_info_t*)peidx_psp(peidx);
657
658         /*
659          * Processor recovery status must key off of the PAL recovery
660          * status in the Processor State Parameter.
661          */
662
663         /*
664          * The machine check is corrected.
665          */
666         if (psp->cm == 1)
667                 return mca_recovered("machine check is already corrected.");
668
669         /*
670          * The error was not contained.  Software must be reset.
671          */
672         if (psp->us || psp->ci == 0)
673                 return fatal_mca("error not contained");
674
675         /*
676          * Look for recoverable TLB check
677          */
678         if (psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc))
679                 return recover_from_tlb_check(peidx);
680
681         /*
682          * The cache check and bus check bits have four possible states
683          *   cc bc
684          *    1  1      Memory error, attempt recovery
685          *    1  0      Cache error, attempt recovery
686          *    0  1      I/O error, attempt recovery
687          *    0  0      Other error type, not recovered
688          */
689         if (psp->cc == 0 && (psp->bc == 0 || pbci == NULL))
690                 return fatal_mca("No cache or bus check");
691
692         /*
693          * Cannot handle more than one bus check.
694          */
695         if (peidx_bus_check_num(peidx) > 1)
696                 return fatal_mca("Too many bus checks");
697
698         if (pbci->ib)
699                 return fatal_mca("Internal Bus error");
700         if (pbci->eb && pbci->bsi > 0)
701                 return fatal_mca("External bus check fatal status");
702
703         /*
704          * This is a local MCA and estimated as a recoverable error.
705          */
706         if (platform)
707                 return recover_from_platform_error(slidx, peidx, pbci, sos);
708
709         /*
710          * On account of strange SAL error record, we cannot recover.
711          */
712         return fatal_mca("Strange SAL record");
713 }
714
715 /**
716  * mca_try_to_recover - Try to recover from MCA
717  * @rec:        pointer to a SAL error record
718  * @sos:        pointer to hand off struct between SAL and OS
719  *
720  * Return value:
721  *      1 on Success / 0 on Failure
722  */
723
724 static int
725 mca_try_to_recover(void *rec, struct ia64_sal_os_state *sos)
726 {
727         int platform_err;
728         int n_proc_err;
729         slidx_table_t slidx;
730         peidx_table_t peidx;
731         pal_bus_check_info_t pbci;
732
733         /* Make index of SAL error record */
734         platform_err = mca_make_slidx(rec, &slidx);
735
736         /* Count processor error sections */
737         n_proc_err = slidx_count(&slidx, proc_err);
738
739          /* Now, OS can recover when there is one processor error section */
740         if (n_proc_err > 1)
741                 return fatal_mca("Too Many Errors");
742         else if (n_proc_err == 0)
743                 /* Weird SAL record ... We can't do anything */
744                 return fatal_mca("Weird SAL record");
745
746         /* Make index of processor error section */
747         mca_make_peidx((sal_log_processor_info_t*)
748                 slidx_first_entry(&slidx.proc_err)->hdr, &peidx);
749
750         /* Extract Processor BUS_CHECK[0] */
751         *((u64*)&pbci) = peidx_check_info(&peidx, bus_check, 0);
752
753         /* Check whether MCA is global or not */
754         if (is_mca_global(&peidx, &pbci, sos))
755                 return fatal_mca("global MCA");
756         
757         /* Try to recover a processor error */
758         return recover_from_processor_error(platform_err, &slidx, &peidx,
759                                             &pbci, sos);
760 }
761
762 /*
763  * =============================================================================
764  */
765
766 int __init mca_external_handler_init(void)
767 {
768         if (init_record_index_pools())
769                 return -ENOMEM;
770
771         /* register external mca handlers */
772         if (ia64_reg_MCA_extension(mca_try_to_recover)) {       
773                 printk(KERN_ERR "ia64_reg_MCA_extension failed.\n");
774                 kfree(slidx_pool.buffer);
775                 return -EFAULT;
776         }
777         return 0;
778 }
779
780 void __exit mca_external_handler_exit(void)
781 {
782         /* unregister external mca handlers */
783         ia64_unreg_MCA_extension();
784         kfree(slidx_pool.buffer);
785 }
786
787 module_init(mca_external_handler_init);
788 module_exit(mca_external_handler_exit);
789
790 module_param(sal_rec_max, int, 0644);
791 MODULE_PARM_DESC(sal_rec_max, "Max size of SAL error record");
792
793 MODULE_DESCRIPTION("ia64 platform dependent mca handler driver");
794 MODULE_LICENSE("GPL");