1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/types.h>
29 #include <sys/time.h>
30 #include <sys/sysmacros.h>
31 #include <ctype.h>
32 #include <sys/mdb_modapi.h>
33 #include <sys/cpuvar.h>
34 #include <sys/machcpuvar.h>
35 #include <sys/error.h>
36
37
38 /*ARGSUSED*/
39 int
resumable(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)40 resumable(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
41 {
42 uint_t verbose = 0;
43 cpu_t cpu;
44 uintptr_t current, first;
45
46 if (flags & DCMD_ADDRSPEC)
47 return (DCMD_USAGE);
48
49 if (mdb_getopts(argc, argv,
50 'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc)
51 return (DCMD_USAGE);
52
53 if (mdb_readvar(&first, "cpu_list") == -1) {
54 mdb_warn("failed to read 'cpu_list'");
55 return (DCMD_ERR);
56 }
57
58 if (verbose)
59 mdb_printf("CPUID ADDRESS\n");
60
61 current = first;
62 do {
63 if (mdb_vread(&cpu, sizeof (cpu), current) == -1) {
64 mdb_warn("failed to read cpu at %p", current);
65 return (DCMD_ERR);
66 }
67
68 if (verbose) {
69 if (cpu.cpu_m.cpu_rq_lastre == 0)
70 mdb_printf("%-5d empty\n", cpu.cpu_id);
71 else
72 mdb_printf("%-5d %lx\n", cpu.cpu_id,
73 cpu.cpu_m.cpu_rq_lastre);
74 } else if (cpu.cpu_m.cpu_rq_lastre != 0)
75 mdb_printf("%lx\n", cpu.cpu_m.cpu_rq_lastre);
76 } while ((current = (uintptr_t)cpu.cpu_next) != first);
77
78 return (DCMD_OK);
79 }
80
81 /*ARGSUSED*/
82 int
nonresumable(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)83 nonresumable(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
84 {
85 uint_t verbose = 0;
86 cpu_t cpu;
87 uintptr_t current, first;
88
89 if (flags & DCMD_ADDRSPEC)
90 return (DCMD_USAGE);
91
92 if (mdb_getopts(argc, argv,
93 'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc)
94 return (DCMD_USAGE);
95
96 if (mdb_readvar(&first, "cpu_list") == -1) {
97 mdb_warn("failed to read 'cpu_list'");
98 return (DCMD_ERR);
99 }
100
101 if (verbose)
102 mdb_printf("CPUID ADDRESS\n");
103
104 current = first;
105 do {
106 if (mdb_vread(&cpu, sizeof (cpu), current) == -1) {
107 mdb_warn("failed to read cpu at %p", current);
108 return (DCMD_ERR);
109 }
110
111 if (verbose) {
112 if (cpu.cpu_m.cpu_nrq_lastnre == 0)
113 mdb_printf("%-5d empty\n", cpu.cpu_id);
114 else
115 mdb_printf("%-5d %lx\n", cpu.cpu_id,
116 cpu.cpu_m.cpu_nrq_lastnre);
117 } else if (cpu.cpu_m.cpu_nrq_lastnre != 0)
118 mdb_printf("%lx\n", cpu.cpu_m.cpu_nrq_lastnre);
119 } while ((current = (uintptr_t)cpu.cpu_next) != first);
120
121 return (DCMD_OK);
122 }
123
124 /*ARGSUSED*/
125 int
rqueue(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)126 rqueue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
127 {
128 uint_t verbose = 0;
129 cpu_t cpu;
130 uintptr_t ao, lower, upper, current;
131
132 if (!(flags & DCMD_ADDRSPEC))
133 return (DCMD_USAGE);
134
135 if (mdb_getopts(argc, argv,
136 'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc)
137 return (DCMD_USAGE);
138
139 if (mdb_vread(&cpu, sizeof (cpu_t), addr) == -1) {
140 mdb_warn("failed to find cpu at %p", addr);
141 return (DCMD_ERR);
142 }
143
144 ao = (uintptr_t)cpu.cpu_m.cpu_rq_lastre; /* beginning and end */
145 lower = (uintptr_t)cpu.cpu_m.cpu_rq_va + CPU_RQ_SIZE;
146 upper = lower + CPU_RQ_SIZE - Q_ENTRY_SIZE;
147
148 if (ao < lower || upper < ao) {
149 if (verbose)
150 mdb_printf("empty\n");
151 return (DCMD_OK);
152 }
153
154 for (current = ao; current >= lower; current -= Q_ENTRY_SIZE)
155 mdb_printf("%lx\n", current);
156
157 for (current = upper; current > ao; current -= Q_ENTRY_SIZE)
158 mdb_printf("%lx\n", current);
159
160 return (DCMD_OK);
161 }
162
163 /*ARGSUSED*/
164 int
nrqueue(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)165 nrqueue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
166 {
167 uint_t verbose = 0;
168 cpu_t cpu;
169 uintptr_t lower, ao, upper;
170 uintptr_t current;
171
172 if (!(flags & DCMD_ADDRSPEC))
173 return (DCMD_USAGE);
174
175 if (mdb_getopts(argc, argv,
176 'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc)
177 return (DCMD_USAGE);
178
179 if (mdb_vread(&cpu, sizeof (cpu_t), addr) == -1) {
180 mdb_warn("failed to find cpu at %p", addr);
181 return (DCMD_ERR);
182 }
183
184 ao = (uintptr_t)cpu.cpu_m.cpu_nrq_lastnre; /* beginning and end */
185 lower = (uintptr_t)cpu.cpu_m.cpu_nrq_va + CPU_NRQ_SIZE;
186 upper = lower + CPU_NRQ_SIZE - Q_ENTRY_SIZE;
187
188 if (ao < lower || upper < ao) {
189 if (verbose)
190 mdb_printf("empty\n");
191 return (DCMD_OK);
192 }
193
194 for (current = ao; current >= lower; current -= Q_ENTRY_SIZE)
195 mdb_printf("%lx\n", current);
196
197 for (current = upper; current > ao; current -= Q_ENTRY_SIZE)
198 mdb_printf("%lx\n", current);
199
200 return (DCMD_OK);
201 }
202
203 /*ARGSUSED*/
204 int
errh_prtaddr(uintptr_t addr,const void * data,void * private)205 errh_prtaddr(uintptr_t addr, const void *data, void *private)
206 {
207 mdb_printf("%lx\n", addr);
208 return (WALK_NEXT);
209 }
210
211 /*ARGSUSED*/
212 int
rq_walk_init(mdb_walk_state_t * wsp)213 rq_walk_init(mdb_walk_state_t *wsp)
214 {
215 cpu_t cpu;
216 uintptr_t *ao, *lower, *upper;
217
218 if (wsp->walk_addr == NULL) {
219 mdb_warn("address of struct cpu_t is required\n");
220 return (WALK_ERR);
221 }
222
223 if (mdb_vread(&cpu, sizeof (cpu_t), wsp->walk_addr) == -1) {
224 mdb_warn("failed to find cpu at %p", wsp->walk_addr);
225 return (WALK_ERR);
226 }
227
228 wsp->walk_callback = (mdb_walk_cb_t)errh_prtaddr;
229 wsp->walk_addr = (uintptr_t)cpu.cpu_m.cpu_rq_lastre;
230 wsp->walk_data = mdb_alloc(sizeof (uintptr_t) * 3, UM_SLEEP);
231
232 ao = lower = upper = wsp->walk_data;
233 lower += 1;
234 upper += 2;
235
236 *ao = (uintptr_t)wsp->walk_addr; /* beginning and end */
237 *lower = (uintptr_t)cpu.cpu_m.cpu_rq_va + CPU_RQ_SIZE;
238 *upper = (uintptr_t)*lower + CPU_RQ_SIZE - Q_ENTRY_SIZE;
239
240 if (wsp->walk_addr < *lower || *upper < wsp->walk_addr) {
241 mdb_free(wsp->walk_data, sizeof (uintptr_t) * 3);
242 return (WALK_DONE);
243 }
244
245 return (WALK_NEXT);
246 }
247
248 /*ARGSUSED*/
249 int
nrq_walk_init(mdb_walk_state_t * wsp)250 nrq_walk_init(mdb_walk_state_t *wsp)
251 {
252 cpu_t cpu;
253 uintptr_t *ao, *lower, *upper;
254
255 if (wsp->walk_addr == NULL) {
256 mdb_warn("address of struct cpu_t is required\n");
257 return (WALK_ERR);
258 }
259
260 if (mdb_vread(&cpu, sizeof (cpu_t), wsp->walk_addr) == -1) {
261 mdb_warn("failed to find cpu at %p", wsp->walk_addr);
262 return (WALK_ERR);
263 }
264
265 wsp->walk_callback = (mdb_walk_cb_t)errh_prtaddr;
266 wsp->walk_addr = (uintptr_t)cpu.cpu_m.cpu_nrq_lastnre;
267 wsp->walk_data = mdb_alloc(sizeof (uintptr_t) * 3, UM_SLEEP);
268
269 ao = lower = upper = wsp->walk_data;
270 lower += 1;
271 upper += 2;
272
273 *ao = (uintptr_t)wsp->walk_addr; /* beginning and end */
274 *lower = (uintptr_t)cpu.cpu_m.cpu_nrq_va + CPU_NRQ_SIZE;
275 *upper = (uintptr_t)*lower + CPU_NRQ_SIZE - Q_ENTRY_SIZE;
276
277 if (wsp->walk_addr < *lower || *upper < wsp->walk_addr) {
278 mdb_free(wsp->walk_data, sizeof (uintptr_t) * 3);
279 return (WALK_DONE);
280 }
281
282 return (WALK_NEXT);
283 }
284
285 /*ARGSUSED*/
286 int
errh_walk_step(mdb_walk_state_t * wsp)287 errh_walk_step(mdb_walk_state_t *wsp)
288 {
289 int status;
290 uintptr_t *ao, *lower, *upper;
291
292 if (wsp->walk_addr == NULL)
293 return (WALK_DONE);
294
295 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
296 wsp->walk_cbdata);
297
298 wsp->walk_addr -= Q_ENTRY_SIZE;
299
300 ao = lower = upper = wsp->walk_data;
301 lower += 1;
302 upper += 2;
303
304 if (wsp->walk_addr < *lower)
305 wsp->walk_addr = *upper; /* wrap around */
306 else if (wsp->walk_addr == *ao)
307 return (WALK_DONE); /* end of loop */
308
309 return (status);
310 }
311
312 void
errh_walk_fini(mdb_walk_state_t * wsp)313 errh_walk_fini(mdb_walk_state_t *wsp)
314 {
315 mdb_free(wsp->walk_data, sizeof (uintptr_t) * 3);
316 }
317
318 /*
319 * MDB module linkage information:
320 *
321 * Declare a list of structures describing dcmds, and a function
322 * named _mdb_init to return a pointer to module information.
323 */
324
325 static const mdb_dcmd_t dcmds[] = {
326 { "errhre", "[-v]", "addr of sun4v resumable error element",
327 resumable },
328 { "errhnre", "[-v]", "addr of sun4v nonresumable error element",
329 nonresumable },
330 { "errhrq", ":", "addr of sun4v resumable errors in RQ", rqueue },
331 { "errhnrq", ":", "addr of sun4v nonresumable errors in NRQ", nrqueue },
332 { NULL }
333 };
334
335 static const mdb_walker_t walkers[] = {
336 { "errhrq", "walk a cpu-specific sun4v resumble error queue",
337 rq_walk_init, errh_walk_step, errh_walk_fini, NULL },
338 { "errhnrq", "walk a cpu-specific sun4v nonresumble error queue",
339 nrq_walk_init, errh_walk_step, errh_walk_fini, NULL },
340 { NULL }
341 };
342
343 static const mdb_modinfo_t modinfo = {
344 MDB_API_VERSION, dcmds, walkers
345 };
346
347 const mdb_modinfo_t *
_mdb_init(void)348 _mdb_init(void)
349 {
350 return (&modinfo);
351 }
352