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