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