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 2009 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 "[%Y:%03d:%03d:%03d] %s", 1011 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, buf); 1015 mdb_printf("%s", merge); 1016 if (printed != NULL) 1017 (*printed) ++; 1018 } 1019 mdb_free(buf, msg.id_size + 1); 1020 mdb_free(tmppkt, msg.id_size + 1); 1021 } 1022 addr = msg.id_next; 1023 } 1024 1025 return (DCMD_OK); 1026 } 1027 1028 int 1029 fc_dump_old_logmsg(fc_trace_dmsgv1_t *addr, uint_t pktstart, uint_t pktend, 1030 uint_t *printed) 1031 { 1032 fc_trace_dmsgv1_t msg; 1033 caddr_t buf; 1034 char merge[1024]; 1035 caddr_t tmppkt; 1036 char *tmpbuf; /* for tokenising the buffer */ 1037 uint_t pktnum = 0; 1038 1039 while (addr != NULL) { 1040 if (mdb_vread(&msg, sizeof (msg), (uintptr_t)addr) != 1041 sizeof (msg)) { 1042 mdb_warn("failed to read message pointer in kernel"); 1043 return (DCMD_ERR); 1044 } 1045 1046 if (msg.id_size) { 1047 1048 buf = mdb_alloc(msg.id_size + 1, UM_SLEEP); 1049 tmppkt = mdb_alloc(msg.id_size + 1, UM_SLEEP); 1050 1051 if (mdb_vread(buf, msg.id_size, 1052 (uintptr_t)msg.id_buf) != msg.id_size) { 1053 mdb_warn("failed to read buffer contents" 1054 " in kernel"); 1055 mdb_free(buf, msg.id_size + 1); 1056 return (DCMD_ERR); 1057 } 1058 1059 if (buf[0] == '\n') { 1060 mdb_printf("There is a problem in" 1061 "the buffer\n"); 1062 } 1063 /* funky packet processing stuff */ 1064 bcopy(buf, tmppkt, msg.id_size + 1); 1065 1066 tmpbuf = strchr(tmppkt, '='); 1067 *tmpbuf = 0; 1068 pktnum = (uint_t)mdb_strtoull(tmppkt); 1069 1070 if ((pktnum >= pktstart) && (pktnum <= pktend)) { 1071 (void) mdb_snprintf(merge, sizeof (merge), 1072 "[%Y] %s", msg.id_time, buf); 1073 mdb_printf("%s", merge); 1074 if (printed != NULL) 1075 (*printed) ++; 1076 } 1077 mdb_free(buf, msg.id_size + 1); 1078 mdb_free(tmppkt, msg.id_size + 1); 1079 } 1080 addr = msg.id_next; 1081 } 1082 1083 return (DCMD_OK); 1084 } 1085 1086 int 1087 fc_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1088 { 1089 fc_trace_logq_t logq; 1090 uint_t pktnum = 0; 1091 uint_t printed = 0; /* have we printed anything? */ 1092 1093 uintptr_t pktstart = 0; 1094 uintptr_t pktend = UINT_MAX; 1095 int rval = DCMD_OK; 1096 1097 if (mdb_vread(&logq, sizeof (logq), addr) != sizeof (logq)) { 1098 mdb_warn("Failed to read log queue in kernel"); 1099 return (DCMD_ERR); 1100 } 1101 1102 if (mdb_getopts(argc, argv, 1103 's', MDB_OPT_UINTPTR, &pktstart, 1104 'e', MDB_OPT_UINTPTR, &pktend) != argc) { 1105 return (DCMD_USAGE); 1106 } 1107 1108 if (pktstart > pktend) { 1109 return (DCMD_USAGE); 1110 } 1111 1112 if (logq.il_flags & FC_TRACE_LOGQ_V2 != 0) { 1113 rval = fc_dump_logmsg((fc_trace_dmsg_t *)logq.il_msgh, pktstart, 1114 pktend, &printed); 1115 } else { 1116 rval = fc_dump_old_logmsg((fc_trace_dmsgv1_t *)logq.il_msgh, 1117 pktstart, pktend, &printed); 1118 } 1119 1120 if (rval != DCMD_OK) { 1121 return (rval); 1122 } 1123 1124 if (printed == 0) { 1125 mdb_printf("No packets in the buffer match the" 1126 " criteria given"); 1127 } 1128 1129 return (rval); 1130 } 1131 1132 int 1133 fp_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1134 { 1135 if (mdb_readvar(&addr, "fp_logq") == -1) { 1136 mdb_warn("failed to read fp_logq"); 1137 return (DCMD_ERR); 1138 } 1139 1140 if (DCMD_HDRSPEC(flags)) { 1141 mdb_printf("fp trace buffer contents\n"); 1142 } 1143 1144 return (fc_trace_dump(addr, flags, argc, argv)); 1145 } 1146 1147 1148 int 1149 fcp_trace_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1150 { 1151 if (mdb_readvar(&addr, "fcp_logq") == -1) { 1152 mdb_warn("failed to read fcp_logq"); 1153 return (DCMD_ERR); 1154 } 1155 1156 if (DCMD_HDRSPEC(flags)) { 1157 mdb_printf("fcp trace buffer contents\n"); 1158 } 1159 1160 return (fc_trace_dump(addr, flags, argc, argv)); 1161 } 1162 1163 /* 1164 * Leadville job_request walker/dcmd code 1165 */ 1166 1167 /* 1168 * We need to be given the address of a local port structure in order to start 1169 * walking. From that, we can read the job_request list. 1170 */ 1171 1172 static int 1173 job_request_walk_i(mdb_walk_state_t *wsp) 1174 { 1175 if (wsp->walk_addr == NULL) { 1176 mdb_warn("The address of a fc_local_port" 1177 " structure must be given\n"); 1178 return (WALK_ERR); 1179 } 1180 1181 /* 1182 * Input should be a fc_local_port_t, so read it to get the job_request 1183 * lists's head 1184 */ 1185 1186 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) != 1187 sizeof (fc_local_port_t)) { 1188 mdb_warn("Failed to read in the fc_local_port" 1189 " at 0x%p\n", wsp->walk_addr); 1190 return (WALK_ERR); 1191 } 1192 1193 wsp->walk_addr = (uintptr_t)(port.fp_job_head); 1194 wsp->walk_data = mdb_alloc(sizeof (struct job_request), UM_SLEEP); 1195 1196 return (WALK_NEXT); 1197 } 1198 1199 static int 1200 job_request_walk_s(mdb_walk_state_t *wsp) 1201 { 1202 int status; 1203 1204 if (wsp->walk_addr == NULL) 1205 return (WALK_DONE); 1206 1207 if (mdb_vread(wsp->walk_data, sizeof (struct job_request), 1208 wsp->walk_addr) == -1) { 1209 mdb_warn("Failed to read in the job_request at 0x%p\n", 1210 wsp->walk_addr); 1211 return (WALK_DONE); 1212 } 1213 1214 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1215 wsp->walk_cbdata); 1216 1217 wsp->walk_addr = 1218 (uintptr_t)(((struct job_request *)wsp->walk_data)->job_next); 1219 1220 return (status); 1221 } 1222 1223 /* 1224 * The walker's fini function is invoked at the end of each walk. 1225 */ 1226 static void 1227 job_request_walk_f(mdb_walk_state_t *wsp) 1228 { 1229 mdb_free(wsp->walk_data, sizeof (struct job_request)); 1230 } 1231 1232 1233 /* 1234 * Leadville fc_orphan walker/dcmd code 1235 */ 1236 1237 /* 1238 * We need to be given the address of a port structure in order to start 1239 * walking. From that, we can read the orphan list. 1240 */ 1241 1242 static int 1243 orphan_walk_i(mdb_walk_state_t *wsp) 1244 { 1245 if (wsp->walk_addr == NULL) { 1246 mdb_warn("The address of a fc_local_port" 1247 " structure must be given\n"); 1248 return (WALK_ERR); 1249 } 1250 1251 /* 1252 * Input should be a fc_local_port_t, so read it to get the orphan 1253 * lists's head 1254 */ 1255 1256 if (mdb_vread(&port, sizeof (fc_local_port_t), wsp->walk_addr) != 1257 sizeof (fc_local_port_t)) { 1258 mdb_warn("Failed to read in the fc_local_port" 1259 " at 0x%p\n", wsp->walk_addr); 1260 return (WALK_ERR); 1261 } 1262 1263 wsp->walk_addr = (uintptr_t)(port.fp_orphan_list); 1264 wsp->walk_data = mdb_alloc(sizeof (struct fc_orphan), UM_SLEEP); 1265 1266 return (WALK_NEXT); 1267 } 1268 1269 static int 1270 orphan_walk_s(mdb_walk_state_t *wsp) 1271 { 1272 int status; 1273 1274 if (wsp->walk_addr == NULL) 1275 return (WALK_DONE); 1276 1277 if (mdb_vread(wsp->walk_data, sizeof (struct fc_orphan), 1278 wsp->walk_addr) == -1) { 1279 mdb_warn("Failed to read in the fc_orphan at 0x%p\n", 1280 wsp->walk_addr); 1281 return (WALK_DONE); 1282 } 1283 1284 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1285 wsp->walk_cbdata); 1286 1287 wsp->walk_addr = 1288 (uintptr_t)(((struct fc_orphan *)wsp->walk_data)->orp_next); 1289 1290 return (status); 1291 } 1292 1293 /* 1294 * The walker's fini function is invoked at the end of each walk. 1295 */ 1296 static void 1297 orphan_walk_f(mdb_walk_state_t *wsp) 1298 { 1299 mdb_free(wsp->walk_data, sizeof (struct fc_orphan)); 1300 } 1301 1302 1303 /* 1304 * MDB module linkage information: 1305 * 1306 * We declare a list of structures describing our dcmds, a list of structures 1307 * describing our walkers, and a function named _mdb_init to return a pointer 1308 * to our module information. 1309 */ 1310 1311 static const mdb_dcmd_t dcmds[] = { 1312 { "ports", "[-l]", "Leadville port list", ports }, 1313 { "ulps", NULL, "Leadville ULP list", ulps }, 1314 { "ulpmods", NULL, "Leadville ULP module list", ulpmods }, 1315 { "fcport", NULL, "Display a Leadville fc_local_port structure", 1316 fcport }, 1317 { "remote_port", NULL, "Display fc_remote_port structures", 1318 remote_port }, 1319 { "fcptrace", "[-s m][-e n] (m < n)", "Dump the fcp trace buffer, " 1320 "optionally supplying starting and ending packet numbers.", 1321 fcp_trace_dump, NULL }, 1322 { "fptrace", "[-s m][-e n] (m < n)", "Dump the fp trace buffer, " 1323 "optionally supplying starting and ending packet numbers.", 1324 fp_trace_dump, NULL }, 1325 { NULL } 1326 }; 1327 1328 static const mdb_walker_t walkers[] = { 1329 { "ports", "walk list of Leadville port structures", 1330 port_walk_i, port_walk_s, port_walk_f }, 1331 { "ulps", "walk list of Leadville ULP structures", 1332 ulp_walk_i, ulp_walk_s, ulp_walk_f }, 1333 { "ulpmods", "walk list of Leadville ULP module structures", 1334 ulpmod_walk_i, ulpmod_walk_s, ulpmod_walk_f }, 1335 { "pd_by_pwwn", "walk list of fc_remote_port structures hashed by PWWN", 1336 pd_by_pwwn_walk_i, pd_by_pwwn_walk_s, pd_by_pwwn_walk_f }, 1337 { "pd_by_did", "walk list of fc_remote_port structures hashed by D_ID", 1338 pd_by_did_walk_i, pd_by_did_walk_s, pd_by_did_walk_f }, 1339 { "job_request", "walk list of job_request structures for a local port", 1340 job_request_walk_i, job_request_walk_s, job_request_walk_f }, 1341 { "orphan", "walk list of orphan structures for a local port", 1342 orphan_walk_i, orphan_walk_s, orphan_walk_f }, 1343 { NULL } 1344 }; 1345 1346 static const mdb_modinfo_t modinfo = { 1347 MDB_API_VERSION, dcmds, walkers 1348 }; 1349 1350 const mdb_modinfo_t * 1351 _mdb_init(void) 1352 { 1353 return (&modinfo); 1354 } 1355