1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2014 Joyent, Inc.  All rights reserved.
  28  * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  29  */
  30 
  31 #include <limits.h>
  32 #include <sys/mdb_modapi.h>
  33 #include <sys/sysinfo.h>
  34 #include <sys/sunmdi.h>
  35 #include <sys/list.h>
  36 #include <sys/scsi/scsi.h>
  37 
  38 #pragma pack(1)
  39 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
  40 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
  41 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
  42 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
  43 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
  44 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
  45 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h>
  46 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
  47 #pragma pack()
  48 
  49 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
  50 #include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
  51 
  52 struct {
  53         int     value;
  54         char    *text;
  55 } devinfo_array[] = {
  56         { MPI2_SAS_DEVICE_INFO_SEP,             "SEP" },
  57         { MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE,    "ATAPI device" },
  58         { MPI2_SAS_DEVICE_INFO_LSI_DEVICE,      "LSI device" },
  59         { MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH,   "direct attach" },
  60         { MPI2_SAS_DEVICE_INFO_SSP_TARGET,      "SSP tgt" },
  61         { MPI2_SAS_DEVICE_INFO_STP_TARGET,      "STP tgt" },
  62         { MPI2_SAS_DEVICE_INFO_SMP_TARGET,      "SMP tgt" },
  63         { MPI2_SAS_DEVICE_INFO_SATA_DEVICE,     "SATA dev" },
  64         { MPI2_SAS_DEVICE_INFO_SSP_INITIATOR,   "SSP init" },
  65         { MPI2_SAS_DEVICE_INFO_STP_INITIATOR,   "STP init" },
  66         { MPI2_SAS_DEVICE_INFO_SMP_INITIATOR,   "SMP init" },
  67         { MPI2_SAS_DEVICE_INFO_SATA_HOST,       "SATA host" }
  68 };
  69 
  70 int
  71 construct_path(uintptr_t addr, char *result)
  72 {
  73         struct  dev_info        d;
  74         char    devi_node[PATH_MAX];
  75         char    devi_addr[PATH_MAX];
  76 
  77         if (mdb_vread(&d, sizeof (d), addr) == -1) {
  78                 mdb_warn("couldn't read dev_info");
  79                 return (DCMD_ERR);
  80         }
  81 
  82         if (d.devi_parent) {
  83                 construct_path((uintptr_t)d.devi_parent, result);
  84                 mdb_readstr(devi_node, sizeof (devi_node),
  85                     (uintptr_t)d.devi_node_name);
  86                 mdb_readstr(devi_addr, sizeof (devi_addr),
  87                     (uintptr_t)d.devi_addr);
  88                 mdb_snprintf(result+strlen(result),
  89                     PATH_MAX-strlen(result),
  90                     "/%s%s%s", devi_node, (*devi_addr ? "@" : ""),
  91                     devi_addr);
  92         }
  93         return (DCMD_OK);
  94 }
  95 
  96 /* ARGSUSED */
  97 int
  98 mdi_info_cb(uintptr_t addr, const void *data, void *cbdata)
  99 {
 100         struct  mdi_pathinfo    pi;
 101         struct  mdi_client      c;
 102         char    dev_path[PATH_MAX];
 103         char    string[PATH_MAX];
 104         int     mdi_target = 0, mdi_lun = 0;
 105         int     target = *(int *)cbdata;
 106 
 107         if (mdb_vread(&pi, sizeof (pi), addr) == -1) {
 108                 mdb_warn("couldn't read mdi_pathinfo");
 109                 return (DCMD_ERR);
 110         }
 111         mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr);
 112         mdi_target = (int)mdb_strtoull(string);
 113         mdi_lun = (int)mdb_strtoull(strchr(string, ',') + 1);
 114         if (target != mdi_target)
 115                 return (0);
 116 
 117         if (mdb_vread(&c, sizeof (c), (uintptr_t)pi.pi_client) == -1) {
 118                 mdb_warn("couldn't read mdi_client");
 119                 return (-1);
 120         }
 121 
 122         *dev_path = NULL;
 123         if (construct_path((uintptr_t)c.ct_dip, dev_path) != DCMD_OK)
 124                 strcpy(dev_path, "unknown");
 125 
 126         mdb_printf("LUN %d: %s\n", mdi_lun, dev_path);
 127         mdb_printf("       dip: %p %s path", c.ct_dip,
 128             (pi.pi_preferred ? "preferred" : ""));
 129         switch (pi.pi_state & MDI_PATHINFO_STATE_MASK) {
 130                 case MDI_PATHINFO_STATE_INIT:
 131                         mdb_printf(" initializing");
 132                         break;
 133                 case MDI_PATHINFO_STATE_ONLINE:
 134                         mdb_printf(" online");
 135                         break;
 136                 case MDI_PATHINFO_STATE_STANDBY:
 137                         mdb_printf(" standby");
 138                         break;
 139                 case MDI_PATHINFO_STATE_FAULT:
 140                         mdb_printf(" fault");
 141                         break;
 142                 case MDI_PATHINFO_STATE_OFFLINE:
 143                         mdb_printf(" offline");
 144                         break;
 145                 default:
 146                         mdb_printf(" invalid state");
 147                         break;
 148         }
 149         mdb_printf("\n");
 150         return (0);
 151 }
 152 
 153 void
 154 mdi_info(struct mptsas *mp, int target)
 155 {
 156         struct  dev_info        d;
 157         struct  mdi_phci        p;
 158 
 159         if (mdb_vread(&d, sizeof (d), (uintptr_t)mp->m_dip) == -1) {
 160                 mdb_warn("couldn't read m_dip");
 161                 return;
 162         }
 163 
 164         if (MDI_PHCI(&d)) {
 165                 if (mdb_vread(&p, sizeof (p), (uintptr_t)d.devi_mdi_xhci)
 166                     == -1) {
 167                         mdb_warn("couldn't read m_dip.devi_mdi_xhci");
 168                         return;
 169                 }
 170                 if (p.ph_path_head)
 171                         mdb_pwalk("mdipi_phci_list", (mdb_walk_cb_t)mdi_info_cb,
 172                             &target, (uintptr_t)p.ph_path_head);
 173                 return;
 174         }
 175 }
 176 
 177 void
 178 print_cdb(mptsas_cmd_t *m)
 179 {
 180         struct  scsi_pkt        pkt;
 181         uchar_t cdb[512];       /* an arbitrarily large number */
 182         int     j;
 183 
 184         if (mdb_vread(&pkt, sizeof (pkt), (uintptr_t)m->cmd_pkt) == -1) {
 185                 mdb_warn("couldn't read cmd_pkt");
 186                 return;
 187         }
 188 
 189         /*
 190          * We use cmd_cdblen here because 5.10 doesn't
 191          * have the cdb length in the pkt
 192          */
 193         if (mdb_vread(&cdb, m->cmd_cdblen, (uintptr_t)pkt.pkt_cdbp) == -1) {
 194                 mdb_warn("couldn't read pkt_cdbp");
 195                 return;
 196         }
 197 
 198         mdb_printf("%3d,%-3d [ ",
 199             pkt.pkt_address.a_target, pkt.pkt_address.a_lun);
 200 
 201         for (j = 0; j < m->cmd_cdblen; j++)
 202                 mdb_printf("%02x ", cdb[j]);
 203 
 204         mdb_printf("]\n");
 205 }
 206 
 207 
 208 void
 209 display_ports(struct mptsas *mp)
 210 {
 211         int i;
 212         mdb_printf("\n");
 213         mdb_printf("phy number and port mapping table\n");
 214         for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
 215                 if (mp->m_phy_info[i].attached_devhdl) {
 216                         mdb_printf("phy %x --> port %x, phymask %x,"
 217                         "attached_devhdl %x\n", i, mp->m_phy_info[i].port_num,
 218                             mp->m_phy_info[i].phy_mask,
 219                             mp->m_phy_info[i].attached_devhdl);
 220                 }
 221         }
 222         mdb_printf("\n");
 223 }
 224 
 225 static uintptr_t
 226 klist_head(list_t *lp, uintptr_t klp)
 227 {
 228         if ((uintptr_t)lp->list_head.list_next ==
 229             klp + offsetof(struct list, list_head))
 230                 return (NULL);
 231 
 232         return ((uintptr_t)(((char *)lp->list_head.list_next) -
 233             lp->list_offset));
 234 }
 235 
 236 static uintptr_t
 237 klist_next(list_t *lp, uintptr_t klp, void *op)
 238 {
 239         /* LINTED E_BAD_PTR_CAST_ALIG */
 240         struct list_node *np = (struct list_node *)(((char *)op) +
 241             lp->list_offset);
 242 
 243         if ((uintptr_t)np->list_next == klp + offsetof(struct list, list_head))
 244                 return (NULL);
 245 
 246         return (((uintptr_t)(np->list_next)) - lp->list_offset);
 247 }
 248 
 249 static void *
 250 krefhash_first(uintptr_t khp, uintptr_t *addr)
 251 {
 252         refhash_t mh;
 253         uintptr_t klp;
 254         uintptr_t kop;
 255         void *rp;
 256 
 257         mdb_vread(&mh, sizeof (mh), khp);
 258         klp = klist_head(&mh.rh_objs, khp + offsetof(refhash_t, rh_objs));
 259         if (klp == 0)
 260                 return (NULL);
 261 
 262         kop = klp - mh.rh_link_off;
 263         if (addr)
 264                 *addr = kop;
 265         rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
 266         mdb_vread(rp, mh.rh_obj_size, kop);
 267 
 268         return (rp);
 269 }
 270 
 271 static void *
 272 krefhash_next(uintptr_t khp, void *op, uintptr_t *addr)
 273 {
 274         refhash_t mh;
 275         void *prev = op;
 276         refhash_link_t *lp;
 277         uintptr_t klp;
 278         uintptr_t kop;
 279         refhash_link_t ml;
 280         void *rp;
 281 
 282         mdb_vread(&mh, sizeof (mh), khp);
 283         /* LINTED E_BAD_PTR_CAST_ALIG */
 284         lp = (refhash_link_t *)(((char *)(op)) + mh.rh_link_off);
 285         ml = *lp;
 286         while ((klp = klist_next(&mh.rh_objs,
 287             khp + offsetof(refhash_t, rh_objs), &ml)) != NULL) {
 288                 mdb_vread(&ml, sizeof (ml), klp);
 289                 if (!(ml.rhl_flags & RHL_F_DEAD))
 290                         break;
 291         }
 292 
 293         if (klp == 0) {
 294                 mdb_free(prev, mh.rh_obj_size);
 295                 return (NULL);
 296         }
 297 
 298         kop = klp - mh.rh_link_off;
 299         if (addr)
 300                 *addr = kop;
 301         rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
 302         mdb_vread(rp, mh.rh_obj_size, kop);
 303 
 304         mdb_free(prev, mh.rh_obj_size);
 305         return (rp);
 306 }
 307 
 308 void
 309 display_targets(struct mptsas *mp, uint_t verbose)
 310 {
 311         mptsas_target_t *ptgt;
 312         mptsas_smp_t *psmp;
 313         int loop, comma;
 314         uintptr_t p_addr;
 315 
 316         mdb_printf("\n");
 317         mdb_printf(" mptsas_target_t slot devhdl      wwn     ncmds throttle   "
 318             "dr_flag dups\n");
 319         mdb_printf("---------------------------------------"
 320             "-------------------------------\n");
 321         for (ptgt = krefhash_first((uintptr_t)mp->m_targets, &p_addr);
 322             ptgt != NULL;
 323             ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, &p_addr)) {
 324                 if (ptgt->m_addr.mta_wwn ||
 325                     ptgt->m_deviceinfo) {
 326                         mdb_printf("%16p ", p_addr);
 327                         mdb_printf("%4d ", ptgt->m_slot_num);
 328                         mdb_printf("%4d ", ptgt->m_devhdl);
 329                         if (ptgt->m_addr.mta_wwn)
 330                                 mdb_printf("%"PRIx64" ",
 331                                     ptgt->m_addr.mta_wwn);
 332                         mdb_printf("%3d", ptgt->m_t_ncmds);
 333                         switch (ptgt->m_t_throttle) {
 334                                 case QFULL_THROTTLE:
 335                                         mdb_printf("   QFULL ");
 336                                         break;
 337                                 case DRAIN_THROTTLE:
 338                                         mdb_printf("   DRAIN ");
 339                                         break;
 340                                 case HOLD_THROTTLE:
 341                                         mdb_printf("    HOLD ");
 342                                         break;
 343                                 case MAX_THROTTLE:
 344                                         mdb_printf("     MAX ");
 345                                         break;
 346                                 default:
 347                                         mdb_printf("%8d ",
 348                                             ptgt->m_t_throttle);
 349                         }
 350                         switch (ptgt->m_dr_flag) {
 351                                 case MPTSAS_DR_INACTIVE:
 352                                         mdb_printf("  INACTIVE ");
 353                                         break;
 354                                 case MPTSAS_DR_INTRANSITION:
 355                                         mdb_printf("TRANSITION ");
 356                                         break;
 357                                 default:
 358                                         mdb_printf("   UNKNOWN ");
 359                                         break;
 360                                 }
 361                         mdb_printf("%d\n",
 362                             ptgt->m_dups);
 363 
 364                         if (verbose) {
 365                                 mdb_inc_indent(5);
 366                                 if ((ptgt->m_deviceinfo &
 367                                     MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 368                                     MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
 369                                         mdb_printf("Fanout expander: ");
 370                                 if ((ptgt->m_deviceinfo &
 371                                     MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 372                                     MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
 373                                         mdb_printf("Edge expander: ");
 374                                 if ((ptgt->m_deviceinfo &
 375                                     MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 376                                     MPI2_SAS_DEVICE_INFO_END_DEVICE)
 377                                         mdb_printf("End device: ");
 378                                 if ((ptgt->m_deviceinfo &
 379                                     MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 380                                     MPI2_SAS_DEVICE_INFO_NO_DEVICE)
 381                                         mdb_printf("No device ");
 382 
 383                                 for (loop = 0, comma = 0;
 384                                     loop < (sizeof (devinfo_array) /
 385                                     sizeof (devinfo_array[0])); loop++) {
 386                                         if (ptgt->m_deviceinfo &
 387                                             devinfo_array[loop].value) {
 388                                                 mdb_printf("%s%s",
 389                                                     (comma ? ", " : ""),
 390                                                     devinfo_array[loop].text);
 391                                                 comma++;
 392                                         }
 393                                 }
 394                                 mdb_printf("\n");
 395                                 mdi_info(mp, ptgt->m_slot_num);
 396                                 mdb_dec_indent(5);
 397                         }
 398                 }
 399         }
 400 
 401         mdb_printf("\n");
 402         mdb_printf("    mptsas_smp_t devhdl      wwn          phymask\n");
 403         mdb_printf("---------------------------------------"
 404             "------------------\n");
 405         for (psmp = (mptsas_smp_t *)krefhash_first(
 406             (uintptr_t)mp->m_smp_targets, &p_addr);
 407             psmp != NULL;
 408             psmp = krefhash_next((uintptr_t)mp->m_smp_targets, psmp,
 409             &p_addr)) {
 410                 mdb_printf("%16p   ", p_addr);
 411                 mdb_printf("%4d  %"PRIx64"    %04x\n",
 412                     psmp->m_devhdl, psmp->m_addr.mta_wwn,
 413                     psmp->m_addr.mta_phymask);
 414 
 415                 if (!verbose)
 416                         continue;
 417 
 418                 mdb_inc_indent(5);
 419                 if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
 420                     == MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
 421                         mdb_printf("Fanout expander: ");
 422                 if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
 423                     == MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
 424                         mdb_printf("Edge expander: ");
 425                 if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
 426                     == MPI2_SAS_DEVICE_INFO_END_DEVICE)
 427                         mdb_printf("End device: ");
 428                 if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
 429                     == MPI2_SAS_DEVICE_INFO_NO_DEVICE)
 430                         mdb_printf("No device ");
 431 
 432                 for (loop = 0, comma = 0;
 433                     loop < (sizeof (devinfo_array)
 434                     / sizeof (devinfo_array[0]));
 435                     loop++) {
 436                         if (psmp->m_deviceinfo &
 437                             devinfo_array[loop].value) {
 438                                 mdb_printf("%s%s",
 439                                     (comma ? ", " : ""),
 440                                     devinfo_array[loop].text);
 441                                 comma++;
 442                         }
 443                 }
 444                 mdb_printf("\n");
 445                 mdb_dec_indent(5);
 446         }
 447 }
 448 
 449 int
 450 display_slotinfo(struct mptsas *mp, struct mptsas_slots *s)
 451 {
 452         int                     i, nslots;
 453         struct mptsas_cmd       c, *q, *slots;
 454         mptsas_target_t         *ptgt;
 455         int                     header_output = 0;
 456         int                     rv = DCMD_OK;
 457         int                     slots_in_use = 0;
 458         int                     tcmds = 0;
 459         int                     mismatch = 0;
 460         int                     wq, dq;
 461         int                     ncmds = 0;
 462         ulong_t                 saved_indent;
 463         uintptr_t               panicstr;
 464         int                     state;
 465 
 466         if ((state = mdb_get_state()) == MDB_STATE_RUNNING) {
 467                 mdb_warn("mptsas: slot info can only be displayed on a system "
 468                     "dump or under kmdb\n");
 469                 return (DCMD_ERR);
 470         }
 471 
 472         if (mdb_readvar(&panicstr, "panicstr") == -1) {
 473                 mdb_warn("can't read variable 'panicstr'");
 474                 return (DCMD_ERR);
 475         }
 476 
 477         if (state != MDB_STATE_STOPPED && panicstr == NULL) {
 478                 mdb_warn("mptsas: slot info not available for live dump\n");
 479                 return (DCMD_ERR);
 480         }
 481 
 482         nslots = s->m_n_normal;
 483         slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
 484 
 485         for (i = 0; i < nslots; i++)
 486                 if (s->m_slot[i]) {
 487                         slots_in_use++;
 488                         if (mdb_vread(&slots[i], sizeof (mptsas_cmd_t),
 489                             (uintptr_t)s->m_slot[i]) == -1) {
 490                                 mdb_warn("couldn't read slot");
 491                                 s->m_slot[i] = NULL;
 492                         }
 493                         if ((slots[i].cmd_flags & CFLAG_CMDIOC) == 0)
 494                                 tcmds++;
 495                         if (i != slots[i].cmd_slot)
 496                                 mismatch++;
 497                 }
 498 
 499         for (q = mp->m_waitq, wq = 0; q; q = c.cmd_linkp, wq++)
 500                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 501                         mdb_warn("couldn't follow m_waitq");
 502                         rv = DCMD_ERR;
 503                         goto exit;
 504                 }
 505 
 506         for (q = mp->m_doneq, dq = 0; q; q = c.cmd_linkp, dq++)
 507                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 508                         mdb_warn("couldn't follow m_doneq");
 509                         rv = DCMD_ERR;
 510                         goto exit;
 511                 }
 512 
 513         for (ptgt = krefhash_first((uintptr_t)mp->m_targets, NULL);
 514             ptgt != NULL;
 515             ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, NULL)) {
 516                 if (ptgt->m_addr.mta_wwn ||
 517                     ptgt->m_deviceinfo) {
 518                         ncmds += ptgt->m_t_ncmds;
 519                 }
 520         }
 521 
 522         mdb_printf("\n");
 523         mdb_printf("   mpt.  slot               mptsas_slots     slot");
 524         mdb_printf("\n");
 525         mdb_printf("m_ncmds total"
 526             " targ throttle m_t_ncmds targ_tot wq dq");
 527         mdb_printf("\n");
 528         mdb_printf("----------------------------------------------------");
 529         mdb_printf("\n");
 530 
 531         mdb_printf("%7d ", mp->m_ncmds);
 532         mdb_printf("%s", (mp->m_ncmds == slots_in_use ? "  " : "!="));
 533         mdb_printf("%3d               total %3d ", slots_in_use, ncmds);
 534         mdb_printf("%s", (tcmds == ncmds ? "     " : "   !="));
 535         mdb_printf("%3d %2d %2d\n", tcmds, wq, dq);
 536 
 537         saved_indent = mdb_dec_indent(0);
 538         mdb_dec_indent(saved_indent);
 539 
 540         for (i = 0; i < s->m_n_normal; i++)
 541                 if (s->m_slot[i]) {
 542                         if (!header_output) {
 543                                 mdb_printf("\n");
 544                                 mdb_printf("mptsas_cmd          slot cmd_slot "
 545                                     "cmd_flags cmd_pkt_flags scsi_pkt      "
 546                                     "  targ,lun [ pkt_cdbp ...\n");
 547                                 mdb_printf("-------------------------------"
 548                                     "--------------------------------------"
 549                                     "--------------------------------------"
 550                                     "------\n");
 551                                 header_output = 1;
 552                         }
 553                         mdb_printf("%16p %4d %s %4d  %8x      %8x %16p ",
 554                             s->m_slot[i], i,
 555                             (i == slots[i].cmd_slot?"   ":"BAD"),
 556                             slots[i].cmd_slot,
 557                             slots[i].cmd_flags,
 558                             slots[i].cmd_pkt_flags,
 559                             slots[i].cmd_pkt);
 560                         (void) print_cdb(&slots[i]);
 561                 }
 562 
 563         /* print the wait queue */
 564 
 565         for (q = mp->m_waitq; q; q = c.cmd_linkp) {
 566                 if (q == mp->m_waitq)
 567                         mdb_printf("\n");
 568                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
 569                     == -1) {
 570                         mdb_warn("couldn't follow m_waitq");
 571                         rv = DCMD_ERR;
 572                         goto exit;
 573                 }
 574                 mdb_printf("%16p wait n/a %4d  %8x      %8x %16p ",
 575                     q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
 576                     c.cmd_pkt);
 577                 print_cdb(&c);
 578         }
 579 
 580         /* print the done queue */
 581 
 582         for (q = mp->m_doneq; q; q = c.cmd_linkp) {
 583                 if (q == mp->m_doneq)
 584                         mdb_printf("\n");
 585                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
 586                     == -1) {
 587                         mdb_warn("couldn't follow m_doneq");
 588                         rv = DCMD_ERR;
 589                         goto exit;
 590                 }
 591                 mdb_printf("%16p done  n/a %4d  %8x      %8x %16p ",
 592                     q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
 593                     c.cmd_pkt);
 594                 print_cdb(&c);
 595         }
 596 
 597         mdb_inc_indent(saved_indent);
 598 
 599         if (mp->m_ncmds != slots_in_use)
 600                 mdb_printf("WARNING: mpt.m_ncmds does not match the number of "
 601                     "slots in use\n");
 602 
 603         if (tcmds != ncmds)
 604                 mdb_printf("WARNING: the total of m_target[].m_t_ncmds does "
 605                     "not match the slots in use\n");
 606 
 607         if (mismatch)
 608                 mdb_printf("WARNING: corruption in slot table, "
 609                     "m_slot[].cmd_slot incorrect\n");
 610 
 611         /* now check for corruptions */
 612 
 613         for (q = mp->m_waitq; q; q = c.cmd_linkp) {
 614                 for (i = 0; i < nslots; i++)
 615                         if (s->m_slot[i] == q)
 616                                 mdb_printf("WARNING: m_waitq entry"
 617                                     "(mptsas_cmd_t) %p is in m_slot[%i]\n",
 618                                     q, i);
 619 
 620                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 621                         mdb_warn("couldn't follow m_waitq");
 622                         rv = DCMD_ERR;
 623                         goto exit;
 624                 }
 625         }
 626 
 627         for (q = mp->m_doneq; q; q = c.cmd_linkp) {
 628                 for (i = 0; i < nslots; i++)
 629                         if (s->m_slot[i] == q)
 630                                 mdb_printf("WARNING: m_doneq entry "
 631                                 "(mptsas_cmd_t) %p is in m_slot[%i]\n", q, i);
 632 
 633                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 634                         mdb_warn("couldn't follow m_doneq");
 635                         rv = DCMD_ERR;
 636                         goto exit;
 637                 }
 638                 if ((c.cmd_flags & CFLAG_FINISHED) == 0)
 639                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 640                             "should have CFLAG_FINISHED set\n", q);
 641                 if (c.cmd_flags & CFLAG_IN_TRANSPORT)
 642                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 643                             "should not have CFLAG_IN_TRANSPORT set\n", q);
 644                 if (c.cmd_flags & CFLAG_CMDARQ)
 645                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 646                             "should not have CFLAG_CMDARQ set\n", q);
 647                 if (c.cmd_flags & CFLAG_COMPLETED)
 648                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 649                             "should not have CFLAG_COMPLETED set\n", q);
 650         }
 651 
 652 exit:
 653         mdb_free(slots, sizeof (mptsas_cmd_t) * nslots);
 654         return (rv);
 655 }
 656 
 657 void
 658 display_deviceinfo(struct mptsas *mp)
 659 {
 660         char    device_path[PATH_MAX];
 661 
 662         *device_path = 0;
 663         if (construct_path((uintptr_t)mp->m_dip, device_path) != DCMD_OK) {
 664                 strcpy(device_path, "couldn't determine device path");
 665         }
 666 
 667         mdb_printf("\n");
 668         mdb_printf("base_wwid          phys "
 669             " prodid  devid          revid   ssid\n");
 670         mdb_printf("-----------------------------"
 671             "----------------------------------\n");
 672         mdb_printf("%"PRIx64"     %2d  "
 673             "0x%04x 0x%04x ", mp->un.m_base_wwid, mp->m_num_phys,
 674             mp->m_productid, mp->m_devid);
 675         switch (mp->m_devid) {
 676                 case MPI2_MFGPAGE_DEVID_SAS2004:
 677                         mdb_printf("(SAS2004) ");
 678                         break;
 679                 case MPI2_MFGPAGE_DEVID_SAS2008:
 680                         mdb_printf("(SAS2008) ");
 681                         break;
 682                 case MPI2_MFGPAGE_DEVID_SAS2108_1:
 683                 case MPI2_MFGPAGE_DEVID_SAS2108_2:
 684                 case MPI2_MFGPAGE_DEVID_SAS2108_3:
 685                         mdb_printf("(SAS2108) ");
 686                         break;
 687                 case MPI2_MFGPAGE_DEVID_SAS2116_1:
 688                 case MPI2_MFGPAGE_DEVID_SAS2116_2:
 689                         mdb_printf("(SAS2116) ");
 690                         break;
 691                 case MPI2_MFGPAGE_DEVID_SSS6200:
 692                         mdb_printf("(SSS6200) ");
 693                         break;
 694                 case MPI2_MFGPAGE_DEVID_SAS2208_1:
 695                 case MPI2_MFGPAGE_DEVID_SAS2208_2:
 696                 case MPI2_MFGPAGE_DEVID_SAS2208_3:
 697                 case MPI2_MFGPAGE_DEVID_SAS2208_4:
 698                 case MPI2_MFGPAGE_DEVID_SAS2208_5:
 699                 case MPI2_MFGPAGE_DEVID_SAS2208_6:
 700                         mdb_printf("(SAS2208) ");
 701                         break;
 702                 case MPI2_MFGPAGE_DEVID_SAS2308_1:
 703                 case MPI2_MFGPAGE_DEVID_SAS2308_2:
 704                 case MPI2_MFGPAGE_DEVID_SAS2308_3:
 705                         mdb_printf("(SAS2308) ");
 706                         break;
 707                 case MPI25_MFGPAGE_DEVID_SAS3004:
 708                         mdb_printf("(SAS3004) ");
 709                         break;
 710                 case MPI25_MFGPAGE_DEVID_SAS3008:
 711                         mdb_printf("(SAS3008) ");
 712                         break;
 713                 case MPI25_MFGPAGE_DEVID_SAS3108_1:
 714                 case MPI25_MFGPAGE_DEVID_SAS3108_2:
 715                 case MPI25_MFGPAGE_DEVID_SAS3108_5:
 716                 case MPI25_MFGPAGE_DEVID_SAS3108_6:
 717                         mdb_printf("(SAS3108) ");
 718                         break;
 719                 default:
 720                         mdb_printf("(SAS????) ");
 721                         break;
 722         }
 723         mdb_printf("0x%02x 0x%04x\n", mp->m_revid, mp->m_ssid);
 724         mdb_printf("%s\n", device_path);
 725 
 726 }
 727 
 728 void
 729 dump_debug_log(void)
 730 {
 731         uint32_t idx;
 732         size_t  linecnt, linelen;
 733         char    *logbuf;
 734         int     i;
 735 
 736         if (mdb_readsym(&idx, sizeof (uint32_t), "mptsas_dbglog_idx") == -1) {
 737                 mdb_warn("No debug log buffer present");
 738                 return;
 739         }
 740         if (mdb_readsym(&linecnt, sizeof (size_t), "mptsas_dbglog_linecnt")
 741             == -1) {
 742                 mdb_warn("No debug linecnt present");
 743                 return;
 744         }
 745         if (mdb_readsym(&linelen, sizeof (size_t), "mptsas_dbglog_linelen")
 746             == -1) {
 747                 mdb_warn("No debug linelen present");
 748                 return;
 749         }
 750         logbuf = mdb_alloc(linelen * linecnt, UM_SLEEP);
 751 
 752         if (mdb_readsym(logbuf, linelen * linecnt, "mptsas_dbglog_bufs")
 753             == -1) {
 754                 mdb_warn("No debug log buffer present");
 755                 return;
 756         }
 757         mdb_printf("\n");
 758         idx &= linecnt - 1;
 759         for (i = 0; i < linecnt; i++) {
 760                 mdb_printf("%s\n", &logbuf[idx * linelen]);
 761                 idx++;
 762                 idx &= linecnt - 1;
 763         }
 764         mdb_free(logbuf, linelen * linecnt);
 765 }
 766 
 767 static int
 768 mptsas_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 769 {
 770         struct mptsas           m;
 771         struct mptsas_slots     *s;
 772 
 773         int                     nslots;
 774         int                     slot_size = 0;
 775         uint_t                  verbose = FALSE;
 776         uint_t                  target_info = FALSE;
 777         uint_t                  slot_info = FALSE;
 778         uint_t                  device_info = FALSE;
 779         uint_t                  port_info = FALSE;
 780         uint_t                  debug_log = FALSE;
 781         int                     rv = DCMD_OK;
 782 
 783         if (!(flags & DCMD_ADDRSPEC)) {
 784                 void            *mptsas_state = NULL;
 785 
 786                 if (mdb_readvar(&mptsas_state, "mptsas_state") == -1) {
 787                         mdb_warn("can't read mptsas_state");
 788                         return (DCMD_ERR);
 789                 }
 790                 if (mdb_pwalk_dcmd("genunix`softstate", "mpt_sas`mptsas", argc,
 791                     argv, (uintptr_t)mptsas_state) == -1) {
 792                         mdb_warn("mdb_pwalk_dcmd failed");
 793                         return (DCMD_ERR);
 794                 }
 795                 return (DCMD_OK);
 796         }
 797 
 798         if (mdb_getopts(argc, argv,
 799             's', MDB_OPT_SETBITS, TRUE, &slot_info,
 800             'd', MDB_OPT_SETBITS, TRUE, &device_info,
 801             't', MDB_OPT_SETBITS, TRUE, &target_info,
 802             'p', MDB_OPT_SETBITS, TRUE, &port_info,
 803             'v', MDB_OPT_SETBITS, TRUE, &verbose,
 804             'D', MDB_OPT_SETBITS, TRUE, &debug_log,
 805             NULL) != argc)
 806                 return (DCMD_USAGE);
 807 
 808 
 809         if (mdb_vread(&m, sizeof (m), addr) == -1) {
 810                 mdb_warn("couldn't read mpt struct at 0x%p", addr);
 811                 return (DCMD_ERR);
 812         }
 813 
 814         s = mdb_alloc(sizeof (mptsas_slots_t), UM_SLEEP);
 815 
 816         if (mdb_vread(s, sizeof (mptsas_slots_t),
 817             (uintptr_t)m.m_active) == -1) {
 818                 mdb_warn("couldn't read small mptsas_slots_t at 0x%p",
 819                     m.m_active);
 820                 mdb_free(s, sizeof (mptsas_slots_t));
 821                 return (DCMD_ERR);
 822         }
 823 
 824         nslots = s->m_n_normal;
 825 
 826         mdb_free(s, sizeof (mptsas_slots_t));
 827 
 828         slot_size = sizeof (mptsas_slots_t) +
 829             (sizeof (mptsas_cmd_t *) * (nslots-1));
 830 
 831         s = mdb_alloc(slot_size, UM_SLEEP);
 832 
 833         if (mdb_vread(s, slot_size, (uintptr_t)m.m_active) == -1) {
 834                 mdb_warn("couldn't read large mptsas_slots_t at 0x%p",
 835                     m.m_active);
 836                 mdb_free(s, slot_size);
 837                 return (DCMD_ERR);
 838         }
 839 
 840         /* processing completed */
 841 
 842         if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
 843             (flags & DCMD_LOOPFIRST) || slot_info || device_info ||
 844             target_info) {
 845                 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
 846                         mdb_printf("\n");
 847                 mdb_printf("        mptsas_t inst ncmds suspend  power");
 848                 mdb_printf("\n");
 849                 mdb_printf("========================================="
 850                     "=======================================");
 851                 mdb_printf("\n");
 852         }
 853 
 854         mdb_printf("%16p %4d %5d ", addr, m.m_instance, m.m_ncmds);
 855         mdb_printf("%7d", m.m_suspended);
 856         switch (m.m_power_level) {
 857                 case PM_LEVEL_D0:
 858                         mdb_printf(" ON=D0 ");
 859                         break;
 860                 case PM_LEVEL_D1:
 861                         mdb_printf("    D1 ");
 862                         break;
 863                 case PM_LEVEL_D2:
 864                         mdb_printf("    D2 ");
 865                         break;
 866                 case PM_LEVEL_D3:
 867                         mdb_printf("OFF=D3 ");
 868                         break;
 869                 default:
 870                         mdb_printf("INVALD ");
 871         }
 872         mdb_printf("\n");
 873 
 874         mdb_inc_indent(17);
 875 
 876         if (target_info)
 877                 display_targets(&m, verbose);
 878 
 879         if (port_info)
 880                 display_ports(&m);
 881 
 882         if (device_info)
 883                 display_deviceinfo(&m);
 884 
 885         if (slot_info)
 886                 display_slotinfo(&m, s);
 887 
 888         if (debug_log)
 889                 dump_debug_log();
 890 
 891         mdb_dec_indent(17);
 892 
 893         mdb_free(s, slot_size);
 894 
 895         return (rv);
 896 }
 897 
 898 void
 899 mptsas_help()
 900 {
 901         mdb_printf("Prints summary information about each mpt_sas instance, "
 902             "including warning\nmessages when slot usage doesn't match "
 903             "summary information.\n"
 904             "Without the address of a \"struct mptsas\", prints every "
 905             "instance.\n\n"
 906             "Switches:\n"
 907             "  -t[v]  includes information about targets, v = be more verbose\n"
 908             "  -p     includes information about port\n"
 909             "  -s     includes information about mpt slots\n"
 910             "  -d     includes information about the hardware\n"
 911             "  -D     print the mptsas specific debug log\n");
 912 }
 913 
 914 static const mdb_dcmd_t dcmds[] = {
 915         { "mptsas", "?[-tpsdD]", "print mpt_sas information", mptsas_dcmd,
 916             mptsas_help}, { NULL }
 917 };
 918 
 919 static const mdb_modinfo_t modinfo = {
 920         MDB_API_VERSION, dcmds, NULL
 921 };
 922 
 923 const mdb_modinfo_t *
 924 _mdb_init(void)
 925 {
 926         return (&modinfo);
 927 }