1*9dd0f810Scindi /*
2*9dd0f810Scindi  * CDDL HEADER START
3*9dd0f810Scindi  *
4*9dd0f810Scindi  * The contents of this file are subject to the terms of the
5*9dd0f810Scindi  * Common Development and Distribution License (the "License").
6*9dd0f810Scindi  * You may not use this file except in compliance with the License.
7*9dd0f810Scindi  *
8*9dd0f810Scindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9dd0f810Scindi  * or http://www.opensolaris.org/os/licensing.
10*9dd0f810Scindi  * See the License for the specific language governing permissions
11*9dd0f810Scindi  * and limitations under the License.
12*9dd0f810Scindi  *
13*9dd0f810Scindi  * When distributing Covered Code, include this CDDL HEADER in each
14*9dd0f810Scindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9dd0f810Scindi  * If applicable, add the following below this CDDL HEADER, with the
16*9dd0f810Scindi  * fields enclosed by brackets "[]" replaced with your own identifying
17*9dd0f810Scindi  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9dd0f810Scindi  *
19*9dd0f810Scindi  * CDDL HEADER END
20*9dd0f810Scindi  */
21*9dd0f810Scindi /*
22*9dd0f810Scindi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*9dd0f810Scindi  * Use is subject to license terms.
24*9dd0f810Scindi  */
25*9dd0f810Scindi 
26*9dd0f810Scindi #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*9dd0f810Scindi 
28*9dd0f810Scindi #include <sys/types.h>
29*9dd0f810Scindi #include <sys/time.h>
30*9dd0f810Scindi #include <sys/sysmacros.h>
31*9dd0f810Scindi #include <sys/ddifm.h>
32*9dd0f810Scindi #include <sys/nvpair.h>
33*9dd0f810Scindi #include <sys/nvpair_impl.h>
34*9dd0f810Scindi #include <sys/errorq_impl.h>
35*9dd0f810Scindi #include <sys/errorq.h>
36*9dd0f810Scindi #include <sys/fm/protocol.h>
37*9dd0f810Scindi 
38*9dd0f810Scindi #include <ctype.h>
39*9dd0f810Scindi #include <mdb/mdb_modapi.h>
40*9dd0f810Scindi #include <mdb/mdb_ks.h>
41*9dd0f810Scindi 
42*9dd0f810Scindi #include "nvpair.h"
43*9dd0f810Scindi 
44*9dd0f810Scindi int
45*9dd0f810Scindi ereportq_pend_walk_init(mdb_walk_state_t *wsp)
46*9dd0f810Scindi {
47*9dd0f810Scindi 	errorq_t eq;
48*9dd0f810Scindi 	uintptr_t addr;
49*9dd0f810Scindi 
50*9dd0f810Scindi 	if (wsp->walk_addr == NULL &&
51*9dd0f810Scindi 	    mdb_readvar(&addr, "ereport_errorq") == -1) {
52*9dd0f810Scindi 		mdb_warn("failed to read ereport_errorq");
53*9dd0f810Scindi 		return (WALK_ERR);
54*9dd0f810Scindi 	}
55*9dd0f810Scindi 
56*9dd0f810Scindi 	if (mdb_vread(&eq, sizeof (eq), addr) == -1) {
57*9dd0f810Scindi 		mdb_warn("failed to read ereport_errorq at %p", addr);
58*9dd0f810Scindi 		return (WALK_ERR);
59*9dd0f810Scindi 	}
60*9dd0f810Scindi 
61*9dd0f810Scindi 	if (!(eq.eq_flags & ERRORQ_NVLIST)) {
62*9dd0f810Scindi 		mdb_warn("errorq at %p does not service ereports", addr);
63*9dd0f810Scindi 		return (WALK_ERR);
64*9dd0f810Scindi 	}
65*9dd0f810Scindi 
66*9dd0f810Scindi 	wsp->walk_addr = (uintptr_t)eq.eq_pend;
67*9dd0f810Scindi 
68*9dd0f810Scindi 	return (WALK_NEXT);
69*9dd0f810Scindi }
70*9dd0f810Scindi 
71*9dd0f810Scindi int
72*9dd0f810Scindi ereportq_pend_walk_step(mdb_walk_state_t *wsp)
73*9dd0f810Scindi {
74*9dd0f810Scindi 	uintptr_t addr = wsp->walk_addr;
75*9dd0f810Scindi 	nvlist_t nvl;
76*9dd0f810Scindi 	errorq_nvelem_t eqnp;
77*9dd0f810Scindi 	errorq_elem_t elem;
78*9dd0f810Scindi 
79*9dd0f810Scindi 	if (addr == NULL)
80*9dd0f810Scindi 		return (WALK_DONE);
81*9dd0f810Scindi 
82*9dd0f810Scindi 	if (mdb_vread(&elem, sizeof (elem), addr) != sizeof (elem) ||
83*9dd0f810Scindi 	    mdb_vread(&eqnp, sizeof (eqnp), (uintptr_t)elem.eqe_data)
84*9dd0f810Scindi 	    != sizeof (eqnp) || mdb_vread(&nvl, sizeof (nvl),
85*9dd0f810Scindi 	    (uintptr_t)eqnp.eqn_nvl) != sizeof (nvl)) {
86*9dd0f810Scindi 		mdb_warn("failed to read ereportq element at %p", addr);
87*9dd0f810Scindi 		return (WALK_ERR);
88*9dd0f810Scindi 	}
89*9dd0f810Scindi 
90*9dd0f810Scindi 	wsp->walk_addr = (uintptr_t)elem.eqe_prev;
91*9dd0f810Scindi 
92*9dd0f810Scindi 	return (wsp->walk_callback((uintptr_t)eqnp.eqn_nvl, &nvl,
93*9dd0f810Scindi 	    wsp->walk_cbdata));
94*9dd0f810Scindi }
95*9dd0f810Scindi 
96*9dd0f810Scindi int
97*9dd0f810Scindi ereportq_dump_walk_init(mdb_walk_state_t *wsp)
98*9dd0f810Scindi {
99*9dd0f810Scindi 	errorq_t eq;
100*9dd0f810Scindi 	uintptr_t addr;
101*9dd0f810Scindi 
102*9dd0f810Scindi 	if (wsp->walk_addr == NULL &&
103*9dd0f810Scindi 	    mdb_readvar(&addr, "ereport_errorq") == -1) {
104*9dd0f810Scindi 		mdb_warn("failed to read ereport_errorq");
105*9dd0f810Scindi 		return (WALK_ERR);
106*9dd0f810Scindi 	}
107*9dd0f810Scindi 
108*9dd0f810Scindi 	if (mdb_vread(&eq, sizeof (eq), addr) == -1) {
109*9dd0f810Scindi 		mdb_warn("failed to read ereport_errorq at %p", addr);
110*9dd0f810Scindi 		return (WALK_ERR);
111*9dd0f810Scindi 	}
112*9dd0f810Scindi 
113*9dd0f810Scindi 	if (!(eq.eq_flags & ERRORQ_NVLIST)) {
114*9dd0f810Scindi 		mdb_warn("errorq at %p does not service ereports", addr);
115*9dd0f810Scindi 		return (WALK_ERR);
116*9dd0f810Scindi 	}
117*9dd0f810Scindi 
118*9dd0f810Scindi 	wsp->walk_addr = (uintptr_t)eq.eq_dump;
119*9dd0f810Scindi 
120*9dd0f810Scindi 	return (WALK_NEXT);
121*9dd0f810Scindi }
122*9dd0f810Scindi 
123*9dd0f810Scindi int
124*9dd0f810Scindi ereportq_dump_walk_step(mdb_walk_state_t *wsp)
125*9dd0f810Scindi {
126*9dd0f810Scindi 	uintptr_t addr = wsp->walk_addr;
127*9dd0f810Scindi 	nvlist_t nvl;
128*9dd0f810Scindi 	errorq_nvelem_t eqnp;
129*9dd0f810Scindi 	errorq_elem_t elem;
130*9dd0f810Scindi 
131*9dd0f810Scindi 	if (addr == NULL)
132*9dd0f810Scindi 		return (WALK_DONE);
133*9dd0f810Scindi 
134*9dd0f810Scindi 	if (mdb_vread(&elem, sizeof (elem), addr) != sizeof (elem) ||
135*9dd0f810Scindi 	    mdb_vread(&eqnp, sizeof (eqnp), (uintptr_t)elem.eqe_data)
136*9dd0f810Scindi 	    != sizeof (eqnp) || mdb_vread(&nvl, sizeof (nvl),
137*9dd0f810Scindi 	    (uintptr_t)eqnp.eqn_nvl) != sizeof (nvl)) {
138*9dd0f810Scindi 		mdb_warn("failed to read ereportq element at %p", addr);
139*9dd0f810Scindi 		return (WALK_ERR);
140*9dd0f810Scindi 	}
141*9dd0f810Scindi 
142*9dd0f810Scindi 	wsp->walk_addr = (uintptr_t)elem.eqe_dump;
143*9dd0f810Scindi 
144*9dd0f810Scindi 	return (wsp->walk_callback((uintptr_t)eqnp.eqn_nvl, &nvl,
145*9dd0f810Scindi 	    wsp->walk_cbdata));
146*9dd0f810Scindi }
147*9dd0f810Scindi 
148*9dd0f810Scindi /*ARGSUSED*/
149*9dd0f810Scindi int
150*9dd0f810Scindi ereport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
151*9dd0f810Scindi {
152*9dd0f810Scindi 	int ret;
153*9dd0f810Scindi 	uint_t opt_v = 0;
154*9dd0f810Scindi 	char *class = NULL;
155*9dd0f810Scindi 	uint64_t ena = 0;
156*9dd0f810Scindi 	nvlist_t nvl;
157*9dd0f810Scindi 	nvpriv_t nvpriv;
158*9dd0f810Scindi 	i_nvp_t *nvcur, i_nvp;
159*9dd0f810Scindi 
160*9dd0f810Scindi 	if (!(flags & DCMD_ADDRSPEC))
161*9dd0f810Scindi 		return (DCMD_USAGE);
162*9dd0f810Scindi 
163*9dd0f810Scindi 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v) != argc)
164*9dd0f810Scindi 		return (DCMD_USAGE);
165*9dd0f810Scindi 
166*9dd0f810Scindi 	if (mdb_vread(&nvl, sizeof (nvl), addr) == -1) {
167*9dd0f810Scindi 		mdb_warn("failed to read nvlist at %p", addr);
168*9dd0f810Scindi 		return (DCMD_ERR);
169*9dd0f810Scindi 	}
170*9dd0f810Scindi 
171*9dd0f810Scindi 	if (DCMD_HDRSPEC(flags) && !opt_v) {
172*9dd0f810Scindi 		mdb_printf("ENA                CLASS\n");
173*9dd0f810Scindi 	}
174*9dd0f810Scindi 
175*9dd0f810Scindi 	/*
176*9dd0f810Scindi 	 * The following code attempts to pretty print the ereport class
177*9dd0f810Scindi 	 * and ENA.  The code uses project private macros from libnvpair
178*9dd0f810Scindi 	 * that could change and break this functionality.  If we are unable
179*9dd0f810Scindi 	 * to get a valid class and ENA from the nvpair list, we revert to
180*9dd0f810Scindi 	 * dumping the nvlist (same as opt_v).
181*9dd0f810Scindi 	 */
182*9dd0f810Scindi 	if (mdb_vread(&nvpriv, sizeof (nvpriv), nvl.nvl_priv) == -1) {
183*9dd0f810Scindi 		mdb_warn("failed to read nvpriv at %p", nvl.nvl_priv);
184*9dd0f810Scindi 		return (DCMD_ERR);
185*9dd0f810Scindi 	}
186*9dd0f810Scindi 
187*9dd0f810Scindi 	for (nvcur = nvpriv.nvp_list; nvcur != NULL; nvcur = i_nvp.nvi_next) {
188*9dd0f810Scindi 		nvpair_t *nvp, *nvpair;
189*9dd0f810Scindi 		int32_t size;
190*9dd0f810Scindi 
191*9dd0f810Scindi 		if (opt_v)
192*9dd0f810Scindi 			break;
193*9dd0f810Scindi 
194*9dd0f810Scindi 		if (mdb_vread(&i_nvp, sizeof (i_nvp), (uintptr_t)nvcur) == -1) {
195*9dd0f810Scindi 			mdb_warn("failed to read i_nvp at %p", nvcur);
196*9dd0f810Scindi 			return (DCMD_ERR);
197*9dd0f810Scindi 		}
198*9dd0f810Scindi 
199*9dd0f810Scindi 		nvp = &i_nvp.nvi_nvp;
200*9dd0f810Scindi 		size = NVP_SIZE(nvp);
201*9dd0f810Scindi 		if (size == 0) {
202*9dd0f810Scindi 			mdb_warn("nvpair of size zero at %p", nvp);
203*9dd0f810Scindi 			return (DCMD_OK);
204*9dd0f810Scindi 		}
205*9dd0f810Scindi 
206*9dd0f810Scindi 		/* read in the entire nvpair */
207*9dd0f810Scindi 		nvpair = mdb_alloc(size, UM_SLEEP | UM_GC);
208*9dd0f810Scindi 		if (mdb_vread(nvpair, size, (uintptr_t)&nvcur->nvi_nvp) == -1) {
209*9dd0f810Scindi 			mdb_warn("failed to read nvpair and data at %p", nvp);
210*9dd0f810Scindi 			return (DCMD_ERR);
211*9dd0f810Scindi 		}
212*9dd0f810Scindi 
213*9dd0f810Scindi 		if (strcmp(FM_CLASS, NVP_NAME(nvpair)) == 0 &&
214*9dd0f810Scindi 		    NVP_TYPE(nvpair) == DATA_TYPE_STRING && class == NULL) {
215*9dd0f810Scindi 			char *p = (char *)NVP_VALUE(nvpair);
216*9dd0f810Scindi 
217*9dd0f810Scindi 			class = mdb_zalloc(strlen(p) + 1, UM_SLEEP | UM_GC);
218*9dd0f810Scindi 			bcopy(p, class, strlen(p));
219*9dd0f810Scindi 		} else if (strcmp(FM_EREPORT_ENA, NVP_NAME(nvpair)) == 0 &&
220*9dd0f810Scindi 		    NVP_TYPE(nvpair) == DATA_TYPE_UINT64 && ena == 0) {
221*9dd0f810Scindi 			bcopy(NVP_VALUE(nvpair), (char *)&ena,
222*9dd0f810Scindi 			    sizeof (uint64_t));
223*9dd0f810Scindi 		}
224*9dd0f810Scindi 
225*9dd0f810Scindi 		if (class != NULL && ena != 0) {
226*9dd0f810Scindi 			mdb_printf("0x%016llx %s\n", ena, class);
227*9dd0f810Scindi 			return (DCMD_OK);
228*9dd0f810Scindi 		}
229*9dd0f810Scindi 
230*9dd0f810Scindi 	}
231*9dd0f810Scindi 
232*9dd0f810Scindi 	/*
233*9dd0f810Scindi 	 * Dump entire nvlist
234*9dd0f810Scindi 	 */
235*9dd0f810Scindi 	ret = mdb_call_dcmd("nvlist", addr, flags | DCMD_ADDRSPEC,
236*9dd0f810Scindi 	    0, argv);
237*9dd0f810Scindi 	mdb_printf("\n");
238*9dd0f810Scindi 
239*9dd0f810Scindi 	return (ret);
240*9dd0f810Scindi }
241