xref: /onnv-gate/usr/src/uts/sun4v/os/error.c (revision 541)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/machsystm.h>
310Sstevel@tonic-gate #include <sys/cpuvar.h>
320Sstevel@tonic-gate #include <sys/async.h>
330Sstevel@tonic-gate #include <sys/ontrap.h>
340Sstevel@tonic-gate #include <sys/ddifm.h>
350Sstevel@tonic-gate #include <sys/hypervisor_api.h>
360Sstevel@tonic-gate #include <sys/errorq.h>
370Sstevel@tonic-gate #include <sys/promif.h>
380Sstevel@tonic-gate #include <sys/prom_plat.h>
390Sstevel@tonic-gate #include <sys/x_call.h>
400Sstevel@tonic-gate #include <sys/error.h>
410Sstevel@tonic-gate #include <sys/fm/util.h>
42*541Srf157361 #include <sys/ivintr.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #define	MAX_CE_FLTS		10
450Sstevel@tonic-gate #define	MAX_ASYNC_FLTS		6
460Sstevel@tonic-gate 
470Sstevel@tonic-gate errorq_t *ue_queue;			/* queue of uncorrectable errors */
480Sstevel@tonic-gate errorq_t *ce_queue;			/* queue of correctable errors */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * Being used by memory test driver.
520Sstevel@tonic-gate  * ce_verbose_memory - covers CEs in DIMMs
530Sstevel@tonic-gate  * ce_verbose_other - covers "others" (ecache, IO, etc.)
540Sstevel@tonic-gate  *
550Sstevel@tonic-gate  * If the value is 0, nothing is logged.
560Sstevel@tonic-gate  * If the value is 1, the error is logged to the log file, but not console.
570Sstevel@tonic-gate  * If the value is 2, the error is logged to the log file and console.
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate int	ce_verbose_memory = 1;
600Sstevel@tonic-gate int	ce_verbose_other = 1;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate int	ce_show_data = 0;
630Sstevel@tonic-gate int	ce_debug = 0;
640Sstevel@tonic-gate int	ue_debug = 0;
650Sstevel@tonic-gate int	reset_debug = 0;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * Tunables for controlling the handling of asynchronous faults (AFTs). Setting
690Sstevel@tonic-gate  * these to non-default values on a non-DEBUG kernel is NOT supported.
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate int	aft_verbose = 0;	/* log AFT messages > 1 to log only */
720Sstevel@tonic-gate int	aft_panic = 0;		/* panic (not reboot) on fatal usermode AFLT */
730Sstevel@tonic-gate int	aft_testfatal = 0;	/* force all AFTs to panic immediately */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
76*541Srf157361  * Used for vbsc hostshutdown (power-off buton)
77*541Srf157361  */
78*541Srf157361 int	err_shutdown_triggered = 0;	/* only once */
79*541Srf157361 uint_t	err_shutdown_inum = 0;		/* used to pull the trigger */
80*541Srf157361 
81*541Srf157361 /*
820Sstevel@tonic-gate  * Defined in bus_func.c but initialised in error_init
830Sstevel@tonic-gate  */
840Sstevel@tonic-gate extern kmutex_t bfd_lock;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate static uint32_t rq_overflow_count = 0;		/* counter for rq overflow */
870Sstevel@tonic-gate 
880Sstevel@tonic-gate static void cpu_queue_one_event(errh_async_flt_t *);
890Sstevel@tonic-gate static uint32_t count_entries_on_queue(uint64_t, uint64_t, uint32_t);
900Sstevel@tonic-gate static void errh_page_settoxic(errh_async_flt_t *, uchar_t);
910Sstevel@tonic-gate static void errh_page_retire(errh_async_flt_t *);
920Sstevel@tonic-gate static int errh_error_protected(struct regs *, struct async_flt *, int *);
930Sstevel@tonic-gate static void errh_rq_full(struct async_flt *);
940Sstevel@tonic-gate static void ue_drain(void *, struct async_flt *, errorq_elem_t *);
950Sstevel@tonic-gate static void ce_drain(void *, struct async_flt *, errorq_elem_t *);
960Sstevel@tonic-gate 
970Sstevel@tonic-gate /*ARGSUSED*/
980Sstevel@tonic-gate void
990Sstevel@tonic-gate process_resumable_error(struct regs *rp, uint32_t head_offset,
1000Sstevel@tonic-gate     uint32_t tail_offset)
1010Sstevel@tonic-gate {
1020Sstevel@tonic-gate 	struct machcpu *mcpup;
1030Sstevel@tonic-gate 	struct async_flt *aflt;
1040Sstevel@tonic-gate 	errh_async_flt_t errh_flt;
1050Sstevel@tonic-gate 	errh_er_t *head_va;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	mcpup = &(CPU->cpu_m);
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	while (head_offset != tail_offset) {
1100Sstevel@tonic-gate 		/* kernel buffer starts right after the resumable queue */
1110Sstevel@tonic-gate 		head_va = (errh_er_t *)(mcpup->cpu_rq_va + head_offset +
1120Sstevel@tonic-gate 		    CPU_RQ_SIZE);
1130Sstevel@tonic-gate 		/* Copy the error report to local buffer */
1140Sstevel@tonic-gate 		bzero(&errh_flt, sizeof (errh_async_flt_t));
1150Sstevel@tonic-gate 		bcopy((char *)head_va, &(errh_flt.errh_er),
1160Sstevel@tonic-gate 		    sizeof (errh_er_t));
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 		/* Increment the queue head */
1190Sstevel@tonic-gate 		head_offset += Q_ENTRY_SIZE;
1200Sstevel@tonic-gate 		/* Wrap around */
1210Sstevel@tonic-gate 		head_offset &= (CPU_RQ_SIZE - 1);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 		/* set error handle to zero so it can hold new error report */
1240Sstevel@tonic-gate 		head_va->ehdl = 0;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 		switch (errh_flt.errh_er.desc) {
1270Sstevel@tonic-gate 		case ERRH_DESC_UCOR_RE:
1280Sstevel@tonic-gate 			break;
1290Sstevel@tonic-gate 
130*541Srf157361 		case ERRH_DESC_WARN_RE:
131*541Srf157361 			/*
132*541Srf157361 			 * Power-off requested, but handle it one time only.
133*541Srf157361 			 */
134*541Srf157361 			if (!err_shutdown_triggered) {
135*541Srf157361 				setsoftint(err_shutdown_inum);
136*541Srf157361 				++err_shutdown_triggered;
137*541Srf157361 			}
138*541Srf157361 			continue;
139*541Srf157361 
1400Sstevel@tonic-gate 		default:
1410Sstevel@tonic-gate 			cmn_err(CE_WARN, "Error Descriptor 0x%llx "
1420Sstevel@tonic-gate 			    " invalid in resumable error handler",
1430Sstevel@tonic-gate 			    (long long) errh_flt.errh_er.desc);
1440Sstevel@tonic-gate 			continue;
1450Sstevel@tonic-gate 		}
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 		aflt = (struct async_flt *)&(errh_flt.cmn_asyncflt);
1480Sstevel@tonic-gate 		aflt->flt_id = gethrtime();
1490Sstevel@tonic-gate 		aflt->flt_bus_id = getprocessorid();
1500Sstevel@tonic-gate 		aflt->flt_class = CPU_FAULT;
1510Sstevel@tonic-gate 		aflt->flt_prot = AFLT_PROT_NONE;
1520Sstevel@tonic-gate 		aflt->flt_priv = (((errh_flt.errh_er.attr & ERRH_MODE_MASK)
1530Sstevel@tonic-gate 		    >> ERRH_MODE_SHIFT) == ERRH_MODE_PRIV);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 		if (errh_flt.errh_er.attr & ERRH_ATTR_CPU)
1560Sstevel@tonic-gate 			/* If it is an error on other cpu */
1570Sstevel@tonic-gate 			aflt->flt_panic = 1;
1580Sstevel@tonic-gate 		else
1590Sstevel@tonic-gate 			aflt->flt_panic = 0;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 		/*
1620Sstevel@tonic-gate 		 * Handle resumable queue full case.
1630Sstevel@tonic-gate 		 */
1640Sstevel@tonic-gate 		if (errh_flt.errh_er.attr & ERRH_ATTR_RQF) {
1650Sstevel@tonic-gate 			(void) errh_rq_full(aflt);
1660Sstevel@tonic-gate 		}
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 		/*
1690Sstevel@tonic-gate 		 * Queue the error on ce or ue queue depend on flt_panic.
1700Sstevel@tonic-gate 		 * Even if flt_panic is set, the code still keep processing
1710Sstevel@tonic-gate 		 * the rest element on rq until the panic starts.
1720Sstevel@tonic-gate 		 */
1730Sstevel@tonic-gate 		(void) cpu_queue_one_event(&errh_flt);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 		/*
1760Sstevel@tonic-gate 		 * Panic here if aflt->flt_panic has been set.
1770Sstevel@tonic-gate 		 * Enqueued errors will be logged as part of the panic flow.
1780Sstevel@tonic-gate 		 */
1790Sstevel@tonic-gate 		if (aflt->flt_panic) {
1800Sstevel@tonic-gate 			fm_panic("Unrecoverable error on another CPU");
1810Sstevel@tonic-gate 		}
1820Sstevel@tonic-gate 	}
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate void
1860Sstevel@tonic-gate process_nonresumable_error(struct regs *rp, uint64_t tl,
1870Sstevel@tonic-gate     uint32_t head_offset, uint32_t tail_offset)
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate 	struct machcpu *mcpup;
1900Sstevel@tonic-gate 	struct async_flt *aflt;
1910Sstevel@tonic-gate 	errh_async_flt_t errh_flt;
1920Sstevel@tonic-gate 	errh_er_t *head_va;
1930Sstevel@tonic-gate 	int trampolined = 0;
1940Sstevel@tonic-gate 	int expected = DDI_FM_ERR_UNEXPECTED;
1950Sstevel@tonic-gate 	uint64_t exec_mode;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	mcpup = &(CPU->cpu_m);
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	while (head_offset != tail_offset) {
2000Sstevel@tonic-gate 		/* kernel buffer starts right after the nonresumable queue */
2010Sstevel@tonic-gate 		head_va = (errh_er_t *)(mcpup->cpu_nrq_va + head_offset +
2020Sstevel@tonic-gate 		    CPU_NRQ_SIZE);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 		/* Copy the error report to local buffer */
2050Sstevel@tonic-gate 		bzero(&errh_flt, sizeof (errh_async_flt_t));
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 		bcopy((char *)head_va, &(errh_flt.errh_er),
2080Sstevel@tonic-gate 		    sizeof (errh_er_t));
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 		/* Increment the queue head */
2110Sstevel@tonic-gate 		head_offset += Q_ENTRY_SIZE;
2120Sstevel@tonic-gate 		/* Wrap around */
2130Sstevel@tonic-gate 		head_offset &= (CPU_NRQ_SIZE - 1);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 		/* set error handle to zero so it can hold new error report */
2160Sstevel@tonic-gate 		head_va->ehdl = 0;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 		aflt = (struct async_flt *)&(errh_flt.cmn_asyncflt);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 		trampolined = 0;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 		if (errh_flt.errh_er.attr & ERRH_ATTR_PIO)
2230Sstevel@tonic-gate 			aflt->flt_class = BUS_FAULT;
2240Sstevel@tonic-gate 		else
2250Sstevel@tonic-gate 			aflt->flt_class = CPU_FAULT;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 		aflt->flt_id = gethrtime();
2280Sstevel@tonic-gate 		aflt->flt_bus_id = getprocessorid();
2290Sstevel@tonic-gate 		aflt->flt_pc = (caddr_t)rp->r_pc;
2300Sstevel@tonic-gate 		exec_mode = (errh_flt.errh_er.attr & ERRH_MODE_MASK)
2310Sstevel@tonic-gate 		    >> ERRH_MODE_SHIFT;
2320Sstevel@tonic-gate 		aflt->flt_priv = (exec_mode == ERRH_MODE_PRIV ||
2330Sstevel@tonic-gate 		    exec_mode == ERRH_MODE_UNKNOWN);
2340Sstevel@tonic-gate 		aflt->flt_tl = (uchar_t)tl;
2350Sstevel@tonic-gate 		aflt->flt_prot = AFLT_PROT_NONE;
2360Sstevel@tonic-gate 		aflt->flt_panic = ((aflt->flt_tl != 0) ||
2370Sstevel@tonic-gate 		    (aft_testfatal != 0));
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 		switch (errh_flt.errh_er.desc) {
2400Sstevel@tonic-gate 		case ERRH_DESC_PR_NRE:
2410Sstevel@tonic-gate 			/*
2420Sstevel@tonic-gate 			 * Fall through, precise fault also need to check
2430Sstevel@tonic-gate 			 * to see if it was protected.
2440Sstevel@tonic-gate 			 */
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		case ERRH_DESC_DEF_NRE:
2470Sstevel@tonic-gate 			/*
2480Sstevel@tonic-gate 			 * If the trap occurred in privileged mode at TL=0,
2490Sstevel@tonic-gate 			 * we need to check to see if we were executing
2500Sstevel@tonic-gate 			 * in kernel under on_trap() or t_lofault
2510Sstevel@tonic-gate 			 * protection. If so, modify the saved registers
2520Sstevel@tonic-gate 			 * so that we return from the trap to the
2530Sstevel@tonic-gate 			 * appropriate trampoline routine.
2540Sstevel@tonic-gate 			 */
2550Sstevel@tonic-gate 			if (aflt->flt_priv == 1 && aflt->flt_tl == 0)
2560Sstevel@tonic-gate 				trampolined =
2570Sstevel@tonic-gate 				    errh_error_protected(rp, aflt, &expected);
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 			if (!aflt->flt_priv || aflt->flt_prot ==
2600Sstevel@tonic-gate 			    AFLT_PROT_COPY) {
2610Sstevel@tonic-gate 				aflt->flt_panic |= aft_panic;
2620Sstevel@tonic-gate 			} else if (!trampolined &&
2630Sstevel@tonic-gate 			    aflt->flt_class != BUS_FAULT) {
2640Sstevel@tonic-gate 				aflt->flt_panic = 1;
2650Sstevel@tonic-gate 			}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 			/*
2680Sstevel@tonic-gate 			 * If PIO error, we need to query the bus nexus
2690Sstevel@tonic-gate 			 * for fatal errors.
2700Sstevel@tonic-gate 			 */
2710Sstevel@tonic-gate 			if (aflt->flt_class == BUS_FAULT) {
2720Sstevel@tonic-gate 				aflt->flt_addr = errh_flt.errh_er.ra;
2730Sstevel@tonic-gate 				errh_cpu_run_bus_error_handlers(aflt,
2740Sstevel@tonic-gate 				    expected);
2750Sstevel@tonic-gate 			}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 			break;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 		default:
2800Sstevel@tonic-gate 			cmn_err(CE_WARN, "Error Descriptor 0x%llx "
2810Sstevel@tonic-gate 			    " invalid in nonresumable error handler",
2820Sstevel@tonic-gate 			    (long long) errh_flt.errh_er.desc);
2830Sstevel@tonic-gate 			continue;
2840Sstevel@tonic-gate 		}
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 		/*
2870Sstevel@tonic-gate 		 * Queue the error report for further processing. If
2880Sstevel@tonic-gate 		 * flt_panic is set, code still process other errors
2890Sstevel@tonic-gate 		 * in the queue until the panic routine stops the
2900Sstevel@tonic-gate 		 * kernel.
2910Sstevel@tonic-gate 		 */
2920Sstevel@tonic-gate 		(void) cpu_queue_one_event(&errh_flt);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 		/*
2950Sstevel@tonic-gate 		 * Panic here if aflt->flt_panic has been set.
2960Sstevel@tonic-gate 		 * Enqueued errors will be logged as part of the panic flow.
2970Sstevel@tonic-gate 		 */
2980Sstevel@tonic-gate 		if (aflt->flt_panic) {
2990Sstevel@tonic-gate 			fm_panic("Unrecoverable hardware error");
3000Sstevel@tonic-gate 		}
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 		/*
3030Sstevel@tonic-gate 		 * If it is a memory error, we turn on the PAGE_IS_TOXIC
3040Sstevel@tonic-gate 		 * flag. The page will be retired later and scrubbed when
3050Sstevel@tonic-gate 		 * it is freed.
3060Sstevel@tonic-gate 		 */
3070Sstevel@tonic-gate 		if (errh_flt.errh_er.attr & ERRH_ATTR_MEM)
3080Sstevel@tonic-gate 			(void) errh_page_settoxic(&errh_flt, PAGE_IS_TOXIC);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		/*
3110Sstevel@tonic-gate 		 * If we queued an error and the it was in user mode or
3120Sstevel@tonic-gate 		 * protected by t_lofault,
3130Sstevel@tonic-gate 		 * set AST flag so the queue will be drained before
3140Sstevel@tonic-gate 		 * returning to user mode.
3150Sstevel@tonic-gate 		 */
3160Sstevel@tonic-gate 		if (!aflt->flt_priv || aflt->flt_prot == AFLT_PROT_COPY) {
3170Sstevel@tonic-gate 			int pcb_flag = 0;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 			if (aflt->flt_class == CPU_FAULT)
3200Sstevel@tonic-gate 				pcb_flag |= ASYNC_HWERR;
3210Sstevel@tonic-gate 			else if (aflt->flt_class == BUS_FAULT)
3220Sstevel@tonic-gate 				pcb_flag |= ASYNC_BERR;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 			ttolwp(curthread)->lwp_pcb.pcb_flags |= pcb_flag;
3250Sstevel@tonic-gate 			aston(curthread);
3260Sstevel@tonic-gate 		}
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate /*
3310Sstevel@tonic-gate  * For PIO errors, this routine calls nexus driver's error
3320Sstevel@tonic-gate  * callback routines. If the callback routine returns fatal, and
3330Sstevel@tonic-gate  * we are in kernel or unknow mode without any error protection,
3340Sstevel@tonic-gate  * we need to turn on the panic flag.
3350Sstevel@tonic-gate  */
3360Sstevel@tonic-gate void
3370Sstevel@tonic-gate errh_cpu_run_bus_error_handlers(struct async_flt *aflt, int expected)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate 	int status;
3400Sstevel@tonic-gate 	ddi_fm_error_t de;
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	bzero(&de, sizeof (ddi_fm_error_t));
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	de.fme_version = DDI_FME_VERSION;
3450Sstevel@tonic-gate 	de.fme_ena = fm_ena_generate(aflt->flt_id, FM_ENA_FMT1);
3460Sstevel@tonic-gate 	de.fme_flag = expected;
3470Sstevel@tonic-gate 	de.fme_bus_specific = (void *)aflt->flt_addr;
3480Sstevel@tonic-gate 	status = ndi_fm_handler_dispatch(ddi_root_node(), NULL, &de);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	/*
3510Sstevel@tonic-gate 	 * If error is protected, it will jump to proper routine
3520Sstevel@tonic-gate 	 * to handle the handle; if it is in user level, we just
3530Sstevel@tonic-gate 	 * kill the user process; if the driver thinks the error is
3540Sstevel@tonic-gate 	 * not fatal, we can drive on. If none of above are true,
3550Sstevel@tonic-gate 	 * we panic
3560Sstevel@tonic-gate 	 */
3570Sstevel@tonic-gate 	if ((aflt->flt_prot == AFLT_PROT_NONE) && (aflt->flt_priv == 1) &&
3580Sstevel@tonic-gate 	    (status == DDI_FM_FATAL))
3590Sstevel@tonic-gate 		aflt->flt_panic = 1;
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate /*
3630Sstevel@tonic-gate  * This routine checks to see if we are under any error protection when
3640Sstevel@tonic-gate  * the error happens. If we are under error protection, we unwind to
3650Sstevel@tonic-gate  * the protection and indicate fault.
3660Sstevel@tonic-gate  */
3670Sstevel@tonic-gate static int
3680Sstevel@tonic-gate errh_error_protected(struct regs *rp, struct async_flt *aflt, int *expected)
3690Sstevel@tonic-gate {
3700Sstevel@tonic-gate 	int trampolined = 0;
3710Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if (curthread->t_ontrap != NULL) {
3740Sstevel@tonic-gate 		on_trap_data_t *otp = curthread->t_ontrap;
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 		if (otp->ot_prot & OT_DATA_EC) {
3770Sstevel@tonic-gate 			aflt->flt_prot = AFLT_PROT_EC;
3780Sstevel@tonic-gate 			otp->ot_trap |= OT_DATA_EC;
3790Sstevel@tonic-gate 			rp->r_pc = otp->ot_trampoline;
3800Sstevel@tonic-gate 			rp->r_npc = rp->r_pc +4;
3810Sstevel@tonic-gate 			trampolined = 1;
3820Sstevel@tonic-gate 		}
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 		if (otp->ot_prot & OT_DATA_ACCESS) {
3850Sstevel@tonic-gate 			aflt->flt_prot = AFLT_PROT_ACCESS;
3860Sstevel@tonic-gate 			otp->ot_trap |= OT_DATA_ACCESS;
3870Sstevel@tonic-gate 			rp->r_pc = otp->ot_trampoline;
3880Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
3890Sstevel@tonic-gate 			trampolined = 1;
3900Sstevel@tonic-gate 			/*
3910Sstevel@tonic-gate 			 * for peek and caut_gets
3920Sstevel@tonic-gate 			 * errors are expected
3930Sstevel@tonic-gate 			 */
3940Sstevel@tonic-gate 			hp = (ddi_acc_hdl_t *)otp->ot_handle;
3950Sstevel@tonic-gate 			if (!hp)
3960Sstevel@tonic-gate 				*expected = DDI_FM_ERR_PEEK;
3970Sstevel@tonic-gate 			else if (hp->ah_acc.devacc_attr_access ==
3980Sstevel@tonic-gate 			    DDI_CAUTIOUS_ACC)
3990Sstevel@tonic-gate 				*expected = DDI_FM_ERR_EXPECTED;
4000Sstevel@tonic-gate 		}
4010Sstevel@tonic-gate 	} else if (curthread->t_lofault) {
4020Sstevel@tonic-gate 		aflt->flt_prot = AFLT_PROT_COPY;
4030Sstevel@tonic-gate 		rp->r_g1 = EFAULT;
4040Sstevel@tonic-gate 		rp->r_pc = curthread->t_lofault;
4050Sstevel@tonic-gate 		rp->r_npc = rp->r_pc + 4;
4060Sstevel@tonic-gate 		trampolined = 1;
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	return (trampolined);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate /*
4130Sstevel@tonic-gate  * Queue one event.
4140Sstevel@tonic-gate  */
4150Sstevel@tonic-gate static void
4160Sstevel@tonic-gate cpu_queue_one_event(errh_async_flt_t *errh_fltp)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	struct async_flt *aflt = (struct async_flt *)errh_fltp;
4190Sstevel@tonic-gate 	errorq_t *eqp;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	if (aflt->flt_panic)
4220Sstevel@tonic-gate 		eqp = ue_queue;
4230Sstevel@tonic-gate 	else
4240Sstevel@tonic-gate 		eqp = ce_queue;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	errorq_dispatch(eqp, errh_fltp, sizeof (errh_async_flt_t),
4270Sstevel@tonic-gate 	    aflt->flt_panic);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate  * The cpu_async_log_err() function is called by the ce/ue_drain() function to
4320Sstevel@tonic-gate  * handle logging for CPU events that are dequeued.  As such, it can be invoked
4330Sstevel@tonic-gate  * from softint context, from AST processing in the trap() flow, or from the
4340Sstevel@tonic-gate  * panic flow.  We decode the CPU-specific data, and log appropriate messages.
4350Sstevel@tonic-gate  */
4360Sstevel@tonic-gate void
4370Sstevel@tonic-gate cpu_async_log_err(void *flt)
4380Sstevel@tonic-gate {
4390Sstevel@tonic-gate 	errh_async_flt_t *errh_fltp = (errh_async_flt_t *)flt;
4400Sstevel@tonic-gate 	errh_er_t *errh_erp = (errh_er_t *)&errh_fltp->errh_er;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	switch (errh_erp->desc) {
4430Sstevel@tonic-gate 	case ERRH_DESC_UCOR_RE:
4440Sstevel@tonic-gate 		if (errh_erp->attr & ERRH_ATTR_MEM) {
4450Sstevel@tonic-gate 			/*
4460Sstevel@tonic-gate 			 * Turn on the PAGE_IS_TOXIC flag. The page will be
4470Sstevel@tonic-gate 			 * scrubbed when it is freed.
4480Sstevel@tonic-gate 			 */
4490Sstevel@tonic-gate 			(void) errh_page_settoxic(errh_fltp, PAGE_IS_TOXIC);
4500Sstevel@tonic-gate 		}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 		break;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	case ERRH_DESC_PR_NRE:
4550Sstevel@tonic-gate 	case ERRH_DESC_DEF_NRE:
4560Sstevel@tonic-gate 		if (errh_erp->attr & ERRH_ATTR_MEM) {
4570Sstevel@tonic-gate 			/*
4580Sstevel@tonic-gate 			 * For non-resumable memory error, retire
4590Sstevel@tonic-gate 			 * the page here.
4600Sstevel@tonic-gate 			 */
4610Sstevel@tonic-gate 			errh_page_retire(errh_fltp);
4620Sstevel@tonic-gate 		}
4630Sstevel@tonic-gate 		break;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	default:
4660Sstevel@tonic-gate 		break;
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate /*
4710Sstevel@tonic-gate  * Called from ce_drain().
4720Sstevel@tonic-gate  */
4730Sstevel@tonic-gate void
4740Sstevel@tonic-gate cpu_ce_log_err(struct async_flt *aflt)
4750Sstevel@tonic-gate {
4760Sstevel@tonic-gate 	switch (aflt->flt_class) {
4770Sstevel@tonic-gate 	case CPU_FAULT:
4780Sstevel@tonic-gate 		cpu_async_log_err(aflt);
4790Sstevel@tonic-gate 		break;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	case BUS_FAULT:
4820Sstevel@tonic-gate 		cpu_async_log_err(aflt);
4830Sstevel@tonic-gate 		break;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	default:
4860Sstevel@tonic-gate 		break;
4870Sstevel@tonic-gate 	}
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate /*
4910Sstevel@tonic-gate  * Called from ue_drain().
4920Sstevel@tonic-gate  */
4930Sstevel@tonic-gate void
4940Sstevel@tonic-gate cpu_ue_log_err(struct async_flt *aflt)
4950Sstevel@tonic-gate {
4960Sstevel@tonic-gate 	switch (aflt->flt_class) {
4970Sstevel@tonic-gate 	case CPU_FAULT:
4980Sstevel@tonic-gate 		cpu_async_log_err(aflt);
4990Sstevel@tonic-gate 		break;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	case BUS_FAULT:
5020Sstevel@tonic-gate 		cpu_async_log_err(aflt);
5030Sstevel@tonic-gate 		break;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	default:
5060Sstevel@tonic-gate 		break;
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate  * Turn on flag on the error memory region.
5120Sstevel@tonic-gate  */
5130Sstevel@tonic-gate static void
5140Sstevel@tonic-gate errh_page_settoxic(errh_async_flt_t *errh_fltp, uchar_t flag)
5150Sstevel@tonic-gate {
5160Sstevel@tonic-gate 	page_t *pp;
5170Sstevel@tonic-gate 	uint64_t flt_real_addr_start = errh_fltp->errh_er.ra;
5180Sstevel@tonic-gate 	uint64_t flt_real_addr_end = flt_real_addr_start +
5190Sstevel@tonic-gate 	    errh_fltp->errh_er.sz - 1;
5200Sstevel@tonic-gate 	int64_t current_addr;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	if (errh_fltp->errh_er.sz == 0)
5230Sstevel@tonic-gate 		return;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	for (current_addr = flt_real_addr_start;
5260Sstevel@tonic-gate 	    current_addr < flt_real_addr_end; current_addr += MMU_PAGESIZE) {
5270Sstevel@tonic-gate 		pp = page_numtopp_nolock((pfn_t)
5280Sstevel@tonic-gate 		    (current_addr >> MMU_PAGESHIFT));
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 		if (pp != NULL) {
5310Sstevel@tonic-gate 			page_settoxic(pp, flag);
5320Sstevel@tonic-gate 		}
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate }
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate /*
5370Sstevel@tonic-gate  * Retire the page(s) indicated in the error report.
5380Sstevel@tonic-gate  */
5390Sstevel@tonic-gate static void
5400Sstevel@tonic-gate errh_page_retire(errh_async_flt_t *errh_fltp)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	page_t *pp;
5430Sstevel@tonic-gate 	uint64_t flt_real_addr_start = errh_fltp->errh_er.ra;
5440Sstevel@tonic-gate 	uint64_t flt_real_addr_end = flt_real_addr_start +
5450Sstevel@tonic-gate 	    errh_fltp->errh_er.sz - 1;
5460Sstevel@tonic-gate 	int64_t current_addr;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	if (errh_fltp->errh_er.sz == 0)
5490Sstevel@tonic-gate 		return;
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	for (current_addr = flt_real_addr_start;
5520Sstevel@tonic-gate 	    current_addr < flt_real_addr_end; current_addr += MMU_PAGESIZE) {
5530Sstevel@tonic-gate 		pp = page_numtopp_nolock((pfn_t)
5540Sstevel@tonic-gate 		    (current_addr >> MMU_PAGESHIFT));
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 		if (pp != NULL) {
5570Sstevel@tonic-gate 			(void) page_retire(pp, PAGE_IS_TOXIC);
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 	}
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate void
5630Sstevel@tonic-gate mem_scrub(uint64_t paddr, uint64_t len)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate 	uint64_t pa, length, scrubbed_len;
5660Sstevel@tonic-gate 	uint64_t ret = H_EOK;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	pa = paddr;
5690Sstevel@tonic-gate 	length = len;
5700Sstevel@tonic-gate 	scrubbed_len = 0;
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	while (ret == H_EOK) {
5730Sstevel@tonic-gate 		ret = hv_mem_scrub(pa, length, &scrubbed_len);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 		if (ret == H_EOK || scrubbed_len >= length) {
5760Sstevel@tonic-gate 			break;
5770Sstevel@tonic-gate 		}
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 		pa += scrubbed_len;
5800Sstevel@tonic-gate 		length -= scrubbed_len;
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate void
5850Sstevel@tonic-gate mem_sync(caddr_t va, size_t len)
5860Sstevel@tonic-gate {
5870Sstevel@tonic-gate 	uint64_t pa, length, flushed;
5880Sstevel@tonic-gate 	uint64_t ret = H_EOK;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	pa = va_to_pa((caddr_t)va);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	if (pa == (uint64_t)-1)
5930Sstevel@tonic-gate 		return;
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	length = len;
5960Sstevel@tonic-gate 	flushed = 0;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	while (ret == H_EOK) {
5990Sstevel@tonic-gate 		ret = hv_mem_sync(pa, length, &flushed);
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		if (ret == H_EOK || flushed >= length) {
6020Sstevel@tonic-gate 			break;
6030Sstevel@tonic-gate 		}
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 		pa += flushed;
6060Sstevel@tonic-gate 		length -= flushed;
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate /*
6110Sstevel@tonic-gate  * If resumable queue is full, we need to check if any cpu is in
6120Sstevel@tonic-gate  * error state. If not, we drive on. If yes, we need to panic. The
6130Sstevel@tonic-gate  * hypervisor call hv_cpu_state() is being used for checking the
6140Sstevel@tonic-gate  * cpu state.
6150Sstevel@tonic-gate  */
6160Sstevel@tonic-gate static void
6170Sstevel@tonic-gate errh_rq_full(struct async_flt *afltp)
6180Sstevel@tonic-gate {
6190Sstevel@tonic-gate 	processorid_t who;
6200Sstevel@tonic-gate 	uint64_t cpu_state;
6210Sstevel@tonic-gate 	uint64_t retval;
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	for (who = 0; who < NCPU; who++)
6240Sstevel@tonic-gate 		if (CPU_IN_SET(cpu_ready_set, who)) {
6250Sstevel@tonic-gate 			retval = hv_cpu_state(who, &cpu_state);
6260Sstevel@tonic-gate 			if (retval != H_EOK || cpu_state == CPU_STATE_ERROR) {
6270Sstevel@tonic-gate 				afltp->flt_panic = 1;
6280Sstevel@tonic-gate 				break;
6290Sstevel@tonic-gate 			}
6300Sstevel@tonic-gate 		}
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate /*
6340Sstevel@tonic-gate  * Return processor specific async error structure
6350Sstevel@tonic-gate  * size used.
6360Sstevel@tonic-gate  */
6370Sstevel@tonic-gate int
6380Sstevel@tonic-gate cpu_aflt_size(void)
6390Sstevel@tonic-gate {
6400Sstevel@tonic-gate 	return (sizeof (errh_async_flt_t));
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate #define	SZ_TO_ETRS_SHIFT	6
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate /*
6460Sstevel@tonic-gate  * Message print out when resumable queue is overflown
6470Sstevel@tonic-gate  */
6480Sstevel@tonic-gate /*ARGSUSED*/
6490Sstevel@tonic-gate void
6500Sstevel@tonic-gate rq_overflow(struct regs *rp, uint64_t head_offset,
6510Sstevel@tonic-gate     uint64_t tail_offset)
6520Sstevel@tonic-gate {
6530Sstevel@tonic-gate 	rq_overflow_count++;
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate /*
6570Sstevel@tonic-gate  * Handler to process a fatal error.  This routine can be called from a
6580Sstevel@tonic-gate  * softint, called from trap()'s AST handling, or called from the panic flow.
6590Sstevel@tonic-gate  */
6600Sstevel@tonic-gate /*ARGSUSED*/
6610Sstevel@tonic-gate static void
6620Sstevel@tonic-gate ue_drain(void *ignored, struct async_flt *aflt, errorq_elem_t *eqep)
6630Sstevel@tonic-gate {
6640Sstevel@tonic-gate 	cpu_ue_log_err(aflt);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate  * Handler to process a correctable error.  This routine can be called from a
6690Sstevel@tonic-gate  * softint.  We just call the CPU module's logging routine.
6700Sstevel@tonic-gate  */
6710Sstevel@tonic-gate /*ARGSUSED*/
6720Sstevel@tonic-gate static void
6730Sstevel@tonic-gate ce_drain(void *ignored, struct async_flt *aflt, errorq_elem_t *eqep)
6740Sstevel@tonic-gate {
6750Sstevel@tonic-gate 	cpu_ce_log_err(aflt);
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate /*
679*541Srf157361  * Handler to process vbsc hostshutdown (power-off button).
680*541Srf157361  */
681*541Srf157361 static int
682*541Srf157361 err_shutdown_softintr()
683*541Srf157361 {
684*541Srf157361 	cmn_err(CE_WARN, "Power-off requested, system will now shutdown.");
685*541Srf157361 	do_shutdown();
686*541Srf157361 
687*541Srf157361 	/*
688*541Srf157361 	 * just in case do_shutdown() fails
689*541Srf157361 	 */
690*541Srf157361 	(void) timeout((void(*)(void *))power_down, NULL, 100 * hz);
691*541Srf157361 	return (DDI_INTR_CLAIMED);
692*541Srf157361 }
693*541Srf157361 
694*541Srf157361 /*
6950Sstevel@tonic-gate  * Allocate error queue sizes based on max_ncpus.  max_ncpus is set just
6960Sstevel@tonic-gate  * after ncpunode has been determined.  ncpus is set in start_other_cpus
6970Sstevel@tonic-gate  * which is called after error_init() but may change dynamically.
6980Sstevel@tonic-gate  */
6990Sstevel@tonic-gate void
7000Sstevel@tonic-gate error_init(void)
7010Sstevel@tonic-gate {
7020Sstevel@tonic-gate 	char tmp_name[MAXSYSNAME];
7030Sstevel@tonic-gate 	dnode_t node;
7040Sstevel@tonic-gate 	size_t size = cpu_aflt_size();
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/*
7070Sstevel@tonic-gate 	 * Initialize the correctable and uncorrectable error queues.
7080Sstevel@tonic-gate 	 */
7090Sstevel@tonic-gate 	ue_queue = errorq_create("ue_queue", (errorq_func_t)ue_drain, NULL,
7100Sstevel@tonic-gate 	    MAX_ASYNC_FLTS * (max_ncpus + 1), size, PIL_2, ERRORQ_VITAL);
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	ce_queue = errorq_create("ce_queue", (errorq_func_t)ce_drain, NULL,
7130Sstevel@tonic-gate 	    MAX_CE_FLTS * (max_ncpus + 1), size, PIL_1, 0);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	if (ue_queue == NULL || ce_queue == NULL)
7160Sstevel@tonic-gate 		panic("failed to create required system error queue");
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	/*
719*541Srf157361 	 * Setup interrupt handler for power-off button.
720*541Srf157361 	 */
721*541Srf157361 	err_shutdown_inum = add_softintr(PIL_9,
722*541Srf157361 	    (softintrfunc)err_shutdown_softintr, NULL);
723*541Srf157361 
724*541Srf157361 	/*
7250Sstevel@tonic-gate 	 * Initialize the busfunc list mutex.  This must be a PIL_15 spin lock
7260Sstevel@tonic-gate 	 * because we will need to acquire it from cpu_async_error().
7270Sstevel@tonic-gate 	 */
7280Sstevel@tonic-gate 	mutex_init(&bfd_lock, NULL, MUTEX_SPIN, (void *)PIL_15);
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	node = prom_rootnode();
7310Sstevel@tonic-gate 	if ((node == OBP_NONODE) || (node == OBP_BADNODE)) {
7320Sstevel@tonic-gate 		cmn_err(CE_CONT, "error_init: node 0x%x\n", (uint_t)node);
7330Sstevel@tonic-gate 		return;
7340Sstevel@tonic-gate 	}
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	if (((size = prom_getproplen(node, "reset-reason")) != -1) &&
7370Sstevel@tonic-gate 	    (size <= MAXSYSNAME) &&
7380Sstevel@tonic-gate 	    (prom_getprop(node, "reset-reason", tmp_name) != -1)) {
7390Sstevel@tonic-gate 		if (reset_debug) {
7400Sstevel@tonic-gate 			cmn_err(CE_CONT, "System booting after %s\n", tmp_name);
7410Sstevel@tonic-gate 		} else if (strncmp(tmp_name, "FATAL", 5) == 0) {
7420Sstevel@tonic-gate 			cmn_err(CE_CONT,
7430Sstevel@tonic-gate 			    "System booting after fatal error %s\n", tmp_name);
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate }
747