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_sas3/mpi/mpi2_type.h>
  40 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h>
  41 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
  42 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h>
  43 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h>
  44 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_sas.h>
  45 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_raid.h>
  46 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h>
  47 #pragma pack()
  48 
  49 #include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
  50 #include <sys/scsi/adapters/mpt_sas3/mptsas3_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 = (mptsas_target_t *)krefhash_first(
 322                 (uintptr_t)mp->m_targets, &p_addr);
 323             ptgt != NULL;
 324             ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, &p_addr)) {
 325                 if (ptgt->m_addr.mta_wwn ||
 326                     ptgt->m_deviceinfo) {
 327                         mdb_printf("%16p ", p_addr);
 328                         mdb_printf("%4d ", ptgt->m_slot_num);
 329                         mdb_printf("%4d ", ptgt->m_devhdl);
 330                         if (ptgt->m_addr.mta_wwn)
 331                                 mdb_printf("%"PRIx64" ",
 332                                     ptgt->m_addr.mta_wwn);
 333                         mdb_printf("%3d", ptgt->m_t_ncmds);
 334                         switch (ptgt->m_t_throttle) {
 335                                 case QFULL_THROTTLE:
 336                                         mdb_printf("   QFULL ");
 337                                         break;
 338                                 case DRAIN_THROTTLE:
 339                                         mdb_printf("   DRAIN ");
 340                                         break;
 341                                 case HOLD_THROTTLE:
 342                                         mdb_printf("    HOLD ");
 343                                         break;
 344                                 case MAX_THROTTLE:
 345                                         mdb_printf("     MAX ");
 346                                         break;
 347                                 default:
 348                                         mdb_printf("%8d ",
 349                                             ptgt->m_t_throttle);
 350                         }
 351                         switch (ptgt->m_dr_flag) {
 352                                 case MPTSAS_DR_INACTIVE:
 353                                         mdb_printf("  INACTIVE ");
 354                                         break;
 355                                 case MPTSAS_DR_INTRANSITION:
 356                                         mdb_printf("TRANSITION ");
 357                                         break;
 358                                 default:
 359                                         mdb_printf("   UNKNOWN ");
 360                                         break;
 361                                 }
 362                         mdb_printf("%d\n",
 363                             ptgt->m_dups);
 364 
 365                         if (verbose) {
 366                                 mdb_inc_indent(5);
 367                                 if ((ptgt->m_deviceinfo &
 368                                     MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 369                                     MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
 370                                         mdb_printf("Fanout expander: ");
 371                                 if ((ptgt->m_deviceinfo &
 372                                     MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 373                                     MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
 374                                         mdb_printf("Edge expander: ");
 375                                 if ((ptgt->m_deviceinfo &
 376                                     MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 377                                     MPI2_SAS_DEVICE_INFO_END_DEVICE)
 378                                         mdb_printf("End device: ");
 379                                 if ((ptgt->m_deviceinfo &
 380                                     MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 381                                     MPI2_SAS_DEVICE_INFO_NO_DEVICE)
 382                                         mdb_printf("No device ");
 383 
 384                                 for (loop = 0, comma = 0;
 385                                     loop < (sizeof (devinfo_array) /
 386                                     sizeof (devinfo_array[0])); loop++) {
 387                                         if (ptgt->m_deviceinfo &
 388                                             devinfo_array[loop].value) {
 389                                                 mdb_printf("%s%s",
 390                                                     (comma ? ", " : ""),
 391                                                     devinfo_array[loop].text);
 392                                                 comma++;
 393                                         }
 394                                 }
 395                                 mdb_printf("\n");
 396                                 mdi_info(mp, ptgt->m_slot_num);
 397                                 mdb_dec_indent(5);
 398                         }
 399                 }
 400         }
 401 
 402         mdb_printf("\n");
 403         mdb_printf("    mptsas_smp_t devhdl      wwn          phymask\n");
 404         mdb_printf("---------------------------------------"
 405             "------------------\n");
 406         for (psmp = (mptsas_smp_t *)krefhash_first(
 407             (uintptr_t)mp->m_smp_targets, &p_addr);
 408             psmp != NULL;
 409             psmp = krefhash_next((uintptr_t)mp->m_smp_targets, psmp,
 410             &p_addr)) {
 411                 mdb_printf("%16p   ", p_addr);
 412                 mdb_printf("%4d  %"PRIx64"    %04x\n",
 413                     psmp->m_devhdl, psmp->m_addr.mta_wwn,
 414                     psmp->m_addr.mta_phymask);
 415                 if (verbose) {
 416                         mdb_inc_indent(5);
 417                         if ((psmp->m_deviceinfo &
 418                                 MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 419                             MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
 420                                 mdb_printf("Fanout expander: ");
 421                         if ((psmp->m_deviceinfo &
 422                                 MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 423                             MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
 424                                 mdb_printf("Edge expander: ");
 425                         if ((psmp->m_deviceinfo &
 426                                 MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 427                             MPI2_SAS_DEVICE_INFO_END_DEVICE)
 428                                 mdb_printf("End device: ");
 429                         if ((psmp->m_deviceinfo &
 430                                 MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
 431                             MPI2_SAS_DEVICE_INFO_NO_DEVICE)
 432                                 mdb_printf("No device ");
 433 
 434                         for (loop = 0, comma = 0;
 435                              loop < (sizeof (devinfo_array) /
 436                                  sizeof (devinfo_array[0])); loop++) {
 437                                 if (psmp->m_deviceinfo &
 438                                     devinfo_array[loop].value) {
 439                                         mdb_printf("%s%s",
 440                                             (comma ? ", " : ""),
 441                                             devinfo_array[loop].text);
 442                                         comma++;
 443                                 }
 444                         }
 445                         mdb_printf("\n");
 446                         mdb_dec_indent(5);
 447                 }
 448         }
 449 }
 450 
 451 int
 452 display_slotinfo(struct mptsas *mp, struct mptsas_slots *s)
 453 {
 454         int                     i, nslots;
 455         struct mptsas_cmd       c, *q, *slots;
 456         mptsas_target_t         *ptgt;
 457         int                     header_output = 0;
 458         int                     rv = DCMD_OK;
 459         int                     slots_in_use = 0;
 460         int                     tcmds = 0;
 461         int                     mismatch = 0;
 462         int                     wq, dq;
 463         int                     ncmds = 0;
 464         ulong_t                 saved_indent;
 465 
 466         nslots = s->m_n_normal;
 467         slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
 468 
 469         for (i = 0; i < nslots; i++)
 470                 if (s->m_slot[i]) {
 471                         slots_in_use++;
 472                         if (mdb_vread(&slots[i], sizeof (mptsas_cmd_t),
 473                             (uintptr_t)s->m_slot[i]) == -1) {
 474                                 mdb_warn("couldn't read slot");
 475                                 s->m_slot[i] = NULL;
 476                         }
 477                         if ((slots[i].cmd_flags & CFLAG_CMDIOC) == 0)
 478                                 tcmds++;
 479                         if (i != slots[i].cmd_slot)
 480                                 mismatch++;
 481                 }
 482 
 483         for (q = mp->m_waitq, wq = 0; q; q = c.cmd_linkp, wq++)
 484                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 485                         mdb_warn("couldn't follow m_waitq");
 486                         rv = DCMD_ERR;
 487                         goto exit;
 488                 }
 489 
 490         for (q = mp->m_dlist.dl_q, dq = 0; q; q = c.cmd_linkp, dq++)
 491                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 492                         mdb_warn("couldn't follow m_doneq");
 493                         rv = DCMD_ERR;
 494                         goto exit;
 495                 }
 496 
 497         for (ptgt = (mptsas_target_t *)krefhash_first(
 498                 (uintptr_t)mp->m_targets, NULL);
 499             ptgt != NULL;
 500              ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, NULL)) {
 501                 if (ptgt->m_addr.mta_wwn ||
 502                     ptgt->m_deviceinfo) {
 503                         ncmds += ptgt->m_t_ncmds;
 504                 }
 505         }
 506 
 507         mdb_printf("\n");
 508         mdb_printf("   mpt.  slot               mptsas_slots     slot");
 509         mdb_printf("\n");
 510         mdb_printf("m_ncmds total"
 511             " targ throttle m_t_ncmds targ_tot wq dq");
 512         mdb_printf("\n");
 513         mdb_printf("----------------------------------------------------");
 514         mdb_printf("\n");
 515 
 516         mdb_printf("%7d ", mp->m_ncmds);
 517         mdb_printf("%s", (mp->m_ncmds == slots_in_use ? "  " : "!="));
 518         mdb_printf("%3d               total %3d ", slots_in_use, ncmds);
 519         mdb_printf("%s", (tcmds == ncmds ? "     " : "   !="));
 520         mdb_printf("%3d %2d %2d\n", tcmds, wq, dq);
 521 
 522         saved_indent = mdb_dec_indent(0);
 523         mdb_dec_indent(saved_indent);
 524 
 525         for (i = 0; i < s->m_n_normal; i++)
 526                 if (s->m_slot[i]) {
 527                         if (!header_output) {
 528                                 mdb_printf("\n");
 529                                 mdb_printf("mptsas_cmd          slot cmd_slot "
 530                                     "cmd_flags cmd_pkt_flags scsi_pkt      "
 531                                     "  targ,lun [ pkt_cdbp ...\n");
 532                                 mdb_printf("-------------------------------"
 533                                     "--------------------------------------"
 534                                     "--------------------------------------"
 535                                     "------\n");
 536                                 header_output = 1;
 537                         }
 538                         mdb_printf("%16p %4d %s %4d  %8x      %8x %16p ",
 539                             s->m_slot[i], i,
 540                             (i == slots[i].cmd_slot?"   ":"BAD"),
 541                             slots[i].cmd_slot,
 542                             slots[i].cmd_flags,
 543                             slots[i].cmd_pkt_flags,
 544                             slots[i].cmd_pkt);
 545                         (void) print_cdb(&slots[i]);
 546                 }
 547 
 548         /* print the wait queue */
 549 
 550         for (q = mp->m_waitq; q; q = c.cmd_linkp) {
 551                 if (q == mp->m_waitq)
 552                         mdb_printf("\n");
 553                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
 554                     == -1) {
 555                         mdb_warn("couldn't follow m_waitq");
 556                         rv = DCMD_ERR;
 557                         goto exit;
 558                 }
 559                 mdb_printf("%16p wait n/a %4d  %8x      %8x %16p ",
 560                     q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
 561                     c.cmd_pkt);
 562                 print_cdb(&c);
 563         }
 564 
 565         /* print the done queue */
 566 
 567         for (q = mp->m_dlist.dl_q; q; q = c.cmd_linkp) {
 568                 if (q == mp->m_dlist.dl_q)
 569                         mdb_printf("\n");
 570                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
 571                     == -1) {
 572                         mdb_warn("couldn't follow m_doneq");
 573                         rv = DCMD_ERR;
 574                         goto exit;
 575                 }
 576                 mdb_printf("%16p done  n/a %4d  %8x      %8x %16p ",
 577                     q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
 578                     c.cmd_pkt);
 579                 print_cdb(&c);
 580         }
 581 
 582         mdb_inc_indent(saved_indent);
 583 
 584         if (mp->m_ncmds != slots_in_use)
 585                 mdb_printf("WARNING: mpt.m_ncmds does not match the number of "
 586                     "slots in use\n");
 587 
 588         if (tcmds != ncmds)
 589                 mdb_printf("WARNING: the total of m_target[].m_t_ncmds does "
 590                     "not match the slots in use\n");
 591 
 592         if (mismatch)
 593                 mdb_printf("WARNING: corruption in slot table, "
 594                     "m_slot[].cmd_slot incorrect\n");
 595 
 596         /* now check for corruptions */
 597 
 598         for (q = mp->m_waitq; q; q = c.cmd_linkp) {
 599                 for (i = 0; i < nslots; i++)
 600                         if (s->m_slot[i] == q)
 601                                 mdb_printf("WARNING: m_waitq entry"
 602                                     "(mptsas_cmd_t) %p is in m_slot[%i]\n",
 603                                     q, i);
 604 
 605                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 606                         mdb_warn("couldn't follow m_waitq");
 607                         rv = DCMD_ERR;
 608                         goto exit;
 609                 }
 610         }
 611 
 612         for (q = mp->m_dlist.dl_q; q; q = c.cmd_linkp) {
 613                 for (i = 0; i < nslots; i++)
 614                         if (s->m_slot[i] == q)
 615                                 mdb_printf("WARNING: m_doneq entry "
 616                                 "(mptsas_cmd_t) %p is in m_slot[%i]\n", q, i);
 617 
 618                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 619                         mdb_warn("couldn't follow m_doneq");
 620                         rv = DCMD_ERR;
 621                         goto exit;
 622                 }
 623                 if ((c.cmd_flags & CFLAG_FINISHED) == 0)
 624                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 625                             "should have CFLAG_FINISHED set\n", q);
 626                 if (c.cmd_flags & CFLAG_IN_TRANSPORT)
 627                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 628                             "should not have CFLAG_IN_TRANSPORT set\n", q);
 629                 if (c.cmd_flags & CFLAG_CMDARQ)
 630                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 631                             "should not have CFLAG_CMDARQ set\n", q);
 632                 if (c.cmd_flags & CFLAG_COMPLETED)
 633                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 634                             "should not have CFLAG_COMPLETED set\n", q);
 635         }
 636 
 637 exit:
 638         mdb_free(slots, sizeof (mptsas_cmd_t) * nslots);
 639         return (rv);
 640 }
 641 
 642 void
 643 display_deviceinfo(struct mptsas *mp)
 644 {
 645         char    device_path[PATH_MAX];
 646 
 647         *device_path = 0;
 648         if (construct_path((uintptr_t)mp->m_dip, device_path) != DCMD_OK) {
 649                 strcpy(device_path, "couldn't determine device path");
 650         }
 651 
 652         mdb_printf("\n");
 653         mdb_printf("base_wwid          phys "
 654             " prodid  devid          revid   ssid\n");
 655         mdb_printf("-----------------------------"
 656             "----------------------------------\n");
 657         mdb_printf("%"PRIx64"     %2d  "
 658             "0x%04x 0x%04x ", mp->un.m_base_wwid, mp->m_num_phys,
 659             mp->m_productid, mp->m_devid);
 660         switch (mp->m_devid) {
 661                 case MPI2_MFGPAGE_DEVID_SAS2004:
 662                         mdb_printf("(SAS2004) ");
 663                         break;
 664                 case MPI2_MFGPAGE_DEVID_SAS2008:
 665                         mdb_printf("(SAS2008) ");
 666                         break;
 667                 case MPI2_MFGPAGE_DEVID_SAS2108_1:
 668                 case MPI2_MFGPAGE_DEVID_SAS2108_2:
 669                 case MPI2_MFGPAGE_DEVID_SAS2108_3:
 670                         mdb_printf("(SAS2108) ");
 671                         break;
 672                 case MPI2_MFGPAGE_DEVID_SAS2116_1:
 673                 case MPI2_MFGPAGE_DEVID_SAS2116_2:
 674                         mdb_printf("(SAS2116) ");
 675                         break;
 676                 case MPI2_MFGPAGE_DEVID_SSS6200:
 677                         mdb_printf("(SSS6200) ");
 678                         break;
 679                 case MPI2_MFGPAGE_DEVID_SAS2208_1:
 680                 case MPI2_MFGPAGE_DEVID_SAS2208_2:
 681                 case MPI2_MFGPAGE_DEVID_SAS2208_3:
 682                 case MPI2_MFGPAGE_DEVID_SAS2208_4:
 683                 case MPI2_MFGPAGE_DEVID_SAS2208_5:
 684                 case MPI2_MFGPAGE_DEVID_SAS2208_6:
 685 #if 0
 686                 /* Same as 2308_1/2 ?? */
 687                 case MPI2_MFGPAGE_DEVID_SAS2208_7:
 688                 case MPI2_MFGPAGE_DEVID_SAS2208_8:
 689 #endif
 690                         mdb_printf("(SAS2208) ");
 691                         break;
 692                 case MPI2_MFGPAGE_DEVID_SAS2308_1:
 693                 case MPI2_MFGPAGE_DEVID_SAS2308_2:
 694                 case MPI2_MFGPAGE_DEVID_SAS2308_3:
 695                         mdb_printf("(SAS2308) ");
 696                         break;
 697                 case MPI25_MFGPAGE_DEVID_SAS3004:
 698                         mdb_printf("(SAS3004) ");
 699                         break;
 700                 case MPI25_MFGPAGE_DEVID_SAS3008:
 701                         mdb_printf("(SAS3008) ");
 702                         break;
 703                 case MPI25_MFGPAGE_DEVID_SAS3108_1:
 704                 case MPI25_MFGPAGE_DEVID_SAS3108_2:
 705                 case MPI25_MFGPAGE_DEVID_SAS3108_3:
 706                 case MPI25_MFGPAGE_DEVID_SAS3108_4:
 707                 case MPI25_MFGPAGE_DEVID_SAS3108_5:
 708                 case MPI25_MFGPAGE_DEVID_SAS3108_6:
 709                         mdb_printf("(SAS3108) ");
 710                         break;
 711                 default:
 712                         mdb_printf("(SAS????) ");
 713                         break;
 714         }
 715         mdb_printf("0x%02x 0x%04x\n", mp->m_revid, mp->m_ssid);
 716         mdb_printf("%s\n", device_path);
 717 }
 718 
 719 void
 720 dump_debug_log(struct mptsas *mp)
 721 {
 722         uint_t  idx;
 723         char    *logbuf;
 724         int     i;
 725 
 726         if (mdb_readsym(&idx, sizeof (uint_t),
 727                 "mptsas_dbglog_idx") == -1) {
 728                 mdb_warn("No debug log buffer present");
 729                 return;
 730         }
 731         logbuf = mdb_alloc(32*256, UM_SLEEP);
 732         if (idx == 0) {
 733                 mdb_warn("Logging turned off");
 734                 return;
 735         }
 736 
 737         if (mdb_readsym(logbuf, 32*256,
 738                 "mptsas_dbglog_bufs") == -1) {
 739                 mdb_warn("No debug log buffer present");
 740                 return;
 741         }
 742         mdb_printf("\n");
 743         idx &= 0x1f;
 744         for (i = 0; i < 32; i++) {
 745                 mdb_printf("%s\n", &logbuf[idx*256]);
 746                 idx = (idx+1) & 0x1f;
 747         }
 748         mdb_free(logbuf, 32*256);
 749 }
 750 
 751 static int
 752 mptsas_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 753 {
 754         struct mptsas           m;
 755         struct mptsas_slots     *s;
 756 
 757         int                     nslots;
 758         int                     slot_size = 0;
 759         uint_t                  verbose = FALSE;
 760         uint_t                  target_info = FALSE;
 761         uint_t                  slot_info = FALSE;
 762         uint_t                  device_info = FALSE;
 763         uint_t                  port_info = FALSE;
 764         uint_t                  debug_log = FALSE;
 765         int                     rv = DCMD_OK;
 766 
 767         if (!(flags & DCMD_ADDRSPEC)) {
 768                 void            *mptsas3_state = NULL;
 769 
 770                 if (mdb_readvar(&mptsas3_state, "mptsas3_state") == -1) {
 771                         mdb_warn("can't read mptsas3_state");
 772                         return (DCMD_ERR);
 773                 }
 774                 if (mdb_pwalk_dcmd("genunix`softstate",
 775                         "mpt_sas3`mptsas3", argc,
 776                         argv, (uintptr_t)mptsas3_state) == -1) {
 777                         mdb_warn("mdb_pwalk_dcmd failed");
 778                         return (DCMD_ERR);
 779                 }
 780                 return (DCMD_OK);
 781         }
 782 
 783         if (mdb_getopts(argc, argv,
 784             's', MDB_OPT_SETBITS, TRUE, &slot_info,
 785             'd', MDB_OPT_SETBITS, TRUE, &device_info,
 786             't', MDB_OPT_SETBITS, TRUE, &target_info,
 787             'p', MDB_OPT_SETBITS, TRUE, &port_info,
 788             'v', MDB_OPT_SETBITS, TRUE, &verbose,
 789             'D', MDB_OPT_SETBITS, TRUE, &debug_log,
 790             NULL) != argc)
 791                 return (DCMD_USAGE);
 792 
 793 
 794         if (mdb_vread(&m, sizeof (m), addr) == -1) {
 795                 mdb_warn("couldn't read mpt struct at 0x%p", addr);
 796                 return (DCMD_ERR);
 797         }
 798 
 799         s = mdb_alloc(sizeof (mptsas_slots_t), UM_SLEEP);
 800 
 801         if (mdb_vread(s, sizeof (mptsas_slots_t),
 802             (uintptr_t)m.m_active) == -1) {
 803                 mdb_warn("couldn't read small mptsas_slots_t at 0x%p",
 804                     m.m_active);
 805                 mdb_free(s, sizeof (mptsas_slots_t));
 806                 return (DCMD_ERR);
 807         }
 808 
 809         nslots = s->m_n_normal;
 810 
 811         mdb_free(s, sizeof (mptsas_slots_t));
 812 
 813         slot_size = sizeof (mptsas_slots_t) +
 814             (sizeof (mptsas_cmd_t *) * (nslots-1));
 815 
 816         s = mdb_alloc(slot_size, UM_SLEEP);
 817 
 818         if (mdb_vread(s, slot_size, (uintptr_t)m.m_active) == -1) {
 819                 mdb_warn("couldn't read large mptsas_slots_t at 0x%p",
 820                     m.m_active);
 821                 mdb_free(s, slot_size);
 822                 return (DCMD_ERR);
 823         }
 824 
 825         /* processing completed */
 826 
 827         if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
 828             (flags & DCMD_LOOPFIRST) || slot_info || device_info ||
 829             target_info) {
 830                 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
 831                         mdb_printf("\n");
 832                 mdb_printf("        mptsas_t inst ncmds suspend  power");
 833                 mdb_printf("\n");
 834                 mdb_printf("========================================="
 835                     "=======================================");
 836                 mdb_printf("\n");
 837         }
 838 
 839         mdb_printf("%16p %4d %5d ", addr, m.m_instance, m.m_ncmds);
 840         mdb_printf("%7d", m.m_suspended);
 841         switch (m.m_power_level) {
 842                 case PM_LEVEL_D0:
 843                         mdb_printf(" ON=D0 ");
 844                         break;
 845                 case PM_LEVEL_D1:
 846                         mdb_printf("    D1 ");
 847                         break;
 848                 case PM_LEVEL_D2:
 849                         mdb_printf("    D2 ");
 850                         break;
 851                 case PM_LEVEL_D3:
 852                         mdb_printf("OFF=D3 ");
 853                         break;
 854                 default:
 855                         mdb_printf("INVALD ");
 856         }
 857         mdb_printf("\n");
 858 
 859         mdb_inc_indent(17);
 860 
 861         if (target_info)
 862                 display_targets(&m, verbose);
 863 
 864         if (port_info)
 865                 display_ports(&m);
 866 
 867         if (device_info)
 868                 display_deviceinfo(&m);
 869 
 870         if (slot_info)
 871                 display_slotinfo(&m, s);
 872 
 873         if (debug_log)
 874                 dump_debug_log(&m);
 875 
 876         mdb_dec_indent(17);
 877 
 878         mdb_free(s, slot_size);
 879 
 880         return (rv);
 881 }
 882 
 883 void
 884 mptsas_help()
 885 {
 886         mdb_printf("Prints summary information about each mpt_sas3 instance, "
 887             "including warning\nmessages when slot usage doesn't match "
 888             "summary information.\n"
 889             "Without the address of a \"struct mptsas\", prints every "
 890             "instance.\n\n"
 891             "Switches:\n"
 892             "  -t[v]  includes information about targets, v = be more verbose\n"
 893             "  -p     includes information about port\n"
 894             "  -s     includes information about mpt slots\n"
 895             "  -d     includes information about the hardware\n"
 896             "  -D     print the mptsas specific debug log\n");
 897 }
 898 
 899 static const mdb_dcmd_t dcmds[] = {
 900         { "mptsas3", "?[-tpsdD]", "print mpt_sas3 information", mptsas_dcmd,
 901             mptsas_help}, { NULL }
 902 };
 903 
 904 static const mdb_modinfo_t modinfo = {
 905         MDB_API_VERSION, dcmds, NULL
 906 };
 907 
 908 const mdb_modinfo_t *
 909 _mdb_init(void)
 910 {
 911         return (&modinfo);
 912 }