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 47 #define FT(var, typ) (*((typ *)(&(var)))) 48 49 static int dump_states(uintptr_t array_vaddr, int verbose, 50 struct i_ddi_soft_state *sp); 51 static int i_vhci_states(uintptr_t addr, uint_t flags, int argc, 52 const mdb_arg_t *argv, struct i_ddi_soft_state *sp); 53 static int vhci_states(uintptr_t addr, uint_t flags, int argc, 54 const mdb_arg_t *argv); 55 56 static int mdiclient(uintptr_t addr, uint_t flags, int argc, 57 const mdb_arg_t *argv); 58 static int vhciguid(uintptr_t addr, uint_t flags, int argc, 59 const mdb_arg_t *argv); 60 static int vhcilun(uintptr_t addr, uint_t flags, int argc, 61 const mdb_arg_t *argv); 62 static int i_vhcilun(uintptr_t addr, uint_t display_single_guid, char *guid); 63 64 /* Utils */ 65 static int get_mdbstr(uintptr_t addr, char *name); 66 static void dump_mutex(kmutex_t m, char *name); 67 static void dump_condvar(kcondvar_t c, char *name); 68 static void dump_string(uintptr_t addr, char *name); 69 static void dump_flags(unsigned long long flags, char **strings); 70 static void dump_state_str(char *name, uintptr_t addr, char **strings); 71 72 static int mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata); 73 74 static const mdb_dcmd_t dcmds[] = { 75 { "vhci_states", "[ -v ]", "dump all the vhci state pointers", 76 vhci_states }, 77 { "vhciguid", NULL, "list all clients or given a guid, list one client", 78 vhciguid }, 79 { NULL } 80 }; 81 82 static const mdb_modinfo_t modinfo = { 83 MDB_API_VERSION, dcmds, NULL 84 }; 85 86 static char *client_lb_str[] = 87 { 88 "NONE", 89 "RR", 90 "LBA", 91 NULL 92 }; 93 94 static char *mdi_client_states[] = 95 { 96 NULL, 97 "OPTIMAL", 98 "DEGRADED", 99 "FAILED", 100 NULL 101 }; 102 103 static char *client_flags[] = 104 { 105 "MDI_CLIENT_FLAGS_OFFLINE", 106 "MDI_CLIENT_FLAGS_SUSPEND", 107 "MDI_CLIENT_FLAGS_POWER_DOWN", 108 "MDI_CLIENT_FLAGS_DETACH", 109 "MDI_CLIENT_FLAGS_FAILOVER", 110 "MDI_CLIENT_FLAGS_REPORT_DEV", 111 "MDI_CLIENT_FLAGS_PATH_FREE_IN_PROGRESS", 112 "MDI_CLIENT_FLAGS_ASYNC_FREE", 113 "MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED", 114 NULL 115 }; 116 117 static char *vhci_conf_flags[] = 118 { 119 "VHCI_CONF_FLAGS_AUTO_FAILBACK", 120 NULL 121 }; 122 123 static char *svlun_flags[] = 124 { 125 "VLUN_TASK_D_ALIVE_FLG", 126 "VLUN_RESERVE_ACTIVE_FLG", 127 "VLUN_QUIESCED_FLG", 128 NULL 129 }; 130 131 static char mdipathinfo_cb_str[] = "::print struct mdi_pathinfo"; 132 133 const mdb_modinfo_t * 134 _mdb_init(void) 135 { 136 return (&modinfo); 137 } 138 139 /* 140 * mdiclient() 141 * 142 * Dump mdi_client_t info and list all paths. 143 */ 144 /* ARGSUSED */ 145 static int 146 mdiclient(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 147 { 148 struct mdi_client value; 149 150 if (!(flags & DCMD_ADDRSPEC)) { 151 mdb_warn("mdiclient: requires an address"); 152 return (DCMD_ERR); 153 } 154 155 if (mdb_vread(&value, sizeof (struct mdi_client), addr) 156 != sizeof (struct mdi_client)) { 157 mdb_warn("mdiclient: Failed read on %l#r\n", addr); 158 return (DCMD_ERR); 159 } 160 mdb_printf("----------------- mdi_client @ %#lr ----------\n", addr); 161 dump_string((uintptr_t)value.ct_guid, "GUID (ct_guid)"); 162 dump_string((uintptr_t)value.ct_drvname, "Driver Name (ct_drvname)"); 163 dump_state_str("Load Balance (ct_lb)", value.ct_lb, client_lb_str); 164 mdb_printf("\n"); 165 mdb_printf("ct_hnext: %26l#r::print struct mdi_client\n", 166 value.ct_hnext); 167 mdb_printf("ct_hprev: %26l#r::print struct mdi_client\n", 168 value.ct_hprev); 169 mdb_printf("ct_dip: %28l#r::print struct dev_info\n", value.ct_dip); 170 mdb_printf("ct_vhci: %27l#r::print struct mdi_vhci\n", value.ct_vhci); 171 mdb_printf("ct_cprivate: %23l#r\n", value.ct_cprivate); 172 mdb_printf("\nct_path_head: %22l#r::print struct mdi_pathinfo\n", 173 value.ct_path_head); 174 mdb_printf("ct_path_tail: %22l#r::print struct mdi_pathinfo\n", 175 value.ct_path_tail); 176 mdb_printf("ct_path_last: %22l#r::print struct mdi_pathfinfo\n", 177 value.ct_path_last); 178 mdb_printf("ct_path_count: %21d\n", value.ct_path_count); 179 mdb_printf("List of paths:\n"); 180 mdb_pwalk("mdipi_client_list", (mdb_walk_cb_t)mpxio_walk_cb, 181 mdipathinfo_cb_str, (uintptr_t)value.ct_path_head); 182 183 mdb_printf("\n"); 184 dump_state_str("Client State (ct_state)", value.ct_state, 185 mdi_client_states); 186 dump_mutex(value.ct_mutex, "per-client mutex (ct_mutex):"); 187 mdb_printf("ct_flags: %26d\n", value.ct_flags); 188 if (value.ct_flags) { 189 dump_flags((unsigned long long)value.ct_flags, client_flags); 190 } 191 mdb_printf("ct_unstable: %23d\n", value.ct_unstable); 192 dump_condvar(value.ct_unstable_cv, "ct_unstable_cv"); 193 dump_condvar(value.ct_failover_cv, "ct_failover_cv"); 194 195 mdb_printf("\n"); 196 mdb_printf("ct_failover_flags TEMP_VAR: %8d\n", value.ct_failover_flags) 197 ; 198 mdb_printf("ct_failover_status UNUSED: %9d\n", value.ct_failover_status) 199 ; 200 201 return (DCMD_OK); 202 } 203 204 /* 205 * vhcilun() 206 * 207 * Get client info given a guid. 208 */ 209 /* ARGSUSED */ 210 static int 211 vhcilun(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 212 { 213 if (!(flags & DCMD_ADDRSPEC)) { 214 mdb_warn("sv_lun: requires an address"); 215 return (DCMD_ERR); 216 } 217 218 return (i_vhcilun(addr, 0 /* display_single_guid */, 0)); 219 } 220 221 /* 222 * vhciguid() 223 * 224 * List all the clients. 225 */ 226 /* ARGSUSED */ 227 static int 228 vhciguid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 229 { 230 231 struct i_ddi_soft_state ss; 232 int i; 233 234 mdi_vhci_t *mdi_vhci_value; 235 mdi_client_t *mdi_client_value; 236 struct client_hash *ct_hash_val; 237 struct client_hash *ct_hash_table_val; 238 239 int len = strlen(MDI_HCI_CLASS_SCSI); 240 int mdi_vhci_len = sizeof (*mdi_vhci_value); 241 int mdi_client_len = sizeof (*mdi_client_value); 242 int ct_hash_len = sizeof (*ct_hash_val); 243 244 int ct_hash_count = 0; 245 char *class; 246 int found = 0; 247 uintptr_t buf; 248 uintptr_t temp; 249 250 251 252 if (flags & DCMD_ADDRSPEC) 253 mdb_warn("This command doesn't use an address\n"); 254 255 if (i_vhci_states(0, 0, 0, 0, &ss) != DCMD_OK) 256 return (DCMD_ERR); 257 258 if (mdb_readvar(&buf, "mdi_vhci_head") == -1) { 259 mdb_warn("mdi driver variable mdi_vhci_head not found.\n"); 260 mdb_warn("Is the driver loaded ?\n"); 261 return (DCMD_ERR); 262 } 263 mdb_printf("----------------- mdi_vhci_head @ %#lr ----------\n", buf); 264 mdi_vhci_value = (mdi_vhci_t *)mdb_alloc(mdi_vhci_len, UM_SLEEP|UM_GC); 265 if (mdb_vread(mdi_vhci_value, mdi_vhci_len, buf) != mdi_vhci_len) { 266 mdb_warn("vhciguid: Failed read on %l#r\n", mdi_vhci_value); 267 mdb_free(mdi_vhci_value, mdi_vhci_len); 268 return (DCMD_ERR); 269 } 270 temp = (uintptr_t)mdi_vhci_value->vh_class; 271 class = (char *)mdb_alloc(len, UM_SLEEP|UM_GC); 272 if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI), temp) 273 != strlen(MDI_HCI_CLASS_SCSI)) { 274 mdb_warn("vhciguid: Failed read of class %l#r\n", 275 mdi_vhci_value); 276 mdb_free(mdi_vhci_value, mdi_vhci_len); 277 mdb_free(class, len); 278 return (DCMD_ERR); 279 } 280 class[len] = 0; 281 mdb_printf("----------------- class @ %s----------\n", class); 282 while (class) { 283 if (strcmp(class, MDI_HCI_CLASS_SCSI) == 0) { 284 found = 1; 285 break; 286 } 287 if (mdi_vhci_value->vh_next == NULL) { 288 break; 289 } 290 temp = (uintptr_t)mdi_vhci_value->vh_next; 291 if (mdb_vread(mdi_vhci_value, mdi_vhci_len, temp) 292 != mdi_vhci_len) { 293 mdb_warn("vhciguid: Failed read on vh->next %l#r\n", 294 mdi_vhci_value); 295 break; 296 } 297 temp = (uintptr_t)mdi_vhci_value->vh_class; 298 if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI), temp) != 299 strlen(MDI_HCI_CLASS_SCSI)) { 300 mdb_warn("vhciguid: Failed read on vh->next %l#r\n", 301 mdi_vhci_value); 302 break; 303 } 304 class[len] = 0; 305 } 306 307 if (found == 0) { 308 mdb_warn("vhciguid: No scsi_vhci class found"); 309 mdb_free(mdi_vhci_value, mdi_vhci_len); 310 mdb_free(class, len); 311 return (DCMD_ERR); 312 } 313 mdb_printf("----- Number of devices found %d ----------\n", 314 mdi_vhci_value->vh_client_count); 315 for (i = 0; i < CLIENT_HASH_TABLE_SIZE; i++) { 316 ct_hash_table_val = &mdi_vhci_value->vh_client_table[i]; 317 if (ct_hash_table_val == NULL) 318 continue; 319 320 /* Read client_hash structure */ 321 ct_hash_val = (struct client_hash *)mdb_alloc(ct_hash_len, 322 UM_SLEEP|UM_GC); 323 temp = (uintptr_t)ct_hash_table_val; 324 if (mdb_vread(ct_hash_val, ct_hash_len, temp) != ct_hash_len) { 325 mdb_warn("Failed read on hash %l#r\n", 326 ct_hash_val); 327 break; 328 } 329 mdb_printf("----hash[%d] %l#r: devices mapped = %d --\n", 330 i, ct_hash_table_val, ct_hash_val->ct_hash_count); 331 if (ct_hash_val->ct_hash_count == 0) { 332 continue; 333 } 334 335 ct_hash_count = ct_hash_val->ct_hash_count; 336 337 /* Read mdi_client structures */ 338 mdi_client_value = (mdi_client_t *)mdb_alloc(mdi_client_len, 339 UM_SLEEP|UM_GC); 340 temp = (uintptr_t)ct_hash_val->ct_hash_head; 341 if (mdb_vread(mdi_client_value, mdi_client_len, temp) 342 != mdi_client_len) { 343 mdb_warn("Failed read on client %l#r\n", 344 mdi_client_value); 345 break; 346 } 347 mdb_printf("mdi_client %l#r %l#r ------\n", 348 mdi_client_value, mdi_client_value->ct_vprivate); 349 vhcilun((uintptr_t)mdi_client_value->ct_vprivate, 350 DCMD_ADDRSPEC, 0, 0); 351 352 while (--ct_hash_count) { 353 temp = (uintptr_t)mdi_client_value->ct_hnext; 354 if (mdb_vread(mdi_client_value, mdi_client_len, 355 temp) != mdi_client_len) { 356 mdb_warn("Failed read on client %l#r\n", 357 mdi_client_value); 358 break; 359 } 360 vhcilun((uintptr_t)mdi_client_value->ct_vprivate, 361 DCMD_ADDRSPEC, 0, 0); 362 } 363 } 364 mdb_printf("----------done----------\n"); 365 366 return (DCMD_OK); 367 } 368 369 /* 370 * Print the flag name by comparing flags to the mask variable. 371 */ 372 static void 373 dump_flags(unsigned long long flags, char **strings) 374 { 375 int i, linel = 8, first = 1; 376 unsigned long long mask = 1; 377 378 for (i = 0; i < 64; i++) { 379 if (strings[i] == NULL) 380 break; 381 if (flags & mask) { 382 if (!first) { 383 mdb_printf(" | "); 384 } else { 385 first = 0; 386 } 387 /* make output pretty */ 388 linel += strlen(strings[i]) + 3; 389 if (linel > 80) { 390 mdb_printf("\n\t"); 391 linel = strlen(strings[i]) + 1 + 8; 392 } 393 mdb_printf("%s", strings[i]); 394 } 395 mask <<= 1; 396 } 397 mdb_printf("\n"); 398 } 399 400 /* ARGSUSED */ 401 static int 402 vhci_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 403 { 404 return (i_vhci_states(addr, flags, argc, argv, NULL)); 405 } 406 407 /* 408 * dump_states() 409 * 410 * Print the state information for vhci_states(). 411 */ 412 static int 413 dump_states(uintptr_t array_vaddr, int verbose, struct i_ddi_soft_state *sp) 414 { 415 int i; 416 int array_size; 417 struct i_ddi_soft_state *ss; 418 struct scsi_vhci vhci; 419 420 if (sp == NULL) { 421 ss = (struct i_ddi_soft_state *)mdb_alloc(sizeof (*ss), 422 UM_SLEEP|UM_GC); 423 } else { 424 ss = sp; 425 } 426 if (mdb_vread(ss, sizeof (*ss), array_vaddr) != sizeof (*ss)) { 427 mdb_warn("Cannot read softstate struct (Invalid pointer?).\n"); 428 return (DCMD_ERR); 429 } 430 array_size = ss->n_items * (sizeof (void *)); 431 array_vaddr = (uintptr_t)ss->array; 432 ss->array = mdb_alloc(array_size, UM_SLEEP|UM_GC); 433 if (mdb_vread(ss->array, array_size, array_vaddr) != array_size) { 434 mdb_warn("Corrupted softstate struct.\n"); 435 return (DCMD_ERR); 436 } 437 if (sp != NULL) 438 return (DCMD_OK); 439 if (verbose) { 440 /* 441 * ss->size is of type size_t which is 4 bytes and 8 bytes 442 * on 32-bit and 64-bit systems respectively. 443 */ 444 #ifdef _LP64 445 mdb_printf("Softstate size is %lld(0x%llx) bytes.\n\n", 446 ss->size, ss->size); 447 #else 448 mdb_printf("Softstate size is %ld(0x%lx) bytes.\n\n", 449 ss->size, ss->size); 450 #endif 451 mdb_printf("state pointer\t\t\t\t\tinstance\n"); 452 mdb_printf("=============\t\t\t\t\t========\n"); 453 } 454 for (i = 0; i < ss->n_items; i++) { 455 if (ss->array[i] == 0) 456 continue; 457 458 if (mdb_vread(&vhci, sizeof (vhci), (uintptr_t)ss->array[i]) 459 != sizeof (vhci)) { 460 mdb_warn("Corrupted softstate struct.\n"); 461 return (DCMD_ERR); 462 } 463 if (verbose) { 464 mdb_printf("%l#r::print struct scsi_vhci\t\t %d\n", 465 ss->array[i], i); 466 mdb_printf("\nvhci_conf_flags: %d\n", 467 vhci.vhci_conf_flags); 468 if (vhci.vhci_conf_flags) { 469 mdb_printf("\t"); 470 dump_flags((unsigned long long) 471 vhci.vhci_conf_flags, vhci_conf_flags); 472 } 473 } else { 474 mdb_printf("%l#r\n", ss->array[i]); 475 } 476 } 477 return (DCMD_OK); 478 } 479 480 static int 481 get_mdbstr(uintptr_t addr, char *string_val) 482 { 483 if (mdb_readstr(string_val, MAXNAMELEN, addr) == -1) { 484 mdb_warn("Error Reading String from %l#r\n", addr); 485 return (1); 486 } 487 488 return (0); 489 } 490 491 static void 492 dump_state_str(char *name, uintptr_t addr, char **strings) 493 { 494 mdb_printf("%s: %s (%l#r)\n", name, strings[(unsigned long)addr], addr); 495 } 496 497 /* VHCI UTILS */ 498 499 /* 500 * i_vhci_states() 501 * 502 * Internal routine for vhci_states() to check for -v arg and then 503 * print state info. 504 */ 505 /* ARGSUSED */ 506 static int 507 i_vhci_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 508 struct i_ddi_soft_state *sp) 509 { 510 uintptr_t adr; 511 int verbose = 0; 512 513 if (mdb_readvar(&adr, "vhci_softstate") == -1) { 514 mdb_warn("vhci driver variable vhci_softstate not found.\n"); 515 mdb_warn("Is the driver loaded ?\n"); 516 return (DCMD_ERR); 517 } 518 if (sp == NULL) { 519 if (mdb_getopts(argc, argv, 520 'v', MDB_OPT_SETBITS, TRUE, &verbose) != argc) { 521 return (DCMD_USAGE); 522 } 523 } 524 525 return (dump_states(adr, verbose, sp)); 526 } 527 528 /* 529 * i_vhcilun() 530 * 531 * Internal routine for vhciguid() to print client info. 532 */ 533 static int 534 i_vhcilun(uintptr_t addr, uint_t display_single_guid, char *guid) 535 { 536 537 scsi_vhci_lun_t value; 538 struct dev_info dev_info_value; 539 char string_val[MAXNAMELEN]; 540 int found = 0; 541 struct mdi_client ct_value; 542 uintptr_t temp_addr; 543 544 do { 545 if (mdb_vread(&value, sizeof (scsi_vhci_lun_t), addr) != 546 sizeof (scsi_vhci_lun_t)) { 547 mdb_warn("sv_lun: Failed read on %l#r", addr); 548 return (DCMD_ERR); 549 } 550 551 temp_addr = addr; 552 addr = (uintptr_t)value.svl_hash_next; 553 554 if (!get_mdbstr((uintptr_t)value.svl_lun_wwn, string_val)) { 555 if (display_single_guid) { 556 if (strcmp(string_val, guid) == 0) { 557 found = 1; 558 } else continue; 559 } 560 } 561 562 mdb_printf("%t%l#r::print struct scsi_vhci_lun", temp_addr); 563 564 if (mdb_vread(&dev_info_value, sizeof (struct dev_info), 565 (uintptr_t)value.svl_dip) != sizeof (struct dev_info)) { 566 mdb_warn("svl_dip: Failed read on %l#r", 567 value.svl_dip); 568 return (DCMD_ERR); 569 } 570 571 mdb_printf("\n%tGUID: %s\n", string_val); 572 if (value.svl_active_pclass != NULL) { 573 if (!get_mdbstr((uintptr_t)value.svl_active_pclass, 574 string_val)) { 575 mdb_printf("%tActv_cl: %s", string_val); 576 } 577 } else { 578 mdb_printf(" No active pclass"); 579 } 580 if (display_single_guid) { 581 mdb_printf(" (%l#r)", value.svl_active_pclass); 582 } 583 584 mdb_printf("\n%t%l#r::print struct mdi_client", 585 dev_info_value.devi_mdi_client); 586 587 if (value.svl_flags) { 588 mdb_printf("\t"); 589 dump_flags((unsigned long long)value.svl_flags, 590 svlun_flags); 591 } else { 592 mdb_printf("\n"); 593 } 594 595 if (found) { 596 mdiclient((uintptr_t)dev_info_value.devi_mdi_client, 597 DCMD_ADDRSPEC, 0, 0); 598 } else { 599 if (mdb_vread(&ct_value, sizeof (struct mdi_client), 600 (uintptr_t)dev_info_value.devi_mdi_client) != 601 sizeof (struct mdi_client)) { 602 mdb_warn("mdiclient: Failed read on %l#r", 603 dev_info_value.devi_mdi_client); 604 return (DCMD_ERR); 605 } 606 if (ct_value.ct_flags) { 607 mdb_printf("\t"); 608 dump_flags((unsigned long long) 609 ct_value.ct_flags, client_flags); 610 } 611 mdb_printf("%t"); 612 dump_state_str("LB", ct_value.ct_lb, client_lb_str); 613 mdb_printf("\n"); 614 } 615 } while (addr && !found); 616 return (DCMD_OK); 617 } 618 619 static void 620 dump_mutex(kmutex_t m, char *name) 621 { 622 mdb_printf("%s is%s held\n", name, FT(m, uint64_t) == 0 ? " not" : ""); 623 } 624 625 static void 626 dump_condvar(kcondvar_t c, char *name) 627 { 628 mdb_printf("Threads sleeping on %s = %d\n", name, (int)FT(c, ushort_t)); 629 } 630 631 static void 632 dump_string(uintptr_t addr, char *name) 633 { 634 char string_val[MAXNAMELEN]; 635 636 if (get_mdbstr(addr, string_val)) { 637 return; 638 } 639 mdb_printf("%s: %s (%l#r)\n", name, string_val, addr); 640 } 641 642 /* ARGSUSED */ 643 static int 644 mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata) 645 { 646 mdb_printf("%t%l#r%s\n", addr, (char *)cbdata); 647 return (0); 648 } 649