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
find_dip(uintptr_t dip_addr,const void * local_dip,void * cb_arg)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)) == 0) {
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
usba_device2dip(uintptr_t usb_dev_addr,uintptr_t * dip_addr)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
usba_list_walk_init(mdb_walk_state_t * wsp)184 usba_list_walk_init(mdb_walk_state_t *wsp)
185 {
186 /* Must have a start addr. */
187 if (wsp->walk_addr == 0) {
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
usba_list_walk_step(mdb_walk_state_t * wsp)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 == 0) {
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
usb_pipe_handle_walk_init(mdb_walk_state_t * wsp)240 usb_pipe_handle_walk_init(mdb_walk_state_t *wsp)
241 {
242 if (wsp->walk_addr == 0) {
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
usb_pipe_handle_walk_step(mdb_walk_state_t * wsp)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
usb_pipe_handle(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
usba_device_walk_init(mdb_walk_state_t * wsp)404 usba_device_walk_init(mdb_walk_state_t *wsp)
405 {
406 usba_list_entry_t list_entry;
407
408 if (wsp->walk_addr != 0) {
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
usba_hubd_walk_init(mdb_walk_state_t * wsp)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
usba_hubd_walk_step(mdb_walk_state_t * wsp)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
usba_device(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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 = 0;
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 = 0;
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
usba_debug_buf(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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) == 0) {
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
usba_clear_debug_buf(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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 *
_mdb_init(void)871 _mdb_init(void)
872 {
873 return (&modinfo);
874 }
875