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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/mdb_modapi.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/sunldi.h> 31 32 #include <sys/nsctl/nsctl.h> 33 #include <sys/unistat/spcs_s.h> 34 #include <sys/unistat/spcs_s_k.h> 35 36 #include <sys/nsctl/sv.h> 37 #include <sys/nsctl/sv_impl.h> 38 39 #include <sys/nsctl/nsvers.h> 40 41 /* 42 * Walker for an array of sv_dev_t structures. 43 * A global walk is assumed to start at sv_devs. 44 */ 45 46 struct sv_dev_winfo { 47 uintptr_t start; 48 uintptr_t end; 49 }; 50 51 52 static int 53 sv_dev_winit(mdb_walk_state_t *wsp) 54 { 55 struct sv_dev_winfo *winfo; 56 sv_dev_t *sv_devs; 57 int sv_max_devices; 58 59 winfo = mdb_zalloc(sizeof (struct sv_dev_winfo), UM_SLEEP); 60 61 if (mdb_readvar(&sv_devs, "sv_devs") == -1) { 62 mdb_warn("failed to read 'sv_devs'"); 63 mdb_free(winfo, sizeof (struct sv_dev_winfo)); 64 return (WALK_ERR); 65 } 66 67 if (mdb_readvar(&sv_max_devices, "sv_max_devices") == -1) { 68 mdb_warn("failed to read 'sv_max_devices'"); 69 mdb_free(winfo, sizeof (struct sv_dev_winfo)); 70 return (WALK_ERR); 71 } 72 73 winfo->start = (uintptr_t)sv_devs; 74 winfo->end = (uintptr_t)(sv_devs + sv_max_devices); 75 76 if (wsp->walk_addr == NULL) 77 wsp->walk_addr = winfo->start; 78 79 wsp->walk_data = winfo; 80 return (WALK_NEXT); 81 } 82 83 84 static int 85 sv_dev_wstep(mdb_walk_state_t *wsp) 86 { 87 struct sv_dev_winfo *winfo = wsp->walk_data; 88 int status; 89 90 if (wsp->walk_addr == NULL) 91 return (WALK_DONE); 92 93 if (wsp->walk_addr >= winfo->end) 94 return (WALK_DONE); 95 96 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 97 wsp->walk_cbdata); 98 99 wsp->walk_addr += sizeof (sv_dev_t); 100 return (status); 101 } 102 103 104 static void 105 sv_dev_wfini(mdb_walk_state_t *wsp) 106 { 107 mdb_free(wsp->walk_data, sizeof (struct sv_dev_winfo)); 108 } 109 110 111 /* 112 * Walker for an sv hash chain. 113 * Global walks are disallowed. 114 */ 115 116 static int 117 sv_hash_winit(mdb_walk_state_t *wsp) 118 { 119 if (wsp->walk_addr == NULL) 120 return (WALK_ERR); 121 122 wsp->walk_data = mdb_zalloc(sizeof (sv_dev_t), UM_SLEEP); 123 124 return (WALK_NEXT); 125 } 126 127 128 static int 129 sv_hash_wstep(mdb_walk_state_t *wsp) 130 { 131 int status; 132 133 if (wsp->walk_addr == NULL) 134 return (WALK_DONE); 135 136 if (mdb_vread(wsp->walk_data, 137 sizeof (sv_dev_t), wsp->walk_addr) == -1) { 138 mdb_warn("failed to read sv_dev at %p", wsp->walk_addr); 139 return (WALK_DONE); 140 } 141 142 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 143 wsp->walk_cbdata); 144 145 wsp->walk_addr = (uintptr_t)(((sv_dev_t *)wsp->walk_data)->sv_hash); 146 return (status); 147 } 148 149 150 static void 151 sv_hash_wfini(mdb_walk_state_t *wsp) 152 { 153 mdb_free(wsp->walk_data, sizeof (sv_dev_t)); 154 } 155 156 157 /* 158 * Walker for an array of sv_maj_t structures. 159 * A global walk is assumed to start at sv_majors. 160 */ 161 162 sv_maj_t *sv_majors[SV_MAJOR_HASH_CNT + 1] = {0}; 163 164 static int 165 sv_maj_winit(mdb_walk_state_t *wsp) 166 { 167 if (wsp->walk_addr == NULL) { 168 if (mdb_readvar(&sv_majors, "sv_majors") == -1) { 169 mdb_warn("failed to read 'sv_majors'"); 170 return (WALK_ERR); 171 } 172 } else { 173 sv_majors[0] = (sv_maj_t *)wsp->walk_addr; 174 } 175 176 wsp->walk_addr = (uintptr_t)&sv_majors[0]; 177 wsp->walk_data = mdb_zalloc(sizeof (sv_maj_t), UM_SLEEP); 178 179 return (WALK_NEXT); 180 } 181 182 183 static int 184 sv_maj_wstep(mdb_walk_state_t *wsp) 185 { 186 uintptr_t addr; 187 int status = DCMD_OK; 188 189 if (wsp->walk_addr == NULL) 190 return (WALK_DONE); 191 192 if (wsp->walk_addr >= (uintptr_t)&sv_majors[SV_MAJOR_HASH_CNT]) 193 return (WALK_DONE); 194 195 for (addr = *(uintptr_t *)wsp->walk_addr; addr; 196 addr = (uintptr_t)(((sv_maj_t *)wsp->walk_data)->sm_next)) { 197 198 if (mdb_vread(wsp->walk_data, sizeof (sv_maj_t), addr) 199 != sizeof (sv_maj_t)) { 200 mdb_warn("failed to read sv_maj at %p", addr); 201 status = DCMD_ERR; 202 break; 203 } 204 205 status = wsp->walk_callback(addr, wsp->walk_data, 206 wsp->walk_cbdata); 207 if (status != DCMD_OK) 208 break; 209 } 210 211 wsp->walk_addr += sizeof (sv_maj_t *); 212 return (status); 213 } 214 215 216 static void 217 sv_maj_wfini(mdb_walk_state_t *wsp) 218 { 219 mdb_free(wsp->walk_data, sizeof (sv_maj_t)); 220 } 221 222 223 /* 224 * Walker for an sv gclient chain. 225 * A global walk is assumed to start at sv_gclients. 226 */ 227 228 static int 229 sv_gclient_winit(mdb_walk_state_t *wsp) 230 { 231 if (wsp->walk_addr == NULL && 232 mdb_readvar(&wsp->walk_addr, "sv_gclients") == -1) { 233 mdb_warn("unable to read 'sv_gclients'"); 234 return (WALK_ERR); 235 } 236 237 wsp->walk_data = mdb_zalloc(sizeof (sv_gclient_t), UM_SLEEP); 238 239 return (WALK_NEXT); 240 } 241 242 243 static int 244 sv_gclient_wstep(mdb_walk_state_t *wsp) 245 { 246 int status; 247 248 if (wsp->walk_addr == NULL) 249 return (WALK_DONE); 250 251 if (mdb_vread(wsp->walk_data, 252 sizeof (sv_gclient_t), wsp->walk_addr) == -1) { 253 mdb_warn("failed to read sv_gclient at %p", wsp->walk_addr); 254 return (WALK_DONE); 255 } 256 257 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 258 wsp->walk_cbdata); 259 260 wsp->walk_addr = (uintptr_t)(((sv_gclient_t *)wsp->walk_data)->sg_next); 261 return (status); 262 } 263 264 265 static void 266 sv_gclient_wfini(mdb_walk_state_t *wsp) 267 { 268 mdb_free(wsp->walk_data, sizeof (sv_gclient_t)); 269 } 270 271 272 /* 273 * Display a single sv_glcient_t structure. 274 * If called with no address, performs a global walk of all sv_gclients. 275 */ 276 static int 277 sv_gclient(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 278 { 279 sv_gclient_t sg; 280 char name[64]; 281 282 if (argc != 0) 283 return (DCMD_USAGE); 284 285 if (!(flags & DCMD_ADDRSPEC)) { 286 /* 287 * paranoid mode on: qualify walker name with module name 288 * using '`' syntax. 289 */ 290 if (mdb_walk_dcmd("sv`sv_gclient", 291 "sv`sv_gclient", argc, argv) == -1) { 292 mdb_warn("failed to walk 'sv_gclient'"); 293 return (DCMD_ERR); 294 } 295 return (DCMD_OK); 296 } 297 298 if (mdb_vread(&sg, sizeof (sg), addr) != sizeof (sg)) { 299 mdb_warn("failed to read sv_gclient at %p", addr); 300 return (DCMD_ERR); 301 } 302 303 if (DCMD_HDRSPEC(flags)) { 304 mdb_printf("%-?s %8T%-?s %8T%-16s %8T%s\n", 305 "ADDR", "NEXT", "ID", "NAME"); 306 } 307 308 if (mdb_readstr(name, sizeof (name), (uintptr_t)sg.sg_name) == -1) { 309 mdb_warn("failed to read sv_gclient name at %p", addr); 310 return (DCMD_ERR); 311 } 312 313 mdb_printf("%p %8T%p %8T%llx %8T%s", 314 addr, sg.sg_next, sg.sg_id, name); 315 316 return (DCMD_OK); 317 } 318 319 320 /* 321 * Display a single sv_maj_t structure. 322 * If called with no address, performs a global walk of all sv_majs. 323 * -a : all (i.e. display all devices, even if disabled 324 * -v : verbose 325 */ 326 static int 327 sv_maj(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 328 { 329 sv_maj_t *maj; 330 int a_opt, v_opt; 331 int i; 332 333 a_opt = v_opt = FALSE; 334 335 if (mdb_getopts(argc, argv, 336 'a', MDB_OPT_SETBITS, TRUE, &a_opt, 337 'v', MDB_OPT_SETBITS, TRUE, &v_opt) != argc) 338 return (DCMD_USAGE); 339 340 if (!(flags & DCMD_ADDRSPEC)) { 341 /* 342 * paranoid mode on: qualify walker name with module name 343 * using '`' syntax. 344 */ 345 if (mdb_walk_dcmd("sv`sv_maj", "sv`sv_maj", argc, argv) == -1) { 346 mdb_warn("failed to walk 'sv_maj'"); 347 return (DCMD_ERR); 348 } 349 return (DCMD_OK); 350 } 351 352 if (DCMD_HDRSPEC(flags)) { 353 mdb_printf("%-?s %8T%s\n", "ADDR", "INUSE"); 354 } 355 356 maj = mdb_zalloc(sizeof (*maj), UM_GC); 357 if (mdb_vread(maj, sizeof (*maj), addr) != sizeof (*maj)) { 358 mdb_warn("failed to read sv_maj at %p", addr); 359 return (DCMD_ERR); 360 } 361 362 if (!a_opt && maj->sm_inuse == 0) 363 return (DCMD_OK); 364 365 mdb_printf("%?p %8T%d\n", addr, maj->sm_inuse); 366 367 if (!v_opt) 368 return (DCMD_OK); 369 370 /* 371 * verbose - print the rest of the structure as well. 372 */ 373 374 mdb_inc_indent(4); 375 mdb_printf("\n"); 376 377 mdb_printf("dev_ops: %a (%p)\n", maj->sm_dev_ops, maj->sm_dev_ops); 378 mdb_printf("flag: %08x %8Tsequence: %d %8Tmajor: %d\n", 379 maj->sm_flag, maj->sm_seq, maj->sm_major); 380 381 mdb_printf("function pointers:\n"); 382 mdb_inc_indent(4); 383 mdb_printf("%-20a%-20a%\n%-20a%-20a%\n%-20a%-20a%\n%-20a%-20a%\n", 384 maj->sm_open, maj->sm_close, 385 maj->sm_read, maj->sm_write, 386 maj->sm_aread, maj->sm_awrite, 387 maj->sm_strategy, maj->sm_ioctl); 388 mdb_dec_indent(4); 389 390 391 mdb_printf("hash chain:\n"); 392 mdb_inc_indent(4); 393 for (i = 0; i < SV_MINOR_HASH_CNT; i++) { 394 mdb_printf("%?p", maj->sm_hash[i]); 395 mdb_printf(((i % 4) == 3) ? "\n" : " %8T"); 396 } 397 mdb_printf("\n\n"); 398 mdb_dec_indent(4); 399 mdb_dec_indent(4); 400 return (DCMD_OK); 401 } 402 403 404 /* 405 * Display a sv_dev_t hash chain. 406 * Requires an address. 407 * Same options as sv_dev(). 408 */ 409 static int 410 sv_hash(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 411 { 412 if (!(flags & DCMD_ADDRSPEC)) 413 return (DCMD_USAGE); 414 415 /* 416 * paranoid mode on: qualify walker name with module name 417 * using '`' syntax. 418 */ 419 if (mdb_pwalk_dcmd("sv`sv_hash", "sv`sv_dev", argc, argv, addr) == -1) { 420 mdb_warn("failed to walk sv_dev hash chain"); 421 return (DCMD_ERR); 422 } 423 424 return (DCMD_OK); 425 } 426 427 428 /* 429 * Display a single sv_dev_t structure. 430 * If called with no address, performs a global walk of all sv_devs. 431 * -a : all (i.e. display all devices, even if disabled 432 * -v : verbose 433 */ 434 435 const mdb_bitmask_t sv_flag_bits[] = { 436 { "NSC_DEVICE", NSC_DEVICE, NSC_DEVICE }, 437 { "NSC_CACHE", NSC_CACHE, NSC_CACHE }, 438 { NULL, 0, 0 } 439 }; 440 441 static int 442 sv_dev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 443 { 444 sv_dev_t *svp; 445 int a_opt, v_opt; 446 int dev_t_chars; 447 448 a_opt = v_opt = FALSE; 449 dev_t_chars = sizeof (dev_t) * 2; /* # chars to display dev_t */ 450 451 if (mdb_getopts(argc, argv, 452 'a', MDB_OPT_SETBITS, TRUE, &a_opt, 453 'v', MDB_OPT_SETBITS, TRUE, &v_opt) != argc) 454 return (DCMD_USAGE); 455 456 svp = mdb_zalloc(sizeof (*svp), UM_GC); 457 458 if (!(flags & DCMD_ADDRSPEC)) { 459 /* 460 * paranoid mode on: qualify walker name with module name 461 * using '`' syntax. 462 */ 463 if (mdb_walk_dcmd("sv`sv_dev", "sv`sv_dev", argc, argv) == -1) { 464 mdb_warn("failed to walk 'sv_dev'"); 465 return (DCMD_ERR); 466 } 467 return (DCMD_OK); 468 } 469 470 if (DCMD_HDRSPEC(flags)) { 471 mdb_printf("%-?s %8T%-*s %8T%s\n", "ADDR", 472 dev_t_chars, "DEV", "STATE"); 473 } 474 475 if (mdb_vread(svp, sizeof (*svp), addr) != sizeof (*svp)) { 476 mdb_warn("failed to read sv_dev at %p", addr); 477 return (DCMD_ERR); 478 } 479 480 if (!a_opt && svp->sv_state == SV_DISABLE) 481 return (DCMD_OK); 482 483 mdb_printf("%?p %8T%0*lx %8T", addr, dev_t_chars, svp->sv_dev); 484 485 if (svp->sv_state == SV_DISABLE) 486 mdb_printf("disabled"); 487 else if (svp->sv_state == SV_PENDING) 488 mdb_printf("pending"); 489 else if (svp->sv_state == SV_ENABLE) 490 mdb_printf("enabled"); 491 492 mdb_printf("\n"); 493 494 if (!v_opt) 495 return (DCMD_OK); 496 497 /* 498 * verbose - print the rest of the structure as well. 499 */ 500 501 mdb_inc_indent(4); 502 mdb_printf("\n"); 503 504 mdb_printf("hash chain: 0x%p %8Tlock: 0x%p %8Tolock: 0x%p\n", 505 svp->sv_hash, 506 addr + OFFSETOF(sv_dev_t, sv_lock), 507 addr + OFFSETOF(sv_dev_t, sv_olock)); 508 509 mdb_printf("fd: 0x%p %8T\n", svp->sv_fd); 510 511 mdb_printf("maxfbas: %d %8Tnblocks: %d %8Tstate: %d\n", 512 svp->sv_maxfbas, svp->sv_nblocks, svp->sv_state); 513 514 mdb_printf("gclients: 0x%llx %8Tgkernel: 0x%llx\n", 515 svp->sv_gclients, svp->sv_gkernel); 516 517 mdb_printf("openlcnt: %d %8Ttimestamp: 0x%lx\n", 518 svp->sv_openlcnt, svp->sv_timestamp); 519 520 mdb_printf("flags: 0x%08x <%b>\n", 521 svp->sv_flag, svp->sv_flag, sv_flag_bits); 522 523 mdb_printf("lh: 0x%p %8Tpending: 0x%p\n", 524 svp->sv_lh, svp->sv_pending); 525 526 mdb_dec_indent(4); 527 return (DCMD_OK); 528 } 529 530 531 /* 532 * Display general sv module information. 533 */ 534 535 #define sv_get_print(kvar, str, fmt, val) \ 536 if (mdb_readvar(&(val), #kvar) == -1) { \ 537 mdb_dec_indent(4); \ 538 mdb_warn("unable to read '" #kvar "'"); \ 539 return (DCMD_ERR); \ 540 } \ 541 mdb_printf("%-20s" fmt "\n", str ":", val) 542 543 /* ARGSUSED */ 544 static int 545 sv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 546 { 547 clock_t clock; 548 int maj, min, mic, baseline, i; 549 550 if (argc != 0) 551 return (DCMD_USAGE); 552 553 if (mdb_readvar(&maj, "sv_major_rev") == -1) { 554 mdb_warn("unable to read 'sv_major_rev'"); 555 return (DCMD_ERR); 556 } 557 558 if (mdb_readvar(&min, "sv_minor_rev") == -1) { 559 mdb_warn("unable to read 'sv_minor_rev'"); 560 return (DCMD_ERR); 561 } 562 563 if (mdb_readvar(&mic, "sv_micro_rev") == -1) { 564 mdb_warn("unable to read 'sv_micro_rev'"); 565 return (DCMD_ERR); 566 } 567 568 if (mdb_readvar(&baseline, "sv_baseline_rev") == -1) { 569 mdb_warn("unable to read 'sv_baseline_rev'"); 570 return (DCMD_ERR); 571 } 572 573 mdb_printf("SV module version: kernel %d.%d.%d.%d; mdb %d.%d.%d.%d\n", 574 maj, min, mic, baseline, 575 ISS_VERSION_MAJ, ISS_VERSION_MIN, ISS_VERSION_MIC, ISS_VERSION_NUM); 576 mdb_inc_indent(4); 577 578 sv_get_print(sv_config_time, "last config time", "0x%lx", clock); 579 sv_get_print(sv_stats_on, "stats on", "%d", i); 580 sv_get_print(sv_debug, "debug", "%d", i); 581 sv_get_print(sv_max_devices, "max sv devices", "%d", i); 582 583 mdb_dec_indent(4); 584 return (DCMD_OK); 585 } 586 587 588 /* 589 * MDB module linkage information: 590 */ 591 592 static const mdb_dcmd_t dcmds[] = { 593 { "sv", NULL, "display sv module info", sv }, 594 { "sv_dev", "?[-av]", "list sv_dev structure", sv_dev }, 595 { "sv_gclient", "?", "list sv_gclient structure", sv_gclient }, 596 { "sv_hash", ":[-av]", "display sv_dev hash chain", sv_hash }, 597 { "sv_maj", "?[-av]", "list sv_maj structure", sv_maj }, 598 { NULL } 599 }; 600 601 602 static const mdb_walker_t walkers[] = { 603 { "sv_dev", "walk array of sv_dev structures", 604 sv_dev_winit, sv_dev_wstep, sv_dev_wfini }, 605 { "sv_gclient", "walk sb_gclient chain", 606 sv_gclient_winit, sv_gclient_wstep, sv_gclient_wfini }, 607 { "sv_hash", "walk sv_dev hash chain", 608 sv_hash_winit, sv_hash_wstep, sv_hash_wfini }, 609 { "sv_maj", "walk array of sv_maj structures", 610 sv_maj_winit, sv_maj_wstep, sv_maj_wfini }, 611 { NULL } 612 }; 613 614 615 static const mdb_modinfo_t modinfo = { 616 MDB_API_VERSION, dcmds, walkers 617 }; 618 619 620 const mdb_modinfo_t * 621 _mdb_init(void) 622 { 623 return (&modinfo); 624 } 625