xref: /titanic_50/usr/src/cmd/mdb/sun4v/modules/errh/errh.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
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
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
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
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
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
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
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
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
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
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 *
348 _mdb_init(void)
349 {
350 	return (&modinfo);
351 }
352