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