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  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/dditypes.h>
  28 #include <sys/mdb_modapi.h>
  29 #include <sys/modctl.h>
  30 #include <sys/sunddi.h>
  31 #include <sys/lpif.h>
  32 #include <sys/stmf.h>
  33 #include <sys/portif.h>
  34 #include <sys/list.h>
  35 #include <stmf_impl.h>
  36 #include <lun_map.h>
  37 #include <stmf_state.h>
  38 
  39 #include <sys/fct.h>
  40 #include <fct_impl.h>
  41 
  42 #include "cmd_options.h"
  43 
  44 static int
  45 stmf_ilport_walk_i(mdb_walk_state_t *wsp)
  46 {
  47         if (wsp->walk_addr == NULL) {
  48                 struct stmf_state state;
  49 
  50                 if (mdb_readsym(&state, sizeof (struct stmf_state),
  51                     "stmf_state") == -1) {
  52                         mdb_warn("failed to read stmf_state");
  53                         return (WALK_ERR);
  54                 }
  55                 wsp->walk_addr = (uintptr_t)state.stmf_ilportlist;
  56         }
  57 
  58         wsp->walk_data = mdb_alloc(sizeof (stmf_i_local_port_t), UM_SLEEP);
  59         return (WALK_NEXT);
  60 }
  61 
  62 static int
  63 stmf_ilport_walk_s(mdb_walk_state_t *wsp)
  64 {
  65         int status = WALK_NEXT;
  66 
  67         if (wsp->walk_addr == NULL)
  68                 return (WALK_DONE);
  69 
  70         if (mdb_vread(wsp->walk_data, sizeof (struct stmf_i_local_port),
  71             wsp->walk_addr) == -1) {
  72                 mdb_warn("failed to read stmf_i_local_port_t at %p",
  73                     wsp->walk_addr);
  74                 return (WALK_ERR);
  75         }
  76 
  77         if (wsp->walk_callback)
  78                 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
  79                     wsp->walk_cbdata);
  80 
  81         wsp->walk_addr = (uintptr_t)
  82             (((struct stmf_i_local_port *)wsp->walk_data)->ilport_next);
  83 
  84         return (status);
  85 }
  86 
  87 static void
  88 stmf_ilport_walk_f(mdb_walk_state_t *wsp)
  89 {
  90         mdb_free(wsp->walk_data, sizeof (struct stmf_i_local_port));
  91 }
  92 
  93 static int
  94 dump_ilport(struct stmf_i_local_port *ilportp, int verbose)
  95 {
  96         if (ilportp == NULL)
  97                 return (DCMD_OK);
  98 
  99         mdb_printf("%p\n", ilportp);
 100 
 101         if (verbose) {
 102                 /* here assume the alias is maximumly 1024 bytes */
 103                 char alias[255];
 104                 struct stmf_local_port lport;
 105                 struct stmf_i_local_port ilport;
 106 
 107                 if (mdb_vread(&ilport, sizeof (ilport), (uintptr_t)ilportp)
 108                     == -1) {
 109                         mdb_warn("failed to read stmf_i_local_port at %p",
 110                             ilportp);
 111                         return (DCMD_ERR);
 112                 }
 113 
 114                 memset(alias, 0, sizeof (alias));
 115                 if (mdb_vread(&lport, sizeof (lport),
 116                     (uintptr_t)ilport.ilport_lport) == -1) {
 117                         mdb_warn("failed to read stmf_local_port at %p",
 118                             ilport.ilport_lport);
 119                         return (DCMD_ERR);
 120                 }
 121                 if (lport.lport_alias && mdb_vread(alias, sizeof (alias),
 122                     (uintptr_t)lport.lport_alias) == -1) {
 123                         mdb_warn("failed to read memory at %p",
 124                             lport.lport_alias);
 125                         return (DCMD_ERR);
 126                 }
 127 
 128                 mdb_printf("  lport: %p\n", ilport.ilport_lport);
 129                 if (lport.lport_alias)
 130                         mdb_printf("  port alias: %s\n", alias);
 131                 mdb_printf("  port provider: %p\n", lport.lport_pp);
 132         }
 133 
 134         return (DCMD_OK);
 135 }
 136 
 137 /*ARGSUSED*/
 138 static int
 139 stmf_ilports(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 140 {
 141         int i;
 142         int verbose = 0;
 143         mdb_walk_state_t ws = {NULL, };
 144 
 145         for (i = 0; i < argc; i++) {
 146                 char *ptr = (char *)argv[i].a_un.a_str;
 147 
 148                 if (ptr[0] == '-')
 149                         ptr++;
 150                 while (*ptr) {
 151                         if (*ptr == 'v')
 152                                 verbose = 1;
 153                         ptr++;
 154                 }
 155         }
 156 
 157         if (stmf_ilport_walk_i(&ws) == WALK_ERR)
 158                 return (DCMD_ERR);
 159 
 160         dump_ilport((stmf_i_local_port_t *)ws.walk_addr, verbose);
 161 
 162         while (stmf_ilport_walk_s(&ws) == WALK_NEXT)
 163                 dump_ilport((stmf_i_local_port_t *)ws.walk_addr, verbose);
 164 
 165         stmf_ilport_walk_f(&ws);
 166         return (DCMD_OK);
 167 }
 168 
 169 struct stmf_i_local_port *
 170 next_stmf_port(mdb_walk_state_t *wsp)
 171 {
 172         if (wsp->walk_addr == NULL) {
 173                 if (stmf_ilport_walk_i(wsp) == WALK_ERR) {
 174                         stmf_ilport_walk_f(wsp);
 175                         return (NULL);
 176                 }
 177                 if (wsp->walk_addr == NULL)
 178                         stmf_ilport_walk_f(wsp);
 179                 return ((struct stmf_i_local_port *)wsp->walk_addr);
 180         }
 181 
 182         if (stmf_ilport_walk_s(wsp) == WALK_ERR) {
 183                 stmf_ilport_walk_f(wsp);
 184                 return (NULL);
 185         }
 186         if (wsp->walk_addr == NULL)
 187                 stmf_ilport_walk_f(wsp);
 188         return ((struct stmf_i_local_port *)wsp->walk_addr);
 189 }
 190 
 191 
 192 /*ARGSUSED*/
 193 static int
 194 stmf_iss(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 195 {
 196         struct stmf_i_local_port iport;
 197         struct stmf_i_scsi_session *issp;
 198         struct stmf_i_scsi_session iss;
 199         int i;
 200         int verbose = 0;
 201 
 202         for (i = 0; i < argc; i++) {
 203                 char *ptr = (char *)argv[i].a_un.a_str;
 204 
 205                 if (ptr[0] == '-')
 206                         ptr++;
 207                 while (*ptr) {
 208                         if (*ptr == 'v')
 209                                 verbose = 1;
 210                         ptr++;
 211                 }
 212         }
 213 
 214         if (addr == NULL) {
 215                 mdb_warn("address of stmf_i_local_port should be specified\n");
 216                 return (DCMD_ERR);
 217         }
 218 
 219         /*
 220          * Input should be stmf_i_local_port_t.
 221          */
 222         if (mdb_vread(&iport, sizeof (struct stmf_i_local_port), addr)
 223             != sizeof (struct stmf_i_local_port)) {
 224                 mdb_warn("Unable to read in stmf_i_local_port at %p\n", addr);
 225                 return (DCMD_ERR);
 226         }
 227 
 228         issp = iport.ilport_ss_list;
 229 
 230         while (issp) {
 231                 if (mdb_vread(&iss, sizeof (iss), (uintptr_t)issp) == -1) {
 232                         mdb_warn("failed to read stmf_i_scsi_session_t at %p",
 233                             issp);
 234                         return (DCMD_ERR);
 235                 }
 236 
 237                 mdb_printf("%p\n", issp);
 238                 if (verbose) {
 239                         mdb_printf("  scsi session: %p\n", iss.iss_ss);
 240                 }
 241 
 242                 issp = iss.iss_next;
 243         }
 244 
 245         return (DCMD_OK);
 246 }
 247 
 248 /*ARGSUSED*/
 249 static int
 250 stmf_ilus(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 251 {
 252         struct stmf_state state;
 253         struct stmf_i_lu ilu;
 254         struct stmf_i_lu *ilup;
 255         int i;
 256         int verbose = 0;
 257 
 258         for (i = 0; i < argc; i++) {
 259                 char *ptr = (char *)argv[i].a_un.a_str;
 260 
 261                 if (ptr[0] == '-')
 262                         ptr++;
 263                 while (*ptr) {
 264                         if (*ptr == 'v')
 265                                 verbose = 1;
 266                         ptr++;
 267                 }
 268         }
 269 
 270         if (mdb_readsym(&state, sizeof (struct stmf_state), "stmf_state")
 271             == -1) {
 272                 mdb_warn("failed to read stmf_state");
 273                 return (DCMD_ERR);
 274         }
 275 
 276         ilup = state.stmf_ilulist;
 277         while (ilup) {
 278                 if (mdb_vread(&ilu, sizeof (struct stmf_i_lu), (uintptr_t)ilup)
 279                     == -1) {
 280                         mdb_warn("failed to read stmf_i_lu_t at %p", ilup);
 281                         return (DCMD_ERR);
 282                 }
 283 
 284                 mdb_printf("%p\n", ilup);
 285                 if (verbose) {
 286                         mdb_printf("  lu: %p\n", ilu.ilu_lu);
 287 
 288                         /* XXX lu_alias? what is its size? */
 289                 }
 290 
 291                 ilup = ilu.ilu_next;
 292         }
 293 
 294         return (DCMD_OK);
 295 }
 296 
 297 /*ARGSUSED*/
 298 static int
 299 stmf_i_lu_providers(uintptr_t addr, uint_t flags, int argc,
 300     const mdb_arg_t *argv)
 301 {
 302         struct stmf_state state;
 303         struct stmf_i_lu_provider ilp;
 304         struct stmf_i_lu_provider *ilpp;
 305         int i;
 306         int verbose = 0;
 307 
 308         for (i = 0; i < argc; i++) {
 309                 char *ptr = (char *)argv[i].a_un.a_str;
 310 
 311                 if (ptr[0] == '-')
 312                         ptr++;
 313                 while (*ptr) {
 314                         if (*ptr == 'v')
 315                                 verbose = 1;
 316                         ptr++;
 317                 }
 318         }
 319 
 320         if (mdb_readsym(&state, sizeof (struct stmf_state), "stmf_state")
 321             == -1) {
 322                 mdb_warn("failed to read stmf_state");
 323                 return (DCMD_ERR);
 324         }
 325 
 326         ilpp = state.stmf_ilplist;
 327         while (ilpp) {
 328                 if (mdb_vread(&ilp, sizeof (stmf_i_lu_provider_t),
 329                     (uintptr_t)ilpp) == -1) {
 330                         mdb_warn("failed to read stmf_i_lu_provider_t at %p",
 331                             ilpp);
 332                         return (DCMD_ERR);
 333                 }
 334 
 335                 mdb_printf("%p\n", ilpp);
 336                 if (verbose) {
 337                         mdb_printf("  lu provider: %p\n", ilp.ilp_lp);
 338                 }
 339 
 340                 ilpp = ilp.ilp_next;
 341         }
 342 
 343         return (DCMD_OK);
 344 }
 345 
 346 /*ARGSUSED*/
 347 static int
 348 stmf_i_port_providers(uintptr_t addr, uint_t flags, int argc,
 349     const mdb_arg_t *argv)
 350 {
 351         struct stmf_state state;
 352         struct stmf_i_port_provider ipp;
 353         struct stmf_i_port_provider *ippp;
 354         int i;
 355         int verbose = 0;
 356 
 357         for (i = 0; i < argc; i++) {
 358                 char *ptr = (char *)argv[i].a_un.a_str;
 359 
 360                 if (ptr[0] == '-')
 361                         ptr++;
 362                 while (*ptr) {
 363                         if (*ptr == 'v')
 364                                 verbose = 1;
 365                         ptr++;
 366                 }
 367         }
 368 
 369         if (mdb_readsym(&state, sizeof (struct stmf_state), "stmf_state")
 370             == -1) {
 371                 mdb_warn("failed to read stmf_state");
 372                 return (DCMD_ERR);
 373         }
 374 
 375         ippp = state.stmf_ipplist;
 376         while (ippp) {
 377                 if (mdb_vread(&ipp, sizeof (stmf_i_port_provider_t),
 378                     (uintptr_t)ippp) == -1) {
 379                         mdb_warn("failed to read stmf_i_port_provider_t at %p",
 380                             ippp);
 381                         return (DCMD_ERR);
 382                 }
 383 
 384                 mdb_printf("%p\n", ippp);
 385                 if (verbose) {
 386                         mdb_printf("  port provider: %p\n", ipp.ipp_pp);
 387                 }
 388 
 389                 ippp = ipp.ipp_next;
 390         }
 391 
 392         return (DCMD_OK);
 393 }
 394 
 395 int string2wwn(const char *s, uint8_t wwn[8]);
 396 
 397 static uint16_t port_max_logins;
 398 static int      rp_index;
 399 
 400 /*
 401  * Cervert stmf_i_local_port to fct_i_local_port
 402  */
 403 /*ARGSUSED*/
 404 static struct fct_i_local_port *
 405 __ilport2iport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 406 {
 407         struct stmf_i_local_port iport;
 408         struct stmf_local_port   lport;
 409         struct fct_local_port    fport;
 410 
 411         if (!(flags & DCMD_ADDRSPEC)) {
 412                 mdb_warn("stmf_i_local_port address should be specified");
 413                 return (NULL);
 414         }
 415 
 416         /*
 417          * Input should be stmf_i_local_port_t.
 418          */
 419         if (mdb_vread(&iport, sizeof (struct stmf_i_local_port), addr)
 420             != sizeof (struct stmf_i_local_port)) {
 421                 mdb_warn("Unable to read in stmf_i_local_port\n");
 422                 return (NULL);
 423         }
 424 
 425         if (mdb_vread(&lport, sizeof (stmf_local_port_t),
 426             (uintptr_t)iport.ilport_lport) != sizeof (stmf_local_port_t)) {
 427                 mdb_warn("Unable to read in stmf_local_port\n");
 428                 return (NULL);
 429         }
 430 
 431         if (mdb_vread(&fport, sizeof (fct_local_port_t),
 432             (uintptr_t)lport.lport_port_private)
 433             != sizeof (fct_local_port_t)) {
 434                 mdb_warn("Unable to read in fct_local_port\n");
 435                 return (NULL);
 436         }
 437 
 438         return (fport.port_fct_private);
 439 }
 440 
 441 static int
 442 ilport2iport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 443 {
 444         struct fct_i_local_port *iportp;
 445         int i;
 446         int verbose = 0;
 447 
 448         for (i = 0; i < argc; i++) {
 449                 char *ptr = (char *)argv[i].a_un.a_str;
 450 
 451                 if (ptr[0] == '-')
 452                         ptr++;
 453                 while (*ptr) {
 454                         if (*ptr == 'v')
 455                                 verbose = 1;
 456                         ptr++;
 457                 }
 458         }
 459 
 460 
 461         iportp = __ilport2iport(addr, flags, argc, argv);
 462         if (iportp) {
 463                 mdb_printf("%p\n", iportp);
 464                 if (verbose) {
 465                         struct fct_i_local_port iport;
 466                         /* is the alias always 16 bytes in size ? */
 467                         char alias[16];
 468 
 469                         memset(alias, 0, sizeof (alias));
 470                         if (mdb_vread(&iport, sizeof (fct_i_local_port_t),
 471                             (uintptr_t)iportp)
 472                             != sizeof (fct_i_local_port_t)) {
 473                                 mdb_warn("Unable to read in fct_i_local_port"
 474                                     "at %p\n", iportp);
 475                                 return (DCMD_ERR);
 476                         }
 477                         if (iport.iport_alias &&
 478                             mdb_vread(alias, sizeof (alias),
 479                             (uintptr_t)iport.iport_alias)
 480                             != sizeof (alias)) {
 481                                 mdb_warn("Unable to read in memory at %p",
 482                                     iport.iport_alias);
 483                                 return (DCMD_ERR);
 484                         }
 485                         mdb_printf("  port: %p\n", iport.iport_port);
 486                         if (iport.iport_alias)
 487                                 mdb_printf("  alias: %s\n", alias);
 488                 }
 489         }
 490         return (DCMD_OK);
 491 }
 492 
 493 /*
 494  * by wwn, we can only find one local port
 495  */
 496 static struct stmf_i_local_port *
 497 find_lport_by_wwn(uint8_t wwn[8])
 498 {
 499         struct stmf_i_local_port *siport;
 500         struct fct_i_local_port *fiport;
 501         struct fct_i_local_port iport;
 502         struct fct_local_port fport;
 503         mdb_walk_state_t ws = {NULL, };
 504 
 505         while ((siport = next_stmf_port(&ws)) != NULL) {
 506                 fiport = __ilport2iport((uintptr_t)siport, DCMD_ADDRSPEC,
 507                     0, NULL);
 508                 if (fiport == NULL)
 509                         return (NULL);
 510 
 511                 if (mdb_vread(&iport, sizeof (fct_i_local_port_t),
 512                     (uintptr_t)fiport)
 513                     != sizeof (fct_i_local_port_t)) {
 514                         mdb_warn("Unable to read in fct_i_local_port\n");
 515                         return (NULL);
 516                 }
 517                 if (mdb_vread(&fport, sizeof (fct_local_port_t),
 518                     (uintptr_t)iport.iport_port)
 519                     != sizeof (fct_local_port_t)) {
 520                         mdb_warn("Unable to read in fct_local_port\n");
 521                         return (NULL);
 522                 }
 523 
 524 #if 0
 525                 mdb_printf("pwwn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
 526                     fport.port_pwwn[0], fport.port_pwwn[1],
 527                     fport.port_pwwn[2], fport.port_pwwn[3],
 528                     fport.port_pwwn[4], fport.port_pwwn[5],
 529                     fport.port_pwwn[6], fport.port_pwwn[7]);
 530 #endif
 531                 if (memcmp(fport.port_pwwn, wwn, 8) == 0) {
 532                         return (siport);
 533                 }
 534         }
 535 
 536         return (NULL);
 537 }
 538 
 539 /*ARGSUSED*/
 540 static int
 541 stmf_find_ilport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 542 {
 543         struct find_options *options;
 544         struct stmf_i_local_port *siport;
 545 
 546         options = parse_options(argc, argv);
 547         /* need to free options manually ? */
 548         if (options == NULL || ! options->lpname_defined) {
 549                 mdb_printf("lpname=<wwn.12345678 or 12345678> "
 550                     "should be specified\n");
 551                 return (DCMD_OK);
 552         }
 553 
 554         if ((siport = find_lport_by_wwn(options->lpname)) != NULL)
 555                 mdb_printf("%p\n", siport);
 556 
 557         return (DCMD_OK);
 558 }
 559 
 560 static int
 561 fct_irp_walk_i(mdb_walk_state_t *wsp)
 562 {
 563         struct fct_local_port port;
 564         struct fct_i_local_port iport;
 565 
 566         if (wsp->walk_addr == NULL) {
 567                 mdb_warn("Can not perform global walk");
 568                 return (WALK_ERR);
 569         }
 570 
 571         /*
 572          * Input should be fct_i_local_port_t.
 573          */
 574         if (mdb_vread(&iport, sizeof (struct fct_i_local_port), wsp->walk_addr)
 575             != sizeof (struct fct_i_local_port)) {
 576                 mdb_warn("Unable to read in fct_i_local_port\n");
 577                 return (WALK_ERR);
 578         }
 579 
 580         if (mdb_vread(&port, sizeof (struct fct_local_port),
 581             (uintptr_t)iport.iport_port)
 582             != sizeof (struct fct_local_port)) {
 583                 mdb_warn("Unable to read in fct_local_port\n");
 584                 return (WALK_ERR);
 585         }
 586 
 587         port_max_logins = port.port_max_logins;
 588         rp_index = 0;
 589         wsp->walk_addr = (uintptr_t)iport.iport_rp_slots;
 590 
 591         return (WALK_NEXT);
 592 }
 593 
 594 static int
 595 fct_irp_walk_s(mdb_walk_state_t *wsp)
 596 {
 597         int status = WALK_NEXT;
 598         fct_i_remote_port_t *rp;
 599 
 600         if (wsp->walk_addr == NULL)
 601                 return (WALK_DONE);
 602 
 603         if (rp_index++ >= port_max_logins)
 604                 return (WALK_DONE);
 605 
 606         if (mdb_vread(&rp, sizeof (fct_i_remote_port_t *),
 607             wsp->walk_addr) == -1) {
 608                 mdb_warn("failed to read address of fct_i_remote_port_t at %p",
 609                     wsp->walk_addr);
 610                 return (WALK_DONE);
 611         }
 612 
 613         if (rp != NULL && wsp->walk_callback != NULL)
 614                 status = wsp->walk_callback((uintptr_t)rp, rp,
 615                     wsp->walk_cbdata);
 616 
 617         wsp->walk_addr = (uintptr_t)
 618             &(((fct_i_remote_port_t **)wsp->walk_addr)[1]);
 619 
 620         return (status);
 621 }
 622 
 623 static void
 624 fct_irp_walk_f(mdb_walk_state_t *wsp)
 625 {
 626         wsp->walk_addr = NULL;
 627 }
 628 
 629 /*
 630  * to set remote_port
 631  */
 632 /*ARGSUSED*/
 633 static int
 634 walk_fct_irp_cb(uintptr_t p, const void * arg, void *cbdata)
 635 {
 636         *((uintptr_t *)cbdata) = p;
 637         return (WALK_NEXT);
 638 }
 639 
 640 static int
 641 fct_irps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 642 {
 643         static uint64_t cbdata = 0;
 644         mdb_walk_state_t ws = {walk_fct_irp_cb, &cbdata, addr};
 645         fct_i_remote_port_t *irpp;
 646         int i;
 647         int verbose = 0;
 648 
 649         for (i = 0; i < argc; i++) {
 650                 char *ptr = (char *)argv[i].a_un.a_str;
 651 
 652                 if (ptr[0] == '-')
 653                         ptr++;
 654                 while (*ptr) {
 655                         if (*ptr == 'v')
 656                                 verbose = 1;
 657                         ptr++;
 658                 }
 659         }
 660 
 661         if (!(flags & DCMD_ADDRSPEC)) {
 662                 mdb_warn("fct_i_local_port_t address should be specified");
 663                 return (DCMD_ERR);
 664         }
 665 
 666         fct_irp_walk_i(&ws);
 667         while (fct_irp_walk_s(&ws) == WALK_NEXT) {
 668                 irpp = *((fct_i_remote_port_t **)ws.walk_cbdata);
 669 
 670                 if (irpp) {
 671                         *((fct_i_remote_port_t **)ws.walk_cbdata) = NULL;
 672 
 673                         mdb_printf("%p\n", irpp);
 674                         if (verbose) {
 675                                 fct_i_remote_port_t irp;
 676 
 677                                 if (mdb_vread(&irp, sizeof (irp),
 678                                     (uintptr_t)irpp) != sizeof (irp)) {
 679                                         mdb_warn("Unable to read in "
 680                                             "fct_i_remote_port at %p\n", irpp);
 681                                         return (DCMD_ERR);
 682                                 }
 683                                 mdb_printf("  remote port: %p\n", irp.irp_rp);
 684                                 mdb_printf("  port id: %x\n", irp.irp_portid);
 685                         }
 686                 }
 687         }
 688         fct_irp_walk_f(&ws);
 689 
 690         return (DCMD_OK);
 691 }
 692 
 693 static uintptr_t cur_iport_for_irp_loop = NULL;
 694 
 695 static fct_i_remote_port_t *
 696 next_rport(struct fct_i_local_port *iport)
 697 {
 698         static uint64_t cbdata = 0;
 699         static mdb_walk_state_t ws = {walk_fct_irp_cb, &cbdata};
 700         int ret;
 701         fct_i_remote_port_t *irp;
 702 
 703         if (ws.walk_addr == NULL || cur_iport_for_irp_loop !=
 704             (uintptr_t)iport) {
 705                 *((fct_i_remote_port_t **)ws.walk_cbdata) = NULL;
 706                 cur_iport_for_irp_loop = (uintptr_t)iport;
 707                 ws.walk_addr = (uintptr_t)iport;
 708                 if (fct_irp_walk_i(&ws) == WALK_ERR) {
 709                         fct_irp_walk_f(&ws);
 710                         return (NULL);
 711                 }
 712                 if (ws.walk_addr == NULL) {
 713                         fct_irp_walk_f(&ws);
 714                         return (NULL);
 715                 }
 716         }
 717 
 718         while ((ret = fct_irp_walk_s(&ws)) == WALK_NEXT) {
 719                 if (*((fct_i_remote_port_t **)ws.walk_cbdata) != 0) {
 720                         irp = *((fct_i_remote_port_t **)ws.walk_cbdata);
 721                         *((fct_i_remote_port_t **)ws.walk_cbdata) = NULL;
 722                         return (irp);
 723                 }
 724         }
 725         fct_irp_walk_f(&ws);
 726 
 727         /*
 728          * If it is WALK_DONE, there may be one remote port there
 729          */
 730         if (ret == WALK_DONE) {
 731                 irp = *((fct_i_remote_port_t **)ws.walk_cbdata);
 732                 *((fct_i_remote_port_t **)ws.walk_cbdata) = NULL;
 733                 return (irp);
 734         }
 735         return (NULL);
 736 }
 737 
 738 static struct stmf_i_local_port *
 739 irp_to_ilport(struct fct_i_remote_port *irpp)
 740 {
 741         struct fct_i_remote_port irp;
 742         struct fct_remote_port rp;
 743         struct fct_local_port port;
 744         struct stmf_local_port lport;
 745 
 746         if (mdb_vread(&irp, sizeof (struct fct_i_remote_port),
 747             (uintptr_t)irpp)
 748             != sizeof (struct fct_i_remote_port)) {
 749                 mdb_warn("Unable to read in fct_i_remote_port\n");
 750                 return (NULL);
 751         }
 752         if (mdb_vread(&rp, sizeof (struct fct_remote_port),
 753             (uintptr_t)irp.irp_rp)
 754             != sizeof (struct fct_remote_port)) {
 755                 mdb_warn("Unable to read in fct_remote_port\n");
 756                 return (NULL);
 757         }
 758 
 759         if (mdb_vread(&port, sizeof (struct fct_local_port),
 760             (uintptr_t)rp.rp_port)
 761             != sizeof (struct fct_local_port)) {
 762                 mdb_warn("Unable to read in fct_local_port\n");
 763                 return (NULL);
 764         }
 765         if (mdb_vread(&lport, sizeof (struct stmf_local_port),
 766             (uintptr_t)port.port_lport)
 767             != sizeof (struct stmf_local_port)) {
 768                 mdb_warn("Unable to read in stmf_local_port\n");
 769                 return (NULL);
 770         }
 771         return (lport.lport_stmf_private);
 772 }
 773 
 774 /*
 775  * by wwn, we may find more than one remote port, so we need to know its
 776  * corresponding local port
 777  */
 778 static struct fct_i_remote_port *
 779 find_irp_by_wwn(struct stmf_i_local_port *siport, uint8_t wwn[8])
 780 {
 781         struct fct_i_local_port *fiport;
 782         fct_i_remote_port_t *irpp;
 783         struct fct_i_remote_port irp;
 784         struct fct_remote_port rp;
 785         fct_i_remote_port_t *ret = NULL;
 786 
 787         fiport = __ilport2iport((uintptr_t)siport, DCMD_ADDRSPEC, 0, NULL);
 788         if (fiport == NULL)
 789                 return (NULL);
 790 
 791         while ((irpp = next_rport(fiport)) != NULL) {
 792                 if (mdb_vread(&irp, sizeof (struct fct_i_remote_port),
 793                     (uintptr_t)irpp)
 794                     != sizeof (struct fct_i_remote_port)) {
 795                         mdb_warn("Unable to read in fct_i_remote_port\n");
 796                         break;
 797                 }
 798                 if (mdb_vread(&rp, sizeof (struct fct_remote_port),
 799                     (uintptr_t)irp.irp_rp)
 800                     != sizeof (struct fct_remote_port)) {
 801                         mdb_warn("Unable to read in fct_remote_port\n");
 802                         break;
 803                 }
 804 
 805                 if (memcmp(rp.rp_pwwn, wwn, 8) == 0) {
 806                         ret = irpp;
 807                         break;
 808                 }
 809         }
 810         cur_iport_for_irp_loop = NULL;
 811         return (ret);
 812 }
 813 
 814 /*ARGSUSED*/
 815 static int
 816 stmf_find_fct_irp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 817 {
 818         struct stmf_i_local_port *siport;
 819         struct find_options *options;
 820         fct_i_remote_port_t *irpp;
 821         mdb_walk_state_t ws = {NULL, };
 822 
 823         options = parse_options(argc, argv);
 824         /* need to free options manually ? */
 825         if (options == NULL || (options->rpname_defined == 0 &&
 826             options->rp_defined == 0)) {
 827                 mdb_printf("rpname=<wwn.12345678> or rp=<3000586778734>"
 828                     " should be specified\n");
 829                 return (DCMD_OK);
 830         }
 831         if (options->rpname_defined && options->rp_defined) {
 832                 mdb_printf("rpname=<wwn.12345678> or rp=<3000586778734>"
 833                     " should be specified, but not both\n");
 834                 return (DCMD_OK);
 835         }
 836 
 837         if (options->rp_defined) {
 838                 siport = irp_to_ilport(options->rp);
 839                 if (siport != NULL)
 840                         mdb_printf("stmf_i_local_port=%p,"
 841                             " fct_i_remote_port=%p\n",
 842                             siport, options->rp);
 843                 return (DCMD_OK);
 844         }
 845 
 846         /* if options->rpname_defined */
 847         while ((siport = next_stmf_port(&ws)) != NULL) {
 848                 if ((irpp = find_irp_by_wwn(siport, options->rpname)) != NULL)
 849                         mdb_printf("stmf_i_local_port=%p, "
 850                             "fct_i_remote_port=%p\n",
 851                             siport, irpp);
 852         }
 853 
 854         return (DCMD_OK);
 855 }
 856 
 857 typedef void (*cmd_filter_t) (struct fct_i_cmd *,
 858     struct find_options *, void *);
 859 
 860 /*ARGSUSED*/
 861 static void
 862 print_tasks(struct fct_i_cmd *icmdp, struct find_options *options, void *arg)
 863 {
 864         struct fct_i_cmd icmd;
 865         struct fct_cmd cmd;
 866 
 867         if (mdb_vread(&icmd, sizeof (struct fct_i_cmd),
 868             (uintptr_t)icmdp) != sizeof (struct fct_i_cmd)) {
 869                 mdb_warn("Unable to read in fct_i_cmd\n");
 870                 return;
 871         }
 872         if (mdb_vread(&cmd, sizeof (struct fct_cmd),
 873             (uintptr_t)icmd.icmd_cmd) != sizeof (struct fct_cmd)) {
 874                 mdb_warn("Unable to read in fct_cmd\n");
 875                 return;
 876         }
 877 
 878         if (cmd.cmd_type == FCT_CMD_FCP_XCHG) {
 879                 struct scsi_task task;
 880                 int colon_printed = 0;
 881 
 882                 if (mdb_vread(&task, sizeof (struct scsi_task),
 883                     (uintptr_t)cmd.cmd_specific)
 884                     != sizeof (struct scsi_task)) {
 885                         mdb_warn("Unable to read in scsi_task\n");
 886                         return;
 887                 }
 888 
 889                 mdb_printf("%p", cmd.cmd_specific);
 890                 if (options->show_task_flags) {
 891                         mdb_printf(":");
 892                         colon_printed = 1;
 893                         mdb_printf(" task_flags=%x", task.task_flags);
 894                 }
 895 
 896                 if (options->show_lport) {
 897                         if (colon_printed == 0) {
 898                                 mdb_printf(":");
 899                                 colon_printed = 1;
 900                         }
 901                         mdb_printf(" lport=%p", task.task_lport);
 902                 }
 903                 mdb_printf("\n");
 904         }
 905 }
 906 
 907 static void
 908 print_tasks_on_rp(struct fct_i_cmd *icmdp, struct find_options *options,
 909     void *arg)
 910 {
 911         struct fct_i_cmd icmd;
 912         struct fct_cmd cmd;
 913         fct_i_remote_port_t irp;
 914 
 915         if (mdb_vread(&icmd, sizeof (struct fct_i_cmd),
 916             (uintptr_t)icmdp) != sizeof (struct fct_i_cmd)) {
 917                 mdb_warn("Unable to read in fct_i_cmd\n");
 918                 return;
 919         }
 920         if (mdb_vread(&cmd, sizeof (struct fct_cmd),
 921             (uintptr_t)icmd.icmd_cmd) != sizeof (struct fct_cmd)) {
 922                 mdb_warn("Unable to read in fct_cmd\n");
 923                 return;
 924         }
 925 
 926         /* arg is a pointer to fct_i_remote_port */
 927         if (mdb_vread(&irp, sizeof (struct fct_i_remote_port),
 928             (uintptr_t)arg) != sizeof (struct fct_i_remote_port)) {
 929                 mdb_warn("Unable to read in fct_i_remote_port\n");
 930                 return;
 931         }
 932 
 933         if (cmd.cmd_type == FCT_CMD_FCP_XCHG && cmd.cmd_rp == irp.irp_rp) {
 934                 struct scsi_task task;
 935                 int colon_printed = 0;
 936 
 937                 if (mdb_vread(&task, sizeof (struct scsi_task),
 938                     (uintptr_t)cmd.cmd_specific)
 939                     != sizeof (struct scsi_task)) {
 940                         mdb_warn("Unable to read in scsi_task\n");
 941                         return;
 942                 }
 943 
 944                 mdb_printf("%p", cmd.cmd_specific);
 945                 if (options->show_task_flags) {
 946                         mdb_printf(":");
 947                         colon_printed = 1;
 948                         mdb_printf(" task_flags=%x", task.task_flags);
 949                 }
 950 
 951                 if (options->show_lport) {
 952                         if (colon_printed == 0) {
 953                                 mdb_printf(":");
 954                                 colon_printed = 1;
 955                         }
 956                         mdb_printf(" lport=%p", task.task_lport);
 957                 }
 958                 mdb_printf("\n");
 959         }
 960 }
 961 
 962 /*ARGSUSED*/
 963 static void
 964 print_all_cmds(struct fct_i_cmd *icmd, struct find_options *options, void *arg)
 965 {
 966         mdb_printf("%p\n", icmd);
 967 }
 968 
 969 /*
 970  * find outstanding cmds (fct_i_cmd) on local port
 971  */
 972 static int
 973 outstanding_cmds_on_lport(struct stmf_i_local_port *siport, cmd_filter_t filter,
 974     struct find_options *options, void *arg)
 975 {
 976         struct fct_i_local_port *iportp;
 977         struct fct_i_local_port iport;
 978         struct fct_local_port port;
 979         struct fct_cmd_slot *slotp;
 980         struct fct_cmd_slot slot;
 981         int i;
 982 
 983         iportp = __ilport2iport((uintptr_t)siport, DCMD_ADDRSPEC, 0, NULL);
 984         if (iportp == NULL)
 985                 return (DCMD_ERR);
 986 
 987         if (mdb_vread(&iport, sizeof (struct fct_i_local_port),
 988             (uintptr_t)iportp) != sizeof (struct fct_i_local_port)) {
 989                 mdb_warn("Unable to read in fct_i_local_port\n");
 990                 return (DCMD_ERR);
 991         }
 992         if (mdb_vread(&port, sizeof (struct fct_local_port),
 993             (uintptr_t)iport.iport_port) != sizeof (struct fct_local_port)) {
 994                 mdb_warn("Unable to read in fct_local_port\n");
 995                 return (DCMD_ERR);
 996         }
 997 
 998         slotp = iport.iport_cmd_slots;
 999         for (i = 0; i < port.port_max_xchges; i++) {
1000                 if (mdb_vread(&slot, sizeof (struct fct_cmd_slot),
1001                     (uintptr_t)slotp) != sizeof (struct fct_cmd_slot)) {
1002                         mdb_warn("Unable to read in fct_cmd_slot\n");
1003                         return (DCMD_ERR);
1004                 }
1005                 if (slot.slot_cmd != NULL) {
1006                         if (filter == NULL)
1007                                 mdb_printf("%p\n", slot.slot_cmd);
1008                         else
1009                                 filter(slot.slot_cmd, options, arg);
1010                 }
1011                 slotp ++;
1012         }
1013 
1014         return (DCMD_OK);
1015 }
1016 
1017 /*ARGSUSED*/
1018 static int
1019 stmf_find_tasks(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1020 {
1021         struct find_options *options;
1022         struct stmf_i_local_port *siport;
1023 
1024         options = parse_options(argc, argv);
1025         if (options == NULL ||
1026             (options->lpname_defined == 0 && options->rpname_defined == 0)) {
1027                 mdb_printf("lpname=<wwn.12345678> or rpname=<wwn.12345678>"
1028                     " should be specified\n");
1029                 return (DCMD_OK);
1030         }
1031 
1032         if (options->lpname_defined) {
1033                 siport = find_lport_by_wwn(options->lpname);
1034                 if (siport == NULL)
1035                         return (DCMD_ERR);
1036 
1037                 outstanding_cmds_on_lport(siport, print_tasks, options, NULL);
1038                 return (DCMD_OK);
1039         }
1040 
1041         if (options->rpname_defined) {
1042                 mdb_walk_state_t ws = {NULL, };
1043                 fct_i_remote_port_t *irpp;
1044 
1045                 while ((siport = next_stmf_port(&ws)) != NULL) {
1046                         if ((irpp = find_irp_by_wwn(siport, options->rpname))
1047                             != NULL) {
1048                                 outstanding_cmds_on_lport(siport,
1049                                     print_tasks_on_rp, options, irpp);
1050                         }
1051                 }
1052         }
1053 
1054         return (DCMD_OK);
1055 }
1056 
1057 /*ARGSUSED*/
1058 static int
1059 fct_find_cmds(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1060 {
1061         struct find_options *options;
1062         struct stmf_i_local_port *siport;
1063 
1064         options = parse_options(argc, argv);
1065         if (options == NULL || options->lpname_defined == 0) {
1066                 mdb_printf("lpname=<wwn.12345678> should be specified\n");
1067                 return (DCMD_OK);
1068         }
1069 
1070         siport = find_lport_by_wwn(options->lpname);
1071         if (siport == NULL)
1072                 return (DCMD_ERR);
1073 
1074         outstanding_cmds_on_lport(siport, print_all_cmds, options, NULL);
1075         return (DCMD_OK);
1076 }
1077 
1078 static int
1079 fct_icmds(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1080 {
1081         struct fct_i_local_port iport;
1082         struct fct_i_cmd icmd;
1083         struct fct_i_cmd *icmdp;
1084         int i;
1085         int verbose = 0;
1086 
1087         for (i = 0; i < argc; i++) {
1088                 char *ptr = (char *)argv[i].a_un.a_str;
1089 
1090                 if (ptr[0] == '-')
1091                         ptr++;
1092                 while (*ptr) {
1093                         if (*ptr == 'v')
1094                                 verbose = 1;
1095                         ptr++;
1096                 }
1097         }
1098 
1099         if (!(flags & DCMD_ADDRSPEC)) {
1100                 mdb_warn("fct_i_local_port_t address should be specified");
1101                 return (DCMD_ERR);
1102         }
1103 
1104         if (mdb_vread(&iport, sizeof (struct fct_i_local_port), addr)
1105             != sizeof (struct fct_i_local_port)) {
1106                 mdb_warn("Unable to read in fct_i_local_port at %p\n", addr);
1107                 return (DCMD_ERR);
1108         }
1109 
1110         icmdp = list_head(&iport.iport_cached_cmdlist);
1111         while (icmdp) {
1112 
1113                 if (mdb_vread(&icmd, sizeof (struct fct_i_cmd),
1114                     (uintptr_t)icmdp) == -1) {
1115                         mdb_warn("failed to read fct_i_cmd at %p", icmdp);
1116                         return (DCMD_ERR);
1117                 }
1118 
1119                 mdb_printf("%p\n", icmdp);
1120                 if (verbose) {
1121                         mdb_printf("  fct cmd: %p\n", icmd.icmd_cmd);
1122                 }
1123 
1124                 icmdp = list_next(&iport.iport_cached_cmdlist, icmdp);
1125         }
1126 
1127         return (DCMD_OK);
1128 }
1129 
1130 /*
1131  * Walker to list the addresses of all the active STMF scsi tasks (scsi_task_t),
1132  * given a stmf_worker address
1133  *
1134  * To list all the active STMF scsi tasks, use
1135  * "::walk stmf_worker |::walk stmf_scsi_task"
1136  * To list the active tasks of a particular worker, use
1137  * <stmf_worker addr>::walk stmf_scsi_task
1138  */
1139 static int
1140 stmf_scsi_task_walk_init(mdb_walk_state_t *wsp)
1141 {
1142         stmf_worker_t   worker;
1143 
1144         /*
1145          * Input should be a stmf_worker, so read it to get the
1146          * worker_task_head to get the start of the task list
1147          */
1148         if (wsp->walk_addr == NULL) {
1149                 mdb_warn("<worker addr>::walk stmf_scsi_task\n");
1150                 return (WALK_ERR);
1151         }
1152 
1153         if (mdb_vread(&worker, sizeof (stmf_worker_t), wsp->walk_addr) !=
1154             sizeof (stmf_worker_t)) {
1155                 mdb_warn("failed to read in the task address\n");
1156                 return (WALK_ERR);
1157         }
1158 
1159         wsp->walk_addr = (uintptr_t)(worker.worker_task_head);
1160         wsp->walk_data = mdb_alloc(sizeof (scsi_task_t), UM_SLEEP);
1161 
1162         return (WALK_NEXT);
1163 }
1164 
1165 static int
1166 stmf_scsi_task_walk_step(mdb_walk_state_t *wsp)
1167 {
1168         stmf_i_scsi_task_t      itask;
1169         int                     status;
1170 
1171         if (wsp->walk_addr == NULL) {
1172                 return (WALK_DONE);
1173         }
1174 
1175         /* Save the stmf_i_scsi_task for use later to get the next entry */
1176         if (mdb_vread(&itask, sizeof (stmf_i_scsi_task_t),
1177             wsp->walk_addr) != sizeof (stmf_i_scsi_task_t)) {
1178                 mdb_warn("failed to read stmf_i_scsi_task at %p",
1179                     wsp->walk_addr);
1180                 return (WALK_DONE);
1181         }
1182 
1183         wsp->walk_addr = (uintptr_t)itask.itask_task;
1184 
1185         if (mdb_vread(wsp->walk_data, sizeof (scsi_task_t),
1186             wsp->walk_addr) != sizeof (scsi_task_t)) {
1187                 mdb_warn("failed to read scsi_task_t at %p", wsp->walk_addr);
1188                 return (DCMD_ERR);
1189         }
1190 
1191         status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1192             wsp->walk_cbdata);
1193 
1194         wsp->walk_addr = (uintptr_t)(itask.itask_worker_next);
1195 
1196         return (status);
1197 }
1198 
1199 static void
1200 stmf_scsi_task_walk_fini(mdb_walk_state_t *wsp)
1201 {
1202         mdb_free(wsp->walk_data, sizeof (scsi_task_t));
1203 }
1204 
1205 /*ARGSUSED*/
1206 static int
1207 stmf_scsi_task(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1208 {
1209         stmf_worker_t           worker;
1210         stmf_i_scsi_task_t      itask;
1211         scsi_task_t             *task_addr, task;
1212 
1213         /*
1214          * A stmf_worker address is given to the left of ::stmf_scsi_task
1215          * i.e. display the scsi_task for the given worker
1216          */
1217         if (!(flags & DCMD_ADDRSPEC)) {
1218                 if (mdb_walk_dcmd("stmf_worker", "stmf_scsi_task", argc,
1219                     argv) == -1) {
1220                         mdb_warn("Failed to walk the stmf_scsi_task entries");
1221                         return (DCMD_ERR);
1222                 }
1223                 return (DCMD_OK);
1224         }
1225 
1226         if (DCMD_HDRSPEC(flags) && (!(flags & DCMD_PIPE_OUT))) {
1227                 mdb_printf("%<u>%-19s %-10s %-19s%</u>\n",
1228                     "scsi_task_t", "Flags", "LPort");
1229         }
1230 
1231         if (mdb_vread(&worker, sizeof (stmf_worker_t),
1232             addr) != sizeof (stmf_worker_t)) {
1233                 mdb_warn("failed to read in the worker address");
1234                 return (DCMD_ERR);
1235         }
1236 
1237         /* Read the scsi_task */
1238         if (worker.worker_task_head == NULL) {
1239                 return (DCMD_OK);
1240         }
1241 
1242         if (mdb_vread(&itask, sizeof (stmf_i_scsi_task_t),
1243             (uintptr_t)worker.worker_task_head) == -1) {
1244                 mdb_warn("failed to read stmf_i_scsi_task_t at %p",
1245                     worker.worker_task_head);
1246                 return (DCMD_ERR);
1247         }
1248 
1249         task_addr = itask.itask_task;
1250 
1251         if (mdb_vread(&task, sizeof (scsi_task_t),
1252             (uintptr_t)task_addr) != sizeof (scsi_task_t)) {
1253                 mdb_warn("failed to read scsi_task_t at %p", task_addr);
1254                 return (DCMD_ERR);
1255         }
1256 
1257         if ((flags & DCMD_PIPE_OUT)) {
1258                 mdb_printf("%p\n", task_addr);
1259         } else {
1260                 /* pretty print */
1261                 mdb_printf("%-19p %-10x %-19p\n",
1262                     task_addr, task.task_flags, task.task_lport);
1263         }
1264 
1265         return (DCMD_OK);
1266 }
1267 
1268 /*
1269  * Walker to list the addresses of all the stmf_worker in the queue
1270  */
1271 typedef struct stmf_worker_walk_data {
1272         int             worker_current;
1273         int             worker_count;
1274 } stmf_worker_walk_data_t;
1275 
1276 /* stmf_workers_state definition from stmf.c (static) */
1277 enum {
1278         STMF_WORKERS_DISABLED = 0,
1279         STMF_WORKERS_ENABLING,
1280         STMF_WORKERS_ENABLED
1281 } stmf_workers_state;
1282 
1283 /*
1284  * Initialize the stmf_worker_t walker by either using the given starting
1285  * address, or reading the value of the kernel's global stmf_workers pointer.
1286  */
1287 /*ARGSUSED*/
1288 static int
1289 stmf_worker_walk_init(mdb_walk_state_t *wsp)
1290 {
1291         int                     worker_state;
1292         int                     nworkers;
1293         stmf_worker_t           *worker;
1294         stmf_worker_walk_data_t *walk_data;
1295 
1296         if (mdb_readvar(&worker_state, "stmf_workers_state") == -1) {
1297                 mdb_warn("failed to read stmf_workers_state");
1298                 return (WALK_ERR);
1299         }
1300         if (worker_state != STMF_WORKERS_ENABLED) {
1301                 mdb_warn("stmf_workers_state not initialized");
1302                 return (WALK_ERR);
1303         }
1304 
1305         /*
1306          * Look up the stmf_nworkers_accepting_cmds to
1307          * determine number of entries in the worker queue
1308          */
1309         if (mdb_readvar(&nworkers, "stmf_nworkers_accepting_cmds") == -1) {
1310                 mdb_warn("failed to read stmf_nworkers_accepting_cmds");
1311                 return (WALK_ERR);
1312         }
1313 
1314         if (mdb_readvar(&worker, "stmf_workers") == -1) {
1315                 mdb_warn("failed to read stmf_workers");
1316                 return (WALK_ERR);
1317         }
1318 
1319         walk_data = mdb_alloc(sizeof (stmf_worker_walk_data_t), UM_SLEEP);
1320         walk_data->worker_current    = 0;
1321         walk_data->worker_count              = nworkers;
1322 
1323         wsp->walk_addr = (uintptr_t)worker;
1324         wsp->walk_data = walk_data;
1325 
1326         return (WALK_NEXT);
1327 }
1328 
1329 static int
1330 stmf_worker_walk_step(mdb_walk_state_t *wsp)
1331 {
1332         stmf_worker_walk_data_t *walk_data = wsp->walk_data;
1333         int                     status;
1334 
1335         if (wsp->walk_addr == NULL) {
1336                 return (WALK_DONE);
1337         }
1338 
1339         if (walk_data->worker_current >= walk_data->worker_count) {
1340                 return (WALK_DONE);
1341         }
1342 
1343         status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1344             wsp->walk_cbdata);
1345 
1346         walk_data->worker_current++;
1347         wsp->walk_addr += sizeof (stmf_worker_t);
1348 
1349         return (status);
1350 }
1351 
1352 static void
1353 stmf_worker_walk_fini(mdb_walk_state_t *wsp)
1354 {
1355         mdb_free(wsp->walk_data, sizeof (stmf_worker_walk_data_t));
1356 }
1357 
1358 int
1359 stmf_worker(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1360 {
1361         stmf_worker_t           worker;
1362 
1363         if (!(flags & DCMD_ADDRSPEC)) {
1364                 if (mdb_walk_dcmd("stmf_worker", "stmf_worker", argc,
1365                     argv) == -1) {
1366                         mdb_warn("Failed to walk the stmf_worker entries");
1367                         return (DCMD_ERR);
1368                 }
1369                 return (DCMD_OK);
1370         }
1371 
1372         if (mdb_vread(&worker, sizeof (stmf_worker_t),
1373             addr) != sizeof (stmf_worker_t)) {
1374                 mdb_warn("failed to read stmf_worker at %p", addr);
1375                 return (DCMD_ERR);
1376         }
1377 
1378         if (flags & DCMD_PIPE_OUT) {
1379                 mdb_printf("%-19p\n", addr);
1380         } else {
1381                 /* pretty print */
1382                 if (DCMD_HDRSPEC(flags)) {
1383                         mdb_printf("%<u>%-19s %-10s %-10s %-10s%</u>\n",
1384                             "stmf_worker_t", "State", "Ref_Count", "Tasks");
1385                 }
1386 
1387                 mdb_printf("%-19p %-10s %-10d %-5d%\n", addr,
1388                     (worker.worker_flags == STMF_WORKER_STARTED) ? "STARTED" :
1389                     (worker.worker_flags & STMF_WORKER_ACTIVE) ?
1390                     "ACTIVE" : "TERMINATED",
1391                     worker.worker_ref_count,
1392                     worker.worker_queue_depth);
1393         }
1394 
1395         return (DCMD_OK);
1396 }
1397 
1398 struct find_options *
1399 parse_options(int argc, const mdb_arg_t *argv)
1400 {
1401         int i;
1402         struct find_options *options;
1403         int len;
1404         char *ptr;
1405         int ret;
1406 
1407         if (argc == 0)
1408                 return (NULL);
1409         options = mdb_zalloc(sizeof (struct find_options), UM_SLEEP);
1410         for (i = 0; i < argc; i++) {
1411                 switch (argv[i].a_type) {
1412                 case MDB_TYPE_STRING:
1413                         break;
1414                 case MDB_TYPE_IMMEDIATE:
1415                 case MDB_TYPE_CHAR:
1416                         mdb_printf("unknown type\n");
1417                 }
1418                 if ((ptr = strchr(argv[i].a_un.a_str, '=')) == NULL) {
1419                         mdb_printf("invalid argument: %s\n",
1420                             argv[i].a_un.a_str);
1421                         goto out;
1422                 }
1423                 len = ptr - argv[i].a_un.a_str;
1424                 ptr++;  /* point to value now */
1425 
1426                 if (len == strlen("lpname") &&
1427                     strncmp(argv[i].a_un.a_str, "lpname", len) == 0) {
1428                         if (strstr(ptr, "wwn.") == ptr)
1429                                 ptr += 4;
1430                         ret = string2wwn(ptr, options->lpname);
1431                         if (ret == -1)
1432                                 goto out;
1433 #if 0
1434         mdb_printf("wwn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
1435             wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
1436 #endif
1437                         options->lpname_defined = 1;
1438 
1439                 } else if (len == strlen("rp") &&
1440                     strncmp(argv[i].a_un.a_str, "rp", len) == 0) {
1441                         options->rp_defined = 1;
1442                         options->rp =
1443                             (void *)(unsigned long)mdb_strtoull(ptr);
1444 
1445                 } else if (len == strlen("rpname") &&
1446                     strncmp(argv[i].a_un.a_str, "rpname", len) == 0) {
1447                         if (strstr(ptr, "wwn.") == ptr)
1448                                 ptr += 4;
1449                         ret = string2wwn(ptr, options->rpname);
1450                         if (ret == -1)
1451                                 goto out;
1452                         options->rpname_defined = 1;
1453 
1454                 } else if (len == strlen("show") &&
1455                     strncmp(argv[i].a_un.a_str, "show", len) == 0) {
1456                         char *s;
1457                         int l;
1458 
1459                         for (;;) {
1460                                 s = strchr(ptr, ',');
1461                                 if (s)
1462                                         l = s - ptr;
1463                                 else
1464                                         l = strlen(ptr);
1465                                 if (l == strlen("task_flags") &&
1466                                     strncmp(ptr, "task_flags", l) == 0)
1467                                         options->show_task_flags = 1;
1468                                 else if (l == strlen("lport") &&
1469                                     strncmp(ptr, "lport", l) == 0)
1470                                         options->show_lport = 1;
1471                                 else {
1472                                         mdb_printf("unknown shower: %s\n",
1473                                             ptr);
1474                                         goto out;
1475                                 }
1476                                 if (s == NULL)
1477                                         break;
1478                                 ptr = s + 1;
1479                         }
1480                 } else {
1481                         mdb_printf("unknown argument: %s\n",
1482                             argv[i].a_un.a_str);
1483                         goto out;
1484                 }
1485         }
1486 
1487         return (options);
1488 out:
1489         mdb_free(options, sizeof (struct find_options));
1490         return (NULL);
1491 }
1492 
1493 int
1494 string2wwn(const char *s, uint8_t wwn[8])
1495 {
1496         int i;
1497         char tmp[17];
1498         char *p;
1499 
1500         if (strlen(s) > 16) {
1501                 mdb_printf("invalid wwn %s\n", s);
1502                 return (-1);
1503         }
1504 
1505         strcpy(tmp, s);
1506         p = tmp + strlen(tmp) - 2;
1507         memset(wwn, 0, 8);
1508         /* figure out wwn from the tail to beginning */
1509         for (i = 7; i >= 0 && p >= tmp; i--, p -= 2) {
1510                 wwn[i] = mdb_strtoull(p);
1511                 *p = 0;
1512         }
1513         return (0);
1514 }
1515 
1516 void
1517 fct_find_cmds_help(void)
1518 {
1519         mdb_printf(
1520             "Find all cached fct_i_cmd_t for a local port. If a local port \n"
1521             "name is specified, find all pending cmds for it and print the \n"
1522             "address. Example:\n"
1523             "    fct_find_cmds lpname=<wwn.12345678 or 12345678>\n");
1524 }
1525 void
1526 stmf_find_ilport_help(void)
1527 {
1528         mdb_printf(
1529             "Find the fct_i_local_port if local port name is "
1530             "specified. Example:\n"
1531             "    stmf_find_ilport lpname=<wwn.12345678 or 12345678>\n");
1532 }
1533 void
1534 stmf_find_fct_irp_help(void)
1535 {
1536         mdb_printf(
1537             "If a remote port name or stmf_i_remote_port_t address is\n"
1538             "specified, loop through all local ports, to which this remote \n"
1539             "port has logged in, print address for stmf_i_local_port_t and \n"
1540             "stmf_i_remote_port. Example:\n"
1541             "    stmf_find_fct_irp rpname=<wwn.12345678 or 12345678>\n"
1542             "    stmf_find_fct_irp rp=<3000586778734>\n");
1543 }
1544 
1545 void
1546 stmf_find_tasks_help(void)
1547 {
1548         mdb_printf(
1549             "Find all pending scsi_task_t for a given local port and/or\n"
1550             "remote port. Various different fields for each task are printed\n"
1551             "depending on what is requested. Example:\n"
1552             "    stmf_find_tasks rpname=<wwn.12345678 or 12345678>\n"
1553             "    stmf_find_tasks lpname=<wwn.12345678 or 12345678> "
1554             "show=task_flags,lport\n");
1555 }
1556 
1557 void
1558 stmf_scsi_task_help(void)
1559 {
1560         mdb_printf(
1561             "List all active scsi_task_t on a given stmf_worker_t. Example\n"
1562             "    addr::stmf_scsi_task\n");
1563 }
1564 
1565 static const mdb_dcmd_t dcmds[] = {
1566         { "stmf_ilports", "[-v]",
1567             "Print a list of stmf_i_local_port", stmf_ilports },
1568         { "ilport2iport", "?[-v]",
1569             "Convert stmf_i_local_port to corresponding fct_i_local_port",
1570             ilport2iport },
1571         { "stmf_iss", "?[-v]",
1572             "List all active sessions for a given local port",
1573             stmf_iss },
1574         { "stmf_ilus", "[-v]", "Print a list of stmf_i_lu", stmf_ilus },
1575         { "stmf_i_lu_providers", "[-v]",
1576             "Print a list of stmf_i_lu_provider", stmf_i_lu_providers },
1577         { "stmf_i_port_providers", "[-v]",
1578             "Print a list of stmf_i_port_provider", stmf_i_port_providers },
1579         { "fct_irps", "?[-v]",
1580             "Print all fct_i_remote_port for a given fct_i_local_port",
1581             fct_irps },
1582         { "fct_icmds", "?[-v]",
1583             "Print all cached fct_i_cmd_t on fct_i_local_port",
1584             fct_icmds },
1585         { "fct_find_cmds", "lpname",
1586             "Find all fct_i_cmd_t for a given local port",
1587             fct_find_cmds, fct_find_cmds_help},
1588         { "stmf_find_ilport", "lpname",
1589             "Find local port information based on its wwn",
1590             stmf_find_ilport, stmf_find_ilport_help},
1591         { "stmf_find_fct_irp", "rpname|rp",
1592             "Print fct remote port information based on its wwn",
1593             stmf_find_fct_irp, stmf_find_fct_irp_help},
1594         { "stmf_find_tasks", "lpname|rpname [show]",
1595             "Find all pending task for a local port or remote port",
1596             stmf_find_tasks, stmf_find_tasks_help},
1597         { "stmf_worker", "?", "List all the stmf_worker entries", stmf_worker},
1598         { "stmf_scsi_task", ":",
1599             "List all the active STMF SCSI tasks per worker", stmf_scsi_task,
1600             stmf_scsi_task_help},
1601         { NULL }
1602 };
1603 
1604 static const mdb_walker_t walkers[] = {
1605         { "stmf_worker", "Walk STMF worker queue", stmf_worker_walk_init,
1606             stmf_worker_walk_step, stmf_worker_walk_fini},
1607         { "stmf_scsi_task", "Walk active STMF SCSI tasks per worker",
1608             stmf_scsi_task_walk_init,
1609             stmf_scsi_task_walk_step, stmf_scsi_task_walk_fini },
1610         { NULL }
1611 };
1612 
1613 static const mdb_modinfo_t modinfo = {
1614         MDB_API_VERSION, dcmds, walkers
1615 };
1616 
1617 const mdb_modinfo_t *
1618 _mdb_init(void)
1619 {
1620         return (&modinfo);
1621 }