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 27 #include <sys/mdb_modapi.h> 28 #include <sys/mutex.h> 29 #include <sys/modctl.h> 30 #include <time.h> 31 #include <sys/fibre-channel/fc.h> 32 #include <sys/fibre-channel/impl/fctl_private.h> 33 #include <sys/fibre-channel/impl/fc_ulpif.h> 34 #include <sys/fibre-channel/impl/fc_portif.h> 35 #include <sys/fibre-channel/impl/fc_fcaif.h> 36 37 38 /* 39 * If we #include <string.h> then other definitions fail. This is 40 * the easiest way of getting access to the function 41 */ 42 extern char *strtok(char *string, const char *sepset); 43 44 /* we need 26 bytes for the cftime() call */ 45 #define TIMESTAMPSIZE 26 * sizeof (char) 46 47 /* for backward compatibility */ 48 typedef struct fc_trace_dmsgv1 { 49 int id_size; 50 int id_flag; 51 time_t id_time; 52 caddr_t id_buf; 53 struct fc_trace_dmsgv1 *id_next; 54 } fc_trace_dmsgv1_t; 55 56 static struct pwwn_hash *fp_pwwn_table; 57 static struct d_id_hash *fp_did_table; 58 static uint32_t pd_hash_index; 59 struct fc_local_port port; 60 61 /* 62 * Leadville port walker/dcmd code 63 */ 64 65 /* 66 * Initialize the fc_fca_port_t walker by either using the given starting 67 * address, or reading the value of the kernel's fctl_fca_portlist pointer. 68 * We also allocate a fc_fca_port_t for storage, and save this using the 69 * walk_data pointer. 70 */ 71 static int 72 port_walk_i(mdb_walk_state_t *wsp) 73 { 74 if (wsp->walk_addr == NULL && 75 mdb_readvar(&wsp->walk_addr, "fctl_fca_portlist") == -1) { 76 mdb_warn("failed to read 'fctl_fca_portlist'"); 77 return (WALK_ERR); 78 } 79 80 wsp->walk_data = mdb_alloc(sizeof (fc_fca_port_t), UM_SLEEP); 81 return (WALK_NEXT); 82 } 83 84 /* 85 * At each step, read a fc_fca_port_t into our private storage, and then invoke 86 * the callback function. We terminate when we reach a NULL p_next pointer. 87 */ 88 static int 89 port_walk_s(mdb_walk_state_t *wsp) 90 { 91 int status; 92 93 if (wsp->walk_addr == NULL) 94 return (WALK_DONE); 95 96 if (mdb_vread(wsp->walk_data, sizeof (fc_fca_port_t), wsp->walk_addr) 97 == -1) { 98 mdb_warn("failed to read fc_fca_port_t at %p", wsp->walk_addr); 99 return (WALK_DONE); 100 } 101 102 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 103 wsp->walk_cbdata); 104 105 wsp->walk_addr = 106 (uintptr_t)(((fc_fca_port_t *)wsp->walk_data)->port_next); 107 108 return (status); 109 } 110 111 /* 112 * The walker's fini function is invoked at the end of each walk. Since we 113 * dynamically allocated a fc_fca_port_t in port_walk_i, we must free it now. 114 */ 115 static void 116 port_walk_f(mdb_walk_state_t *wsp) 117 { 118 mdb_free(wsp->walk_data, sizeof (fc_fca_port_t)); 119 } 120 121 122 static int 123 ports(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 124 { 125 fc_fca_port_t portlist; 126 fc_local_port_t port; 127 int longlist = FALSE; 128 129 if (argc > 1) { 130 return (DCMD_USAGE); 131 } 132 133 if (mdb_getopts(argc, argv, 134 'l', MDB_OPT_SETBITS, TRUE, &longlist) != argc) { 135 return (DCMD_USAGE); 136 } 137 138 139 if (!(flags & DCMD_ADDRSPEC)) { 140 if (longlist == 0) { 141 if (mdb_walk_dcmd("ports", "ports", 142 argc, argv) == -1) { 143 mdb_warn("failed to walk 'fctl_fca_portlist'"); 144 return (DCMD_ERR); 145 } 146 } else { 147 if (mdb_walk_dcmd("ports", "fcport", 148 argc, argv) == -1) { 149 mdb_warn("failed to walk 'fctl_fca_portlist'"); 150 return (DCMD_ERR); 151 } 152 } 153 154 return (DCMD_OK); 155 } 156 157 /* 158 * If this is the first invocation of the command, print a nice 159 * header line for the output that will follow. 160 */ 161 if (DCMD_HDRSPEC(flags)) 162 mdb_printf("%16s %-2s %4s %-4s%16s %16s %16s\n", 163 "Port", "I#", "State", "Soft", "FCA Handle", 164 "Port DIP", "FCA Port DIP"); 165 166 /* 167 * For each port, we just need to read the fc_fca_port_t struct, read 168 * the port_handle 169 */ 170 if (mdb_vread(&portlist, sizeof (fc_fca_port_t), addr) == 171 sizeof (fc_fca_port_t)) { 172 /* 173 * Now read that port in 174 */ 175 176 if (mdb_vread(&port, sizeof (fc_local_port_t), (uintptr_t) 177 portlist.port_handle) == sizeof (fc_local_port_t)) { 178 mdb_printf("%16p %2d %4x %4x %16p %16p %16p\n", 179 portlist.port_handle, port.fp_instance, 180 port.fp_state, port.fp_soft_state, 181 port.fp_fca_handle, port.fp_port_dip, 182 port.fp_fca_dip); 183 } else 184 mdb_warn("failed to read port at %p", 185 portlist.port_handle); 186 187 } else 188 mdb_warn("failed to read port info at %p", addr); 189 190 return (DCMD_OK); 191 } 192 193 194 /* 195 * Leadville ULP walker/dcmd code 196 */ 197 198 static int 199 ulp_walk_i(mdb_walk_state_t *wsp) 200 { 201 if (wsp->walk_addr == NULL && 202 mdb_readvar(&wsp->walk_addr, "fctl_ulp_list") == -1) { 203 mdb_warn("failed to read 'fctl_ulp_list'"); 204 return (WALK_ERR); 205 } 206 207 wsp->walk_data = mdb_alloc(sizeof (fc_ulp_list_t), UM_SLEEP); 208 return (WALK_NEXT); 209 } 210 211 212 213 static int 214 ulp_walk_s(mdb_walk_state_t *wsp) 215 { 216 int status; 217 218 if (wsp->walk_addr == NULL) 219 return (WALK_DONE); 220 221 if (mdb_vread(wsp->walk_data, sizeof (fc_ulp_list_t), wsp->walk_addr) 222 == -1) { 223 mdb_warn("failed to read fctl_ulp_list %p", wsp->walk_addr); 224 return (WALK_DONE); 225 } 226 227 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 228 wsp->walk_cbdata); 229 230 wsp->walk_addr = 231 (uintptr_t)(((fc_ulp_list_t *)wsp->walk_data)->ulp_next); 232 233 return (status); 234 } 235 236 237 static void 238 ulp_walk_f(mdb_walk_state_t *wsp) 239 { 240 mdb_free(wsp->walk_data, sizeof (fc_ulp_list_t)); 241 } 242 243 244 static int 245 ulps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 246 { 247 fc_ulp_list_t ulplist; 248 fc_ulp_modinfo_t ulp; 249 char ulp_name[30]; 250 251 if (argc != 0) { 252 return (DCMD_USAGE); 253 } 254 255 /* 256 * If no fc_ulp_list_t address was specified on the command line, we can 257 * print out all processes by invoking the walker, using this 258 * dcmd itself as the callback. 259 */ 260 if (!(flags & DCMD_ADDRSPEC)) { 261 if (mdb_walk_dcmd("ulps", "ulps", argc, argv) == -1) { 262 mdb_warn("failed to walk 'fc_ulp_list_t'"); 263 return (DCMD_ERR); 264 } 265 return (DCMD_OK); 266 } 267 268 /* 269 * If this is the first invocation of the command, print a nice 270 * header line for the output that will follow. 271 */ 272 if (DCMD_HDRSPEC(flags)) 273 mdb_printf("%30s %4s %8s\n", "ULP Name", "Type", "Revision"); 274 275 /* 276 * For each port, we just need to read the fc_fca_port_t struct, read 277 * the port_handle 278 */ 279 if (mdb_vread(&ulplist, sizeof (fc_ulp_list_t), addr) == 280 sizeof (fc_ulp_list_t)) { 281 /* 282 * Now read that port in 283 */ 284 285 if (mdb_vread(&ulp, sizeof (fc_ulp_modinfo_t), 286 (uintptr_t)ulplist.ulp_info) == sizeof (fc_ulp_modinfo_t)) { 287 if (mdb_vread(&ulp_name, 30, 288 (uintptr_t)ulp.ulp_name) > 0) { 289 mdb_printf("%30s %4x %8x\n", 290 ulp_name, ulp.ulp_type, ulp.ulp_rev); 291 } 292 } else 293 mdb_warn("failed to read ulp at %p", 294 ulplist.ulp_info); 295 296 } else 297 mdb_warn("failed to read ulplist at %p", addr); 298 299 return (DCMD_OK); 300 } 301 302 303 304 /* 305 * Leadville ULP module walker/dcmd code 306 */ 307 308 static int 309 ulpmod_walk_i(mdb_walk_state_t *wsp) 310 { 311 if (wsp->walk_addr == NULL && 312 mdb_readvar(&wsp->walk_addr, "fctl_ulp_modules") == -1) { 313 mdb_warn("failed to read 'fctl_ulp_modules'"); 314 return (WALK_ERR); 315 } 316 317 wsp->walk_data = mdb_alloc(sizeof (fc_ulp_module_t), UM_SLEEP); 318 return (WALK_NEXT); 319 } 320 321 322 323 static int 324 ulpmod_walk_s(mdb_walk_state_t *wsp) 325 { 326 int status; 327 328 if (wsp->walk_addr == NULL) 329 return (WALK_DONE); 330 331 if (mdb_vread(wsp->walk_data, sizeof (fc_ulp_module_t), wsp->walk_addr) 332 == -1) { 333 mdb_warn("failed to read fctl_ulp_modules %p", wsp->walk_addr); 334 return (WALK_DONE); 335 } 336 337 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 338 wsp->walk_cbdata); 339 340 wsp->walk_addr = 341 (uintptr_t)(((fc_ulp_module_t *)wsp->walk_data)->mod_next); 342 343 return (status); 344 } 345 346 347 static void 348 ulpmod_walk_f(mdb_walk_state_t *wsp) 349 { 350 mdb_free(wsp->walk_data, sizeof (fc_ulp_module_t)); 351 } 352 353 354 static int 355 ulpmods(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 356 { 357 fc_ulp_module_t modlist; 358 fc_ulp_modinfo_t modinfo; 359 fc_ulp_ports_t ulp_port; 360 361 if (argc != 0) { 362 return (DCMD_USAGE); 363 } 364 365 if (!(flags & DCMD_ADDRSPEC)) { 366 if (mdb_walk_dcmd("ulpmods", "ulpmods", argc, argv) 367 == -1) { 368 mdb_warn("failed to walk 'fc_ulp_module_t'"); 369 return (DCMD_ERR); 370 } 371 return (DCMD_OK); 372 } 373 374 /* 375 * If this is the first invocation of the command, print a nice 376 * header line for the output that will follow. 377 */ 378 if (DCMD_HDRSPEC(flags)) 379 mdb_printf("%4s %16s %8s %8s\n", 380 "Type", "Port Handle", "dstate", "statec"); 381 382 /* 383 * For each port, we just need to read the fc_fca_port_t struct, read 384 * the port_handle 385 */ 386 if (mdb_vread(&modlist, sizeof (fc_ulp_module_t), addr) == 387 sizeof (fc_ulp_module_t)) { 388 /* 389 * Now read that module info in 390 */ 391 392 if (mdb_vread(&modinfo, sizeof (fc_ulp_modinfo_t), 393 (uintptr_t)modlist.mod_info) == sizeof (fc_ulp_modinfo_t)) { 394 /* Now read all the ports for this module */ 395 if (mdb_vread(&ulp_port, sizeof (fc_ulp_ports_t), 396 (uintptr_t)modlist.mod_ports) == 397 sizeof (fc_ulp_ports_t)) { 398 while (ulp_port.port_handle != NULL) { 399 mdb_printf("%4x %16p %8x %8x\n", 400 modinfo.ulp_type, 401 ulp_port.port_handle, 402 ulp_port.port_dstate, 403 ulp_port.port_statec); 404 405 if (ulp_port.port_next == NULL) 406 break; 407 408 mdb_vread(&ulp_port, 409 sizeof (fc_ulp_ports_t), 410 (uintptr_t)ulp_port.port_next); 411 } 412 } 413 } else 414 mdb_warn("failed to read modinfo at %p", 415 modlist.mod_info); 416 417 } else 418 mdb_warn("failed to read modlist at %p", addr); 419 420 return (DCMD_OK); 421 } 422 423 424 /* 425 * Display an fc_local_port_t struct 426 */ 427 static int 428 fcport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 429 { 430 fc_fca_port_t portlist; 431 fc_local_port_t port; 432 int idx; 433 int first = 1; 434 int walking_fc_fca_portlist = 0; 435 436 if (argc != 0) { 437 int result; 438 439 if (argc != 1) 440 return (DCMD_USAGE); 441 442 if (argv->a_type != MDB_TYPE_STRING) 443 return (DCMD_USAGE); 444 445 walking_fc_fca_portlist = 1; 446 } 447 448 if (!(flags & DCMD_ADDRSPEC)) { 449 mdb_printf("Sorry, you must provide an address\n"); 450 return (DCMD_ERR); 451 } 452 453 if (walking_fc_fca_portlist) { 454 /* 455 * Must read the fc_fca_portlist to get the fc_local_port addr 456 */ 457 if (mdb_vread(&portlist, sizeof (fc_fca_port_t), addr) == 458 sizeof (fc_fca_port_t)) { 459 addr = (uintptr_t)portlist.port_handle; 460 } 461 } 462 463 mdb_printf("Reading fc_local_port_t at %p:\n", addr); 464 465 /* 466 * For each port, we just need to read the fc_local_port_t struct 467 */ 468 469 if (mdb_vread(&port, sizeof (fc_local_port_t), 470 addr) == sizeof (fc_local_port_t)) { 471 mdb_printf(" fp_mutex : 0x%p\n", port.fp_mutex); 472 mdb_printf(" fp_state : 0x%-8x\n", port.fp_state); 473 mdb_printf(" fp_port_id : 0x%-06x\n", 474 port.fp_port_id.port_id); 475 mdb_printf(" fp_fca_handle : 0x%p\n", port.fp_fca_handle); 476 mdb_printf(" fp_fca_tran : 0x%p\n", port.fp_fca_tran); 477 mdb_printf(" fp_job_head : 0x%p\n", port.fp_job_head); 478 mdb_printf(" fp_job_tail : 0x%p\n", port.fp_job_tail); 479 mdb_printf(" fp_wait_head : 0x%p\n", port.fp_wait_head); 480 mdb_printf(" fp_wait_tail : 0x%p\n", port.fp_wait_tail); 481 mdb_printf(" fp_topology : %u\n", port.fp_topology); 482 mdb_printf(" fp_task : %d\n", port.fp_task); 483 mdb_printf(" fp_last_task : %d\n", port.fp_last_task); 484 mdb_printf(" fp_soft_state : 0x%-4x\n", 485 port.fp_soft_state); 486 mdb_printf(" fp_flag : 0x%-2x\n", port.fp_flag); 487 mdb_printf(" fp_statec_busy : 0x%-8x\n", 488 port.fp_statec_busy); 489 mdb_printf(" fp_port_num : %d\n", port.fp_port_num); 490 mdb_printf(" fp_instance : %d\n", port.fp_instance); 491 mdb_printf(" fp_ulp_attach : %d\n", port.fp_ulp_attach); 492 mdb_printf(" fp_dev_count : %d\n", port.fp_dev_count); 493 mdb_printf(" fp_total_devices : %d\n", port.fp_total_devices); 494 mdb_printf(" fp_bind_state : 0x%-8x\n", 495 port.fp_bind_state); 496 mdb_printf(" fp_options : 0x%-8x\n", port.fp_options); 497 mdb_printf(" fp_port_type : 0x%-2x\n", 498 port.fp_port_type.port_type); 499 mdb_printf(" fp_ub_count : %d\n", port.fp_ub_count); 500 mdb_printf(" fp_active_ubs : %d\n", port.fp_active_ubs); 501 mdb_printf(" fp_port_dip : 0x%p\n", port.fp_port_dip); 502 mdb_printf(" fp_fca_dip : 0x%p\n", port.fp_fca_dip); 503 504 for (idx = 0; idx < 16; idx++) { 505 if (port.fp_ip_addr[idx] != 0) 506 break; 507 } 508 509 if (idx != 16) { 510 mdb_printf(" fp_ip_addr : %-2x:%-2x:%-2x:%-2x:" 511 "%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x:%-2x" 512 ":%-2x:%-2x\n", 513 port.fp_ip_addr[0], port.fp_ip_addr[1], 514 port.fp_ip_addr[2], port.fp_ip_addr[3], 515 port.fp_ip_addr[4], port.fp_ip_addr[5], 516 port.fp_ip_addr[6], port.fp_ip_addr[7], 517 port.fp_ip_addr[8], port.fp_ip_addr[9], 518 port.fp_ip_addr[10], port.fp_ip_addr[11], 519 port.fp_ip_addr[12], port.fp_ip_addr[13], 520 port.fp_ip_addr[14], port.fp_ip_addr[15]); 521 } else { 522 mdb_printf(" fp_ip_addr : N/A\n"); 523 } 524 525 mdb_printf(" fp_fc4_types : "); 526 527 for (idx = 0; idx < 8; idx++) { 528 if (port.fp_fc4_types[idx] != 0) { 529 if (first) { 530 mdb_printf("%d", 531 port.fp_fc4_types[idx]); 532 first = 0; 533 } else { 534 mdb_printf(", %d", 535 port.fp_fc4_types[idx]); 536 } 537 } 538 } 539 540 if (first) { 541 mdb_printf("None\n"); 542 } else { 543 mdb_printf("\n"); 544 } 545 546 mdb_printf(" fp_pm_level : %d\n", port.fp_pm_level); 547 mdb_printf(" fp_pm_busy : %d\n", port.fp_pm_busy); 548 mdb_printf(" fp_pm_busy_nocomp : 0x%-8x\n", 549 port.fp_pm_busy_nocomp); 550 mdb_printf(" fp_hard_addr : 0x%-6x\n", 551 port.fp_hard_addr.hard_addr); 552 mdb_printf(" fp_sym_port_name : \"%s\"\n", 553 port.fp_sym_port_name); 554 mdb_printf(" fp_sym_node_name : \"%s\"\n", 555 port.fp_sym_node_name); 556 mdb_printf(" fp_rscn_count : %d\n", port.fp_rscn_count); 557 } else { 558 mdb_warn("failed to read fc_local_port_t at 0x%p", addr); 559 } 560 561 mdb_printf("\n"); 562 563 return (DCMD_OK); 564 } 565 566 567 /* 568 * Leadville remote_port walker/dcmd code 569 */ 570 571 /* 572 * We need to be given the address of a port structure in order to start 573 * walking. From that, we can read the pwwn table. 574 */ 575 static int 576 pd_by_pwwn_walk_i(mdb_walk_state_t *wsp) 577 { 578 fc_local_port_t port; 579 580 if (wsp->walk_addr == NULL) { 581 mdb_warn("pd_by_pwwn walk doesn't support global walks\n"); 582 return (WALK_ERR); 583 } 584 585 /* 586 * Allocate space for the pwwn_hash table 587 */ 588 589 fp_pwwn_table = mdb_alloc(sizeof (struct pwwn_hash) * 590 PWWN_HASH_TABLE_SIZE, UM_SLEEP); 591 592 /* 593 * Input should be an fc_local_port_t, so read it to get the pwwn 594 * table's head 595 */ 596 597 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) != 598 sizeof (fc_local_port_t)) { 599 mdb_warn("Unable to read in the port structure address\n"); 600 return (WALK_ERR); 601 } 602 603 if (mdb_vread(fp_pwwn_table, sizeof (struct pwwn_hash) * 604 PWWN_HASH_TABLE_SIZE, (uintptr_t)port.fp_pwwn_table) == -1) { 605 mdb_warn("Unable to read in the pwwn hash table\n"); 606 return (WALK_ERR); 607 } 608 609 pd_hash_index = 0; 610 611 while ((fp_pwwn_table[pd_hash_index].pwwn_head == NULL) && 612 (pd_hash_index < PWWN_HASH_TABLE_SIZE)) { 613 pd_hash_index++; 614 } 615 616 wsp->walk_addr = (uintptr_t)fp_pwwn_table[pd_hash_index].pwwn_head; 617 618 wsp->walk_data = mdb_alloc(sizeof (fc_remote_port_t), UM_SLEEP); 619 return (WALK_NEXT); 620 } 621 622 /* 623 * At each step, read a fc_remote_port_t into our private storage, and then 624 * invoke the callback function. We terminate when we reach a NULL p_next 625 * pointer. 626 */ 627 static int 628 pd_by_pwwn_walk_s(mdb_walk_state_t *wsp) 629 { 630 int status; 631 632 if ((wsp->walk_addr == NULL) && 633 (pd_hash_index >= (PWWN_HASH_TABLE_SIZE - 1))) { 634 return (WALK_DONE); 635 } 636 637 if (mdb_vread(wsp->walk_data, sizeof (fc_remote_port_t), wsp->walk_addr) 638 == -1) { 639 mdb_warn("failed to read fc_remote_port at %p", wsp->walk_addr); 640 return (WALK_DONE); 641 } 642 643 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 644 wsp->walk_cbdata); 645 646 wsp->walk_addr = 647 (uintptr_t)(((fc_remote_port_t *)wsp->walk_data)->pd_wwn_hnext); 648 649 if (wsp->walk_addr == NULL) { 650 /* 651 * Try the next hash list, if there is one. 652 */ 653 654 pd_hash_index++; 655 656 while ((fp_pwwn_table[pd_hash_index].pwwn_head == NULL) && 657 (pd_hash_index < PWWN_HASH_TABLE_SIZE)) { 658 pd_hash_index++; 659 } 660 661 if (pd_hash_index == PWWN_HASH_TABLE_SIZE) { 662 /* We're done */ 663 return (status); 664 } 665 666 wsp->walk_addr = 667 (uintptr_t)fp_pwwn_table[pd_hash_index].pwwn_head; 668 } 669 670 return (status); 671 } 672 673 /* 674 * The walker's fini function is invoked at the end of each walk. 675 */ 676 static void 677 pd_by_pwwn_walk_f(mdb_walk_state_t *wsp) 678 { 679 mdb_free(wsp->walk_data, sizeof (fc_remote_port_t)); 680 mdb_free(fp_pwwn_table, sizeof (struct pwwn_hash) * 681 PWWN_HASH_TABLE_SIZE); 682 fp_pwwn_table = NULL; 683 } 684 685 /* 686 * This is the same walker as pd_by_pwwn, but we walk the D_ID hash table 687 */ 688 689 static int 690 pd_by_did_walk_i(mdb_walk_state_t *wsp) 691 { 692 fc_local_port_t port; 693 694 if (wsp->walk_addr == NULL) { 695 mdb_warn("pd_by_did walk doesn't support global walks\n"); 696 return (WALK_ERR); 697 } 698 699 /* 700 * Allocate space for the did_hash table 701 */ 702 703 fp_did_table = mdb_alloc(sizeof (struct d_id_hash) * 704 D_ID_HASH_TABLE_SIZE, UM_SLEEP); 705 706 /* 707 * Input should be an fc_local_port_t, so read it to get the d_id 708 * table's head 709 */ 710 711 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) != 712 sizeof (fc_local_port_t)) { 713 mdb_warn("Unable to read in the port structure address\n"); 714 return (WALK_ERR); 715 } 716 717 if (mdb_vread(fp_did_table, sizeof (struct d_id_hash) * 718 D_ID_HASH_TABLE_SIZE, (uintptr_t)port.fp_did_table) == -1) { 719 mdb_warn("Unable to read in the D_ID hash table\n"); 720 return (WALK_ERR); 721 } 722 pd_hash_index = 0; 723 724 while ((fp_did_table[pd_hash_index].d_id_head == NULL) && 725 (pd_hash_index < D_ID_HASH_TABLE_SIZE)) { 726 pd_hash_index++; 727 } 728 729 wsp->walk_addr = (uintptr_t)fp_did_table[pd_hash_index].d_id_head; 730 731 wsp->walk_data = mdb_alloc(sizeof (fc_remote_port_t), UM_SLEEP); 732 return (WALK_NEXT); 733 } 734 735 /* 736 * At each step, read a fc_remote_port_t into our private storage, and then 737 * invoke the callback function. We terminate when we reach a NULL p_next 738 * pointer. 739 */ 740 static int 741 pd_by_did_walk_s(mdb_walk_state_t *wsp) 742 { 743 int status; 744 745 if ((wsp->walk_addr == NULL) && 746 (pd_hash_index >= (D_ID_HASH_TABLE_SIZE - 1))) { 747 return (WALK_DONE); 748 } 749 750 if (mdb_vread(wsp->walk_data, sizeof (fc_remote_port_t), wsp->walk_addr) 751 == -1) { 752 mdb_warn("failed to read fc_remote_port at %p", wsp->walk_addr); 753 return (WALK_DONE); 754 } 755 756 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 757 wsp->walk_cbdata); 758 759 wsp->walk_addr = 760 (uintptr_t)(((fc_remote_port_t *)wsp->walk_data)->pd_did_hnext); 761 762 if (wsp->walk_addr == NULL) { 763 /* 764 * Try the next hash list, if there is one. 765 */ 766 767 pd_hash_index++; 768 769 while ((fp_did_table[pd_hash_index].d_id_head == NULL) && 770 (pd_hash_index < D_ID_HASH_TABLE_SIZE)) { 771 pd_hash_index++; 772 } 773 774 if (pd_hash_index == D_ID_HASH_TABLE_SIZE) { 775 /* We're done */ 776 return (status); 777 } 778 779 wsp->walk_addr = 780 (uintptr_t)fp_did_table[pd_hash_index].d_id_head; 781 } 782 783 return (status); 784 } 785 786 /* 787 * The walker's fini function is invoked at the end of each walk. 788 */ 789 static void 790 pd_by_did_walk_f(mdb_walk_state_t *wsp) 791 { 792 mdb_free(wsp->walk_data, sizeof (fc_remote_port_t)); 793 mdb_free(fp_did_table, sizeof (struct d_id_hash) * 794 D_ID_HASH_TABLE_SIZE); 795 fp_did_table = NULL; 796 } 797 798 799 /* 800 * Display a remote_port structure 801 */ 802 static int 803 remote_port(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 804 { 805 fc_remote_port_t pd; 806 int idx; 807 int first = 1; 808 809 if (argc > 0) { 810 return (DCMD_USAGE); 811 } 812 813 if (!(flags & DCMD_ADDRSPEC)) { 814 mdb_printf("Sorry, you must provide an address\n"); 815 return (DCMD_ERR); 816 } 817 818 if (mdb_vread(&pd, sizeof (fc_remote_port_t), addr) != 819 sizeof (fc_remote_port_t)) { 820 mdb_warn("Error reading pd at 0x%x\n", addr); 821 return (DCMD_ERR); 822 } 823 824 mdb_printf("Reading remote_port at 0x%p\n", addr); 825 mdb_printf(" mutex : 0x%p\n", pd.pd_mutex); 826 mdb_printf(" port_id : 0x%-8x\n", pd.pd_port_id); 827 mdb_printf(" port_name : 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 828 pd.pd_port_name.raw_wwn[0], pd.pd_port_name.raw_wwn[1], 829 pd.pd_port_name.raw_wwn[2], pd.pd_port_name.raw_wwn[3], 830 pd.pd_port_name.raw_wwn[4], pd.pd_port_name.raw_wwn[5], 831 pd.pd_port_name.raw_wwn[6], pd.pd_port_name.raw_wwn[7]); 832 mdb_printf(" login_count : %d\n", pd.pd_login_count); 833 mdb_printf(" state : 0x%x ", pd.pd_state); 834 835 switch (pd.pd_state) { 836 case PORT_DEVICE_INVALID: 837 mdb_printf("(invalid)\n"); 838 break; 839 case PORT_DEVICE_VALID: 840 mdb_printf("(valid)\n"); 841 break; 842 case PORT_DEVICE_LOGGED_IN: 843 mdb_printf("(logged in)\n"); 844 break; 845 default: 846 mdb_printf("(Unknown state)\n"); 847 } 848 849 mdb_printf(" remote node : 0x%p\n", pd.pd_remote_nodep); 850 mdb_printf(" hard_addr : 0x%x\n", pd.pd_hard_addr); 851 mdb_printf(" local port : 0x%p\n", pd.pd_port); 852 mdb_printf(" type : %d ", pd.pd_type); 853 854 switch (pd.pd_type) { 855 case PORT_DEVICE_NOCHANGE: 856 mdb_printf("(No change)\n"); 857 break; 858 case PORT_DEVICE_NEW: 859 mdb_printf("(New)\n"); 860 break; 861 case PORT_DEVICE_OLD: 862 mdb_printf("(Old)\n"); 863 break; 864 case PORT_DEVICE_CHANGED: 865 mdb_printf("(Changed)\n"); 866 break; 867 case PORT_DEVICE_DELETE: 868 mdb_printf("(Delete)\n"); 869 break; 870 case PORT_DEVICE_USER_LOGIN: 871 mdb_printf("(User login)\n"); 872 break; 873 case PORT_DEVICE_USER_LOGOUT: 874 mdb_printf("(User logout)\n"); 875 break; 876 case PORT_DEVICE_USER_CREATE: 877 mdb_printf("(User create)\n"); 878 break; 879 case PORT_DEVICE_USER_DELETE: 880 mdb_printf("(User delete)\n"); 881 break; 882 default: 883 mdb_printf("(Unknown type)\n"); 884 } 885 886 mdb_printf(" flags : 0x%x ", pd.pd_flags); 887 888 switch (pd.pd_flags) { 889 case PD_IDLE: 890 mdb_printf("(Idle)\n"); 891 break; 892 case PD_ELS_IN_PROGRESS: 893 mdb_printf("(ELS in progress)\n"); 894 break; 895 case PD_ELS_MARK: 896 mdb_printf("(Mark)\n"); 897 break; 898 default: 899 mdb_printf("(Unknown flag value)\n"); 900 } 901 902 mdb_printf(" login_class : 0x%x\n", pd.pd_login_class); 903 mdb_printf(" recipient : %d\n", pd.pd_recepient); 904 mdb_printf(" ref_count : %d\n", pd.pd_ref_count); 905 mdb_printf(" aux_flags : 0x%x ", pd.pd_aux_flags); 906 907 first = 1; 908 if (pd.pd_aux_flags & PD_IN_DID_QUEUE) { 909 mdb_printf("(IN_DID_QUEUE"); 910 first = 0; 911 } 912 913 if (pd.pd_aux_flags & PD_DISABLE_RELOGIN) { 914 if (first) { 915 mdb_printf("(DISABLE_RELOGIN"); 916 } else { 917 mdb_printf(", DISABLE_RELOGIN"); 918 } 919 first = 0; 920 } 921 922 if (pd.pd_aux_flags & PD_NEEDS_REMOVAL) { 923 if (first) { 924 mdb_printf("(NEEDS_REMOVAL"); 925 } else { 926 mdb_printf(", NEEDS_REMOVAL"); 927 } 928 first = 0; 929 } 930 931 if (pd.pd_aux_flags & PD_LOGGED_OUT) { 932 if (first) { 933 mdb_printf("(LOGGED_OUT"); 934 } else { 935 mdb_printf(", LOGGED_OUT"); 936 } 937 first = 0; 938 } 939 940 if (pd.pd_aux_flags & PD_GIVEN_TO_ULPS) { 941 if (first) { 942 mdb_printf("(GIVEN_TO_ULPS"); 943 } else { 944 mdb_printf(", GIVEN_TO_ULPS"); 945 } 946 first = 0; 947 } 948 949 if (first == 0) { 950 mdb_printf(")\n"); 951 } else { 952 mdb_printf("\n"); 953 } 954 955 mdb_printf(" sig : %p\n", pd.pd_logo_tc.sig); 956 mdb_printf(" active : %d\n", pd.pd_logo_tc.active); 957 mdb_printf(" counter : %d\n", pd.pd_logo_tc.counter); 958 mdb_printf(" max_value : %d\n", pd.pd_logo_tc.max_value); 959 mdb_printf(" timer : %d\n", pd.pd_logo_tc.timer); 960 mdb_printf("\n"); 961 962 return (DCMD_OK); 963 } 964 965 int 966 fc_dump_logmsg(fc_trace_dmsg_t *addr, uint_t pktstart, uint_t pktend, 967 uint_t *printed) 968 { 969 fc_trace_dmsg_t msg; 970 caddr_t buf; 971 char merge[1024]; 972 caddr_t tmppkt; 973 char *tmpbuf; /* for tokenising the buffer */ 974 uint_t pktnum = 0; 975 976 while (addr != NULL) { 977 if (mdb_vread(&msg, sizeof (msg), (uintptr_t)addr) != 978 sizeof (msg)) { 979 mdb_warn("failed to read message pointer in kernel"); 980 return (DCMD_ERR); 981 } 982 983 if (msg.id_size) { 984 985 buf = mdb_alloc(msg.id_size + 1, UM_SLEEP); 986 tmppkt = mdb_alloc(msg.id_size + 1, UM_SLEEP); 987 988 if (mdb_vread(buf, msg.id_size, 989 (uintptr_t)msg.id_buf) != msg.id_size) { 990 mdb_warn("failed to read buffer contents" 991 " in kernel"); 992 mdb_free(buf, msg.id_size + 1); 993 return (DCMD_ERR); 994 } 995 996 if (buf[0] == '\n') { 997 mdb_printf("There is a problem in" 998 "the buffer\n"); 999 } 1000 /* funky packet processing stuff */ 1001 bcopy(buf, tmppkt, msg.id_size + 1); 1002 1003 /* find the equals sign, and put a null there */ 1004 tmpbuf = strchr(tmppkt, '='); 1005 *tmpbuf = 0; 1006 pktnum = (uint_t)mdb_strtoull(tmppkt); 1007 1008 if ((pktnum >= pktstart) && (pktnum <= pktend)) { 1009 (void) mdb_snprintf(merge, sizeof (merge), 1010 "[%09d:%03d:%03d:%03d] %s", 1011 (int)msg.id_time.tv_sec, 1012 (int)msg.id_time.tv_nsec/1000000, 1013 (int)(msg.id_time.tv_nsec/1000)%1000, 1014 (int)msg.id_time.tv_nsec%1000, 1015 buf); 1016 mdb_printf("%s", merge); 1017 if (printed != NULL) 1018 (*printed) ++; 1019 } 1020 mdb_free(buf, msg.id_size + 1); 1021 mdb_free(tmppkt, msg.id_size + 1); 1022 } 1023 addr = msg.id_next; 1024 } 1025 1026 return (DCMD_OK); 1027 } 1028 1029 int 1030 fc_dump_old_logmsg(fc_trace_dmsgv1_t *addr, uint_t pktstart, uint_t pktend, 1031 uint_t *printed) 1032 { 1033 fc_trace_dmsgv1_t msg; 1034 caddr_t buf; 1035 char merge[1024]; 1036 caddr_t tmppkt; 1037 char *tmpbuf; /* for tokenising the buffer */ 1038 uint_t pktnum = 0; 1039 1040 while (addr != NULL) { 1041 if (mdb_vread(&msg, sizeof (msg), (uintptr_t)addr) != 1042 sizeof (msg)) { 1043 mdb_warn("failed to read message pointer in kernel"); 1044 return (DCMD_ERR); 1045 } 1046 1047 if (msg.id_size) { 1048 1049 buf = mdb_alloc(msg.id_size + 1, UM_SLEEP); 1050 tmppkt = mdb_alloc(msg.id_size + 1, UM_SLEEP); 1051 1052 if (mdb_vread(buf, msg.id_size, 1053 (uintptr_t)msg.id_buf) != msg.id_size) { 1054 mdb_warn("failed to read buffer contents" 1055 " in kernel"); 1056 mdb_free(buf, msg.id_size + 1); 1057 return (DCMD_ERR); 1058 } 1059 1060 if (buf[0] == '\n') { 1061 mdb_printf("There is a problem in" 1062 "the buffer\n"); 1063 } 1064 /* funky packet processing stuff */ 1065 bcopy(buf, tmppkt, msg.id_size + 1); 1066 1067 tmpbuf = strchr(tmppkt, '='); 1068 *tmpbuf = 0; 1069 pktnum = (uint_t)mdb_strtoull(tmppkt); 1070 1071 if ((pktnum >= pktstart) && (pktnum <= pktend)) { 1072 (void) mdb_snprintf(merge, sizeof (merge), 1073 "[%d] %s", 1074 msg.id_time, 1075 buf); 1076 mdb_printf("%s", merge); 1077 if (printed != NULL) 1078 (*printed) ++; 1079 } 1080 mdb_free(buf, msg.id_size + 1); 1081 mdb_free(tmppkt, msg.id_size + 1); 1082 } 1083 addr = msg.id_next; 1084 } 1085 1086 return (DCMD_OK); 1087 } 1088 1089 int 1090 fc_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1091 { 1092 fc_trace_logq_t logq; 1093 uint_t pktnum = 0; 1094 uint_t printed = 0; /* have we printed anything? */ 1095 1096 uintptr_t pktstart = 0; 1097 uintptr_t pktend = UINT_MAX; 1098 int rval = DCMD_OK; 1099 1100 if (mdb_vread(&logq, sizeof (logq), addr) != sizeof (logq)) { 1101 mdb_warn("Failed to read log queue in kernel"); 1102 return (DCMD_ERR); 1103 } 1104 1105 if (mdb_getopts(argc, argv, 1106 's', MDB_OPT_UINTPTR, &pktstart, 1107 'e', MDB_OPT_UINTPTR, &pktend) != argc) { 1108 return (DCMD_USAGE); 1109 } 1110 1111 if (pktstart > pktend) { 1112 return (DCMD_USAGE); 1113 } 1114 1115 if (logq.il_flags & FC_TRACE_LOGQ_V2 != 0) { 1116 rval = fc_dump_logmsg((fc_trace_dmsg_t *)logq.il_msgh, pktstart, 1117 pktend, &printed); 1118 } else { 1119 rval = fc_dump_old_logmsg((fc_trace_dmsgv1_t *)logq.il_msgh, 1120 pktstart, pktend, &printed); 1121 } 1122 1123 if (rval != DCMD_OK) { 1124 return (rval); 1125 } 1126 1127 if (printed == 0) { 1128 mdb_printf("No packets in the buffer match the" 1129 " criteria given"); 1130 } 1131 1132 return (rval); 1133 } 1134 1135 int 1136 fp_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1137 { 1138 if (mdb_readvar(&addr, "fp_logq") == -1) { 1139 mdb_warn("failed to read fp_logq"); 1140 return (DCMD_ERR); 1141 } 1142 1143 if (DCMD_HDRSPEC(flags)) { 1144 mdb_printf("fp trace buffer contents\n"); 1145 } 1146 1147 return (fc_trace_dump(addr, flags, argc, argv)); 1148 } 1149 1150 1151 int 1152 fcp_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1153 { 1154 if (mdb_readvar(&addr, "fcp_logq") == -1) { 1155 mdb_warn("failed to read fcp_logq"); 1156 return (DCMD_ERR); 1157 } 1158 1159 if (DCMD_HDRSPEC(flags)) { 1160 mdb_printf("fcp trace buffer contents\n"); 1161 } 1162 1163 return (fc_trace_dump(addr, flags, argc, argv)); 1164 } 1165 1166 /* 1167 * Leadville job_request walker/dcmd code 1168 */ 1169 1170 /* 1171 * We need to be given the address of a local port structure in order to start 1172 * walking. From that, we can read the job_request list. 1173 */ 1174 1175 static int 1176 job_request_walk_i(mdb_walk_state_t *wsp) 1177 { 1178 if (wsp->walk_addr == NULL) { 1179 mdb_warn("The address of a fc_local_port" 1180 " structure must be given\n"); 1181 return (WALK_ERR); 1182 } 1183 1184 /* 1185 * Input should be a fc_local_port_t, so read it to get the job_request 1186 * lists's head 1187 */ 1188 1189 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) != 1190 sizeof (fc_local_port_t)) { 1191 mdb_warn("Failed to read in the fc_local_port" 1192 " at 0x%p\n", wsp->walk_addr); 1193 return (WALK_ERR); 1194 } 1195 1196 wsp->walk_addr = (uintptr_t)(port.fp_job_head); 1197 wsp->walk_data = mdb_alloc(sizeof (struct job_request), UM_SLEEP); 1198 1199 return (WALK_NEXT); 1200 } 1201 1202 static int 1203 job_request_walk_s(mdb_walk_state_t *wsp) 1204 { 1205 int status; 1206 1207 if (wsp->walk_addr == NULL) 1208 return (WALK_DONE); 1209 1210 if (mdb_vread(wsp->walk_data, sizeof (struct job_request), 1211 wsp->walk_addr) == -1) { 1212 mdb_warn("Failed to read in the job_request at 0x%p\n", 1213 wsp->walk_addr); 1214 return (WALK_DONE); 1215 } 1216 1217 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1218 wsp->walk_cbdata); 1219 1220 wsp->walk_addr = 1221 (uintptr_t)(((struct job_request *)wsp->walk_data)->job_next); 1222 1223 return (status); 1224 } 1225 1226 /* 1227 * The walker's fini function is invoked at the end of each walk. 1228 */ 1229 static void 1230 job_request_walk_f(mdb_walk_state_t *wsp) 1231 { 1232 mdb_free(wsp->walk_data, sizeof (struct job_request)); 1233 } 1234 1235 1236 /* 1237 * Leadville fc_orphan walker/dcmd code 1238 */ 1239 1240 /* 1241 * We need to be given the address of a port structure in order to start 1242 * walking. From that, we can read the orphan list. 1243 */ 1244 1245 static int 1246 orphan_walk_i(mdb_walk_state_t *wsp) 1247 { 1248 if (wsp->walk_addr == NULL) { 1249 mdb_warn("The address of a fc_local_port" 1250 " structure must be given\n"); 1251 return (WALK_ERR); 1252 } 1253 1254 /* 1255 * Input should be a fc_local_port_t, so read it to get the orphan 1256 * lists's head 1257 */ 1258 1259 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) != 1260 sizeof (fc_local_port_t)) { 1261 mdb_warn("Failed to read in the fc_local_port" 1262 " at 0x%p\n", wsp->walk_addr); 1263 return (WALK_ERR); 1264 } 1265 1266 wsp->walk_addr = (uintptr_t)(port.fp_orphan_list); 1267 wsp->walk_data = mdb_alloc(sizeof (struct fc_orphan), UM_SLEEP); 1268 1269 return (WALK_NEXT); 1270 } 1271 1272 static int 1273 orphan_walk_s(mdb_walk_state_t *wsp) 1274 { 1275 int status; 1276 1277 if (wsp->walk_addr == NULL) 1278 return (WALK_DONE); 1279 1280 if (mdb_vread(wsp->walk_data, sizeof (struct fc_orphan), 1281 wsp->walk_addr) == -1) { 1282 mdb_warn("Failed to read in the fc_orphan at 0x%p\n", 1283 wsp->walk_addr); 1284 return (WALK_DONE); 1285 } 1286 1287 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1288 wsp->walk_cbdata); 1289 1290 wsp->walk_addr = 1291 (uintptr_t)(((struct fc_orphan *)wsp->walk_data)->orp_next); 1292 1293 return (status); 1294 } 1295 1296 /* 1297 * The walker's fini function is invoked at the end of each walk. 1298 */ 1299 static void 1300 orphan_walk_f(mdb_walk_state_t *wsp) 1301 { 1302 mdb_free(wsp->walk_data, sizeof (struct fc_orphan)); 1303 } 1304 1305 1306 /* 1307 * MDB module linkage information: 1308 * 1309 * We declare a list of structures describing our dcmds, a list of structures 1310 * describing our walkers, and a function named _mdb_init to return a pointer 1311 * to our module information. 1312 */ 1313 1314 static const mdb_dcmd_t dcmds[] = { 1315 { "ports", "[-l]", "Leadville port list", ports }, 1316 { "ulps", NULL, "Leadville ULP list", ulps }, 1317 { "ulpmods", NULL, "Leadville ULP module list", ulpmods }, 1318 { "fcport", NULL, "Display a Leadville fc_local_port structure", 1319 fcport }, 1320 { "remote_port", NULL, "Display fc_remote_port structures", 1321 remote_port }, 1322 { "fcptrace", "[-s m][-e n] (m < n)", "Dump the fcp trace buffer, " 1323 "optionally supplying starting and ending packet numbers.", 1324 fcp_trace_dump, NULL }, 1325 { "fptrace", "[-s m][-e n] (m < n)", "Dump the fp trace buffer, " 1326 "optionally supplying starting and ending packet numbers.", 1327 fp_trace_dump, NULL }, 1328 { NULL } 1329 }; 1330 1331 static const mdb_walker_t walkers[] = { 1332 { "ports", "walk list of Leadville port structures", 1333 port_walk_i, port_walk_s, port_walk_f }, 1334 { "ulps", "walk list of Leadville ULP structures", 1335 ulp_walk_i, ulp_walk_s, ulp_walk_f }, 1336 { "ulpmods", "walk list of Leadville ULP module structures", 1337 ulpmod_walk_i, ulpmod_walk_s, ulpmod_walk_f }, 1338 { "pd_by_pwwn", "walk list of fc_remote_port structures hashed by PWWN", 1339 pd_by_pwwn_walk_i, pd_by_pwwn_walk_s, pd_by_pwwn_walk_f }, 1340 { "pd_by_did", "walk list of fc_remote_port structures hashed by D_ID", 1341 pd_by_did_walk_i, pd_by_did_walk_s, pd_by_did_walk_f }, 1342 { "job_request", "walk list of job_request structures for a local port", 1343 job_request_walk_i, job_request_walk_s, job_request_walk_f }, 1344 { "orphan", "walk list of orphan structures for a local port", 1345 orphan_walk_i, orphan_walk_s, orphan_walk_f }, 1346 { NULL } 1347 }; 1348 1349 static const mdb_modinfo_t modinfo = { 1350 MDB_API_VERSION, dcmds, walkers 1351 }; 1352 1353 const mdb_modinfo_t * 1354 _mdb_init(void) 1355 { 1356 return (&modinfo); 1357 } 1358