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