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 2006 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/kmem.h> 29 #include <sys/proc.h> 30 #include <sys/time.h> 31 #include <sys/conf.h> 32 #include <sys/file.h> 33 #include <sys/ddi.h> 34 #include <sys/ddi_impldefs.h> 35 #include <sys/modctl.h> 36 #include <sys/sunddi.h> 37 #include <sys/scsi/scsi.h> 38 #include <sys/scsi/impl/scsi_reset_notify.h> 39 #include <sys/sunmdi.h> 40 #include <sys/mdi_impldefs.h> 41 #include <sys/scsi/adapters/scsi_vhci.h> 42 #include <sys/scsi/scsi_types.h> 43 #include <sys/disp.h> 44 #include <sys/types.h> 45 #include <sys/mdb_modapi.h> 46 #include "mdi.h" 47 48 #define FT(var, typ) (*((typ *)(&(var)))) 49 50 /* Utils */ 51 static int get_mdbstr(uintptr_t addr, char *name); 52 static void dump_flags(unsigned long long flags, char **strings); 53 static void dump_mutex(kmutex_t m, char *name); 54 static void dump_condvar(kcondvar_t c, char *name); 55 static void dump_string(uintptr_t addr, char *name); 56 static void dump_state_str(char *name, uintptr_t addr, char **strings); 57 58 static int mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata); 59 60 static char *client_lb_str[] = 61 { 62 "NONE", 63 "RR", 64 "LBA", 65 NULL 66 }; 67 68 static char *mdi_pathinfo_states[] = 69 { 70 "MDI_PATHINFO_STATE_INIT", 71 "MDI_PATHINFO_STATE_ONLINE", 72 "MDI_PATHINFO_STATE_STANDBY", 73 "MDI_PATHINFO_STATE_FAULT", 74 "MDI_PATHINFO_STATE_OFFLINE", 75 NULL 76 }; 77 78 static char *mdi_pathinfo_ext_states[] = 79 { 80 "MDI_PATHINFO_STATE_USER_DISABLE", 81 "MDI_PATHINFO_STATE_DRV_DISABLE", 82 "MDI_PATHINFO_STATE_DRV_DISABLE_TRANSIENT", 83 NULL 84 }; 85 86 static char *mdi_phci_flags[] = 87 { 88 "MDI_PHCI_FLAGS_OFFLINE", 89 "MDI_PHCI_FLAGS_SUSPEND", 90 "MDI_PHCI_FLAGS_POWER_DOWN", 91 "MDI_PHCI_FLAGS_DETACH", 92 "MDI_PHCI_FLAGS_USER_DISABLE", 93 "MDI_PHCI_FLAGS_D_DISABLE", 94 "MDI_PHCI_FLAGS_D_DISABLE_TRANS", 95 "MDI_PHCI_FLAGS_POWER_TRANSITION", 96 NULL 97 }; 98 99 static uintptr_t firstaddr = 0; 100 static char mdipathinfo_cb_str[] = "::print struct mdi_pathinfo"; 101 static char mdiphci_cb_str[] = "::print struct mdi_phci"; 102 103 /* 104 * mdipi() 105 * 106 * Given a path, dump mdi_pathinfo struct and detailed pi_prop list. 107 */ 108 /* ARGSUSED */ 109 int 110 mdipi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 111 { 112 struct mdi_pathinfo value; 113 114 if (!(flags & DCMD_ADDRSPEC)) { 115 mdb_warn("mdipi: requires an address"); 116 return (DCMD_ERR); 117 } 118 119 if (mdb_vread(&value, sizeof (struct mdi_pathinfo), addr) != 120 sizeof (struct mdi_pathinfo)) { 121 mdb_warn("mdipi: Failed read on %l#r\n", addr); 122 return (DCMD_ERR); 123 } 124 mdb_printf("------------- mdi_pathinfo @ %#lr ----------\n", addr); 125 126 dump_string((uintptr_t)value.pi_addr, "PWWN,LUN (pi_addr)"); 127 128 mdb_printf("\n"); 129 mdb_printf("pi_client: %25l#r::print struct mdi_client\n", 130 value.pi_client); 131 mdb_printf("pi_phci: %27l#r::print struct mdi_phci\n", value.pi_phci); 132 mdb_printf("pi_pprivate: %23l#r\n", value.pi_pprivate); 133 mdb_printf("pi_client_link: %20l#r::print struct mdi_pathinfo\n", 134 value.pi_client_link); 135 mdb_printf("pi_phci_link: %22l#r::print struct mdi_pathinfo\n", 136 value.pi_phci_link); 137 mdb_printf("pi_prop: %27l#r::print struct nv_list\n", value.pi_prop); 138 139 mdiprops((uintptr_t)value.pi_prop, flags, 0, NULL); 140 141 mdb_printf("\n"); 142 dump_state_str("Pathinfo State (pi_state) ", 143 MDI_PI_STATE(&value), mdi_pathinfo_states); 144 if (MDI_PI_IS_TRANSIENT(&value)) { 145 mdb_printf("Pathinfo State is TRANSIENT\n"); 146 } 147 if (MDI_PI_EXT_STATE(&value)) { 148 mdb_printf(" Extended (pi_state) : "); 149 /* 150 * Need to shift right 20 bits to match mdi_pathinfo_ext_states 151 * array. 152 */ 153 dump_flags((unsigned long long)MDI_PI_EXT_STATE(&value) >> 20, 154 mdi_pathinfo_ext_states); 155 } 156 dump_state_str("Old Pathinfo State (pi_old_state)", 157 MDI_PI_OLD_STATE(&value), mdi_pathinfo_states); 158 if (MDI_PI_OLD_EXT_STATE(&value)) { 159 mdb_printf(" Extended (pi_old_state) : "); 160 /* 161 * Need to shift right 20 bits to match mdi_pathinfo_ext_states 162 * array. 163 */ 164 dump_flags((unsigned long long)MDI_PI_OLD_EXT_STATE(&value) 165 >> 20, mdi_pathinfo_ext_states); 166 } 167 dump_mutex(value.pi_mutex, "per-path mutex (pi_mutex):"); 168 dump_condvar(value.pi_state_cv, "Path state (pi_state_cv)"); 169 170 mdb_printf("\n"); 171 mdb_printf("pi_ref_cnt: %d\n", value.pi_ref_cnt); 172 dump_condvar(value.pi_ref_cv, "pi_ref_cv"); 173 174 mdb_printf("\n"); 175 mdb_printf("pi_kstats: %25l#r::print struct mdi_pi_kstats\n", 176 value.pi_kstats); 177 mdb_printf("pi_cprivate UNUSED: %16l#r \n", value.pi_cprivate); 178 179 return (DCMD_OK); 180 } 181 182 /* 183 * mdiprops() 184 * 185 * Given a pi_prop, dump the pi_prop list. 186 */ 187 /* ARGSUSED */ 188 int 189 mdiprops(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 190 { 191 if (!(flags & DCMD_ADDRSPEC)) { 192 mdb_warn("mdiprops: requires an address"); 193 return (DCMD_ERR); 194 } 195 196 mdb_printf("\tnvpairs @ %#lr:\n", addr); 197 mdb_pwalk_dcmd("nvpair", "nvpair", argc, argv, addr); 198 mdb_printf("\n"); 199 200 return (DCMD_OK); 201 } 202 203 /* 204 * mdiphci() 205 * 206 * Given a phci, dump mdi_phci struct. 207 */ 208 /* ARGSUSED */ 209 int 210 mdiphci(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 211 { 212 struct mdi_phci value; 213 214 if (!(flags & DCMD_ADDRSPEC)) { 215 mdb_warn("mdiphci: requires an address"); 216 return (DCMD_ERR); 217 } 218 219 if (mdb_vread(&value, sizeof (struct mdi_phci), addr) != 220 sizeof (struct mdi_phci)) { 221 mdb_warn("mdiphci: Failed read on %l#r\n", addr); 222 return (DCMD_ERR); 223 } 224 mdb_printf("---------------- mdi_phci @ %#lr ----------\n", addr); 225 226 mdb_printf("ph_next: %27l#r::print struct mdi_phci\n", value.ph_next); 227 mdb_printf("ph_prev: %27l#r::print struct mdi_phci\n", value.ph_prev); 228 mdb_printf("ph_vhci: %27l#r::print struct mdi_vhci\n", value.ph_vhci); 229 mdb_printf("ph_dip: %28l#r::print struct dev_info\n", value.ph_dip); 230 mdb_printf("\nph_path_head: %22l#r::print struct mdi_pathinfo\n", 231 value.ph_path_head); 232 mdb_printf("ph_path_tail: %22l#r::print struct mdi_pathinfo\n", 233 value.ph_path_tail); 234 mdb_printf("ph_path_count: %21d\n", value.ph_path_count); 235 mdb_printf("List of paths:\n"); 236 mdb_pwalk("mdipi_phci_list", (mdb_walk_cb_t)mpxio_walk_cb, 237 mdipathinfo_cb_str, (uintptr_t)value.ph_path_head); 238 239 mdb_printf("\n"); 240 mdb_printf("ph_flags: %26d\n", value.ph_flags); 241 if (value.ph_flags) { 242 dump_flags((unsigned long long)value.ph_flags, mdi_phci_flags); 243 } 244 dump_mutex(value.ph_mutex, "per-pHCI mutex (ph_mutex):"); 245 dump_condvar(value.ph_unstable_cv, 246 "Paths in transient state (ph_unstable_cv)"); 247 mdb_printf("ph_unstable: %23d\n", value.ph_unstable); 248 249 return (DCMD_OK); 250 } 251 252 /* 253 * mdivhci() 254 * 255 * Given a vhci, dump mdi_vhci struct and list all phcis. 256 */ 257 /* ARGSUSED */ 258 int 259 mdivhci(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 260 { 261 struct mdi_vhci value; 262 263 if (!(flags & DCMD_ADDRSPEC)) { 264 mdb_warn("mdivhci: requires an address"); 265 return (DCMD_ERR); 266 } 267 268 if (mdb_vread(&value, sizeof (struct mdi_vhci), addr) != 269 sizeof (struct mdi_vhci)) { 270 mdb_warn("mdivhci: Failed read on %l#r\n", addr); 271 return (DCMD_ERR); 272 } 273 mdb_printf("----------------- mdi_vhci @ %#lr ----------\n", addr); 274 275 dump_string((uintptr_t)value.vh_class, "Class name (vh_class)"); 276 mdb_printf("vh_refcnt: %19d\n", value.vh_refcnt); 277 mdb_printf("vh_dip: %28l#r::print struct dev_info\n", value.vh_dip); 278 mdb_printf("vh_next: %27l#r::print struct mdi_vhci\n", value.vh_next); 279 mdb_printf("vh_prev: %27l#r::print struct mdi_vhci\n", value.vh_prev); 280 dump_state_str("Load Balance (vh_lb)", value.vh_lb, client_lb_str); 281 mdb_printf("vh_ops: %28l#r::print struct mdi_vhci_ops\n", 282 value.vh_ops); 283 284 dump_mutex(value.vh_phci_mutex, "phci mutex (vh_phci_mutex):"); 285 mdb_printf("vh_phci_count: %21d\n", value.vh_phci_count); 286 mdb_printf("\nvh_phci_head: %22l#r::print struct mdi_phci\n", 287 value.vh_phci_head); 288 mdb_printf("vh_phci_tail: %22l#r::print struct mdi_phci\n", 289 value.vh_phci_tail); 290 291 dump_mutex(value.vh_phci_mutex, "client mutex (vh_client_mutex):"); 292 mdb_printf("vh_client_count: %19d\n", value.vh_client_count); 293 mdb_printf("vh_client_table: %19l#r::print struct client_hash\n", 294 value.vh_client_table); 295 296 mdb_printf("List of pHCIs:\n"); 297 mdb_pwalk("mdiphci_list", (mdb_walk_cb_t)mpxio_walk_cb, 298 mdiphci_cb_str, (uintptr_t)value.vh_phci_head); 299 mdb_printf("\n"); 300 return (DCMD_OK); 301 } 302 303 /* mdi_pathinfo client walker */ 304 305 /* ARGUSED */ 306 int 307 mdi_pi_client_link_walk_init(mdb_walk_state_t *wsp) 308 { 309 if (wsp->walk_addr == NULL) { 310 mdb_warn("Address is required"); 311 return (WALK_ERR); 312 } 313 wsp->walk_data = mdb_alloc(sizeof (struct mdi_pathinfo), UM_SLEEP); 314 firstaddr = wsp->walk_addr; 315 return (WALK_NEXT); 316 } 317 318 /* ARGUSED */ 319 int 320 mdi_pi_client_link_walk_step(mdb_walk_state_t *wsp) 321 { 322 int status = 0; 323 static int counts = 0; 324 325 if (firstaddr == wsp->walk_addr && counts != 0) { 326 counts = 0; 327 return (WALK_DONE); 328 } 329 if (wsp->walk_addr == NULL) { 330 counts = 0; 331 return (WALK_DONE); 332 } 333 if (mdb_vread(wsp->walk_data, sizeof (struct mdi_pathinfo), 334 wsp->walk_addr) == -1) { 335 mdb_warn("failed to read mdi_pathinfo at %p", wsp->walk_addr); 336 return (WALK_DONE); 337 } 338 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 339 wsp->walk_cbdata); 340 wsp->walk_addr = (uintptr_t) 341 (((struct mdi_pathinfo *)wsp->walk_data)->pi_client_link); 342 counts++; 343 return (status); 344 } 345 346 /* ARGUSED */ 347 void 348 mdi_pi_client_link_walk_fini(mdb_walk_state_t *wsp) 349 { 350 mdb_free(wsp->walk_data, sizeof (struct mdi_pathinfo)); 351 } 352 353 /* 354 * mdiclient_paths() 355 * 356 * Given a path, walk through mdi_pathinfo client links. 357 */ 358 /* ARGUSED */ 359 int 360 mdiclient_paths(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 361 { 362 int status; 363 if (argc != 0) 364 return (DCMD_USAGE); 365 366 if (!(flags & DCMD_ADDRSPEC)) { 367 mdb_warn("Address needs to be specified"); 368 return (DCMD_ERR); 369 } 370 status = 371 mdb_pwalk_dcmd("mdipi_client_list", "mdipi", argc, argv, addr); 372 return (status); 373 } 374 375 /* mdi_pathinfo phci walker */ 376 int 377 mdi_pi_phci_link_walk_init(mdb_walk_state_t *wsp) 378 { 379 if (wsp->walk_addr == NULL) { 380 mdb_warn("Address is required"); 381 return (WALK_ERR); 382 } 383 wsp->walk_data = mdb_alloc(sizeof (struct mdi_pathinfo), UM_SLEEP); 384 firstaddr = wsp->walk_addr; 385 return (WALK_NEXT); 386 } 387 388 int 389 mdi_pi_phci_link_walk_step(mdb_walk_state_t *wsp) 390 { 391 int status; 392 static int counts = 0; 393 394 if (firstaddr == wsp->walk_addr && counts != 0) { 395 counts = 0; 396 return (WALK_DONE); 397 } 398 if (wsp->walk_addr == NULL) { 399 counts = 0; 400 return (WALK_DONE); 401 } 402 if (mdb_vread(wsp->walk_data, sizeof (struct mdi_pathinfo), 403 wsp->walk_addr) == -1) { 404 mdb_warn("failed to read mdi_pathinfo at %p", wsp->walk_addr); 405 return (WALK_DONE); 406 } 407 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 408 wsp->walk_cbdata); 409 wsp->walk_addr = (uintptr_t) 410 (((struct mdi_pathinfo *)wsp->walk_data)->pi_phci_link); 411 counts++; 412 return (status); 413 } 414 415 void 416 mdi_pi_phci_link_walk_fini(mdb_walk_state_t *wsp) 417 { 418 mdb_free(wsp->walk_data, sizeof (struct mdi_pathinfo)); 419 } 420 421 /* 422 * mdiphci_paths() 423 * 424 * Given a path, walk through mdi_pathinfo phci links. 425 */ 426 int 427 mdiphci_paths(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 428 { 429 int status; 430 if (argc != 0) 431 return (DCMD_USAGE); 432 433 if (!(flags & DCMD_ADDRSPEC)) { 434 mdb_warn("Address needs to be specified"); 435 return (DCMD_ERR); 436 } 437 status = 438 mdb_pwalk_dcmd("mdipi_phci_list", "mdipi", argc, argv, addr); 439 return (status); 440 } 441 442 /* mdi_phci walker */ 443 int 444 mdi_phci_ph_next_walk_init(mdb_walk_state_t *wsp) 445 { 446 if (wsp->walk_addr == NULL) { 447 mdb_warn("Address is required"); 448 return (WALK_ERR); 449 } 450 wsp->walk_data = mdb_alloc(sizeof (struct mdi_phci), UM_SLEEP); 451 firstaddr = wsp->walk_addr; 452 return (WALK_NEXT); 453 } 454 455 int 456 mdi_phci_ph_next_walk_step(mdb_walk_state_t *wsp) 457 { 458 int status; 459 static int counts = 0; 460 461 if (firstaddr == wsp->walk_addr && counts != 0) { 462 counts = 0; 463 return (WALK_DONE); 464 } 465 if (wsp->walk_addr == NULL) { 466 counts = 0; 467 return (WALK_DONE); 468 } 469 if (mdb_vread(wsp->walk_data, sizeof (struct mdi_phci), wsp->walk_addr) 470 == -1) { 471 mdb_warn("failed to read mdi_phci at %p", wsp->walk_addr); 472 return (WALK_DONE); 473 } 474 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 475 wsp->walk_cbdata); 476 wsp->walk_addr = (uintptr_t) 477 (((struct mdi_phci *)wsp->walk_data)->ph_next); 478 counts++; 479 return (status); 480 } 481 482 void 483 mdi_phci_ph_next_walk_fini(mdb_walk_state_t *wsp) 484 { 485 mdb_free(wsp->walk_data, sizeof (struct mdi_phci)); 486 } 487 488 /* 489 * mdiphcis() 490 * 491 * Given a phci, walk through mdi_phci ph_next links. 492 */ 493 int 494 mdiphcis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 495 { 496 int status; 497 if (argc != 0) 498 return (DCMD_USAGE); 499 500 if (!(flags & DCMD_ADDRSPEC)) { 501 mdb_warn("Address needs to be specified"); 502 return (DCMD_ERR); 503 } 504 status = 505 mdb_pwalk_dcmd("mdiphci_list", "mdiphci", argc, argv, addr); 506 return (status); 507 } 508 509 /* 510 * Print the flag name by comparing flags to the mask variable. 511 */ 512 static void 513 dump_flags(unsigned long long flags, char **strings) 514 { 515 int i, linel = 8, first = 1; 516 unsigned long long mask = 1; 517 518 for (i = 0; i < 64; i++) { 519 if (strings[i] == NULL) 520 break; 521 if (flags & mask) { 522 if (!first) { 523 mdb_printf(" | "); 524 } else { 525 first = 0; 526 } 527 /* make output pretty */ 528 linel += strlen(strings[i]) + 3; 529 if (linel > 80) { 530 mdb_printf("\n\t"); 531 linel = strlen(strings[i]) + 1 + 8; 532 } 533 mdb_printf("%s", strings[i]); 534 } 535 mask <<= 1; 536 } 537 mdb_printf("\n"); 538 } 539 540 static void 541 dump_mutex(kmutex_t m, char *name) 542 { 543 mdb_printf("%s is%s held\n", name, FT(m, uint64_t) == 0 ? " not" : ""); 544 } 545 546 static void 547 dump_condvar(kcondvar_t c, char *name) 548 { 549 mdb_printf("Threads sleeping on %s = %d\n", name, (int)FT(c, ushort_t)); 550 } 551 552 static int 553 get_mdbstr(uintptr_t addr, char *string_val) 554 { 555 if (mdb_readstr(string_val, MAXNAMELEN, addr) == -1) { 556 mdb_warn("Error Reading String from %l#r\n", addr); 557 return (1); 558 } 559 560 return (0); 561 } 562 563 static void 564 dump_string(uintptr_t addr, char *name) 565 { 566 char string_val[MAXNAMELEN]; 567 568 if (get_mdbstr(addr, string_val)) { 569 return; 570 } 571 mdb_printf("%s: %s (%l#r)\n", name, string_val, addr); 572 } 573 574 static void 575 dump_state_str(char *name, uintptr_t addr, char **strings) 576 { 577 mdb_printf("%s: %s (%l#r)\n", name, strings[(unsigned long)addr], addr); 578 } 579 580 /* ARGSUSED */ 581 static int 582 mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata) 583 { 584 mdb_printf("%t%l#r%s\n", addr, (char *)cbdata); 585 return (0); 586 } 587