/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include /*ARGSUSED*/ int resumable(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { uint_t verbose = 0; cpu_t cpu; uintptr_t current, first; if (flags & DCMD_ADDRSPEC) return (DCMD_USAGE); if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc) return (DCMD_USAGE); if (mdb_readvar(&first, "cpu_list") == -1) { mdb_warn("failed to read 'cpu_list'"); return (DCMD_ERR); } if (verbose) mdb_printf("CPUID ADDRESS\n"); current = first; do { if (mdb_vread(&cpu, sizeof (cpu), current) == -1) { mdb_warn("failed to read cpu at %p", current); return (DCMD_ERR); } if (verbose) { if (cpu.cpu_m.cpu_rq_lastre == 0) mdb_printf("%-5d empty\n", cpu.cpu_id); else mdb_printf("%-5d %lx\n", cpu.cpu_id, cpu.cpu_m.cpu_rq_lastre); } else if (cpu.cpu_m.cpu_rq_lastre != 0) mdb_printf("%lx\n", cpu.cpu_m.cpu_rq_lastre); } while ((current = (uintptr_t)cpu.cpu_next) != first); return (DCMD_OK); } /*ARGSUSED*/ int nonresumable(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { uint_t verbose = 0; cpu_t cpu; uintptr_t current, first; if (flags & DCMD_ADDRSPEC) return (DCMD_USAGE); if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc) return (DCMD_USAGE); if (mdb_readvar(&first, "cpu_list") == -1) { mdb_warn("failed to read 'cpu_list'"); return (DCMD_ERR); } if (verbose) mdb_printf("CPUID ADDRESS\n"); current = first; do { if (mdb_vread(&cpu, sizeof (cpu), current) == -1) { mdb_warn("failed to read cpu at %p", current); return (DCMD_ERR); } if (verbose) { if (cpu.cpu_m.cpu_nrq_lastnre == 0) mdb_printf("%-5d empty\n", cpu.cpu_id); else mdb_printf("%-5d %lx\n", cpu.cpu_id, cpu.cpu_m.cpu_nrq_lastnre); } else if (cpu.cpu_m.cpu_nrq_lastnre != 0) mdb_printf("%lx\n", cpu.cpu_m.cpu_nrq_lastnre); } while ((current = (uintptr_t)cpu.cpu_next) != first); return (DCMD_OK); } /*ARGSUSED*/ int rqueue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { uint_t verbose = 0; cpu_t cpu; uintptr_t ao, lower, upper, current; if (!(flags & DCMD_ADDRSPEC)) return (DCMD_USAGE); if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc) return (DCMD_USAGE); if (mdb_vread(&cpu, sizeof (cpu_t), addr) == -1) { mdb_warn("failed to find cpu at %p", addr); return (DCMD_ERR); } ao = (uintptr_t)cpu.cpu_m.cpu_rq_lastre; /* beginning and end */ lower = (uintptr_t)cpu.cpu_m.cpu_rq_va + CPU_RQ_SIZE; upper = lower + CPU_RQ_SIZE - Q_ENTRY_SIZE; if (ao < lower || upper < ao) { if (verbose) mdb_printf("empty\n"); return (DCMD_OK); } for (current = ao; current >= lower; current -= Q_ENTRY_SIZE) mdb_printf("%lx\n", current); for (current = upper; current > ao; current -= Q_ENTRY_SIZE) mdb_printf("%lx\n", current); return (DCMD_OK); } /*ARGSUSED*/ int nrqueue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { uint_t verbose = 0; cpu_t cpu; uintptr_t lower, ao, upper; uintptr_t current; if (!(flags & DCMD_ADDRSPEC)) return (DCMD_USAGE); if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc) return (DCMD_USAGE); if (mdb_vread(&cpu, sizeof (cpu_t), addr) == -1) { mdb_warn("failed to find cpu at %p", addr); return (DCMD_ERR); } ao = (uintptr_t)cpu.cpu_m.cpu_nrq_lastnre; /* beginning and end */ lower = (uintptr_t)cpu.cpu_m.cpu_nrq_va + CPU_NRQ_SIZE; upper = lower + CPU_NRQ_SIZE - Q_ENTRY_SIZE; if (ao < lower || upper < ao) { if (verbose) mdb_printf("empty\n"); return (DCMD_OK); } for (current = ao; current >= lower; current -= Q_ENTRY_SIZE) mdb_printf("%lx\n", current); for (current = upper; current > ao; current -= Q_ENTRY_SIZE) mdb_printf("%lx\n", current); return (DCMD_OK); } /*ARGSUSED*/ int errh_prtaddr(uintptr_t addr, const void *data, void *private) { mdb_printf("%lx\n", addr); return (WALK_NEXT); } /*ARGSUSED*/ int rq_walk_init(mdb_walk_state_t *wsp) { cpu_t cpu; uintptr_t *ao, *lower, *upper; if (wsp->walk_addr == NULL) { mdb_warn("address of struct cpu_t is required\n"); return (WALK_ERR); } if (mdb_vread(&cpu, sizeof (cpu_t), wsp->walk_addr) == -1) { mdb_warn("failed to find cpu at %p", wsp->walk_addr); return (WALK_ERR); } wsp->walk_callback = (mdb_walk_cb_t)errh_prtaddr; wsp->walk_addr = (uintptr_t)cpu.cpu_m.cpu_rq_lastre; wsp->walk_data = mdb_alloc(sizeof (uintptr_t) * 3, UM_SLEEP); ao = lower = upper = wsp->walk_data; lower += 1; upper += 2; *ao = (uintptr_t)wsp->walk_addr; /* beginning and end */ *lower = (uintptr_t)cpu.cpu_m.cpu_rq_va + CPU_RQ_SIZE; *upper = (uintptr_t)*lower + CPU_RQ_SIZE - Q_ENTRY_SIZE; if (wsp->walk_addr < *lower || *upper < wsp->walk_addr) { mdb_free(wsp->walk_data, sizeof (uintptr_t) * 3); return (WALK_DONE); } return (WALK_NEXT); } /*ARGSUSED*/ int nrq_walk_init(mdb_walk_state_t *wsp) { cpu_t cpu; uintptr_t *ao, *lower, *upper; if (wsp->walk_addr == NULL) { mdb_warn("address of struct cpu_t is required\n"); return (WALK_ERR); } if (mdb_vread(&cpu, sizeof (cpu_t), wsp->walk_addr) == -1) { mdb_warn("failed to find cpu at %p", wsp->walk_addr); return (WALK_ERR); } wsp->walk_callback = (mdb_walk_cb_t)errh_prtaddr; wsp->walk_addr = (uintptr_t)cpu.cpu_m.cpu_nrq_lastnre; wsp->walk_data = mdb_alloc(sizeof (uintptr_t) * 3, UM_SLEEP); ao = lower = upper = wsp->walk_data; lower += 1; upper += 2; *ao = (uintptr_t)wsp->walk_addr; /* beginning and end */ *lower = (uintptr_t)cpu.cpu_m.cpu_nrq_va + CPU_NRQ_SIZE; *upper = (uintptr_t)*lower + CPU_NRQ_SIZE - Q_ENTRY_SIZE; if (wsp->walk_addr < *lower || *upper < wsp->walk_addr) { mdb_free(wsp->walk_data, sizeof (uintptr_t) * 3); return (WALK_DONE); } return (WALK_NEXT); } /*ARGSUSED*/ int errh_walk_step(mdb_walk_state_t *wsp) { int status; uintptr_t *ao, *lower, *upper; if (wsp->walk_addr == NULL) return (WALK_DONE); status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, wsp->walk_cbdata); wsp->walk_addr -= Q_ENTRY_SIZE; ao = lower = upper = wsp->walk_data; lower += 1; upper += 2; if (wsp->walk_addr < *lower) wsp->walk_addr = *upper; /* wrap around */ else if (wsp->walk_addr == *ao) return (WALK_DONE); /* end of loop */ return (status); } void errh_walk_fini(mdb_walk_state_t *wsp) { mdb_free(wsp->walk_data, sizeof (uintptr_t) * 3); } /* * MDB module linkage information: * * Declare a list of structures describing dcmds, and a function * named _mdb_init to return a pointer to module information. */ static const mdb_dcmd_t dcmds[] = { { "errhre", "[-v]", "addr of sun4v resumable error element", resumable }, { "errhnre", "[-v]", "addr of sun4v nonresumable error element", nonresumable }, { "errhrq", ":", "addr of sun4v resumable errors in RQ", rqueue }, { "errhnrq", ":", "addr of sun4v nonresumable errors in NRQ", nrqueue }, { NULL } }; static const mdb_walker_t walkers[] = { { "errhrq", "walk a cpu-specific sun4v resumble error queue", rq_walk_init, errh_walk_step, errh_walk_fini, NULL }, { "errhnrq", "walk a cpu-specific sun4v nonresumble error queue", nrq_walk_init, errh_walk_step, errh_walk_fini, NULL }, { NULL } }; static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; const mdb_modinfo_t * _mdb_init(void) { return (&modinfo); }