xref: /titanic_44/usr/src/cmd/mdb/common/modules/uhci/uhci.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <gelf.h>
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <sys/mdb_modapi.h>
32*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_ks.h>
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_types.h>
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhci.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhciutil.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate #define	UHCI_TD	0
43*7c478bd9Sstevel@tonic-gate #define	UHCI_QH	1
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate /* Prototypes */
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate int	uhci_td(uintptr_t, uint_t, int, const mdb_arg_t *);
49*7c478bd9Sstevel@tonic-gate int	uhci_qh(uintptr_t, uint_t, int, const mdb_arg_t *);
50*7c478bd9Sstevel@tonic-gate int	uhci_td_walk_init(mdb_walk_state_t *);
51*7c478bd9Sstevel@tonic-gate int	uhci_td_walk_step(mdb_walk_state_t *);
52*7c478bd9Sstevel@tonic-gate int	uhci_qh_walk_init(mdb_walk_state_t *);
53*7c478bd9Sstevel@tonic-gate int	uhci_qh_walk_step(mdb_walk_state_t *);
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate /*
57*7c478bd9Sstevel@tonic-gate  * Callback for find_uhci_statep (called back from walk "softstate" in
58*7c478bd9Sstevel@tonic-gate  * find_uhci_statep).
59*7c478bd9Sstevel@tonic-gate  *
60*7c478bd9Sstevel@tonic-gate  * - uhci_instancep is the value of the current pointer in the array of soft
61*7c478bd9Sstevel@tonic-gate  * state instance pointers (see i_ddi_soft_state in ddi_impldefs.h)
62*7c478bd9Sstevel@tonic-gate  * - local_ss is a pointer to the copy of the i_ddi_soft_state in local space
63*7c478bd9Sstevel@tonic-gate  * - cb_arg is a pointer to the cb arg (an instance of state_find_data).
64*7c478bd9Sstevel@tonic-gate  *
65*7c478bd9Sstevel@tonic-gate  * For the current uchi_state_t*, see if the td address is in its pool.
66*7c478bd9Sstevel@tonic-gate  *
67*7c478bd9Sstevel@tonic-gate  * Returns WALK_NEXT on success (match not found yet), WALK_ERR on errors.
68*7c478bd9Sstevel@tonic-gate  *
69*7c478bd9Sstevel@tonic-gate  * WALK_DONE is returned, cb_data.found is set to TRUE, and
70*7c478bd9Sstevel@tonic-gate  * *cb_data.fic_uhci_statep is filled in with the contents of the state
71*7c478bd9Sstevel@tonic-gate  * struct in core. This forces the walk to terminate.
72*7c478bd9Sstevel@tonic-gate  */
73*7c478bd9Sstevel@tonic-gate typedef struct find_instance_struct {
74*7c478bd9Sstevel@tonic-gate 	void		*fic_td_qh;	/* td/qh we want uhci instance for */
75*7c478bd9Sstevel@tonic-gate 	boolean_t	fic_td_or_qh;	/* which one td_qh points to */
76*7c478bd9Sstevel@tonic-gate 	boolean_t	fic_found;
77*7c478bd9Sstevel@tonic-gate 	uhci_state_t	*fic_uhci_statep; /* buffer uhci_state's written into */
78*7c478bd9Sstevel@tonic-gate } find_instance_cb_t;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
81*7c478bd9Sstevel@tonic-gate static int
find_uhci_instance(uintptr_t uhci_instancep,const void * local_ss,void * cb_arg)82*7c478bd9Sstevel@tonic-gate find_uhci_instance(uintptr_t uhci_instancep, const void *local_ss, void *cb_arg)
83*7c478bd9Sstevel@tonic-gate {
84*7c478bd9Sstevel@tonic-gate 	int			td_pool_size, qh_pool_size;
85*7c478bd9Sstevel@tonic-gate 	find_instance_cb_t	*cb_data = (find_instance_cb_t *)cb_arg;
86*7c478bd9Sstevel@tonic-gate 	uhci_state_t		*uhcip = cb_data->fic_uhci_statep;
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(cb_data->fic_uhci_statep, sizeof (uhci_state_t),
90*7c478bd9Sstevel@tonic-gate 	    uhci_instancep) == -1) {
91*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read uhci_state at %p", uhci_instancep);
92*7c478bd9Sstevel@tonic-gate 		return (-1);
93*7c478bd9Sstevel@tonic-gate 	}
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&td_pool_size, sizeof (int), "uhci_td_pool_size") ==
96*7c478bd9Sstevel@tonic-gate 	    -1) {
97*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read uhci_td_pool_size");
98*7c478bd9Sstevel@tonic-gate 		return (-1);
99*7c478bd9Sstevel@tonic-gate 	}
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&qh_pool_size, sizeof (int), "uhci_qh_pool_size") ==
102*7c478bd9Sstevel@tonic-gate 	    -1) {
103*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read uhci_td_pool_size");
104*7c478bd9Sstevel@tonic-gate 		return (-1);
105*7c478bd9Sstevel@tonic-gate 	}
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	/*
108*7c478bd9Sstevel@tonic-gate 	 * See if the addr is within the appropriate pool for this instance.
109*7c478bd9Sstevel@tonic-gate 	 */
110*7c478bd9Sstevel@tonic-gate 	if ((cb_data->fic_td_or_qh == UHCI_TD &&
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	    ((uhci_td_t *)cb_data->fic_td_qh >= uhcip->uhci_td_pool_addr &&
113*7c478bd9Sstevel@tonic-gate 	    (uhci_td_t *)cb_data->fic_td_qh <= (uhcip->uhci_td_pool_addr +
114*7c478bd9Sstevel@tonic-gate 	    td_pool_size - sizeof (uhci_td_t)))) ||
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	    (cb_data->fic_td_or_qh == UHCI_QH &&
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	    ((queue_head_t *)cb_data->fic_td_qh >= uhcip->uhci_qh_pool_addr &&
119*7c478bd9Sstevel@tonic-gate 	    (queue_head_t *)cb_data->fic_td_qh <= (uhcip->uhci_qh_pool_addr +
120*7c478bd9Sstevel@tonic-gate 	    qh_pool_size - sizeof (queue_head_t))))) {
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 		/* td/qh address is within pool for this instance of uhci. */
123*7c478bd9Sstevel@tonic-gate 		cb_data->fic_found = TRUE;
124*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
125*7c478bd9Sstevel@tonic-gate 	}
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
128*7c478bd9Sstevel@tonic-gate }
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate /*
131*7c478bd9Sstevel@tonic-gate  * Figure out which instance of uhci owns a td/qh.
132*7c478bd9Sstevel@tonic-gate  *
133*7c478bd9Sstevel@tonic-gate  * - td_qh: a pointer to a uhci td or qh
134*7c478bd9Sstevel@tonic-gate  * - td_or_qh: a flag indicating which it is (td/qh),
135*7c478bd9Sstevel@tonic-gate  * - uhci_statep, pointer to a uhci_state_t, to be filled in with data from
136*7c478bd9Sstevel@tonic-gate  * the found instance of uhci_state_t.
137*7c478bd9Sstevel@tonic-gate  *
138*7c478bd9Sstevel@tonic-gate  * Only works for Cntl/Interrupt tds/qhs; others are dynamically allocated
139*7c478bd9Sstevel@tonic-gate  * and so cannot be found with this method.
140*7c478bd9Sstevel@tonic-gate  *
141*7c478bd9Sstevel@tonic-gate  * Returns 0 on success (no match found), 1 on success (match found),
142*7c478bd9Sstevel@tonic-gate  * -1 on errors.
143*7c478bd9Sstevel@tonic-gate  */
144*7c478bd9Sstevel@tonic-gate static int
find_uhci_statep(void * td_qh,boolean_t td_or_qh,uhci_state_t * uhci_statep)145*7c478bd9Sstevel@tonic-gate find_uhci_statep(void *td_qh, boolean_t td_or_qh, uhci_state_t *uhci_statep)
146*7c478bd9Sstevel@tonic-gate {
147*7c478bd9Sstevel@tonic-gate 	find_instance_cb_t	cb_data;
148*7c478bd9Sstevel@tonic-gate 	uintptr_t		uhci_ss;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	if (uhci_statep == NULL) {
152*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to find uhci statep: "
153*7c478bd9Sstevel@tonic-gate 		    "NULL uhci_statep param\n");
154*7c478bd9Sstevel@tonic-gate 		return (-1);
155*7c478bd9Sstevel@tonic-gate 	}
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	cb_data.fic_td_qh = td_qh;
158*7c478bd9Sstevel@tonic-gate 	cb_data.fic_td_or_qh = td_or_qh;
159*7c478bd9Sstevel@tonic-gate 	cb_data.fic_found = FALSE;
160*7c478bd9Sstevel@tonic-gate 	cb_data.fic_uhci_statep = uhci_statep;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&uhci_ss, sizeof (uhci_statep),
164*7c478bd9Sstevel@tonic-gate 	    "uhci_statep") == -1) {
165*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read uhci_statep");
166*7c478bd9Sstevel@tonic-gate 		return (-1);
167*7c478bd9Sstevel@tonic-gate 	}
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	/*
171*7c478bd9Sstevel@tonic-gate 	 * Walk all instances of uhci.
172*7c478bd9Sstevel@tonic-gate 	 * The callback func checks if td_qh belongs to a given instance
173*7c478bd9Sstevel@tonic-gate 	 * of uhci.
174*7c478bd9Sstevel@tonic-gate 	 */
175*7c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("softstate", find_uhci_instance, &cb_data,
176*7c478bd9Sstevel@tonic-gate 	    uhci_ss) != 0) {
177*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to walk softstate");
178*7c478bd9Sstevel@tonic-gate 		return (-1);
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	if (cb_data.fic_found == TRUE) {
182*7c478bd9Sstevel@tonic-gate 		return (1);
183*7c478bd9Sstevel@tonic-gate 	}
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	return (0);
186*7c478bd9Sstevel@tonic-gate }
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate /*
189*7c478bd9Sstevel@tonic-gate  * Dump a UHCI TD (transaction descriptor);
190*7c478bd9Sstevel@tonic-gate  * or (-d) the chain of TDs starting with the one specified.
191*7c478bd9Sstevel@tonic-gate  */
192*7c478bd9Sstevel@tonic-gate int
uhci_td(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)193*7c478bd9Sstevel@tonic-gate uhci_td(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
194*7c478bd9Sstevel@tonic-gate {
195*7c478bd9Sstevel@tonic-gate 	uint_t		depth_flag = FALSE;
196*7c478bd9Sstevel@tonic-gate 	uhci_state_t	uhci_state, *uhcip = &uhci_state;
197*7c478bd9Sstevel@tonic-gate 	uhci_td_t	td;
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
201*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	if (addr & ~QH_LINK_PTR_MASK) {
204*7c478bd9Sstevel@tonic-gate 		mdb_warn("address must be on a 16-byte boundary.\n");
205*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
206*7c478bd9Sstevel@tonic-gate 	}
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
209*7c478bd9Sstevel@tonic-gate 	    'd', MDB_OPT_SETBITS, TRUE, &depth_flag,
210*7c478bd9Sstevel@tonic-gate 	    NULL) != argc) {
211*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
212*7c478bd9Sstevel@tonic-gate 	}
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	if (depth_flag) {
216*7c478bd9Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("uhci_td", "uhci_td", 0, NULL, addr) == -1) {
217*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk 'uhci_td'");
218*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
219*7c478bd9Sstevel@tonic-gate 		}
220*7c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
221*7c478bd9Sstevel@tonic-gate 	}
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	if (find_uhci_statep((void *)addr, UHCI_TD, uhcip) != 1) {
225*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to find uhci_statep");
226*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
227*7c478bd9Sstevel@tonic-gate 	}
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&td, sizeof (td), addr) != sizeof (td))  {
230*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read td at vaddr %p", addr);
231*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
232*7c478bd9Sstevel@tonic-gate 	}
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n  UHCI td struct at (vaddr) %08x:\n", addr);
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	if (!(td.link_ptr & HC_END_OF_LIST) && td.link_ptr != NULL) {
237*7c478bd9Sstevel@tonic-gate 		mdb_printf("        link_ptr (paddr)    : %-8x        "
238*7c478bd9Sstevel@tonic-gate 		    "(vaddr)      : %p\n",
239*7c478bd9Sstevel@tonic-gate 		    td.link_ptr,
240*7c478bd9Sstevel@tonic-gate 		    /* Note: uhcip needed by TD_VADDR macro */
241*7c478bd9Sstevel@tonic-gate 		    TD_VADDR(td.link_ptr & QH_LINK_PTR_MASK));
242*7c478bd9Sstevel@tonic-gate 	} else {
243*7c478bd9Sstevel@tonic-gate 		mdb_printf("        link_ptr (paddr)    : %-8x\n",
244*7c478bd9Sstevel@tonic-gate 		    td.link_ptr);
245*7c478bd9Sstevel@tonic-gate 	}
246*7c478bd9Sstevel@tonic-gate 	mdb_printf("        td_dword2           : %08x\n", td.dw2);
247*7c478bd9Sstevel@tonic-gate 	mdb_printf("        td_dword3           : %08x\n", td.dw3);
248*7c478bd9Sstevel@tonic-gate 	mdb_printf("        buffer_address      : %08x\n", td.buffer_address);
249*7c478bd9Sstevel@tonic-gate 	mdb_printf("        qh_td_prev          : %?p        "
250*7c478bd9Sstevel@tonic-gate 	    "tw_td_next   : %?p\n",
251*7c478bd9Sstevel@tonic-gate 	    td.qh_td_prev, td.tw_td_next);
252*7c478bd9Sstevel@tonic-gate 	mdb_printf("        outst_td_prev        : %?p        "
253*7c478bd9Sstevel@tonic-gate 	    "outst_td_next : %?p\n",
254*7c478bd9Sstevel@tonic-gate 	    td.outst_td_prev, td.outst_td_next);
255*7c478bd9Sstevel@tonic-gate 	mdb_printf("        tw                  : %?p        "
256*7c478bd9Sstevel@tonic-gate 	    "flag         : %02x\n", td.tw, td.flag);
257*7c478bd9Sstevel@tonic-gate 	mdb_printf("        isoc_next           : %?p        "
258*7c478bd9Sstevel@tonic-gate 	    "isoc_prev    : %0x\n", td.isoc_next, td.isoc_prev);
259*7c478bd9Sstevel@tonic-gate 	mdb_printf("        isoc_pkt_index      : %0x        "
260*7c478bd9Sstevel@tonic-gate 	    "startingframe: %0x\n", td.isoc_pkt_index, td.starting_frame);
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (td.link_ptr == NULL)  {
264*7c478bd9Sstevel@tonic-gate 		mdb_printf("        --> Link pointer = NULL\n");
265*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
266*7c478bd9Sstevel@tonic-gate 	} else {
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 		/* Inform user if link is to a TD or QH.  */
269*7c478bd9Sstevel@tonic-gate 		if (td.link_ptr & HC_END_OF_LIST)  {
270*7c478bd9Sstevel@tonic-gate 			mdb_printf("        "
271*7c478bd9Sstevel@tonic-gate 			    "--> Link pointer invalid (terminate bit set).\n");
272*7c478bd9Sstevel@tonic-gate 		} else {
273*7c478bd9Sstevel@tonic-gate 			if ((td.link_ptr & HC_QUEUE_HEAD) == HC_QUEUE_HEAD)  {
274*7c478bd9Sstevel@tonic-gate 				mdb_printf("        "
275*7c478bd9Sstevel@tonic-gate 				    "--> Link pointer points to a QH.\n");
276*7c478bd9Sstevel@tonic-gate 			} else {
277*7c478bd9Sstevel@tonic-gate 				mdb_printf("        "
278*7c478bd9Sstevel@tonic-gate 				    "--> Link pointer points to a TD.\n");
279*7c478bd9Sstevel@tonic-gate 			}
280*7c478bd9Sstevel@tonic-gate 		}
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
284*7c478bd9Sstevel@tonic-gate }
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate /*
287*7c478bd9Sstevel@tonic-gate  * Dump a UHCI QH (queue head).
288*7c478bd9Sstevel@tonic-gate  * -b walk/dump the chian of QHs starting with the one specified.
289*7c478bd9Sstevel@tonic-gate  * -d also dump the chain of TDs starting with the one specified.
290*7c478bd9Sstevel@tonic-gate  */
291*7c478bd9Sstevel@tonic-gate int
uhci_qh(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)292*7c478bd9Sstevel@tonic-gate uhci_qh(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
293*7c478bd9Sstevel@tonic-gate {
294*7c478bd9Sstevel@tonic-gate 	uint_t		breadth_flag = FALSE, depth_flag = FALSE;
295*7c478bd9Sstevel@tonic-gate 	uhci_state_t	uhci_state, *uhcip = &uhci_state;
296*7c478bd9Sstevel@tonic-gate 	queue_head_t	qh;
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
300*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	if (addr & ~QH_LINK_PTR_MASK) {
303*7c478bd9Sstevel@tonic-gate 		mdb_warn("address must be on a 16-byte boundary.\n");
304*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
308*7c478bd9Sstevel@tonic-gate 	    'b', MDB_OPT_SETBITS, TRUE, &breadth_flag,
309*7c478bd9Sstevel@tonic-gate 	    'd', MDB_OPT_SETBITS, TRUE, &depth_flag,
310*7c478bd9Sstevel@tonic-gate 	    NULL) != argc) {
311*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	if (breadth_flag) {
316*7c478bd9Sstevel@tonic-gate 		uint_t		new_argc = 0;
317*7c478bd9Sstevel@tonic-gate 		mdb_arg_t	new_argv[1];
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 		if (depth_flag) {
321*7c478bd9Sstevel@tonic-gate 			new_argc = 1;
322*7c478bd9Sstevel@tonic-gate 			new_argv[0].a_type = MDB_TYPE_STRING;
323*7c478bd9Sstevel@tonic-gate 			new_argv[0].a_un.a_str = "-d";
324*7c478bd9Sstevel@tonic-gate 		}
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 		if ((mdb_pwalk_dcmd("uhci_qh", "uhci_qh", new_argc, new_argv,
327*7c478bd9Sstevel@tonic-gate 		    addr)) != 0)  {
328*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk 'uhci_qh'");
329*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
330*7c478bd9Sstevel@tonic-gate 		}
331*7c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
332*7c478bd9Sstevel@tonic-gate 	}
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	if (find_uhci_statep((void *)addr, UHCI_QH, uhcip) != 1) {
336*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to find uhci_statep");
337*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
338*7c478bd9Sstevel@tonic-gate 	}
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&qh, sizeof (qh), addr) != sizeof (qh))  {
342*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read qh at vaddr %p", addr);
343*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
344*7c478bd9Sstevel@tonic-gate 	}
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n  UHCI qh struct at (vaddr) %08x:\n", addr);
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	if (!(qh.link_ptr & HC_END_OF_LIST) && qh.link_ptr != NULL) {
349*7c478bd9Sstevel@tonic-gate 		mdb_printf("        link_ptr (paddr)    : %08x        "
350*7c478bd9Sstevel@tonic-gate 		    "(vaddr)      : %p\n",
351*7c478bd9Sstevel@tonic-gate 		    qh.link_ptr,
352*7c478bd9Sstevel@tonic-gate 		    /* Note: uhcip needed by QH_VADDR macro */
353*7c478bd9Sstevel@tonic-gate 		    QH_VADDR(qh.link_ptr & QH_LINK_PTR_MASK));
354*7c478bd9Sstevel@tonic-gate 	} else {
355*7c478bd9Sstevel@tonic-gate 		mdb_printf(
356*7c478bd9Sstevel@tonic-gate 		    "        link_ptr (paddr)    : %08x\n",
357*7c478bd9Sstevel@tonic-gate 		    qh.link_ptr);
358*7c478bd9Sstevel@tonic-gate 	}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	if (!(qh.element_ptr & HC_END_OF_LIST) && qh.element_ptr != NULL) {
361*7c478bd9Sstevel@tonic-gate 		mdb_printf("        element_ptr (paddr) : %08x        "
362*7c478bd9Sstevel@tonic-gate 		    "(vaddr)      : %p\n",
363*7c478bd9Sstevel@tonic-gate 		    qh.element_ptr,
364*7c478bd9Sstevel@tonic-gate 		    /* Note: uhcip needed by TD_VADDR macro */
365*7c478bd9Sstevel@tonic-gate 		    TD_VADDR(qh.element_ptr & QH_LINK_PTR_MASK));
366*7c478bd9Sstevel@tonic-gate 	} else {
367*7c478bd9Sstevel@tonic-gate 		mdb_printf(
368*7c478bd9Sstevel@tonic-gate 		    "        element_ptr (paddr) : %08x\n", qh.element_ptr);
369*7c478bd9Sstevel@tonic-gate 	}
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	mdb_printf("        node                : %04x            "
372*7c478bd9Sstevel@tonic-gate 	    "flag         : %04x\n",
373*7c478bd9Sstevel@tonic-gate 	    qh.node, qh.qh_flag);
374*7c478bd9Sstevel@tonic-gate 	mdb_printf("        prev_qh             : %?p        "
375*7c478bd9Sstevel@tonic-gate 	    "td_tailp     : %?p\n",
376*7c478bd9Sstevel@tonic-gate 	    qh.prev_qh, qh.td_tailp);
377*7c478bd9Sstevel@tonic-gate 	mdb_printf("        bulk_xfer_isoc_info : %?p\n", qh.bulk_xfer_info);
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	if (qh.link_ptr == NULL)  {
381*7c478bd9Sstevel@tonic-gate 		mdb_printf("        --> Link pointer = NULL\n");
382*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
383*7c478bd9Sstevel@tonic-gate 	} else {
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 		/* Inform user if next link is a TD or QH.  */
386*7c478bd9Sstevel@tonic-gate 		if (qh.link_ptr & HC_END_OF_LIST)  {
387*7c478bd9Sstevel@tonic-gate 			mdb_printf("        "
388*7c478bd9Sstevel@tonic-gate 			    "--> Link pointer invalid (terminate bit set).\n");
389*7c478bd9Sstevel@tonic-gate 		} else {
390*7c478bd9Sstevel@tonic-gate 			if ((qh.link_ptr & HC_QUEUE_HEAD) == HC_QUEUE_HEAD)  {
391*7c478bd9Sstevel@tonic-gate 				mdb_printf("        "
392*7c478bd9Sstevel@tonic-gate 				    "--> Link pointer points to a QH.\n");
393*7c478bd9Sstevel@tonic-gate 			} else {
394*7c478bd9Sstevel@tonic-gate 				/* Should never happen. */
395*7c478bd9Sstevel@tonic-gate 				mdb_warn("        "
396*7c478bd9Sstevel@tonic-gate 				    "--> Link pointer points to a TD.\n");
397*7c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
398*7c478bd9Sstevel@tonic-gate 			}
399*7c478bd9Sstevel@tonic-gate 		}
400*7c478bd9Sstevel@tonic-gate 	}
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	if (qh.element_ptr == NULL)  {
404*7c478bd9Sstevel@tonic-gate 		mdb_printf("        element_ptr = NULL\n");
405*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
406*7c478bd9Sstevel@tonic-gate 	} else {
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 		/* Inform user if next element is a TD or QH.  */
409*7c478bd9Sstevel@tonic-gate 		if (qh.element_ptr & HC_END_OF_LIST)  {
410*7c478bd9Sstevel@tonic-gate 			mdb_printf("        "
411*7c478bd9Sstevel@tonic-gate 			    "-->Element pointer invalid (terminate bit set)."
412*7c478bd9Sstevel@tonic-gate 			    "\n");
413*7c478bd9Sstevel@tonic-gate 			return (DCMD_OK);
414*7c478bd9Sstevel@tonic-gate 		} else {
415*7c478bd9Sstevel@tonic-gate 			if ((qh.element_ptr & HC_QUEUE_HEAD) == HC_QUEUE_HEAD) {
416*7c478bd9Sstevel@tonic-gate 				mdb_printf("        "
417*7c478bd9Sstevel@tonic-gate 				    "--> Element pointer points to a QH.\n");
418*7c478bd9Sstevel@tonic-gate 				/* Should never happen in UHCI implementation */
419*7c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
420*7c478bd9Sstevel@tonic-gate 			} else {
421*7c478bd9Sstevel@tonic-gate 				mdb_printf("        "
422*7c478bd9Sstevel@tonic-gate 				    "--> Element pointer points to a TD.\n");
423*7c478bd9Sstevel@tonic-gate 			}
424*7c478bd9Sstevel@tonic-gate 		}
425*7c478bd9Sstevel@tonic-gate 	}
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	/*
428*7c478bd9Sstevel@tonic-gate 	 * If the user specified the -d (depth) option,
429*7c478bd9Sstevel@tonic-gate 	 * dump all TDs linked to this TD via the element_ptr.
430*7c478bd9Sstevel@tonic-gate 	 */
431*7c478bd9Sstevel@tonic-gate 	if (depth_flag) {
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 		/* Traverse and display all the TDs in the chain */
434*7c478bd9Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("uhci_td", "uhci_td", argc, argv,
435*7c478bd9Sstevel@tonic-gate 		    (uintptr_t)(TD_VADDR(qh.element_ptr &
436*7c478bd9Sstevel@tonic-gate 		    QH_LINK_PTR_MASK))) == -1) {
437*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk 'uhci_td'");
438*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
439*7c478bd9Sstevel@tonic-gate 		}
440*7c478bd9Sstevel@tonic-gate 	}
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
443*7c478bd9Sstevel@tonic-gate }
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate /*
446*7c478bd9Sstevel@tonic-gate  * Walk a list of UHCI Transaction Descriptors (td's).
447*7c478bd9Sstevel@tonic-gate  * Stop at the end of the list, or if the next element in the list is a
448*7c478bd9Sstevel@tonic-gate  * queue head (qh).
449*7c478bd9Sstevel@tonic-gate  * User must specify the address of the first td to look at.
450*7c478bd9Sstevel@tonic-gate  */
451*7c478bd9Sstevel@tonic-gate int
uhci_td_walk_init(mdb_walk_state_t * wsp)452*7c478bd9Sstevel@tonic-gate uhci_td_walk_init(mdb_walk_state_t *wsp)
453*7c478bd9Sstevel@tonic-gate {
454*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)  {
455*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
456*7c478bd9Sstevel@tonic-gate 	}
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (uhci_td_t), UM_SLEEP | UM_GC);
459*7c478bd9Sstevel@tonic-gate 	wsp->walk_arg = mdb_alloc(sizeof (uhci_state_t), UM_SLEEP | UM_GC);
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	/*
463*7c478bd9Sstevel@tonic-gate 	 * Read the uhci_state_t for the instance of uhci
464*7c478bd9Sstevel@tonic-gate 	 * using this td address into buf pointed to by walk_arg.
465*7c478bd9Sstevel@tonic-gate 	 */
466*7c478bd9Sstevel@tonic-gate 	if (find_uhci_statep((void *)wsp->walk_addr, UHCI_TD,
467*7c478bd9Sstevel@tonic-gate 	    wsp->walk_arg) != 1) {
468*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to find uhci_statep");
469*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
470*7c478bd9Sstevel@tonic-gate 	}
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
473*7c478bd9Sstevel@tonic-gate }
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate /*
476*7c478bd9Sstevel@tonic-gate  * At each step, read a TD into our private storage, and then invoke
477*7c478bd9Sstevel@tonic-gate  * the callback function.  We terminate when we reach a QH, or
478*7c478bd9Sstevel@tonic-gate  * link_ptr is NULL.
479*7c478bd9Sstevel@tonic-gate  */
480*7c478bd9Sstevel@tonic-gate int
uhci_td_walk_step(mdb_walk_state_t * wsp)481*7c478bd9Sstevel@tonic-gate uhci_td_walk_step(mdb_walk_state_t *wsp)
482*7c478bd9Sstevel@tonic-gate {
483*7c478bd9Sstevel@tonic-gate 	int status;
484*7c478bd9Sstevel@tonic-gate 	uhci_state_t	*uhcip = (uhci_state_t *)wsp->walk_arg;
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (uhci_td_t), wsp->walk_addr)
488*7c478bd9Sstevel@tonic-gate 		== -1) {
489*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read td at %p", wsp->walk_addr);
490*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
491*7c478bd9Sstevel@tonic-gate 	}
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
494*7c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	/* Next td. */
497*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = ((uhci_td_t *)wsp->walk_data)->link_ptr;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	/* Check if we're at the last element */
500*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL || wsp->walk_addr & HC_END_OF_LIST)
501*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	/* Make sure next element is a TD.  If a QH, stop.  */
504*7c478bd9Sstevel@tonic-gate 	if (((((uhci_td_t *)wsp->walk_data)->link_ptr) & HC_QUEUE_HEAD)
505*7c478bd9Sstevel@tonic-gate 	    == HC_QUEUE_HEAD)  {
506*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
507*7c478bd9Sstevel@tonic-gate 	}
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	/* Strip terminate etc. bits.  */
510*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr &= QH_LINK_PTR_MASK; /* there is no TD_LINK_PTR_MASK */
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
513*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	/*
516*7c478bd9Sstevel@tonic-gate 	 * Convert link_ptr paddr to vaddr
517*7c478bd9Sstevel@tonic-gate 	 * Note: uhcip needed by TD_VADDR macro
518*7c478bd9Sstevel@tonic-gate 	 */
519*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)TD_VADDR(wsp->walk_addr);
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	return (status);
522*7c478bd9Sstevel@tonic-gate }
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate /*
525*7c478bd9Sstevel@tonic-gate  * Walk a list of UHCI Queue Heads (qh's).
526*7c478bd9Sstevel@tonic-gate  * Stop at the end of the list, or if the next element in the list is a
527*7c478bd9Sstevel@tonic-gate  * Transaction Descriptor (td).
528*7c478bd9Sstevel@tonic-gate  * User must specify the address of the first qh to look at.
529*7c478bd9Sstevel@tonic-gate  */
530*7c478bd9Sstevel@tonic-gate int
uhci_qh_walk_init(mdb_walk_state_t * wsp)531*7c478bd9Sstevel@tonic-gate uhci_qh_walk_init(mdb_walk_state_t *wsp)
532*7c478bd9Sstevel@tonic-gate {
533*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
534*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (queue_head_t), UM_SLEEP | UM_GC);
537*7c478bd9Sstevel@tonic-gate 	wsp->walk_arg = mdb_alloc(sizeof (uhci_state_t), UM_SLEEP | UM_GC);
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	/*
541*7c478bd9Sstevel@tonic-gate 	 * Read the uhci_state_t for the instance of uhci
542*7c478bd9Sstevel@tonic-gate 	 * using this td address into buf pointed to by walk_arg.
543*7c478bd9Sstevel@tonic-gate 	 */
544*7c478bd9Sstevel@tonic-gate 	if (find_uhci_statep((void *)wsp->walk_addr, UHCI_QH,
545*7c478bd9Sstevel@tonic-gate 	    (uhci_state_t *)wsp->walk_arg) != 1) {
546*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to find uhci_statep");
547*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
548*7c478bd9Sstevel@tonic-gate 	}
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
551*7c478bd9Sstevel@tonic-gate }
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate /*
554*7c478bd9Sstevel@tonic-gate  * At each step, read a QH into our private storage, and then invoke
555*7c478bd9Sstevel@tonic-gate  * the callback function.  We terminate when we reach a QH, or
556*7c478bd9Sstevel@tonic-gate  * link_ptr is NULL.
557*7c478bd9Sstevel@tonic-gate  */
558*7c478bd9Sstevel@tonic-gate int
uhci_qh_walk_step(mdb_walk_state_t * wsp)559*7c478bd9Sstevel@tonic-gate uhci_qh_walk_step(mdb_walk_state_t *wsp)
560*7c478bd9Sstevel@tonic-gate {
561*7c478bd9Sstevel@tonic-gate 	int status;
562*7c478bd9Sstevel@tonic-gate 	uhci_state_t	*uhcip = (uhci_state_t *)wsp->walk_arg;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)	/* Should never occur */
566*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (queue_head_t), wsp->walk_addr)
569*7c478bd9Sstevel@tonic-gate 	    == -1) {
570*7c478bd9Sstevel@tonic-gate 		mdb_warn("failure reading qh at %p", wsp->walk_addr);
571*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
572*7c478bd9Sstevel@tonic-gate 	}
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
575*7c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	/* Next QH. */
578*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = ((queue_head_t *)wsp->walk_data)->link_ptr;
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	/* Check if we're at the last element */
582*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL || wsp->walk_addr & HC_END_OF_LIST)  {
583*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
584*7c478bd9Sstevel@tonic-gate 	}
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	/* Make sure next element is a QH.  If a TD, stop.  */
587*7c478bd9Sstevel@tonic-gate 	if (!  ((((queue_head_t *)wsp->walk_data)->link_ptr) & HC_QUEUE_HEAD)
588*7c478bd9Sstevel@tonic-gate 	    == HC_QUEUE_HEAD)  {
589*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
590*7c478bd9Sstevel@tonic-gate 	}
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	/* Strip terminate etc. bits.  */
593*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr &= QH_LINK_PTR_MASK;
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
596*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	/*
599*7c478bd9Sstevel@tonic-gate 	 * Convert link_ptr paddr to vaddr
600*7c478bd9Sstevel@tonic-gate 	 * Note: uhcip needed by QH_VADDR macro
601*7c478bd9Sstevel@tonic-gate 	 */
602*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)QH_VADDR(wsp->walk_addr);
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	return (status);
605*7c478bd9Sstevel@tonic-gate }
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate /*
608*7c478bd9Sstevel@tonic-gate  * MDB module linkage information:
609*7c478bd9Sstevel@tonic-gate  *
610*7c478bd9Sstevel@tonic-gate  * We declare a list of structures describing our dcmds, and a function
611*7c478bd9Sstevel@tonic-gate  * named _mdb_init to return a pointer to our module information.
612*7c478bd9Sstevel@tonic-gate  */
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
615*7c478bd9Sstevel@tonic-gate 	{ "uhci_td", ": [-d]", "print UHCI TD", uhci_td, NULL },
616*7c478bd9Sstevel@tonic-gate 	{ "uhci_qh", ": [-bd]", "print UHCI QH", uhci_qh, NULL},
617*7c478bd9Sstevel@tonic-gate 	{ NULL }
618*7c478bd9Sstevel@tonic-gate };
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate static const mdb_walker_t walkers[] = {
622*7c478bd9Sstevel@tonic-gate 	{ "uhci_td", "walk list of UHCI TD structures",
623*7c478bd9Sstevel@tonic-gate 	    uhci_td_walk_init, uhci_td_walk_step, NULL,
624*7c478bd9Sstevel@tonic-gate 	    NULL },
625*7c478bd9Sstevel@tonic-gate 	{ "uhci_qh", "walk list of UHCI QH structures",
626*7c478bd9Sstevel@tonic-gate 	    uhci_qh_walk_init, uhci_qh_walk_step, NULL,
627*7c478bd9Sstevel@tonic-gate 	    NULL },
628*7c478bd9Sstevel@tonic-gate 	{ NULL }
629*7c478bd9Sstevel@tonic-gate };
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate static const mdb_modinfo_t modinfo = {
632*7c478bd9Sstevel@tonic-gate 	MDB_API_VERSION, dcmds, walkers
633*7c478bd9Sstevel@tonic-gate };
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate const mdb_modinfo_t *
_mdb_init(void)637*7c478bd9Sstevel@tonic-gate _mdb_init(void)
638*7c478bd9Sstevel@tonic-gate {
639*7c478bd9Sstevel@tonic-gate 	return (&modinfo);
640*7c478bd9Sstevel@tonic-gate }
641