xref: /illumos-gate/usr/src/uts/sun4v/os/error.c (revision db874c57)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
317c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
327c478bd9Sstevel@tonic-gate #include <sys/async.h>
337c478bd9Sstevel@tonic-gate #include <sys/ontrap.h>
347c478bd9Sstevel@tonic-gate #include <sys/ddifm.h>
357c478bd9Sstevel@tonic-gate #include <sys/hypervisor_api.h>
367c478bd9Sstevel@tonic-gate #include <sys/errorq.h>
377c478bd9Sstevel@tonic-gate #include <sys/promif.h>
387c478bd9Sstevel@tonic-gate #include <sys/prom_plat.h>
397c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
407c478bd9Sstevel@tonic-gate #include <sys/error.h>
417c478bd9Sstevel@tonic-gate #include <sys/fm/util.h>
423cac8019Srf #include <sys/ivintr.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #define	MAX_CE_FLTS		10
457c478bd9Sstevel@tonic-gate #define	MAX_ASYNC_FLTS		6
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate errorq_t *ue_queue;			/* queue of uncorrectable errors */
487c478bd9Sstevel@tonic-gate errorq_t *ce_queue;			/* queue of correctable errors */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Being used by memory test driver.
527c478bd9Sstevel@tonic-gate  * ce_verbose_memory - covers CEs in DIMMs
537c478bd9Sstevel@tonic-gate  * ce_verbose_other - covers "others" (ecache, IO, etc.)
547c478bd9Sstevel@tonic-gate  *
557c478bd9Sstevel@tonic-gate  * If the value is 0, nothing is logged.
567c478bd9Sstevel@tonic-gate  * If the value is 1, the error is logged to the log file, but not console.
577c478bd9Sstevel@tonic-gate  * If the value is 2, the error is logged to the log file and console.
587c478bd9Sstevel@tonic-gate  */
597c478bd9Sstevel@tonic-gate int	ce_verbose_memory = 1;
607c478bd9Sstevel@tonic-gate int	ce_verbose_other = 1;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate int	ce_show_data = 0;
637c478bd9Sstevel@tonic-gate int	ce_debug = 0;
647c478bd9Sstevel@tonic-gate int	ue_debug = 0;
657c478bd9Sstevel@tonic-gate int	reset_debug = 0;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate  * Tunables for controlling the handling of asynchronous faults (AFTs). Setting
697c478bd9Sstevel@tonic-gate  * these to non-default values on a non-DEBUG kernel is NOT supported.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate int	aft_verbose = 0;	/* log AFT messages > 1 to log only */
727c478bd9Sstevel@tonic-gate int	aft_panic = 0;		/* panic (not reboot) on fatal usermode AFLT */
737c478bd9Sstevel@tonic-gate int	aft_testfatal = 0;	/* force all AFTs to panic immediately */
747c478bd9Sstevel@tonic-gate 
753cac8019Srf /*
763cac8019Srf  * Used for vbsc hostshutdown (power-off buton)
773cac8019Srf  */
783cac8019Srf int	err_shutdown_triggered = 0;	/* only once */
793cac8019Srf uint_t	err_shutdown_inum = 0;		/* used to pull the trigger */
803cac8019Srf 
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * Defined in bus_func.c but initialised in error_init
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate extern kmutex_t bfd_lock;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate static uint32_t rq_overflow_count = 0;		/* counter for rq overflow */
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static void cpu_queue_one_event(errh_async_flt_t *);
897c478bd9Sstevel@tonic-gate static uint32_t count_entries_on_queue(uint64_t, uint64_t, uint32_t);
90*db874c57Selowe static void errh_page_retire(errh_async_flt_t *, uchar_t);
917c478bd9Sstevel@tonic-gate static int errh_error_protected(struct regs *, struct async_flt *, int *);
927c478bd9Sstevel@tonic-gate static void errh_rq_full(struct async_flt *);
937c478bd9Sstevel@tonic-gate static void ue_drain(void *, struct async_flt *, errorq_elem_t *);
947c478bd9Sstevel@tonic-gate static void ce_drain(void *, struct async_flt *, errorq_elem_t *);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*ARGSUSED*/
977c478bd9Sstevel@tonic-gate void
987c478bd9Sstevel@tonic-gate process_resumable_error(struct regs *rp, uint32_t head_offset,
997c478bd9Sstevel@tonic-gate     uint32_t tail_offset)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	struct machcpu *mcpup;
1027c478bd9Sstevel@tonic-gate 	struct async_flt *aflt;
1037c478bd9Sstevel@tonic-gate 	errh_async_flt_t errh_flt;
1047c478bd9Sstevel@tonic-gate 	errh_er_t *head_va;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	mcpup = &(CPU->cpu_m);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	while (head_offset != tail_offset) {
1097c478bd9Sstevel@tonic-gate 		/* kernel buffer starts right after the resumable queue */
1107c478bd9Sstevel@tonic-gate 		head_va = (errh_er_t *)(mcpup->cpu_rq_va + head_offset +
1117c478bd9Sstevel@tonic-gate 		    CPU_RQ_SIZE);
1127c478bd9Sstevel@tonic-gate 		/* Copy the error report to local buffer */
1137c478bd9Sstevel@tonic-gate 		bzero(&errh_flt, sizeof (errh_async_flt_t));
1147c478bd9Sstevel@tonic-gate 		bcopy((char *)head_va, &(errh_flt.errh_er),
1157c478bd9Sstevel@tonic-gate 		    sizeof (errh_er_t));
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 		/* Increment the queue head */
1187c478bd9Sstevel@tonic-gate 		head_offset += Q_ENTRY_SIZE;
1197c478bd9Sstevel@tonic-gate 		/* Wrap around */
1207c478bd9Sstevel@tonic-gate 		head_offset &= (CPU_RQ_SIZE - 1);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 		/* set error handle to zero so it can hold new error report */
1237c478bd9Sstevel@tonic-gate 		head_va->ehdl = 0;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 		switch (errh_flt.errh_er.desc) {
1267c478bd9Sstevel@tonic-gate 		case ERRH_DESC_UCOR_RE:
1277c478bd9Sstevel@tonic-gate 			break;
1287c478bd9Sstevel@tonic-gate 
1293cac8019Srf 		case ERRH_DESC_WARN_RE:
1303cac8019Srf 			/*
1313cac8019Srf 			 * Power-off requested, but handle it one time only.
1323cac8019Srf 			 */
1333cac8019Srf 			if (!err_shutdown_triggered) {
1343cac8019Srf 				setsoftint(err_shutdown_inum);
1353cac8019Srf 				++err_shutdown_triggered;
1363cac8019Srf 			}
1373cac8019Srf 			continue;
1383cac8019Srf 
1397c478bd9Sstevel@tonic-gate 		default:
1407c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "Error Descriptor 0x%llx "
1417c478bd9Sstevel@tonic-gate 			    " invalid in resumable error handler",
1427c478bd9Sstevel@tonic-gate 			    (long long) errh_flt.errh_er.desc);
1437c478bd9Sstevel@tonic-gate 			continue;
1447c478bd9Sstevel@tonic-gate 		}
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 		aflt = (struct async_flt *)&(errh_flt.cmn_asyncflt);
1477c478bd9Sstevel@tonic-gate 		aflt->flt_id = gethrtime();
1487c478bd9Sstevel@tonic-gate 		aflt->flt_bus_id = getprocessorid();
1497c478bd9Sstevel@tonic-gate 		aflt->flt_class = CPU_FAULT;
1507c478bd9Sstevel@tonic-gate 		aflt->flt_prot = AFLT_PROT_NONE;
1517c478bd9Sstevel@tonic-gate 		aflt->flt_priv = (((errh_flt.errh_er.attr & ERRH_MODE_MASK)
1527c478bd9Sstevel@tonic-gate 		    >> ERRH_MODE_SHIFT) == ERRH_MODE_PRIV);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 		if (errh_flt.errh_er.attr & ERRH_ATTR_CPU)
1557c478bd9Sstevel@tonic-gate 			/* If it is an error on other cpu */
1567c478bd9Sstevel@tonic-gate 			aflt->flt_panic = 1;
1577c478bd9Sstevel@tonic-gate 		else
1587c478bd9Sstevel@tonic-gate 			aflt->flt_panic = 0;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 		/*
1617c478bd9Sstevel@tonic-gate 		 * Handle resumable queue full case.
1627c478bd9Sstevel@tonic-gate 		 */
1637c478bd9Sstevel@tonic-gate 		if (errh_flt.errh_er.attr & ERRH_ATTR_RQF) {
1647c478bd9Sstevel@tonic-gate 			(void) errh_rq_full(aflt);
1657c478bd9Sstevel@tonic-gate 		}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		/*
1687c478bd9Sstevel@tonic-gate 		 * Queue the error on ce or ue queue depend on flt_panic.
1697c478bd9Sstevel@tonic-gate 		 * Even if flt_panic is set, the code still keep processing
1707c478bd9Sstevel@tonic-gate 		 * the rest element on rq until the panic starts.
1717c478bd9Sstevel@tonic-gate 		 */
1727c478bd9Sstevel@tonic-gate 		(void) cpu_queue_one_event(&errh_flt);
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		/*
1757c478bd9Sstevel@tonic-gate 		 * Panic here if aflt->flt_panic has been set.
1767c478bd9Sstevel@tonic-gate 		 * Enqueued errors will be logged as part of the panic flow.
1777c478bd9Sstevel@tonic-gate 		 */
1787c478bd9Sstevel@tonic-gate 		if (aflt->flt_panic) {
1797c478bd9Sstevel@tonic-gate 			fm_panic("Unrecoverable error on another CPU");
1807c478bd9Sstevel@tonic-gate 		}
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate void
1857c478bd9Sstevel@tonic-gate process_nonresumable_error(struct regs *rp, uint64_t tl,
1867c478bd9Sstevel@tonic-gate     uint32_t head_offset, uint32_t tail_offset)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	struct machcpu *mcpup;
1897c478bd9Sstevel@tonic-gate 	struct async_flt *aflt;
1907c478bd9Sstevel@tonic-gate 	errh_async_flt_t errh_flt;
1917c478bd9Sstevel@tonic-gate 	errh_er_t *head_va;
1927c478bd9Sstevel@tonic-gate 	int trampolined = 0;
1937c478bd9Sstevel@tonic-gate 	int expected = DDI_FM_ERR_UNEXPECTED;
1947c478bd9Sstevel@tonic-gate 	uint64_t exec_mode;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	mcpup = &(CPU->cpu_m);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	while (head_offset != tail_offset) {
1997c478bd9Sstevel@tonic-gate 		/* kernel buffer starts right after the nonresumable queue */
2007c478bd9Sstevel@tonic-gate 		head_va = (errh_er_t *)(mcpup->cpu_nrq_va + head_offset +
2017c478bd9Sstevel@tonic-gate 		    CPU_NRQ_SIZE);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 		/* Copy the error report to local buffer */
2047c478bd9Sstevel@tonic-gate 		bzero(&errh_flt, sizeof (errh_async_flt_t));
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 		bcopy((char *)head_va, &(errh_flt.errh_er),
2077c478bd9Sstevel@tonic-gate 		    sizeof (errh_er_t));
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		/* Increment the queue head */
2107c478bd9Sstevel@tonic-gate 		head_offset += Q_ENTRY_SIZE;
2117c478bd9Sstevel@tonic-gate 		/* Wrap around */
2127c478bd9Sstevel@tonic-gate 		head_offset &= (CPU_NRQ_SIZE - 1);
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 		/* set error handle to zero so it can hold new error report */
2157c478bd9Sstevel@tonic-gate 		head_va->ehdl = 0;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 		aflt = (struct async_flt *)&(errh_flt.cmn_asyncflt);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		trampolined = 0;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 		if (errh_flt.errh_er.attr & ERRH_ATTR_PIO)
2227c478bd9Sstevel@tonic-gate 			aflt->flt_class = BUS_FAULT;
2237c478bd9Sstevel@tonic-gate 		else
2247c478bd9Sstevel@tonic-gate 			aflt->flt_class = CPU_FAULT;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		aflt->flt_id = gethrtime();
2277c478bd9Sstevel@tonic-gate 		aflt->flt_bus_id = getprocessorid();
2287c478bd9Sstevel@tonic-gate 		aflt->flt_pc = (caddr_t)rp->r_pc;
2297c478bd9Sstevel@tonic-gate 		exec_mode = (errh_flt.errh_er.attr & ERRH_MODE_MASK)
2307c478bd9Sstevel@tonic-gate 		    >> ERRH_MODE_SHIFT;
2317c478bd9Sstevel@tonic-gate 		aflt->flt_priv = (exec_mode == ERRH_MODE_PRIV ||
2327c478bd9Sstevel@tonic-gate 		    exec_mode == ERRH_MODE_UNKNOWN);
2337c478bd9Sstevel@tonic-gate 		aflt->flt_tl = (uchar_t)tl;
2347c478bd9Sstevel@tonic-gate 		aflt->flt_prot = AFLT_PROT_NONE;
2357c478bd9Sstevel@tonic-gate 		aflt->flt_panic = ((aflt->flt_tl != 0) ||
2367c478bd9Sstevel@tonic-gate 		    (aft_testfatal != 0));
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 		switch (errh_flt.errh_er.desc) {
2397c478bd9Sstevel@tonic-gate 		case ERRH_DESC_PR_NRE:
2407c478bd9Sstevel@tonic-gate 			/*
2417c478bd9Sstevel@tonic-gate 			 * Fall through, precise fault also need to check
2427c478bd9Sstevel@tonic-gate 			 * to see if it was protected.
2437c478bd9Sstevel@tonic-gate 			 */
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 		case ERRH_DESC_DEF_NRE:
2467c478bd9Sstevel@tonic-gate 			/*
2477c478bd9Sstevel@tonic-gate 			 * If the trap occurred in privileged mode at TL=0,
2487c478bd9Sstevel@tonic-gate 			 * we need to check to see if we were executing
2497c478bd9Sstevel@tonic-gate 			 * in kernel under on_trap() or t_lofault
2507c478bd9Sstevel@tonic-gate 			 * protection. If so, modify the saved registers
2517c478bd9Sstevel@tonic-gate 			 * so that we return from the trap to the
2527c478bd9Sstevel@tonic-gate 			 * appropriate trampoline routine.
2537c478bd9Sstevel@tonic-gate 			 */
2547c478bd9Sstevel@tonic-gate 			if (aflt->flt_priv == 1 && aflt->flt_tl == 0)
2557c478bd9Sstevel@tonic-gate 				trampolined =
2567c478bd9Sstevel@tonic-gate 				    errh_error_protected(rp, aflt, &expected);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 			if (!aflt->flt_priv || aflt->flt_prot ==
2597c478bd9Sstevel@tonic-gate 			    AFLT_PROT_COPY) {
2607c478bd9Sstevel@tonic-gate 				aflt->flt_panic |= aft_panic;
2617c478bd9Sstevel@tonic-gate 			} else if (!trampolined &&
2627c478bd9Sstevel@tonic-gate 			    aflt->flt_class != BUS_FAULT) {
2637c478bd9Sstevel@tonic-gate 				aflt->flt_panic = 1;
2647c478bd9Sstevel@tonic-gate 			}
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 			/*
2677c478bd9Sstevel@tonic-gate 			 * If PIO error, we need to query the bus nexus
2687c478bd9Sstevel@tonic-gate 			 * for fatal errors.
2697c478bd9Sstevel@tonic-gate 			 */
2707c478bd9Sstevel@tonic-gate 			if (aflt->flt_class == BUS_FAULT) {
2717c478bd9Sstevel@tonic-gate 				aflt->flt_addr = errh_flt.errh_er.ra;
2727c478bd9Sstevel@tonic-gate 				errh_cpu_run_bus_error_handlers(aflt,
2737c478bd9Sstevel@tonic-gate 				    expected);
2747c478bd9Sstevel@tonic-gate 			}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 			break;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 		default:
2797c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "Error Descriptor 0x%llx "
2807c478bd9Sstevel@tonic-gate 			    " invalid in nonresumable error handler",
2817c478bd9Sstevel@tonic-gate 			    (long long) errh_flt.errh_er.desc);
2827c478bd9Sstevel@tonic-gate 			continue;
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		/*
2867c478bd9Sstevel@tonic-gate 		 * Queue the error report for further processing. If
2877c478bd9Sstevel@tonic-gate 		 * flt_panic is set, code still process other errors
2887c478bd9Sstevel@tonic-gate 		 * in the queue until the panic routine stops the
2897c478bd9Sstevel@tonic-gate 		 * kernel.
2907c478bd9Sstevel@tonic-gate 		 */
2917c478bd9Sstevel@tonic-gate 		(void) cpu_queue_one_event(&errh_flt);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 		/*
2947c478bd9Sstevel@tonic-gate 		 * Panic here if aflt->flt_panic has been set.
2957c478bd9Sstevel@tonic-gate 		 * Enqueued errors will be logged as part of the panic flow.
2967c478bd9Sstevel@tonic-gate 		 */
2977c478bd9Sstevel@tonic-gate 		if (aflt->flt_panic) {
2987c478bd9Sstevel@tonic-gate 			fm_panic("Unrecoverable hardware error");
2997c478bd9Sstevel@tonic-gate 		}
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 		/*
302*db874c57Selowe 		 * Call page_retire() to handle memory errors.
3037c478bd9Sstevel@tonic-gate 		 */
3047c478bd9Sstevel@tonic-gate 		if (errh_flt.errh_er.attr & ERRH_ATTR_MEM)
305*db874c57Selowe 			errh_page_retire(&errh_flt, PR_UE);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 		/*
3087c478bd9Sstevel@tonic-gate 		 * If we queued an error and the it was in user mode or
3097c478bd9Sstevel@tonic-gate 		 * protected by t_lofault,
3107c478bd9Sstevel@tonic-gate 		 * set AST flag so the queue will be drained before
3117c478bd9Sstevel@tonic-gate 		 * returning to user mode.
3127c478bd9Sstevel@tonic-gate 		 */
3137c478bd9Sstevel@tonic-gate 		if (!aflt->flt_priv || aflt->flt_prot == AFLT_PROT_COPY) {
3147c478bd9Sstevel@tonic-gate 			int pcb_flag = 0;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 			if (aflt->flt_class == CPU_FAULT)
3177c478bd9Sstevel@tonic-gate 				pcb_flag |= ASYNC_HWERR;
3187c478bd9Sstevel@tonic-gate 			else if (aflt->flt_class == BUS_FAULT)
3197c478bd9Sstevel@tonic-gate 				pcb_flag |= ASYNC_BERR;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 			ttolwp(curthread)->lwp_pcb.pcb_flags |= pcb_flag;
3227c478bd9Sstevel@tonic-gate 			aston(curthread);
3237c478bd9Sstevel@tonic-gate 		}
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate /*
3287c478bd9Sstevel@tonic-gate  * For PIO errors, this routine calls nexus driver's error
3297c478bd9Sstevel@tonic-gate  * callback routines. If the callback routine returns fatal, and
3307c478bd9Sstevel@tonic-gate  * we are in kernel or unknow mode without any error protection,
3317c478bd9Sstevel@tonic-gate  * we need to turn on the panic flag.
3327c478bd9Sstevel@tonic-gate  */
3337c478bd9Sstevel@tonic-gate void
3347c478bd9Sstevel@tonic-gate errh_cpu_run_bus_error_handlers(struct async_flt *aflt, int expected)
3357c478bd9Sstevel@tonic-gate {
3367c478bd9Sstevel@tonic-gate 	int status;
3377c478bd9Sstevel@tonic-gate 	ddi_fm_error_t de;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	bzero(&de, sizeof (ddi_fm_error_t));
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	de.fme_version = DDI_FME_VERSION;
3427c478bd9Sstevel@tonic-gate 	de.fme_ena = fm_ena_generate(aflt->flt_id, FM_ENA_FMT1);
3437c478bd9Sstevel@tonic-gate 	de.fme_flag = expected;
3447c478bd9Sstevel@tonic-gate 	de.fme_bus_specific = (void *)aflt->flt_addr;
3457c478bd9Sstevel@tonic-gate 	status = ndi_fm_handler_dispatch(ddi_root_node(), NULL, &de);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/*
3487c478bd9Sstevel@tonic-gate 	 * If error is protected, it will jump to proper routine
3497c478bd9Sstevel@tonic-gate 	 * to handle the handle; if it is in user level, we just
3507c478bd9Sstevel@tonic-gate 	 * kill the user process; if the driver thinks the error is
3517c478bd9Sstevel@tonic-gate 	 * not fatal, we can drive on. If none of above are true,
3527c478bd9Sstevel@tonic-gate 	 * we panic
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate 	if ((aflt->flt_prot == AFLT_PROT_NONE) && (aflt->flt_priv == 1) &&
3557c478bd9Sstevel@tonic-gate 	    (status == DDI_FM_FATAL))
3567c478bd9Sstevel@tonic-gate 		aflt->flt_panic = 1;
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate /*
3607c478bd9Sstevel@tonic-gate  * This routine checks to see if we are under any error protection when
3617c478bd9Sstevel@tonic-gate  * the error happens. If we are under error protection, we unwind to
3627c478bd9Sstevel@tonic-gate  * the protection and indicate fault.
3637c478bd9Sstevel@tonic-gate  */
3647c478bd9Sstevel@tonic-gate static int
3657c478bd9Sstevel@tonic-gate errh_error_protected(struct regs *rp, struct async_flt *aflt, int *expected)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	int trampolined = 0;
3687c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	if (curthread->t_ontrap != NULL) {
3717c478bd9Sstevel@tonic-gate 		on_trap_data_t *otp = curthread->t_ontrap;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		if (otp->ot_prot & OT_DATA_EC) {
3747c478bd9Sstevel@tonic-gate 			aflt->flt_prot = AFLT_PROT_EC;
3757c478bd9Sstevel@tonic-gate 			otp->ot_trap |= OT_DATA_EC;
3767c478bd9Sstevel@tonic-gate 			rp->r_pc = otp->ot_trampoline;
3777c478bd9Sstevel@tonic-gate 			rp->r_npc = rp->r_pc +4;
3787c478bd9Sstevel@tonic-gate 			trampolined = 1;
3797c478bd9Sstevel@tonic-gate 		}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 		if (otp->ot_prot & OT_DATA_ACCESS) {
3827c478bd9Sstevel@tonic-gate 			aflt->flt_prot = AFLT_PROT_ACCESS;
3837c478bd9Sstevel@tonic-gate 			otp->ot_trap |= OT_DATA_ACCESS;
3847c478bd9Sstevel@tonic-gate 			rp->r_pc = otp->ot_trampoline;
3857c478bd9Sstevel@tonic-gate 			rp->r_npc = rp->r_pc + 4;
3867c478bd9Sstevel@tonic-gate 			trampolined = 1;
3877c478bd9Sstevel@tonic-gate 			/*
3887c478bd9Sstevel@tonic-gate 			 * for peek and caut_gets
3897c478bd9Sstevel@tonic-gate 			 * errors are expected
3907c478bd9Sstevel@tonic-gate 			 */
3917c478bd9Sstevel@tonic-gate 			hp = (ddi_acc_hdl_t *)otp->ot_handle;
3927c478bd9Sstevel@tonic-gate 			if (!hp)
3937c478bd9Sstevel@tonic-gate 				*expected = DDI_FM_ERR_PEEK;
3947c478bd9Sstevel@tonic-gate 			else if (hp->ah_acc.devacc_attr_access ==
3957c478bd9Sstevel@tonic-gate 			    DDI_CAUTIOUS_ACC)
3967c478bd9Sstevel@tonic-gate 				*expected = DDI_FM_ERR_EXPECTED;
3977c478bd9Sstevel@tonic-gate 		}
3987c478bd9Sstevel@tonic-gate 	} else if (curthread->t_lofault) {
3997c478bd9Sstevel@tonic-gate 		aflt->flt_prot = AFLT_PROT_COPY;
4007c478bd9Sstevel@tonic-gate 		rp->r_g1 = EFAULT;
4017c478bd9Sstevel@tonic-gate 		rp->r_pc = curthread->t_lofault;
4027c478bd9Sstevel@tonic-gate 		rp->r_npc = rp->r_pc + 4;
4037c478bd9Sstevel@tonic-gate 		trampolined = 1;
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	return (trampolined);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /*
4107c478bd9Sstevel@tonic-gate  * Queue one event.
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate static void
4137c478bd9Sstevel@tonic-gate cpu_queue_one_event(errh_async_flt_t *errh_fltp)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	struct async_flt *aflt = (struct async_flt *)errh_fltp;
4167c478bd9Sstevel@tonic-gate 	errorq_t *eqp;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	if (aflt->flt_panic)
4197c478bd9Sstevel@tonic-gate 		eqp = ue_queue;
4207c478bd9Sstevel@tonic-gate 	else
4217c478bd9Sstevel@tonic-gate 		eqp = ce_queue;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	errorq_dispatch(eqp, errh_fltp, sizeof (errh_async_flt_t),
4247c478bd9Sstevel@tonic-gate 	    aflt->flt_panic);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate /*
4287c478bd9Sstevel@tonic-gate  * The cpu_async_log_err() function is called by the ce/ue_drain() function to
4297c478bd9Sstevel@tonic-gate  * handle logging for CPU events that are dequeued.  As such, it can be invoked
4307c478bd9Sstevel@tonic-gate  * from softint context, from AST processing in the trap() flow, or from the
4317c478bd9Sstevel@tonic-gate  * panic flow.  We decode the CPU-specific data, and log appropriate messages.
4327c478bd9Sstevel@tonic-gate  */
4337c478bd9Sstevel@tonic-gate void
4347c478bd9Sstevel@tonic-gate cpu_async_log_err(void *flt)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate 	errh_async_flt_t *errh_fltp = (errh_async_flt_t *)flt;
4377c478bd9Sstevel@tonic-gate 	errh_er_t *errh_erp = (errh_er_t *)&errh_fltp->errh_er;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	switch (errh_erp->desc) {
4407c478bd9Sstevel@tonic-gate 	case ERRH_DESC_UCOR_RE:
4417c478bd9Sstevel@tonic-gate 		if (errh_erp->attr & ERRH_ATTR_MEM) {
4427c478bd9Sstevel@tonic-gate 			/*
443*db874c57Selowe 			 * Turn on the PR_UE flag. The page will be
4447c478bd9Sstevel@tonic-gate 			 * scrubbed when it is freed.
4457c478bd9Sstevel@tonic-gate 			 */
446*db874c57Selowe 			errh_page_retire(errh_fltp, PR_UE);
4477c478bd9Sstevel@tonic-gate 		}
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 		break;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	case ERRH_DESC_PR_NRE:
4527c478bd9Sstevel@tonic-gate 	case ERRH_DESC_DEF_NRE:
4537c478bd9Sstevel@tonic-gate 		if (errh_erp->attr & ERRH_ATTR_MEM) {
4547c478bd9Sstevel@tonic-gate 			/*
4557c478bd9Sstevel@tonic-gate 			 * For non-resumable memory error, retire
4567c478bd9Sstevel@tonic-gate 			 * the page here.
4577c478bd9Sstevel@tonic-gate 			 */
458*db874c57Selowe 			errh_page_retire(errh_fltp, PR_UE);
4593461bce3Swh 
4603461bce3Swh 			/*
4613461bce3Swh 			 * If we are going to panic, scrub the page first
4623461bce3Swh 			 */
4633461bce3Swh 			if (errh_fltp->cmn_asyncflt.flt_panic)
4643461bce3Swh 				mem_scrub(errh_fltp->errh_er.ra,
4653461bce3Swh 				    errh_fltp->errh_er.sz);
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 		break;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	default:
4707c478bd9Sstevel@tonic-gate 		break;
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate  * Called from ce_drain().
4767c478bd9Sstevel@tonic-gate  */
4777c478bd9Sstevel@tonic-gate void
4787c478bd9Sstevel@tonic-gate cpu_ce_log_err(struct async_flt *aflt)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate 	switch (aflt->flt_class) {
4817c478bd9Sstevel@tonic-gate 	case CPU_FAULT:
4827c478bd9Sstevel@tonic-gate 		cpu_async_log_err(aflt);
4837c478bd9Sstevel@tonic-gate 		break;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	case BUS_FAULT:
4867c478bd9Sstevel@tonic-gate 		cpu_async_log_err(aflt);
4877c478bd9Sstevel@tonic-gate 		break;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	default:
4907c478bd9Sstevel@tonic-gate 		break;
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate  * Called from ue_drain().
4967c478bd9Sstevel@tonic-gate  */
4977c478bd9Sstevel@tonic-gate void
4987c478bd9Sstevel@tonic-gate cpu_ue_log_err(struct async_flt *aflt)
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate 	switch (aflt->flt_class) {
5017c478bd9Sstevel@tonic-gate 	case CPU_FAULT:
5027c478bd9Sstevel@tonic-gate 		cpu_async_log_err(aflt);
5037c478bd9Sstevel@tonic-gate 		break;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	case BUS_FAULT:
5067c478bd9Sstevel@tonic-gate 		cpu_async_log_err(aflt);
5077c478bd9Sstevel@tonic-gate 		break;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	default:
5107c478bd9Sstevel@tonic-gate 		break;
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate /*
5157c478bd9Sstevel@tonic-gate  * Turn on flag on the error memory region.
5167c478bd9Sstevel@tonic-gate  */
5177c478bd9Sstevel@tonic-gate static void
518*db874c57Selowe errh_page_retire(errh_async_flt_t *errh_fltp, uchar_t flag)
5197c478bd9Sstevel@tonic-gate {
5207c478bd9Sstevel@tonic-gate 	uint64_t flt_real_addr_start = errh_fltp->errh_er.ra;
5217c478bd9Sstevel@tonic-gate 	uint64_t flt_real_addr_end = flt_real_addr_start +
5227c478bd9Sstevel@tonic-gate 	    errh_fltp->errh_er.sz - 1;
5237c478bd9Sstevel@tonic-gate 	int64_t current_addr;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (errh_fltp->errh_er.sz == 0)
5267c478bd9Sstevel@tonic-gate 		return;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	for (current_addr = flt_real_addr_start;
5297c478bd9Sstevel@tonic-gate 	    current_addr < flt_real_addr_end; current_addr += MMU_PAGESIZE) {
530*db874c57Selowe 		(void) page_retire(current_addr, flag);
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate void
5357c478bd9Sstevel@tonic-gate mem_scrub(uint64_t paddr, uint64_t len)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	uint64_t pa, length, scrubbed_len;
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	pa = paddr;
5407c478bd9Sstevel@tonic-gate 	length = len;
5417c478bd9Sstevel@tonic-gate 	scrubbed_len = 0;
5427c478bd9Sstevel@tonic-gate 
5433461bce3Swh 	while (length > 0) {
5443461bce3Swh 		if (hv_mem_scrub(pa, length, &scrubbed_len) != H_EOK)
5457c478bd9Sstevel@tonic-gate 			break;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 		pa += scrubbed_len;
5487c478bd9Sstevel@tonic-gate 		length -= scrubbed_len;
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate void
5537c478bd9Sstevel@tonic-gate mem_sync(caddr_t va, size_t len)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate 	uint64_t pa, length, flushed;
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	pa = va_to_pa((caddr_t)va);
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	if (pa == (uint64_t)-1)
5607c478bd9Sstevel@tonic-gate 		return;
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	length = len;
5637c478bd9Sstevel@tonic-gate 	flushed = 0;
5647c478bd9Sstevel@tonic-gate 
5653461bce3Swh 	while (length > 0) {
5663461bce3Swh 		if (hv_mem_sync(pa, length, &flushed) != H_EOK)
5677c478bd9Sstevel@tonic-gate 			break;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		pa += flushed;
5707c478bd9Sstevel@tonic-gate 		length -= flushed;
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate /*
5757c478bd9Sstevel@tonic-gate  * If resumable queue is full, we need to check if any cpu is in
5767c478bd9Sstevel@tonic-gate  * error state. If not, we drive on. If yes, we need to panic. The
5777c478bd9Sstevel@tonic-gate  * hypervisor call hv_cpu_state() is being used for checking the
5787c478bd9Sstevel@tonic-gate  * cpu state.
5797c478bd9Sstevel@tonic-gate  */
5807c478bd9Sstevel@tonic-gate static void
5817c478bd9Sstevel@tonic-gate errh_rq_full(struct async_flt *afltp)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	processorid_t who;
5847c478bd9Sstevel@tonic-gate 	uint64_t cpu_state;
5857c478bd9Sstevel@tonic-gate 	uint64_t retval;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	for (who = 0; who < NCPU; who++)
5887c478bd9Sstevel@tonic-gate 		if (CPU_IN_SET(cpu_ready_set, who)) {
5897c478bd9Sstevel@tonic-gate 			retval = hv_cpu_state(who, &cpu_state);
5907c478bd9Sstevel@tonic-gate 			if (retval != H_EOK || cpu_state == CPU_STATE_ERROR) {
5917c478bd9Sstevel@tonic-gate 				afltp->flt_panic = 1;
5927c478bd9Sstevel@tonic-gate 				break;
5937c478bd9Sstevel@tonic-gate 			}
5947c478bd9Sstevel@tonic-gate 		}
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate /*
5987c478bd9Sstevel@tonic-gate  * Return processor specific async error structure
5997c478bd9Sstevel@tonic-gate  * size used.
6007c478bd9Sstevel@tonic-gate  */
6017c478bd9Sstevel@tonic-gate int
6027c478bd9Sstevel@tonic-gate cpu_aflt_size(void)
6037c478bd9Sstevel@tonic-gate {
6047c478bd9Sstevel@tonic-gate 	return (sizeof (errh_async_flt_t));
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate #define	SZ_TO_ETRS_SHIFT	6
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate /*
6107c478bd9Sstevel@tonic-gate  * Message print out when resumable queue is overflown
6117c478bd9Sstevel@tonic-gate  */
6127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6137c478bd9Sstevel@tonic-gate void
6147c478bd9Sstevel@tonic-gate rq_overflow(struct regs *rp, uint64_t head_offset,
6157c478bd9Sstevel@tonic-gate     uint64_t tail_offset)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	rq_overflow_count++;
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate /*
6217c478bd9Sstevel@tonic-gate  * Handler to process a fatal error.  This routine can be called from a
6227c478bd9Sstevel@tonic-gate  * softint, called from trap()'s AST handling, or called from the panic flow.
6237c478bd9Sstevel@tonic-gate  */
6247c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6257c478bd9Sstevel@tonic-gate static void
6267c478bd9Sstevel@tonic-gate ue_drain(void *ignored, struct async_flt *aflt, errorq_elem_t *eqep)
6277c478bd9Sstevel@tonic-gate {
6287c478bd9Sstevel@tonic-gate 	cpu_ue_log_err(aflt);
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate /*
6327c478bd9Sstevel@tonic-gate  * Handler to process a correctable error.  This routine can be called from a
6337c478bd9Sstevel@tonic-gate  * softint.  We just call the CPU module's logging routine.
6347c478bd9Sstevel@tonic-gate  */
6357c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6367c478bd9Sstevel@tonic-gate static void
6377c478bd9Sstevel@tonic-gate ce_drain(void *ignored, struct async_flt *aflt, errorq_elem_t *eqep)
6387c478bd9Sstevel@tonic-gate {
6397c478bd9Sstevel@tonic-gate 	cpu_ce_log_err(aflt);
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate 
6423cac8019Srf /*
6433cac8019Srf  * Handler to process vbsc hostshutdown (power-off button).
6443cac8019Srf  */
6453cac8019Srf static int
6463cac8019Srf err_shutdown_softintr()
6473cac8019Srf {
6483cac8019Srf 	cmn_err(CE_WARN, "Power-off requested, system will now shutdown.");
6493cac8019Srf 	do_shutdown();
6503cac8019Srf 
6513cac8019Srf 	/*
6523cac8019Srf 	 * just in case do_shutdown() fails
6533cac8019Srf 	 */
6543cac8019Srf 	(void) timeout((void(*)(void *))power_down, NULL, 100 * hz);
6553cac8019Srf 	return (DDI_INTR_CLAIMED);
6563cac8019Srf }
6573cac8019Srf 
6587c478bd9Sstevel@tonic-gate /*
6597c478bd9Sstevel@tonic-gate  * Allocate error queue sizes based on max_ncpus.  max_ncpus is set just
6607c478bd9Sstevel@tonic-gate  * after ncpunode has been determined.  ncpus is set in start_other_cpus
6617c478bd9Sstevel@tonic-gate  * which is called after error_init() but may change dynamically.
6627c478bd9Sstevel@tonic-gate  */
6637c478bd9Sstevel@tonic-gate void
6647c478bd9Sstevel@tonic-gate error_init(void)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	char tmp_name[MAXSYSNAME];
667fa9e4066Sahrens 	pnode_t node;
6687c478bd9Sstevel@tonic-gate 	size_t size = cpu_aflt_size();
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	/*
6717c478bd9Sstevel@tonic-gate 	 * Initialize the correctable and uncorrectable error queues.
6727c478bd9Sstevel@tonic-gate 	 */
6737c478bd9Sstevel@tonic-gate 	ue_queue = errorq_create("ue_queue", (errorq_func_t)ue_drain, NULL,
6747c478bd9Sstevel@tonic-gate 	    MAX_ASYNC_FLTS * (max_ncpus + 1), size, PIL_2, ERRORQ_VITAL);
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	ce_queue = errorq_create("ce_queue", (errorq_func_t)ce_drain, NULL,
6777c478bd9Sstevel@tonic-gate 	    MAX_CE_FLTS * (max_ncpus + 1), size, PIL_1, 0);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	if (ue_queue == NULL || ce_queue == NULL)
6807c478bd9Sstevel@tonic-gate 		panic("failed to create required system error queue");
6817c478bd9Sstevel@tonic-gate 
6823cac8019Srf 	/*
6833cac8019Srf 	 * Setup interrupt handler for power-off button.
6843cac8019Srf 	 */
6853cac8019Srf 	err_shutdown_inum = add_softintr(PIL_9,
6863cac8019Srf 	    (softintrfunc)err_shutdown_softintr, NULL);
6873cac8019Srf 
6887c478bd9Sstevel@tonic-gate 	/*
6897c478bd9Sstevel@tonic-gate 	 * Initialize the busfunc list mutex.  This must be a PIL_15 spin lock
6907c478bd9Sstevel@tonic-gate 	 * because we will need to acquire it from cpu_async_error().
6917c478bd9Sstevel@tonic-gate 	 */
6927c478bd9Sstevel@tonic-gate 	mutex_init(&bfd_lock, NULL, MUTEX_SPIN, (void *)PIL_15);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	node = prom_rootnode();
6957c478bd9Sstevel@tonic-gate 	if ((node == OBP_NONODE) || (node == OBP_BADNODE)) {
6967c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "error_init: node 0x%x\n", (uint_t)node);
6977c478bd9Sstevel@tonic-gate 		return;
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	if (((size = prom_getproplen(node, "reset-reason")) != -1) &&
7017c478bd9Sstevel@tonic-gate 	    (size <= MAXSYSNAME) &&
7027c478bd9Sstevel@tonic-gate 	    (prom_getprop(node, "reset-reason", tmp_name) != -1)) {
7037c478bd9Sstevel@tonic-gate 		if (reset_debug) {
7047c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "System booting after %s\n", tmp_name);
7057c478bd9Sstevel@tonic-gate 		} else if (strncmp(tmp_name, "FATAL", 5) == 0) {
7067c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
7077c478bd9Sstevel@tonic-gate 			    "System booting after fatal error %s\n", tmp_name);
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate }
71118aea0b1Swh 
71218aea0b1Swh /*
71318aea0b1Swh  * Nonresumable queue is full, panic here
71418aea0b1Swh  */
71518aea0b1Swh /*ARGSUSED*/
71618aea0b1Swh void
71718aea0b1Swh nrq_overflow(struct regs *rp)
71818aea0b1Swh {
71918aea0b1Swh 	fm_panic("Nonresumable queue full");
72018aea0b1Swh }
721