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