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
ereportq_pend_walk_init(mdb_walk_state_t * wsp)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
ereportq_pend_walk_step(mdb_walk_state_t * wsp)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
ereportq_dump_walk_init(mdb_walk_state_t * wsp)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
ereportq_dump_walk_step(mdb_walk_state_t * wsp)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
ereport(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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