Print this page
4500 mptsas_hash_traverse() is unsafe, leads to missing devices
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Approved by: Albert Lee <trisk@nexenta.com>
4499 ::mptsas should show slot/enclosure for targets
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Approved by: Albert Lee <trisk@nexenta.com>


   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 <limits.h>
  27 #include <sys/mdb_modapi.h>
  28 #include <sys/sysinfo.h>
  29 #include <sys/sunmdi.h>

  30 #include <sys/scsi/scsi.h>
  31 
  32 #pragma pack(1)
  33 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
  34 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
  35 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
  36 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
  37 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
  38 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
  39 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h>
  40 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
  41 #pragma pack()
  42 
  43 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>

  44 
  45 struct {
  46 
  47         int     value;
  48         char    *text;
  49 } devinfo_array[] = {
  50         { MPI2_SAS_DEVICE_INFO_SEP,             "SEP" },
  51         { MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE,    "ATAPI device" },
  52         { MPI2_SAS_DEVICE_INFO_LSI_DEVICE,      "LSI device" },
  53         { MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH,   "direct attach" },
  54         { MPI2_SAS_DEVICE_INFO_SSP_TARGET,      "SSP tgt" },
  55         { MPI2_SAS_DEVICE_INFO_STP_TARGET,      "STP tgt" },
  56         { MPI2_SAS_DEVICE_INFO_SMP_TARGET,      "SMP tgt" },
  57         { MPI2_SAS_DEVICE_INFO_SATA_DEVICE,     "SATA dev" },
  58         { MPI2_SAS_DEVICE_INFO_SSP_INITIATOR,   "SSP init" },
  59         { MPI2_SAS_DEVICE_INFO_STP_INITIATOR,   "STP init" },
  60         { MPI2_SAS_DEVICE_INFO_SMP_INITIATOR,   "SMP init" },
  61         { MPI2_SAS_DEVICE_INFO_SATA_HOST,       "SATA host" }
  62 };
  63 
  64 static int
  65 atoi(const char *p)
  66 {
  67         int n;
  68         int c = *p++;
  69 
  70         for (n = 0; c >= '0' && c <= '9'; c = *p++) {
  71                 n *= 10; /* two steps to avoid unnecessary overflow */
  72                 n += '0' - c; /* accum neg to avoid surprises at MAX */
  73         }
  74         return (-n);
  75 }
  76 
  77 int
  78 construct_path(uintptr_t addr, char *result)
  79 {
  80         struct  dev_info        d;
  81         char    devi_node[PATH_MAX];
  82         char    devi_addr[PATH_MAX];
  83 
  84         if (mdb_vread(&d, sizeof (d), addr) == -1) {
  85                 mdb_warn("couldn't read dev_info");
  86                 return (DCMD_ERR);
  87         }
  88 
  89         if (d.devi_parent) {
  90                 construct_path((uintptr_t)d.devi_parent, result);
  91                 mdb_readstr(devi_node, sizeof (devi_node),
  92                     (uintptr_t)d.devi_node_name);
  93                 mdb_readstr(devi_addr, sizeof (devi_addr),
  94                     (uintptr_t)d.devi_addr);
  95                 mdb_snprintf(result+strlen(result),
  96                     PATH_MAX-strlen(result),


  99         }
 100         return (DCMD_OK);
 101 }
 102 
 103 /* ARGSUSED */
 104 int
 105 mdi_info_cb(uintptr_t addr, const void *data, void *cbdata)
 106 {
 107         struct  mdi_pathinfo    pi;
 108         struct  mdi_client      c;
 109         char    dev_path[PATH_MAX];
 110         char    string[PATH_MAX];
 111         int     mdi_target = 0, mdi_lun = 0;
 112         int     target = *(int *)cbdata;
 113 
 114         if (mdb_vread(&pi, sizeof (pi), addr) == -1) {
 115                 mdb_warn("couldn't read mdi_pathinfo");
 116                 return (DCMD_ERR);
 117         }
 118         mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr);
 119         mdi_target = atoi(string);
 120         mdi_lun = atoi(strchr(string, ',')+1);
 121         if (target != mdi_target)
 122                 return (0);
 123 
 124         if (mdb_vread(&c, sizeof (c), (uintptr_t)pi.pi_client) == -1) {
 125                 mdb_warn("couldn't read mdi_client");
 126                 return (-1);
 127         }
 128 
 129         *dev_path = NULL;
 130         if (construct_path((uintptr_t)c.ct_dip, dev_path) != DCMD_OK)
 131                 strcpy(dev_path, "unknown");
 132 
 133         mdb_printf("LUN %d: %s\n", mdi_lun, dev_path);
 134         mdb_printf("       dip: %p %s path", c.ct_dip,
 135             (pi.pi_preferred ? "preferred" : ""));
 136         switch (pi.pi_state & MDI_PATHINFO_STATE_MASK) {
 137                 case MDI_PATHINFO_STATE_INIT:
 138                         mdb_printf(" initializing");
 139                         break;
 140                 case MDI_PATHINFO_STATE_ONLINE:


 196         /*
 197          * We use cmd_cdblen here because 5.10 doesn't
 198          * have the cdb length in the pkt
 199          */
 200         if (mdb_vread(&cdb, m->cmd_cdblen, (uintptr_t)pkt.pkt_cdbp) == -1) {
 201                 mdb_warn("couldn't read pkt_cdbp");
 202                 return;
 203         }
 204 
 205         mdb_printf("%3d,%-3d [ ",
 206             pkt.pkt_address.a_target, pkt.pkt_address.a_lun);
 207 
 208         for (j = 0; j < m->cmd_cdblen; j++)
 209                 mdb_printf("%02x ", cdb[j]);
 210 
 211         mdb_printf("]\n");
 212 }
 213 
 214 
 215 void
 216 display_ports(struct mptsas m)
 217 {
 218         int i;
 219         mdb_printf("\n");
 220         mdb_printf("phy number and port mapping table\n");
 221         for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
 222                 if (m.m_phy_info[i].attached_devhdl) {
 223                         mdb_printf("phy %x --> port %x, phymask %x,"
 224                         "attached_devhdl %x\n", i, m.m_phy_info[i].port_num,
 225                             m.m_phy_info[i].phy_mask,
 226                             m.m_phy_info[i].attached_devhdl);
 227                 }
 228         }
 229         mdb_printf("\n");
 230 }
 231 static void *
 232 hash_traverse(mptsas_hash_table_t *hashtab, int pos, int alloc_size)

 233 {
 234         mptsas_hash_node_t *this = NULL;
 235         mptsas_hash_node_t h;
 236         void *ret = NULL;
 237 
 238         if (pos == MPTSAS_HASH_FIRST) {
 239                 hashtab->line = 0;
 240                 hashtab->cur = NULL;
 241                 this = hashtab->head[0];
 242         } else {
 243                 if (hashtab->cur == NULL) {






 244                         return (NULL);
 245                 } else {
 246                         mdb_vread(&h, sizeof (h), (uintptr_t)hashtab->cur);
 247                         this = h.next;
 248                 }
 249         }
 250 
 251         while (this == NULL) {
 252                 hashtab->line++;
 253                 if (hashtab->line >= MPTSAS_HASH_ARRAY_SIZE) {
 254                         /* the traverse reaches the end */
 255                         hashtab->cur = NULL;









 256                         return (NULL);
 257                 } else {
 258                         this = hashtab->head[hashtab->line];


























 259                 }
 260         }
 261         hashtab->cur = this;
 262 
 263         if (mdb_vread(&h, sizeof (h), (uintptr_t)this) == -1) {
 264                 mdb_warn("couldn't read hashtab");
 265                 return (NULL);
 266         }
 267         ret = mdb_alloc(alloc_size, UM_SLEEP);
 268         if (mdb_vread(ret, alloc_size, (uintptr_t)h.data) == -1) {
 269                 mdb_warn("couldn't read hashdata");
 270                 return (NULL);
 271         }
 272         return (ret);

 273 }

 274 void
 275 display_targets(struct mptsas_slots *s)
 276 {
 277         mptsas_target_t *ptgt;
 278         mptsas_smp_t *psmp;
 279 
 280         mdb_printf("\n");
 281         mdb_printf("The SCSI target information\n");
 282         ptgt = (mptsas_target_t *)hash_traverse(&s->m_tgttbl,
 283             MPTSAS_HASH_FIRST, sizeof (mptsas_target_t));
 284         while (ptgt != NULL) {
 285                 mdb_printf("\n");
 286                 mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x,"
 287                     "devinfo %x\n", ptgt->m_devhdl, ptgt->m_sas_wwn,
 288                     ptgt->m_phymask, ptgt->m_deviceinfo);
 289                 mdb_printf("throttle %x, dr_flag %x, m_t_ncmds %x\n",
 290                     ptgt->m_t_throttle, ptgt->m_dr_flag, ptgt->m_t_ncmds);
 291 
 292                 mdb_free(ptgt, sizeof (mptsas_target_t));
 293                 ptgt = (mptsas_target_t *)hash_traverse(
 294                     &s->m_tgttbl, MPTSAS_HASH_NEXT, sizeof (mptsas_target_t));
 295         }

 296         mdb_printf("\n");
 297         mdb_printf("The smp child information\n");
 298         psmp = (mptsas_smp_t *)hash_traverse(&s->m_smptbl,
 299             MPTSAS_HASH_FIRST, sizeof (mptsas_smp_t));
 300         while (psmp != NULL) {

 301                 mdb_printf("\n");
 302                 mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x \n",
 303                     psmp->m_devhdl, psmp->m_sasaddr, psmp->m_phymask);
 304 
 305                 mdb_free(psmp, sizeof (mptsas_smp_t));
 306                 psmp = (mptsas_smp_t *)hash_traverse(
 307                     &s->m_smptbl, MPTSAS_HASH_NEXT, sizeof (mptsas_smp_t));
 308         }
 309         mdb_printf("\n");
 310 #if 0
 311         mdb_printf("targ         wwn      ncmds throttle "
 312             "dr_flag  timeout  dups\n");
 313         mdb_printf("-------------------------------"
 314             "--------------------------------\n");
 315         for (i = 0; i < MPTSAS_MAX_TARGETS; i++) {
 316                 if (s->m_target[i].m_sas_wwn || s->m_target[i].m_deviceinfo) {

 317                         mdb_printf("%4d ", i);
 318                         if (s->m_target[i].m_sas_wwn)
 319                                 mdb_printf("%"PRIx64" ",
 320                                     s->m_target[i].m_sas_wwn);
 321                         mdb_printf("%3d", s->m_target[i].m_t_ncmds);
 322                         switch (s->m_target[i].m_t_throttle) {
 323                                 case QFULL_THROTTLE:
 324                                         mdb_printf("   QFULL ");
 325                                         break;
 326                                 case DRAIN_THROTTLE:
 327                                         mdb_printf("   DRAIN ");
 328                                         break;
 329                                 case HOLD_THROTTLE:
 330                                         mdb_printf("    HOLD ");
 331                                         break;
 332                                 case MAX_THROTTLE:
 333                                         mdb_printf("     MAX ");
 334                                         break;
 335                                 case CHOKE_THROTTLE:
 336                                         mdb_printf("   CHOKE ");
 337                                         break;
 338                                 default:
 339                                         mdb_printf("%8d ",
 340                                             s->m_target[i].m_t_throttle);


 410                 }
 411         }
 412 #endif
 413 }
 414 
 415 int
 416 display_slotinfo()
 417 {
 418 #if 0
 419         int     i, nslots;
 420         struct  mptsas_cmd              c, *q, *slots;
 421         int     header_output = 0;
 422         int     rv = DCMD_OK;
 423         int     slots_in_use = 0;
 424         int     tcmds = 0;
 425         int     mismatch = 0;
 426         int     wq, dq;
 427         int     ncmds = 0;
 428         ulong_t saved_indent;
 429 
 430         nslots = s->m_n_slots;
 431 
 432         slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
 433 
 434         for (i = 0; i < nslots; i++)
 435                 if (s->m_slot[i]) {
 436                         slots_in_use++;
 437                         if (mdb_vread(&slots[i], sizeof (mptsas_cmd_t),
 438                             (uintptr_t)s->m_slot[i]) == -1) {
 439                                 mdb_warn("couldn't read slot");
 440                                 s->m_slot[i] = NULL;
 441                         }
 442                         if ((slots[i].cmd_flags & CFLAG_CMDIOC) == 0)
 443                                 tcmds++;
 444                         if (i != slots[i].cmd_slot)
 445                                 mismatch++;
 446                 }
 447 
 448         for (q = m.m_waitq, wq = 0; q; q = c.cmd_linkp, wq++)
 449                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 450                         mdb_warn("couldn't follow m_waitq");


 463                 ncmds += s->m_target[i].m_t_ncmds;
 464 
 465         mdb_printf("\n");
 466         mdb_printf("   mpt.  slot               mptsas_slots     slot");
 467         mdb_printf("\n");
 468         mdb_printf("m_ncmds total"
 469             " targ throttle m_t_ncmds targ_tot wq dq");
 470         mdb_printf("\n");
 471         mdb_printf("----------------------------------------------------");
 472         mdb_printf("\n");
 473 
 474         mdb_printf("%7d ", m.m_ncmds);
 475         mdb_printf("%s", (m.m_ncmds == slots_in_use ? "  " : "!="));
 476         mdb_printf("%3d               total %3d ", slots_in_use, ncmds);
 477         mdb_printf("%s", (tcmds == ncmds ? "     " : "   !="));
 478         mdb_printf("%3d %2d %2d\n", tcmds, wq, dq);
 479 
 480         saved_indent = mdb_dec_indent(0);
 481         mdb_dec_indent(saved_indent);
 482 
 483         for (i = 0; i < s->m_n_slots; i++)
 484                 if (s->m_slot[i]) {
 485                         if (!header_output) {
 486                                 mdb_printf("\n");
 487                                 mdb_printf("mptsas_cmd          slot cmd_slot "
 488                                     "cmd_flags cmd_pkt_flags scsi_pkt      "
 489                                     "  targ,lun [ pkt_cdbp ...\n");
 490                                 mdb_printf("-------------------------------"
 491                                     "--------------------------------------"
 492                                     "--------------------------------------"
 493                                     "------\n");
 494                                 header_output = 1;
 495                         }
 496                         mdb_printf("%16p %4d %s %4d  %8x      %8x %16p ",
 497                             s->m_slot[i], i,
 498                             (i == slots[i].cmd_slot?"   ":"BAD"),
 499                             slots[i].cmd_slot,
 500                             slots[i].cmd_flags,
 501                             slots[i].cmd_pkt_flags,
 502                             slots[i].cmd_pkt);
 503                         (void) print_cdb(&slots[i]);


 585                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 586                             "should not have CFLAG_IN_TRANSPORT set\n", q);
 587                 if (c.cmd_flags & CFLAG_CMDARQ)
 588                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 589                             "should not have CFLAG_CMDARQ set\n", q);
 590                 if (c.cmd_flags & CFLAG_COMPLETED)
 591                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 592                             "should not have CFLAG_COMPLETED set\n", q);
 593         }
 594 
 595 exit:
 596         mdb_free(slots, sizeof (mptsas_cmd_t) * nslots);
 597         return (rv);
 598 #endif
 599         mdb_printf("\n");
 600         mdb_printf("The slot information is not implemented yet\n");
 601         return (0);
 602 }
 603 
 604 void
 605 display_deviceinfo(struct mptsas m)
 606 {
 607         char    device_path[PATH_MAX];
 608 
 609         *device_path = 0;
 610         if (construct_path((uintptr_t)m.m_dip, device_path) != DCMD_OK) {
 611                 strcpy(device_path, "couldn't determine device path");
 612         }
 613 
 614         mdb_printf("\n");
 615         mdb_printf("Path in device tree %s\n", device_path);
 616 #if 0
 617         mdb_printf("base_wwid          phys "
 618             "mptid prodid  devid        revid   ssid\n");
 619         mdb_printf("-----------------------------"
 620             "----------------------------------\n");
 621         mdb_printf("%"PRIx64"     %2d   %3d "
 622             "0x%04x 0x%04x ", m.un.m_base_wwid, m.m_num_phys, m.m_mptid,
 623             m.m_productid, m.m_devid);
 624         switch (m.m_devid) {
 625                 case MPTSAS_909:
 626                         mdb_printf("(909)   ");
 627                         break;
 628                 case MPTSAS_929:
 629                         mdb_printf("(929)   ");
 630                         break;


 726             'v', MDB_OPT_SETBITS, TRUE, &verbose,
 727             NULL) != argc)
 728                 return (DCMD_USAGE);
 729 
 730 
 731         if (mdb_vread(&m, sizeof (m), addr) == -1) {
 732                 mdb_warn("couldn't read mpt struct at 0x%p", addr);
 733                 return (DCMD_ERR);
 734         }
 735 
 736         s = mdb_alloc(sizeof (mptsas_slots_t), UM_SLEEP);
 737 
 738         if (mdb_vread(s, sizeof (mptsas_slots_t),
 739             (uintptr_t)m.m_active) == -1) {
 740                 mdb_warn("couldn't read small mptsas_slots_t at 0x%p",
 741                     m.m_active);
 742                 mdb_free(s, sizeof (mptsas_slots_t));
 743                 return (DCMD_ERR);
 744         }
 745 
 746         nslots = s->m_n_slots;
 747 
 748         mdb_free(s, sizeof (mptsas_slots_t));
 749 
 750         slot_size = sizeof (mptsas_slots_t) +
 751             (sizeof (mptsas_cmd_t *) * (nslots-1));
 752 
 753         s = mdb_alloc(slot_size, UM_SLEEP);
 754 
 755         if (mdb_vread(s, slot_size, (uintptr_t)m.m_active) == -1) {
 756                 mdb_warn("couldn't read large mptsas_slots_t at 0x%p",
 757                     m.m_active);
 758                 mdb_free(s, slot_size);
 759                 return (DCMD_ERR);
 760         }
 761 
 762         /* processing completed */
 763 
 764         if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
 765             (flags & DCMD_LOOPFIRST) || slot_info || device_info ||
 766             target_info) {


 779                 case PM_LEVEL_D0:
 780                         mdb_printf(" ON=D0 ");
 781                         break;
 782                 case PM_LEVEL_D1:
 783                         mdb_printf("    D1 ");
 784                         break;
 785                 case PM_LEVEL_D2:
 786                         mdb_printf("    D2 ");
 787                         break;
 788                 case PM_LEVEL_D3:
 789                         mdb_printf("OFF=D3 ");
 790                         break;
 791                 default:
 792                         mdb_printf("INVALD ");
 793         }
 794         mdb_printf("\n");
 795 
 796         mdb_inc_indent(17);
 797 
 798         if (target_info)
 799                 display_targets(s);
 800 
 801         if (port_info)
 802                 display_ports(m);
 803 
 804         if (device_info)
 805                 display_deviceinfo(m);
 806 
 807         if (slot_info)
 808                 display_slotinfo();
 809 
 810         mdb_dec_indent(17);
 811 
 812         mdb_free(s, slot_size);
 813 
 814         return (rv);
 815 }
 816 /*
 817  * Only -t is implemented now, will add more later when the driver is stable
 818  */
 819 void
 820 mptsas_help()
 821 {
 822         mdb_printf("Prints summary information about each mpt_sas instance, "
 823             "including warning\nmessages when slot usage doesn't match "
 824             "summary information.\n"
 825             "Without the address of a \"struct mptsas\", prints every "
 826             "instance.\n\n"
 827             "Switches:\n"
 828             "  -t   includes information about targets\n"
 829             "  -p   includes information about port\n"
 830             "  -d   includes information about the hardware\n");
 831 }
 832 
 833 static const mdb_dcmd_t dcmds[] = {
 834         { "mptsas", "?[-tpd]", "print mpt_sas information", mptsas_dcmd,
 835             mptsas_help}, { NULL }
 836 };
 837 
 838 static const mdb_modinfo_t modinfo = {


   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  */
  29 
  30 #include <limits.h>
  31 #include <sys/mdb_modapi.h>
  32 #include <sys/sysinfo.h>
  33 #include <sys/sunmdi.h>
  34 #include <sys/list.h>
  35 #include <sys/scsi/scsi.h>
  36 
  37 #pragma pack(1)
  38 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
  39 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
  40 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
  41 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
  42 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
  43 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
  44 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h>
  45 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
  46 #pragma pack()
  47 
  48 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
  49 #include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
  50 
  51 struct {

  52         int     value;
  53         char    *text;
  54 } devinfo_array[] = {
  55         { MPI2_SAS_DEVICE_INFO_SEP,             "SEP" },
  56         { MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE,    "ATAPI device" },
  57         { MPI2_SAS_DEVICE_INFO_LSI_DEVICE,      "LSI device" },
  58         { MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH,   "direct attach" },
  59         { MPI2_SAS_DEVICE_INFO_SSP_TARGET,      "SSP tgt" },
  60         { MPI2_SAS_DEVICE_INFO_STP_TARGET,      "STP tgt" },
  61         { MPI2_SAS_DEVICE_INFO_SMP_TARGET,      "SMP tgt" },
  62         { MPI2_SAS_DEVICE_INFO_SATA_DEVICE,     "SATA dev" },
  63         { MPI2_SAS_DEVICE_INFO_SSP_INITIATOR,   "SSP init" },
  64         { MPI2_SAS_DEVICE_INFO_STP_INITIATOR,   "STP init" },
  65         { MPI2_SAS_DEVICE_INFO_SMP_INITIATOR,   "SMP init" },
  66         { MPI2_SAS_DEVICE_INFO_SATA_HOST,       "SATA host" }
  67 };
  68 













  69 int
  70 construct_path(uintptr_t addr, char *result)
  71 {
  72         struct  dev_info        d;
  73         char    devi_node[PATH_MAX];
  74         char    devi_addr[PATH_MAX];
  75 
  76         if (mdb_vread(&d, sizeof (d), addr) == -1) {
  77                 mdb_warn("couldn't read dev_info");
  78                 return (DCMD_ERR);
  79         }
  80 
  81         if (d.devi_parent) {
  82                 construct_path((uintptr_t)d.devi_parent, result);
  83                 mdb_readstr(devi_node, sizeof (devi_node),
  84                     (uintptr_t)d.devi_node_name);
  85                 mdb_readstr(devi_addr, sizeof (devi_addr),
  86                     (uintptr_t)d.devi_addr);
  87                 mdb_snprintf(result+strlen(result),
  88                     PATH_MAX-strlen(result),


  91         }
  92         return (DCMD_OK);
  93 }
  94 
  95 /* ARGSUSED */
  96 int
  97 mdi_info_cb(uintptr_t addr, const void *data, void *cbdata)
  98 {
  99         struct  mdi_pathinfo    pi;
 100         struct  mdi_client      c;
 101         char    dev_path[PATH_MAX];
 102         char    string[PATH_MAX];
 103         int     mdi_target = 0, mdi_lun = 0;
 104         int     target = *(int *)cbdata;
 105 
 106         if (mdb_vread(&pi, sizeof (pi), addr) == -1) {
 107                 mdb_warn("couldn't read mdi_pathinfo");
 108                 return (DCMD_ERR);
 109         }
 110         mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr);
 111         mdi_target = (int)mdb_strtoull(string);
 112         mdi_lun = (int)mdb_strtoull(strchr(string, ',') + 1);
 113         if (target != mdi_target)
 114                 return (0);
 115 
 116         if (mdb_vread(&c, sizeof (c), (uintptr_t)pi.pi_client) == -1) {
 117                 mdb_warn("couldn't read mdi_client");
 118                 return (-1);
 119         }
 120 
 121         *dev_path = NULL;
 122         if (construct_path((uintptr_t)c.ct_dip, dev_path) != DCMD_OK)
 123                 strcpy(dev_path, "unknown");
 124 
 125         mdb_printf("LUN %d: %s\n", mdi_lun, dev_path);
 126         mdb_printf("       dip: %p %s path", c.ct_dip,
 127             (pi.pi_preferred ? "preferred" : ""));
 128         switch (pi.pi_state & MDI_PATHINFO_STATE_MASK) {
 129                 case MDI_PATHINFO_STATE_INIT:
 130                         mdb_printf(" initializing");
 131                         break;
 132                 case MDI_PATHINFO_STATE_ONLINE:


 188         /*
 189          * We use cmd_cdblen here because 5.10 doesn't
 190          * have the cdb length in the pkt
 191          */
 192         if (mdb_vread(&cdb, m->cmd_cdblen, (uintptr_t)pkt.pkt_cdbp) == -1) {
 193                 mdb_warn("couldn't read pkt_cdbp");
 194                 return;
 195         }
 196 
 197         mdb_printf("%3d,%-3d [ ",
 198             pkt.pkt_address.a_target, pkt.pkt_address.a_lun);
 199 
 200         for (j = 0; j < m->cmd_cdblen; j++)
 201                 mdb_printf("%02x ", cdb[j]);
 202 
 203         mdb_printf("]\n");
 204 }
 205 
 206 
 207 void
 208 display_ports(struct mptsas *mp)
 209 {
 210         int i;
 211         mdb_printf("\n");
 212         mdb_printf("phy number and port mapping table\n");
 213         for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
 214                 if (mp->m_phy_info[i].attached_devhdl) {
 215                         mdb_printf("phy %x --> port %x, phymask %x,"
 216                         "attached_devhdl %x\n", i, mp->m_phy_info[i].port_num,
 217                             mp->m_phy_info[i].phy_mask,
 218                             mp->m_phy_info[i].attached_devhdl);
 219                 }
 220         }
 221         mdb_printf("\n");
 222 }
 223 
 224 static uintptr_t
 225 klist_head(list_t *lp, uintptr_t klp)
 226 {
 227         if ((uintptr_t)lp->list_head.list_next ==
 228             klp + offsetof(struct list, list_head))
 229                 return (NULL);
 230 
 231         return ((uintptr_t)(((char *)lp->list_head.list_next) -
 232             lp->list_offset));
 233 }
 234 
 235 static uintptr_t
 236 klist_next(list_t *lp, uintptr_t klp, void *op)
 237 {
 238         /* LINTED E_BAD_PTR_CAST_ALIG */
 239         struct list_node *np = (struct list_node *)(((char *)op) +
 240             lp->list_offset);
 241 
 242         if ((uintptr_t)np->list_next == klp + offsetof(struct list, list_head))
 243                 return (NULL);





 244 
 245         return (((uintptr_t)(np->list_next)) - lp->list_offset);
 246 }
 247 
 248 static void *
 249 krefhash_first(uintptr_t khp)
 250 {
 251         refhash_t mh;
 252         uintptr_t klp;
 253         uintptr_t kop;
 254         void *rp;
 255 
 256         mdb_vread(&mh, sizeof (mh), khp);
 257         klp = klist_head(&mh.rh_objs, khp + offsetof(refhash_t, rh_objs));
 258         if (klp == 0)
 259                 return (NULL);
 260 
 261         kop = klp - mh.rh_link_off;
 262         rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
 263         mdb_vread(rp, mh.rh_obj_size, kop);
 264 
 265         return (rp);
 266 }
 267 
 268 static void *
 269 krefhash_next(uintptr_t khp, void *op)
 270 {
 271         refhash_t mh;
 272         void *prev = op;
 273         refhash_link_t *lp;
 274         uintptr_t klp;
 275         uintptr_t kop;
 276         refhash_link_t ml;
 277         void *rp;
 278 
 279         mdb_vread(&mh, sizeof (mh), khp);
 280         /* LINTED E_BAD_PTR_CAST_ALIG */
 281         lp = (refhash_link_t *)(((char *)(op)) + mh.rh_link_off);
 282         ml = *lp;
 283         while ((klp = klist_next(&mh.rh_objs,
 284             khp + offsetof(refhash_t, rh_objs), &ml)) != NULL) {
 285                 mdb_vread(&ml, sizeof (ml), klp);
 286                 if (!(ml.rhl_flags & RHL_F_DEAD))
 287                         break;
 288         }


 289 
 290         if (klp == 0) {
 291                 mdb_free(prev, mh.rh_obj_size);
 292                 return (NULL);
 293         }
 294 
 295         kop = klp - mh.rh_link_off;
 296         rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
 297         mdb_vread(rp, mh.rh_obj_size, kop);
 298 
 299         mdb_free(prev, mh.rh_obj_size);
 300         return (rp);
 301 }
 302 
 303 void
 304 display_targets(struct mptsas *mp)
 305 {
 306         mptsas_target_t *ptgt;
 307         mptsas_smp_t *psmp;
 308 
 309         mdb_printf("\n");
 310         mdb_printf("The SCSI target information\n");
 311         for (ptgt = (mptsas_target_t *)krefhash_first((uintptr_t)mp->m_targets);
 312             ptgt != NULL;
 313             ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt)) {
 314                 mdb_printf("\n");
 315                 mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x,"
 316                     "devinfo %x\n", ptgt->m_devhdl, ptgt->m_addr.mta_wwn,
 317                     ptgt->m_addr.mta_phymask, ptgt->m_deviceinfo);
 318                 mdb_printf("throttle %x, dr_flag %x, m_t_ncmds %x, "
 319                     "enclosure %x, slot_num %x\n", ptgt->m_t_throttle,
 320                     ptgt->m_dr_flag, ptgt->m_t_ncmds, ptgt->m_enclosure,
 321                     ptgt->m_slot_num);


 322         }
 323 
 324         mdb_printf("\n");
 325         mdb_printf("The smp child information\n");
 326         for (psmp = (mptsas_smp_t *)krefhash_first(
 327             (uintptr_t)mp->m_smp_targets);
 328             psmp != NULL;
 329             psmp = krefhash_next((uintptr_t)mp->m_smp_targets, psmp)) {
 330                 mdb_printf("\n");
 331                 mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x \n",
 332                     psmp->m_devhdl, psmp->m_addr.mta_wwn,
 333                     psmp->m_addr.mta_phymask);



 334         }
 335         mdb_printf("\n");
 336 #if 0
 337         mdb_printf("targ         wwn      ncmds throttle "
 338             "dr_flag  timeout  dups\n");
 339         mdb_printf("-------------------------------"
 340             "--------------------------------\n");
 341         for (i = 0; i < MPTSAS_MAX_TARGETS; i++) {
 342                 if (s->m_target[i].m_addr.mta_wwn ||
 343                     s->m_target[i].m_deviceinfo) {
 344                         mdb_printf("%4d ", i);
 345                         if (s->m_target[i].m_addr.mta_wwn)
 346                                 mdb_printf("%"PRIx64" ",
 347                                     s->m_target[i].m_addr.mta_wwn);
 348                         mdb_printf("%3d", s->m_target[i].m_t_ncmds);
 349                         switch (s->m_target[i].m_t_throttle) {
 350                                 case QFULL_THROTTLE:
 351                                         mdb_printf("   QFULL ");
 352                                         break;
 353                                 case DRAIN_THROTTLE:
 354                                         mdb_printf("   DRAIN ");
 355                                         break;
 356                                 case HOLD_THROTTLE:
 357                                         mdb_printf("    HOLD ");
 358                                         break;
 359                                 case MAX_THROTTLE:
 360                                         mdb_printf("     MAX ");
 361                                         break;
 362                                 case CHOKE_THROTTLE:
 363                                         mdb_printf("   CHOKE ");
 364                                         break;
 365                                 default:
 366                                         mdb_printf("%8d ",
 367                                             s->m_target[i].m_t_throttle);


 437                 }
 438         }
 439 #endif
 440 }
 441 
 442 int
 443 display_slotinfo()
 444 {
 445 #if 0
 446         int     i, nslots;
 447         struct  mptsas_cmd              c, *q, *slots;
 448         int     header_output = 0;
 449         int     rv = DCMD_OK;
 450         int     slots_in_use = 0;
 451         int     tcmds = 0;
 452         int     mismatch = 0;
 453         int     wq, dq;
 454         int     ncmds = 0;
 455         ulong_t saved_indent;
 456 
 457         nslots = s->m_n_normal;
 458 
 459         slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
 460 
 461         for (i = 0; i < nslots; i++)
 462                 if (s->m_slot[i]) {
 463                         slots_in_use++;
 464                         if (mdb_vread(&slots[i], sizeof (mptsas_cmd_t),
 465                             (uintptr_t)s->m_slot[i]) == -1) {
 466                                 mdb_warn("couldn't read slot");
 467                                 s->m_slot[i] = NULL;
 468                         }
 469                         if ((slots[i].cmd_flags & CFLAG_CMDIOC) == 0)
 470                                 tcmds++;
 471                         if (i != slots[i].cmd_slot)
 472                                 mismatch++;
 473                 }
 474 
 475         for (q = m.m_waitq, wq = 0; q; q = c.cmd_linkp, wq++)
 476                 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
 477                         mdb_warn("couldn't follow m_waitq");


 490                 ncmds += s->m_target[i].m_t_ncmds;
 491 
 492         mdb_printf("\n");
 493         mdb_printf("   mpt.  slot               mptsas_slots     slot");
 494         mdb_printf("\n");
 495         mdb_printf("m_ncmds total"
 496             " targ throttle m_t_ncmds targ_tot wq dq");
 497         mdb_printf("\n");
 498         mdb_printf("----------------------------------------------------");
 499         mdb_printf("\n");
 500 
 501         mdb_printf("%7d ", m.m_ncmds);
 502         mdb_printf("%s", (m.m_ncmds == slots_in_use ? "  " : "!="));
 503         mdb_printf("%3d               total %3d ", slots_in_use, ncmds);
 504         mdb_printf("%s", (tcmds == ncmds ? "     " : "   !="));
 505         mdb_printf("%3d %2d %2d\n", tcmds, wq, dq);
 506 
 507         saved_indent = mdb_dec_indent(0);
 508         mdb_dec_indent(saved_indent);
 509 
 510         for (i = 0; i < s->m_n_normal; i++)
 511                 if (s->m_slot[i]) {
 512                         if (!header_output) {
 513                                 mdb_printf("\n");
 514                                 mdb_printf("mptsas_cmd          slot cmd_slot "
 515                                     "cmd_flags cmd_pkt_flags scsi_pkt      "
 516                                     "  targ,lun [ pkt_cdbp ...\n");
 517                                 mdb_printf("-------------------------------"
 518                                     "--------------------------------------"
 519                                     "--------------------------------------"
 520                                     "------\n");
 521                                 header_output = 1;
 522                         }
 523                         mdb_printf("%16p %4d %s %4d  %8x      %8x %16p ",
 524                             s->m_slot[i], i,
 525                             (i == slots[i].cmd_slot?"   ":"BAD"),
 526                             slots[i].cmd_slot,
 527                             slots[i].cmd_flags,
 528                             slots[i].cmd_pkt_flags,
 529                             slots[i].cmd_pkt);
 530                         (void) print_cdb(&slots[i]);


 612                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 613                             "should not have CFLAG_IN_TRANSPORT set\n", q);
 614                 if (c.cmd_flags & CFLAG_CMDARQ)
 615                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 616                             "should not have CFLAG_CMDARQ set\n", q);
 617                 if (c.cmd_flags & CFLAG_COMPLETED)
 618                         mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
 619                             "should not have CFLAG_COMPLETED set\n", q);
 620         }
 621 
 622 exit:
 623         mdb_free(slots, sizeof (mptsas_cmd_t) * nslots);
 624         return (rv);
 625 #endif
 626         mdb_printf("\n");
 627         mdb_printf("The slot information is not implemented yet\n");
 628         return (0);
 629 }
 630 
 631 void
 632 display_deviceinfo(struct mptsas *mp)
 633 {
 634         char    device_path[PATH_MAX];
 635 
 636         *device_path = 0;
 637         if (construct_path((uintptr_t)mp->m_dip, device_path) != DCMD_OK) {
 638                 strcpy(device_path, "couldn't determine device path");
 639         }
 640 
 641         mdb_printf("\n");
 642         mdb_printf("Path in device tree %s\n", device_path);
 643 #if 0
 644         mdb_printf("base_wwid          phys "
 645             "mptid prodid  devid        revid   ssid\n");
 646         mdb_printf("-----------------------------"
 647             "----------------------------------\n");
 648         mdb_printf("%"PRIx64"     %2d   %3d "
 649             "0x%04x 0x%04x ", m.un.m_base_wwid, m.m_num_phys, m.m_mptid,
 650             m.m_productid, m.m_devid);
 651         switch (m.m_devid) {
 652                 case MPTSAS_909:
 653                         mdb_printf("(909)   ");
 654                         break;
 655                 case MPTSAS_929:
 656                         mdb_printf("(929)   ");
 657                         break;


 753             'v', MDB_OPT_SETBITS, TRUE, &verbose,
 754             NULL) != argc)
 755                 return (DCMD_USAGE);
 756 
 757 
 758         if (mdb_vread(&m, sizeof (m), addr) == -1) {
 759                 mdb_warn("couldn't read mpt struct at 0x%p", addr);
 760                 return (DCMD_ERR);
 761         }
 762 
 763         s = mdb_alloc(sizeof (mptsas_slots_t), UM_SLEEP);
 764 
 765         if (mdb_vread(s, sizeof (mptsas_slots_t),
 766             (uintptr_t)m.m_active) == -1) {
 767                 mdb_warn("couldn't read small mptsas_slots_t at 0x%p",
 768                     m.m_active);
 769                 mdb_free(s, sizeof (mptsas_slots_t));
 770                 return (DCMD_ERR);
 771         }
 772 
 773         nslots = s->m_n_normal;
 774 
 775         mdb_free(s, sizeof (mptsas_slots_t));
 776 
 777         slot_size = sizeof (mptsas_slots_t) +
 778             (sizeof (mptsas_cmd_t *) * (nslots-1));
 779 
 780         s = mdb_alloc(slot_size, UM_SLEEP);
 781 
 782         if (mdb_vread(s, slot_size, (uintptr_t)m.m_active) == -1) {
 783                 mdb_warn("couldn't read large mptsas_slots_t at 0x%p",
 784                     m.m_active);
 785                 mdb_free(s, slot_size);
 786                 return (DCMD_ERR);
 787         }
 788 
 789         /* processing completed */
 790 
 791         if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
 792             (flags & DCMD_LOOPFIRST) || slot_info || device_info ||
 793             target_info) {


 806                 case PM_LEVEL_D0:
 807                         mdb_printf(" ON=D0 ");
 808                         break;
 809                 case PM_LEVEL_D1:
 810                         mdb_printf("    D1 ");
 811                         break;
 812                 case PM_LEVEL_D2:
 813                         mdb_printf("    D2 ");
 814                         break;
 815                 case PM_LEVEL_D3:
 816                         mdb_printf("OFF=D3 ");
 817                         break;
 818                 default:
 819                         mdb_printf("INVALD ");
 820         }
 821         mdb_printf("\n");
 822 
 823         mdb_inc_indent(17);
 824 
 825         if (target_info)
 826                 display_targets(&m);
 827 
 828         if (port_info)
 829                 display_ports(&m);
 830 
 831         if (device_info)
 832                 display_deviceinfo(&m);
 833 
 834         if (slot_info)
 835                 display_slotinfo();
 836 
 837         mdb_dec_indent(17);
 838 
 839         mdb_free(s, slot_size);
 840 
 841         return (rv);
 842 }
 843 


 844 void
 845 mptsas_help()
 846 {
 847         mdb_printf("Prints summary information about each mpt_sas instance, "
 848             "including warning\nmessages when slot usage doesn't match "
 849             "summary information.\n"
 850             "Without the address of a \"struct mptsas\", prints every "
 851             "instance.\n\n"
 852             "Switches:\n"
 853             "  -t   includes information about targets\n"
 854             "  -p   includes information about port\n"
 855             "  -d   includes information about the hardware\n");
 856 }
 857 
 858 static const mdb_dcmd_t dcmds[] = {
 859         { "mptsas", "?[-tpd]", "print mpt_sas information", mptsas_dcmd,
 860             mptsas_help}, { NULL }
 861 };
 862 
 863 static const mdb_modinfo_t modinfo = {