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 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <stddef.h>
  29 #include <sys/mdb_modapi.h>
  30 #include <mdb/mdb_ks.h>
  31 
  32 #include <sys/usb/usba.h>
  33 #include <sys/ddi_impldefs.h>
  34 #include <sys/usb/usba/usba_types.h>
  35 #include <sys/usb/usba/usba_impl.h>
  36 #include <sys/usb/usba/hcdi_impl.h>
  37 #include <sys/file.h>
  38 #include <sys/sunndi.h>
  39 #include <unistd.h>
  40 
  41 
  42 /*
  43  * Prototypes
  44  */
  45 /* usba.c */
  46 extern uintptr_t mdb_usba_get_usba_device(uintptr_t);
  47 extern uintptr_t mdb_usba_hcdi_get_hcdi(struct dev_info *);
  48 
  49 /*
  50  * Defines
  51  */
  52 /* dcmd options */
  53 #define USB_DUMP_VERBOSE        0x01
  54 #define USB_DUMP_ACTIVE_PIPES   0x02
  55 
  56 /* Hardcoded slop factor designed into debug buf logic */
  57 #define USB_DEBUG_SIZE_EXTRA_ALLOC 8
  58 
  59 
  60 /*
  61  * Callback arg struct for find_dip (callback func used in usba_device2devinfo).
  62  */
  63 typedef struct usba_device2devinfo_data {
  64         uintptr_t       u2d_target_usb_dev_p;   /* one we're looking for */
  65         uintptr_t       *u2d_dip_addr;          /* Where to store result */
  66         boolean_t       u2d_found;              /* Match found */
  67 } usba_device2devinfo_cbdata_t;
  68 
  69 
  70 /*
  71  * Callback for usba_device2dip.
  72  * Callback called from the devinfo_children walk invoked in usba_device2dip.
  73  *
  74  * For the current dip, get the (potential) pointer to its usba_device_t
  75  * struct.
  76  * See if this pointer matches the address of the usba_device_t we're looking
  77  * for (passed in as usb_dev_p).  If so, stuff its value in u2d_dip_addr,
  78  * and terminate the walk.
  79  *
  80  * - dip_addr is the address in core of the dip currently being processed by the
  81  * walk
  82  * - local_dip is a pointer to a copy of the struct dev_info in local memory
  83  * - cb_data is the addr of the callback arg the walker was invoked with
  84  * (passed through transparently from walk invoker).
  85  *
  86  * Returns:
  87  * - WALK_NEXT on success (match not found yet)
  88  * - WALK_ERR on errors.
  89  * - WALK_DONE is returned, cb_data.found is set to TRUE, and
  90  * *cb_data.u2d_dip_addr is set to the matched dip addr if a dip corresponding
  91  * to the desired usba_device_t* is found.
  92  */
  93 /*ARGSUSED*/
  94 static int
  95 find_dip(uintptr_t dip_addr, const void *local_dip, void *cb_arg)
  96 {
  97         uintptr_t                       cur_usb_dev;
  98         usba_device2devinfo_cbdata_t    *cb_data =
  99                             (usba_device2devinfo_cbdata_t *)cb_arg;
 100 
 101         if ((cur_usb_dev = mdb_usba_get_usba_device(dip_addr)) == (uintptr_t)NULL) {
 102                 /*
 103                  * If there's no corresponding usba_device_t, this dip isn't
 104                  * a usb node.  Might be an sd node.  Ignore it.
 105                  */
 106 
 107                 return (WALK_NEXT);
 108         }
 109 
 110         if (cur_usb_dev == cb_data->u2d_target_usb_dev_p) {
 111                 *cb_data->u2d_dip_addr = dip_addr;
 112                 cb_data->u2d_found = TRUE;
 113 
 114                 return (WALK_DONE);
 115         }
 116 
 117         return (WALK_NEXT);
 118 }
 119 
 120 
 121 /*
 122  * Given a usba_device pointer, figure out which dip is associated with it.
 123  * Relies on usba_device.usb_root_hub_dip being accurate.
 124  *
 125  * - usb_dev_addr is a pointer to a usba_device_t in core.
 126  * - dip_addr is the address of a uintptr_t to receive the address in core
 127  * of the found dip (if any).
 128  *
 129  * Returns:
 130  *  0 on success (no match found)
 131  *  1 on success (match found)
 132  * -1 on errors.
 133  */
 134 static int
 135 usba_device2dip(uintptr_t usb_dev_addr, uintptr_t *dip_addr)
 136 {
 137         usba_device_t                   usb_dev;
 138         usba_device2devinfo_cbdata_t    cb_data;
 139 
 140         /*
 141          * Walk all USB children of the root hub devinfo.
 142          * The callback func looks for a match on the usba_device address.
 143          */
 144         cb_data.u2d_target_usb_dev_p = usb_dev_addr;
 145         cb_data.u2d_dip_addr = dip_addr;
 146         cb_data.u2d_found = FALSE;
 147 
 148         if (mdb_vread(&usb_dev, sizeof (usba_device_t),
 149             usb_dev_addr) == -1) {
 150                 mdb_warn("failed to read usba_device struct");
 151 
 152                 return (-1);
 153         }
 154 
 155         /*
 156          * Walk devinfo children starting with the root hub node,
 157          * looking for a match on the usba_device pointer (which is what
 158          * find_dip does).
 159          * Result is placed in cb_data.dip_addr.
 160          */
 161         if (mdb_pwalk("devinfo_children", find_dip, &cb_data,
 162             (uintptr_t)usb_dev.usb_root_hub_dip) != 0) {
 163                 mdb_warn("failed to walk devinfo_children");
 164 
 165                 return (-1);
 166         }
 167 
 168         if (cb_data.u2d_found == TRUE) {
 169 
 170                 return (1);
 171         }
 172 
 173         return (0);
 174 }
 175 
 176 
 177 /*
 178  * Generic walker usba_list_entry_t walker.
 179  * Works for any usba_list_entry_t list.
 180  */
 181 int
 182 usba_list_walk_init(mdb_walk_state_t *wsp)
 183 {
 184         /* Must have a start addr.  */
 185         if (wsp->walk_addr == (uintptr_t)NULL) {
 186                 mdb_warn("not a global walk.  Starting address required\n");
 187 
 188                 return (WALK_ERR);
 189         }
 190 
 191         return (WALK_NEXT);
 192 }
 193 
 194 
 195 /*
 196  * Generic list walker step routine.
 197  * NOTE: multiple walkers share this routine.
 198  */
 199 int
 200 usba_list_walk_step(mdb_walk_state_t *wsp)
 201 {
 202         int                     status;
 203         usba_list_entry_t       list_entry;
 204 
 205         if (mdb_vread(&list_entry, sizeof (usba_list_entry_t),
 206             (uintptr_t)wsp->walk_addr) == -1) {
 207                 mdb_warn("failed to read usba_list_entry_t at %p",
 208                     wsp->walk_addr);
 209 
 210                 return (WALK_ERR);
 211         }
 212 
 213         status = wsp->walk_callback(wsp->walk_addr, &list_entry,
 214             wsp->walk_cbdata);
 215         wsp->walk_addr = (uintptr_t)list_entry.next;
 216 
 217         /* Check if we're at the last element */
 218         if (wsp->walk_addr == (uintptr_t)NULL) {
 219 
 220                 return (WALK_DONE);
 221         }
 222 
 223         return (status);
 224 }
 225 
 226 
 227 /*
 228  * usb_pipe_handle walker
 229  * Given a pointer to a usba_device_t, walk the array of endpoint
 230  * pipe_handle lists.
 231  * For each list, traverse the list, invoking the callback on each element.
 232  *
 233  * Note this function takes the address of a usba_device struct (which is
 234  * easily obtainable), but actually traverses a sub-portion of the struct
 235  * (which address is not so easily obtainable).
 236  */
 237 int
 238 usb_pipe_handle_walk_init(mdb_walk_state_t *wsp)
 239 {
 240         if (wsp->walk_addr == (uintptr_t)NULL) {
 241                 mdb_warn("not a global walk; usba_device_t required\n");
 242 
 243                 return (WALK_ERR);
 244         }
 245 
 246         wsp->walk_data = mdb_alloc((sizeof (usba_ph_impl_t)) * USBA_N_ENDPOINTS,
 247                                         UM_SLEEP | UM_GC);
 248 
 249         /*
 250          * Read the usb_ph_list array into local memory.
 251          * Set start address to first element/endpoint in usb_pipehandle_list
 252          */
 253         if (mdb_vread(wsp->walk_data,
 254             (sizeof (usba_ph_impl_t)) * USBA_N_ENDPOINTS,
 255             (uintptr_t)((size_t)(wsp->walk_addr) +
 256             offsetof(usba_device_t, usb_ph_list))) == -1) {
 257                 mdb_warn("failed to read usb_pipehandle_list at %p",
 258                     wsp->walk_addr);
 259 
 260                 return (WALK_ERR);
 261         }
 262 
 263         wsp->walk_arg = 0;
 264 
 265         return (WALK_NEXT);
 266 }
 267 
 268 
 269 int
 270 usb_pipe_handle_walk_step(mdb_walk_state_t *wsp)
 271 {
 272         int status;
 273         usba_ph_impl_t *impl_list = (usba_ph_impl_t *)(wsp->walk_data);
 274         intptr_t index = (intptr_t)wsp->walk_arg;
 275 
 276         /* Find the first valid endpoint, starting from where we left off. */
 277         while ((index < USBA_N_ENDPOINTS) &&
 278             (impl_list[index].usba_ph_data == NULL)) {
 279                 index++;
 280         }
 281 
 282         /* No more valid endpoints. */
 283         if (index >= USBA_N_ENDPOINTS) {
 284 
 285                 return (WALK_DONE);
 286         }
 287 
 288         status = wsp->walk_callback((uintptr_t)impl_list[index].usba_ph_data,
 289                                         wsp->walk_data, wsp->walk_cbdata);
 290 
 291         /* Set up to start at next pipe handle next time. */
 292         wsp->walk_arg = (void *)(index + 1);
 293 
 294         return (status);
 295 }
 296 
 297 
 298 /*
 299  * Given the address of a usba_pipe_handle_data_t, dump summary info.
 300  */
 301 /*ARGSUSED*/
 302 int
 303 usb_pipe_handle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 304 {
 305         char                    *dir, *type, *state;
 306         usb_ep_descr_t          ept_descr;
 307         usba_pipe_handle_data_t pipe_handle;
 308         usba_ph_impl_t          ph_impl;
 309 
 310         if (!(flags & DCMD_ADDRSPEC)) {
 311 
 312                 return (DCMD_USAGE);
 313         }
 314 
 315         if (mdb_vread(&pipe_handle,
 316             sizeof (usba_pipe_handle_data_t), addr) == -1) {
 317                 mdb_warn("failed to read pipe handle at %p", addr);
 318 
 319                 return (DCMD_ERR);
 320         }
 321 
 322         if (mdb_vread(&ph_impl, sizeof (usba_ph_impl_t),
 323             (uintptr_t)pipe_handle.p_ph_impl) == -1) {
 324                 state = "*******";
 325         } else {
 326                 switch (ph_impl.usba_ph_state) {
 327                 case USB_PIPE_STATE_CLOSED:
 328                         state = "CLOSED ";
 329                         break;
 330 
 331                 case USB_PIPE_STATE_IDLE:
 332                         state = "IDLE   ";
 333                         break;
 334 
 335                 case USB_PIPE_STATE_ACTIVE:
 336                         state = "ACTIVE ";
 337                         break;
 338 
 339                 case USB_PIPE_STATE_ERROR:
 340                         state = "ERROR  ";
 341                         break;
 342 
 343                 case USB_PIPE_STATE_CLOSING:
 344                         state = "CLOSING";
 345                         break;
 346 
 347                 default:
 348                         state = "ILLEGAL";
 349                         break;
 350                 }
 351         }
 352 
 353         bcopy(&pipe_handle.p_ep, &ept_descr, sizeof (usb_ep_descr_t));
 354 
 355         if (DCMD_HDRSPEC(flags)) {
 356                 mdb_printf("\n    %<u>%-3s %5s %3s %7s %-?s %-?s %-?s%</u>\n",
 357                     "EP", "TYPE ", "DIR", "STATE  ", "P_HANDLE", "P_POLICY",
 358                     "EP DESCR");
 359         }
 360 
 361         dir = ((ept_descr.bEndpointAddress & USB_EP_DIR_MASK) &
 362             USB_EP_DIR_IN) ? "In " : "Out";
 363         switch (ept_descr.bmAttributes & USB_EP_ATTR_MASK) {
 364         case USB_EP_ATTR_CONTROL:
 365                 type = "Cntrl";
 366                 break;
 367 
 368         case USB_EP_ATTR_ISOCH:
 369                 type = "Isoch";
 370                 break;
 371 
 372         case USB_EP_ATTR_BULK:
 373                 type = "Bulk ";
 374                 break;
 375 
 376         case USB_EP_ATTR_INTR:
 377                 type = "Intr ";
 378                 break;
 379 
 380         default:
 381                 type = "*****";
 382                 break;
 383         }
 384 
 385         mdb_printf("    %3d %5s %3s %7s %-?p %-?p %-?p\n",
 386             ept_descr.bEndpointAddress & USB_EP_NUM_MASK, type, dir, state,
 387             addr, addr + offsetof(usba_pipe_handle_data_t, p_policy),
 388             addr + offsetof(usba_pipe_handle_data_t, p_ep));
 389 
 390         return (DCMD_OK);
 391 }
 392 
 393 
 394 /*
 395  * usba_device walker:
 396  *
 397  * walks the chain of usba_device structs headed by usba_device_list in usba.c
 398  * NOTE: It uses the generic list walk step routine usba_list_walk_step.
 399  * No walk_fini routine is needed.
 400  */
 401 int
 402 usba_device_walk_init(mdb_walk_state_t *wsp)
 403 {
 404         usba_list_entry_t       list_entry;
 405 
 406         if (wsp->walk_addr != (uintptr_t)NULL) {
 407                 mdb_warn(
 408                     "global walk only.  Must be invoked without an address\n");
 409 
 410                 return (WALK_ERR);
 411         }
 412 
 413         if (mdb_readvar(&list_entry, "usba_device_list") == -1) {
 414                 mdb_warn("failed to read usba_device_list");
 415 
 416                 return (WALK_ERR);
 417         }
 418 
 419         /* List head is not part of usba_device_t, get first usba_device_t */
 420         wsp->walk_addr = (uintptr_t)list_entry.next;
 421 
 422         return (WALK_NEXT);
 423 }
 424 
 425 
 426 /*
 427  * usba_device dcmd
 428  *      Given the address of a usba_device struct, dump summary info
 429  *      -v:     Print more (verbose) info
 430  *      -p:     Walk/dump all open pipes for this usba_device
 431  */
 432 /*ARGSUSED*/
 433 int
 434 usba_device(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 435 {
 436         int             status;
 437         char            pathname[MAXNAMELEN];
 438         char            dname[MODMAXNAMELEN + 1] = "<unatt>"; /* Driver name */
 439         char            drv_statep[MODMAXNAMELEN+ 10];
 440         uint_t          usb_flag  = 0;
 441         boolean_t       no_driver_attached = FALSE;
 442         uintptr_t       dip_addr;
 443         struct dev_info devinfo;
 444 
 445         if (!(flags & DCMD_ADDRSPEC)) {
 446                 /* Global walk */
 447                 if (mdb_walk_dcmd("usba_device", "usba_device", argc,
 448                     argv) == -1) {
 449                         mdb_warn("failed to walk usba_device");
 450 
 451                         return (DCMD_ERR);
 452                 }
 453 
 454                 return (DCMD_OK);
 455         }
 456 
 457         if (mdb_getopts(argc, argv,
 458             'p', MDB_OPT_SETBITS, USB_DUMP_ACTIVE_PIPES, &usb_flag,
 459             'v', MDB_OPT_SETBITS, USB_DUMP_VERBOSE, &usb_flag, NULL) != argc) {
 460 
 461                 return (DCMD_USAGE);
 462         }
 463 
 464         if (usb_flag && !(DCMD_HDRSPEC(flags))) {
 465                 mdb_printf("\n");
 466         }
 467 
 468         if (DCMD_HDRSPEC(flags)) {
 469                 mdb_printf("%<u>%-15s %4s %-?s %-42s%</u>\n",
 470                     "NAME", "INST", "DIP", "PATH                             ");
 471         }
 472 
 473         status = usba_device2dip(addr, &dip_addr);
 474         /*
 475          * -1 = error
 476          * 0 = no error, no match
 477          * 1 = no error, match
 478          */
 479         if (status != 1) {
 480                 if (status == -1) {
 481                         mdb_warn("error looking for dip for usba_device %p",
 482                             addr);
 483                 } else {
 484                         mdb_warn("failed to find dip for usba_device %p\n",
 485                             addr);
 486                 }
 487                 mdb_warn("dip and statep unobtainable\n");
 488 
 489                 return (DCMD_ERR);
 490         }
 491 
 492         /* Figure out what driver (name) is attached to this node. */
 493         (void) mdb_devinfo2driver(dip_addr, (char *)dname, sizeof (dname));
 494 
 495         if (mdb_vread(&devinfo, sizeof (struct dev_info),
 496             dip_addr) == -1) {
 497                 mdb_warn("failed to read devinfo");
 498 
 499                 return (DCMD_ERR);
 500         }
 501 
 502         if (!(DDI_CF2(&devinfo))) {
 503                 no_driver_attached = TRUE;
 504         }
 505 
 506         (void) mdb_ddi_pathname(dip_addr, pathname, sizeof (pathname));
 507         mdb_printf("%-15s %2d   %-?p %s\n", dname, devinfo.devi_instance,
 508             dip_addr, pathname);
 509 
 510         if (usb_flag & USB_DUMP_VERBOSE) {
 511                 int             i;
 512                 uintptr_t       statep = (uintptr_t)NULL;
 513                 char            *string_descr;
 514                 char            **config_cloud, **conf_str_descr;
 515                 usb_dev_descr_t usb_dev_descr;
 516                 usba_device_t   usba_device_struct;
 517 
 518                 if (mdb_vread(&usba_device_struct,
 519                     sizeof (usba_device_t), addr) == -1) {
 520                         mdb_warn("failed to read usba_device struct");
 521 
 522                         return (DCMD_ERR);
 523                 }
 524 
 525                 mdb_printf("    usba_device: %-16p\n\n", (usba_device_t *)addr);
 526 
 527                 if (mdb_vread(&usb_dev_descr, sizeof (usb_dev_descr),
 528                     (uintptr_t)usba_device_struct.usb_dev_descr) == -1) {
 529                         mdb_warn("failed to read usb_dev_descr_t struct");
 530 
 531                         return (DCMD_ERR);
 532                 }
 533 
 534                 mdb_printf("\n    idVendor: 0x%04x idProduct: 0x%04x "
 535                     "usb_addr: 0x%02x\n", usb_dev_descr.idVendor,
 536                     usb_dev_descr.idProduct, usba_device_struct.usb_addr);
 537 
 538                 /* Get the string descriptor string into local space. */
 539                 string_descr = (char *)mdb_alloc(USB_MAXSTRINGLEN, UM_GC);
 540 
 541                 if (usba_device_struct.usb_mfg_str == NULL) {
 542                         (void) strcpy(string_descr, "<No Manufacturer String>");
 543                 } else {
 544                         if (mdb_readstr(string_descr, USB_MAXSTRINGLEN,
 545                             (uintptr_t)usba_device_struct.usb_mfg_str) == -1) {
 546                                 mdb_warn("failed to read manufacturer "
 547                                     "string descriptor");
 548                                 (void) strcpy(string_descr, "???");
 549                         }
 550                 }
 551                 mdb_printf("\n    Manufacturer String:\t%s\n", string_descr);
 552 
 553                 if (usba_device_struct.usb_product_str == NULL) {
 554                         (void) strcpy(string_descr, "<No Product String>");
 555                 } else {
 556                         if (mdb_readstr(string_descr, USB_MAXSTRINGLEN,
 557                             (uintptr_t)usba_device_struct.usb_product_str) ==
 558                             -1) {
 559                                 mdb_warn("failed to read product string "
 560                                     "descriptor");
 561                                 (void) strcpy(string_descr, "???");
 562                         }
 563                 }
 564                 mdb_printf("    Product String:\t\t%s\n", string_descr);
 565 
 566                 if (usba_device_struct.usb_serialno_str == NULL) {
 567                         (void) strcpy(string_descr, "<No SerialNumber String>");
 568                 } else {
 569                         if (mdb_readstr(string_descr, USB_MAXSTRINGLEN,
 570                             (uintptr_t)usba_device_struct.usb_serialno_str) ==
 571                             -1) {
 572                                 mdb_warn("failed to read serial number string "
 573                                     "descriptor");
 574                                 (void) strcpy(string_descr, "???");
 575                         }
 576                 }
 577                 mdb_printf("    SerialNumber String:\t%s\n", string_descr);
 578 
 579                 if (no_driver_attached) {
 580                         mdb_printf("\n");
 581                 } else {
 582                         mdb_printf("      state_p: ");
 583 
 584                         /*
 585                          * Given the dip, find the associated statep. The
 586                          * convention to generate this soft state anchor is:
 587                          *      <driver_name>_statep
 588                          */
 589                         (void) mdb_snprintf(drv_statep, sizeof (drv_statep),
 590                             "%s_statep", dname);
 591                         if (mdb_devinfo2statep(dip_addr, drv_statep,
 592                             &statep) == -1) {
 593                                 mdb_warn("failed to find %s state struct for "
 594                                     "dip %p", drv_statep, dip_addr);
 595 
 596                                 return (DCMD_ERR);
 597                         }
 598                         mdb_printf("%-?p\n", statep);
 599                 }
 600 
 601                 config_cloud = (char **)mdb_alloc(sizeof (void *) *
 602                     usba_device_struct.usb_n_cfgs, UM_GC);
 603 
 604                 conf_str_descr = (char **)mdb_alloc(sizeof (void *) *
 605                     usba_device_struct.usb_n_cfgs, UM_GC);
 606 
 607                 if ((usba_device_struct.usb_cfg_array) &&
 608                     (usba_device_struct.usb_cfg_str_descr)) {
 609                         if ((mdb_vread(config_cloud,  sizeof (void *) *
 610                             usba_device_struct.usb_n_cfgs,
 611                             (uintptr_t)usba_device_struct.usb_cfg_array) ==
 612                             -1) || (mdb_vread(conf_str_descr, sizeof (void *)
 613                             * usba_device_struct.usb_n_cfgs, (uintptr_t)
 614                             usba_device_struct.usb_cfg_str_descr)) == -1) {
 615 
 616                             mdb_warn("failed to read config cloud pointers");
 617 
 618                         } else {
 619 
 620                                 mdb_printf("\n    Device Config Clouds:\n"
 621                                     "    Index\tConfig\t\tConfiguration "
 622                                     "String\n"
 623                                     "    -----\t------\t\t"
 624                                     "--------------------\n");
 625 
 626                                 for (i = 0; i < usba_device_struct.usb_n_cfgs;
 627                                     i++) {
 628                                         if (mdb_readstr(string_descr,
 629                                             USB_MAXSTRINGLEN,
 630                                             (uintptr_t)conf_str_descr[i]) ==
 631                                             -1) {
 632                                                 (void) strcpy(string_descr,
 633                                                     "<No Configuration "
 634                                                     "String>");
 635                                         }
 636                                         mdb_printf("    %4d\t0x%p\t%s\n", i,
 637                                             config_cloud[i], string_descr);
 638                                 }
 639                         }
 640                 }
 641 
 642                 mdb_printf("\n    Active configuration index: %d\n",
 643                     usba_device_struct.usb_active_cfg_ndx);
 644         }
 645 
 646         if (usb_flag & USB_DUMP_ACTIVE_PIPES) {
 647 
 648                 if (mdb_pwalk_dcmd("usb_pipe_handle", "usb_pipe_handle",
 649                     0, NULL, addr) == -1) {
 650                         mdb_warn("failed to walk usb_pipe_handle");
 651                         return (DCMD_ERR);
 652                 }
 653         }
 654 
 655         return (DCMD_OK);
 656 }
 657 
 658 
 659 /*
 660  * Dump the contents of the usba_debug_buf, from the oldest to newest,
 661  * wrapping around if necessary.
 662  */
 663 /*ARGSUSED*/
 664 int
 665 usba_debug_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 666 {
 667         char    *debug_buf_addr;        /* addr in core */
 668         char    *local_debug_buf;       /* local copy of buf */
 669         int     debug_buf_size;
 670         char    *term_p;
 671         int     being_cleared;
 672 
 673         if (flags & DCMD_ADDRSPEC) {
 674 
 675                 return (DCMD_USAGE);
 676         }
 677 
 678         if (mdb_readvar(&being_cleared, "usba_clear_debug_buf_flag") ==
 679             -1) {
 680                 mdb_warn("failed to read usba_clear_debug_buf_flag");
 681 
 682                 return (DCMD_ERR);
 683         }
 684         if (being_cleared) {
 685 
 686                 return (DCMD_OK);
 687         }
 688 
 689         if (mdb_readvar(&debug_buf_addr, "usba_debug_buf") == -1) {
 690                 mdb_warn("failed to read usba_debug_buf");
 691 
 692                 return (DCMD_ERR);
 693         }
 694 
 695         if (debug_buf_addr == NULL) {
 696                 mdb_warn("usba_debug_buf not allocated\n");
 697 
 698                 return (DCMD_OK);
 699         }
 700 
 701 
 702         if (mdb_readvar(&debug_buf_size, "usba_debug_buf_size") == -1) {
 703                 mdb_warn("failed to read usba_debug_buf_size");
 704 
 705                 return (DCMD_ERR);
 706         }
 707 
 708         debug_buf_size += USB_DEBUG_SIZE_EXTRA_ALLOC;
 709         local_debug_buf = (char *)mdb_alloc(debug_buf_size, UM_SLEEP | UM_GC);
 710 
 711         if ((mdb_vread(local_debug_buf, debug_buf_size,
 712             (uintptr_t)debug_buf_addr)) == -1) {
 713                 mdb_warn("failed to read usba_debug_buf at %p",
 714                     local_debug_buf);
 715 
 716                 return (DCMD_ERR);
 717         }
 718         local_debug_buf[debug_buf_size - 1] = '\0';
 719 
 720         if (strlen(local_debug_buf) == 0) {
 721 
 722                 return (DCMD_OK);
 723         }
 724 
 725         if ((term_p = strstr(local_debug_buf, ">>>>")) == NULL) {
 726                 mdb_warn("failed to find terminator \">>>>\"\n");
 727 
 728                 return (DCMD_ERR);
 729         }
 730 
 731         /*
 732          * Print the chunk of buffer from the terminator to the end.
 733          * This will print a null string if no wrap has occurred yet.
 734          */
 735         mdb_printf("%s", term_p+5);     /* after >>>>\0 to end of buf */
 736         mdb_printf("%s\n", local_debug_buf);    /* beg of buf to >>>>\0 */
 737 
 738         return (DCMD_OK);
 739 }
 740 
 741 /*ARGSUSED*/
 742 int
 743 usba_clear_debug_buf(
 744         uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 745 {
 746         int clear = 1;
 747 
 748         /* stop the tracing */
 749         if (mdb_writevar((void*)&clear, "usba_clear_debug_buf_flag") == -1) {
 750                 mdb_warn("failed to set usba_clear_debug_buf_flag");
 751 
 752                 return (DCMD_ERR);
 753         }
 754 
 755         return (DCMD_OK);
 756 }
 757 
 758 /* prtusb entries */
 759 extern int prtusb(uintptr_t, uint_t, int, const mdb_arg_t *);
 760 
 761 extern void prt_usb_usage(void);
 762 
 763 /*
 764  * MDB module linkage information:
 765  *
 766  * We declare a list of structures describing our dcmds, and a function
 767  * named _mdb_init to return a pointer to our module information.
 768  */
 769 static const mdb_dcmd_t dcmds[] = {
 770         { "usb_pipe_handle", ":",
 771             "print a usb_pipe_handle struct", usb_pipe_handle, NULL},
 772         { "usba_device", ": [-pv]",
 773             "print summary info for a usba_device_t struct", usba_device, NULL},
 774         { "usba_debug_buf", NULL,
 775             "print usba_debug_buf", usba_debug_buf, NULL},
 776         { "usba_clear_debug_buf", NULL,
 777             "clear usba_debug_buf", usba_clear_debug_buf, NULL},
 778         { "prtusb", "?[-t] [-v] [-i index]",
 779             "print trees and descriptors for usba_device_t",
 780             prtusb, prt_usb_usage},
 781         { NULL }
 782 };
 783 
 784 static const mdb_walker_t walkers[] = {
 785         /* Generic list walker. */
 786         { "usba_list_entry", "walk list of usba_list_entry_t structures",
 787             usba_list_walk_init, usba_list_walk_step, NULL, NULL },
 788         { "usb_pipe_handle", "walk USB pipe handles, given a usba_device_t ptr",
 789             usb_pipe_handle_walk_init, usb_pipe_handle_walk_step, NULL, NULL },
 790         { "usba_device", "walk global list of usba_device_t structures",
 791             usba_device_walk_init, usba_list_walk_step, NULL, NULL },
 792         { NULL }
 793 };
 794 
 795 static const mdb_modinfo_t modinfo = {
 796         MDB_API_VERSION, dcmds, walkers
 797 };
 798 
 799 const mdb_modinfo_t *
 800 _mdb_init(void)
 801 {
 802         return (&modinfo);
 803 }