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