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 == NULL &&
  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 == NULL)
  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 == NULL &&
 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 == NULL)
 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 == NULL &&
 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 == NULL)
 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 == NULL) {
 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 == NULL) &&
 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 == NULL) {
 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 == NULL) {
 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 == NULL) &&
 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 == NULL) {
 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 == 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 }