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 }