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 /*
30*7c478bd9Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
33*7c478bd9Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
34*7c478bd9Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * This module contains the EHCI driver interrupt code, which handles all
37*7c478bd9Sstevel@tonic-gate  * Checking of status of USB transfers, error recovery and callbacks.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate /*
45*7c478bd9Sstevel@tonic-gate  * EHCI Interrupt Handling functions.
46*7c478bd9Sstevel@tonic-gate  */
47*7c478bd9Sstevel@tonic-gate void		ehci_handle_ue(ehci_state_t		*ehcip);
48*7c478bd9Sstevel@tonic-gate void		ehci_handle_frame_list_rollover(
49*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
50*7c478bd9Sstevel@tonic-gate void		ehci_handle_endpoint_reclaimation(
51*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
52*7c478bd9Sstevel@tonic-gate void		ehci_traverse_active_qtd_list(
53*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
54*7c478bd9Sstevel@tonic-gate static ehci_qtd_t *ehci_create_done_qtd_list(
55*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip);
56*7c478bd9Sstevel@tonic-gate static usb_cr_t ehci_parse_error(
57*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
58*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
59*7c478bd9Sstevel@tonic-gate usb_cr_t	ehci_check_for_error(
60*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
61*7c478bd9Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
62*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
63*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
64*7c478bd9Sstevel@tonic-gate 				uint_t			ctrl);
65*7c478bd9Sstevel@tonic-gate static usb_cr_t	ehci_check_for_short_xfer(
66*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
67*7c478bd9Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
68*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
69*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
70*7c478bd9Sstevel@tonic-gate void		ehci_handle_error(
71*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
72*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
73*7c478bd9Sstevel@tonic-gate 				usb_cr_t		error);
74*7c478bd9Sstevel@tonic-gate static void	ehci_cleanup_data_underrun(
75*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
76*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
77*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
78*7c478bd9Sstevel@tonic-gate static void	ehci_handle_normal_qtd(
79*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
80*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
81*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw);
82*7c478bd9Sstevel@tonic-gate void		ehci_handle_ctrl_qtd(
83*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
84*7c478bd9Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
85*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
86*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
87*7c478bd9Sstevel@tonic-gate 				void			*);
88*7c478bd9Sstevel@tonic-gate void		ehci_handle_bulk_qtd(
89*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
90*7c478bd9Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
91*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
92*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
93*7c478bd9Sstevel@tonic-gate 				void			*);
94*7c478bd9Sstevel@tonic-gate void		ehci_handle_intr_qtd(
95*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
96*7c478bd9Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
97*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
98*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
99*7c478bd9Sstevel@tonic-gate 				void			*);
100*7c478bd9Sstevel@tonic-gate static void	ehci_handle_one_xfer_completion(
101*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
102*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw);
103*7c478bd9Sstevel@tonic-gate static void	ehci_sendup_qtd_message(
104*7c478bd9Sstevel@tonic-gate 				ehci_state_t		*ehcip,
105*7c478bd9Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
106*7c478bd9Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
107*7c478bd9Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
108*7c478bd9Sstevel@tonic-gate 				usb_cr_t		error);
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate /*
112*7c478bd9Sstevel@tonic-gate  * Interrupt Handling functions
113*7c478bd9Sstevel@tonic-gate  */
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate /*
116*7c478bd9Sstevel@tonic-gate  * ehci_handle_ue:
117*7c478bd9Sstevel@tonic-gate  *
118*7c478bd9Sstevel@tonic-gate  * Handling of Unrecoverable Error interrupt (UE).
119*7c478bd9Sstevel@tonic-gate  */
120*7c478bd9Sstevel@tonic-gate void
121*7c478bd9Sstevel@tonic-gate ehci_handle_ue(ehci_state_t	*ehcip)
122*7c478bd9Sstevel@tonic-gate {
123*7c478bd9Sstevel@tonic-gate 	usb_frame_number_t	before_frame_number, after_frame_number;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
128*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_ue: Handling of UE interrupt");
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	/*
131*7c478bd9Sstevel@tonic-gate 	 * First check whether current UE error occurred due to USB or
132*7c478bd9Sstevel@tonic-gate 	 * due to some other subsystem. This can be verified by reading
133*7c478bd9Sstevel@tonic-gate 	 * usb frame numbers before & after a delay of few milliseconds.
134*7c478bd9Sstevel@tonic-gate 	 * If usb frame number read after delay is greater than the one
135*7c478bd9Sstevel@tonic-gate 	 * read before delay, then, USB subsystem is fine. In this case,
136*7c478bd9Sstevel@tonic-gate 	 * disable UE error interrupt and return without shutdowning the
137*7c478bd9Sstevel@tonic-gate 	 * USB subsystem.
138*7c478bd9Sstevel@tonic-gate 	 *
139*7c478bd9Sstevel@tonic-gate 	 * Otherwise, if usb frame number read after delay is less than
140*7c478bd9Sstevel@tonic-gate 	 * or equal to one read before the delay, then, current UE error
141*7c478bd9Sstevel@tonic-gate 	 * occurred from USB subsystem. In this case,go ahead with actual
142*7c478bd9Sstevel@tonic-gate 	 * UE error recovery procedure.
143*7c478bd9Sstevel@tonic-gate 	 *
144*7c478bd9Sstevel@tonic-gate 	 * Get the current usb frame number before waiting for few
145*7c478bd9Sstevel@tonic-gate 	 * milliseconds.
146*7c478bd9Sstevel@tonic-gate 	 */
147*7c478bd9Sstevel@tonic-gate 	before_frame_number = ehci_get_current_frame_number(ehcip);
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	/* Wait for few milliseconds */
150*7c478bd9Sstevel@tonic-gate 	drv_usecwait(EHCI_TIMEWAIT);
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	/*
153*7c478bd9Sstevel@tonic-gate 	 * Get the current usb frame number after waiting for
154*7c478bd9Sstevel@tonic-gate 	 * milliseconds.
155*7c478bd9Sstevel@tonic-gate 	 */
156*7c478bd9Sstevel@tonic-gate 	after_frame_number = ehci_get_current_frame_number(ehcip);
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
159*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_ue: Before Frame Number 0x%llx "
160*7c478bd9Sstevel@tonic-gate 	    "After Frame Number 0x%llx", before_frame_number,
161*7c478bd9Sstevel@tonic-gate 	    after_frame_number);
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	if (after_frame_number > before_frame_number) {
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 		/* Disable UE interrupt */
166*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt, (Get_OpReg(ehci_interrupt) &
167*7c478bd9Sstevel@tonic-gate 		    ~EHCI_INTR_HOST_SYSTEM_ERROR));
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 		return;
170*7c478bd9Sstevel@tonic-gate 	}
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	/*
173*7c478bd9Sstevel@tonic-gate 	 * This UE is due to USB hardware error. Reset ehci controller
174*7c478bd9Sstevel@tonic-gate 	 * and reprogram to bring it back to functional state.
175*7c478bd9Sstevel@tonic-gate 	 */
176*7c478bd9Sstevel@tonic-gate 	if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) {
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
179*7c478bd9Sstevel@tonic-gate 		    "Unrecoverable USB Hardware Error");
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 		/* Disable UE interrupt */
182*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt, (Get_OpReg(ehci_interrupt) &
183*7c478bd9Sstevel@tonic-gate 		    ~EHCI_INTR_HOST_SYSTEM_ERROR));
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 		/* Route all Root hub ports to Classic host controller */
186*7c478bd9Sstevel@tonic-gate 		Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 		/* Set host controller soft state to error */
189*7c478bd9Sstevel@tonic-gate 		ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
190*7c478bd9Sstevel@tonic-gate 	}
191*7c478bd9Sstevel@tonic-gate }
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate /*
195*7c478bd9Sstevel@tonic-gate  * ehci_handle_frame_list_rollover:
196*7c478bd9Sstevel@tonic-gate  *
197*7c478bd9Sstevel@tonic-gate  * Update software based usb frame number part on every frame number
198*7c478bd9Sstevel@tonic-gate  * overflow interrupt.
199*7c478bd9Sstevel@tonic-gate  *
200*7c478bd9Sstevel@tonic-gate  * Refer ehci spec 1.0, section 2.3.2, page 21 for more details.
201*7c478bd9Sstevel@tonic-gate  *
202*7c478bd9Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
203*7c478bd9Sstevel@tonic-gate  */
204*7c478bd9Sstevel@tonic-gate void
205*7c478bd9Sstevel@tonic-gate ehci_handle_frame_list_rollover(ehci_state_t *ehcip)
206*7c478bd9Sstevel@tonic-gate {
207*7c478bd9Sstevel@tonic-gate 	ehcip->ehci_fno += (0x4000 -
208*7c478bd9Sstevel@tonic-gate 	    (((Get_OpReg(ehci_frame_index) & 0x3FFF) ^
209*7c478bd9Sstevel@tonic-gate 	    ehcip->ehci_fno) & 0x2000));
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
212*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_frame_list_rollover:"
213*7c478bd9Sstevel@tonic-gate 	    "Frame Number Higher Part 0x%llx\n", ehcip->ehci_fno);
214*7c478bd9Sstevel@tonic-gate }
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate /*
218*7c478bd9Sstevel@tonic-gate  * ehci_handle_endpoint_reclamation:
219*7c478bd9Sstevel@tonic-gate  *
220*7c478bd9Sstevel@tonic-gate  * Reclamation of Host Controller (HC) Endpoint Descriptors (QH).
221*7c478bd9Sstevel@tonic-gate  */
222*7c478bd9Sstevel@tonic-gate void
223*7c478bd9Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehci_state_t	*ehcip)
224*7c478bd9Sstevel@tonic-gate {
225*7c478bd9Sstevel@tonic-gate 	usb_frame_number_t	current_frame_number;
226*7c478bd9Sstevel@tonic-gate 	usb_frame_number_t	endpoint_frame_number;
227*7c478bd9Sstevel@tonic-gate 	ehci_qh_t		*reclaim_qh;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
230*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_endpoint_reclamation:");
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	current_frame_number = ehci_get_current_frame_number(ehcip);
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	/*
237*7c478bd9Sstevel@tonic-gate 	 * Deallocate all Endpoint Descriptors (QH) which are on the
238*7c478bd9Sstevel@tonic-gate 	 * reclamation list. These QH's are already removed from the
239*7c478bd9Sstevel@tonic-gate 	 * interrupt lattice tree.
240*7c478bd9Sstevel@tonic-gate 	 */
241*7c478bd9Sstevel@tonic-gate 	while (ehcip->ehci_reclaim_list) {
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 		reclaim_qh = ehcip->ehci_reclaim_list;
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 		endpoint_frame_number = (usb_frame_number_t)(uintptr_t)
246*7c478bd9Sstevel@tonic-gate 		    (EHCI_LOOKUP_ID(Get_QH(reclaim_qh->qh_reclaim_frame)));
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
249*7c478bd9Sstevel@tonic-gate 		    "ehci_handle_endpoint_reclamation:"
250*7c478bd9Sstevel@tonic-gate 		    "current frame number 0x%llx endpoint frame number 0x%llx",
251*7c478bd9Sstevel@tonic-gate 		    current_frame_number, endpoint_frame_number);
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 		/*
254*7c478bd9Sstevel@tonic-gate 		 * Deallocate current endpoint only if endpoint's usb frame
255*7c478bd9Sstevel@tonic-gate 		 * number is less than or equal to current usb frame number.
256*7c478bd9Sstevel@tonic-gate 		 *
257*7c478bd9Sstevel@tonic-gate 		 * If endpoint's usb frame number is greater than the current
258*7c478bd9Sstevel@tonic-gate 		 * usb frame number, ignore rest of the endpoints in the list
259*7c478bd9Sstevel@tonic-gate 		 * since rest of the endpoints are inserted into the reclaim
260*7c478bd9Sstevel@tonic-gate 		 * list later than the current reclaim endpoint.
261*7c478bd9Sstevel@tonic-gate 		 */
262*7c478bd9Sstevel@tonic-gate 		if (endpoint_frame_number > current_frame_number) {
263*7c478bd9Sstevel@tonic-gate 			break;
264*7c478bd9Sstevel@tonic-gate 		}
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 		/* Get the next endpoint from the rec. list */
267*7c478bd9Sstevel@tonic-gate 		ehcip->ehci_reclaim_list = ehci_qh_iommu_to_cpu(
268*7c478bd9Sstevel@tonic-gate 		    ehcip, Get_QH(reclaim_qh->qh_reclaim_next));
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 		/* Free 32bit ID */
271*7c478bd9Sstevel@tonic-gate 		EHCI_FREE_ID((uint32_t)Get_QH(reclaim_qh->qh_reclaim_frame));
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 		/* Deallocate the endpoint */
274*7c478bd9Sstevel@tonic-gate 		ehci_deallocate_qh(ehcip, reclaim_qh);
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate }
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate /*
280*7c478bd9Sstevel@tonic-gate  * ehci_traverse_active_qtd_list:
281*7c478bd9Sstevel@tonic-gate  */
282*7c478bd9Sstevel@tonic-gate void
283*7c478bd9Sstevel@tonic-gate ehci_traverse_active_qtd_list(
284*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip)
285*7c478bd9Sstevel@tonic-gate {
286*7c478bd9Sstevel@tonic-gate 	uint_t			state;		/* QTD state */
287*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd = NULL; /* QTD pointers */
288*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*next_qtd = NULL; /* QTD pointers */
289*7c478bd9Sstevel@tonic-gate 	usb_cr_t		error;		/* Error from QTD */
290*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw = NULL;	/* Transfer wrapper */
291*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = NULL;	/* Pipe private field */
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
294*7c478bd9Sstevel@tonic-gate 	    "ehci_traverse_active_qtd_list:");
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	/* Sync QH and QTD pool */
299*7c478bd9Sstevel@tonic-gate 	Sync_QH_QTD_Pool(ehcip);
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	/* Create done qtd list */
302*7c478bd9Sstevel@tonic-gate 	curr_qtd = ehci_create_done_qtd_list(ehcip);
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	/* Traverse the list of transfer descriptors */
305*7c478bd9Sstevel@tonic-gate 	while (curr_qtd) {
306*7c478bd9Sstevel@tonic-gate 		/* Get next qtd from the active qtd list */
307*7c478bd9Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
308*7c478bd9Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 		/* Check for QTD state */
311*7c478bd9Sstevel@tonic-gate 		state = Get_QTD(curr_qtd->qtd_state);
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
314*7c478bd9Sstevel@tonic-gate 		    "ehci_traverse_active_qtd_list:\n\t"
315*7c478bd9Sstevel@tonic-gate 		    "curr_qtd = 0x%p state = 0x%x", (void *)curr_qtd, state);
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 		/* Obtain the  transfer wrapper  for this QTD */
318*7c478bd9Sstevel@tonic-gate 		tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID(
319*7c478bd9Sstevel@tonic-gate 		    (uint32_t)Get_QTD(curr_qtd->qtd_trans_wrapper));
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 		ASSERT(tw != NULL);
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 		pp = tw->tw_pipe_private;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
326*7c478bd9Sstevel@tonic-gate 		    "ehci_traverse_active_qtd_list: "
327*7c478bd9Sstevel@tonic-gate 		    "PP = 0x%p TW = 0x%p", pp, tw);
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 		/*
330*7c478bd9Sstevel@tonic-gate 		 * A QTD that is marked as RECLAIM has already been
331*7c478bd9Sstevel@tonic-gate 		 * processed by QTD timeout handler & client driver
332*7c478bd9Sstevel@tonic-gate 		 * has been informed through exception callback.
333*7c478bd9Sstevel@tonic-gate 		 */
334*7c478bd9Sstevel@tonic-gate 		if (state != EHCI_QTD_RECLAIM) {
335*7c478bd9Sstevel@tonic-gate 			/* Look at the error status */
336*7c478bd9Sstevel@tonic-gate 			error = ehci_parse_error(ehcip, curr_qtd);
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 			if (error == USB_CR_OK) {
339*7c478bd9Sstevel@tonic-gate 				ehci_handle_normal_qtd(ehcip, curr_qtd, tw);
340*7c478bd9Sstevel@tonic-gate 			} else {
341*7c478bd9Sstevel@tonic-gate 				/* handle the error condition */
342*7c478bd9Sstevel@tonic-gate 				ehci_handle_error(ehcip, curr_qtd, error);
343*7c478bd9Sstevel@tonic-gate 			}
344*7c478bd9Sstevel@tonic-gate 		} else {
345*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
346*7c478bd9Sstevel@tonic-gate 			    "ehci_traverse_active_qtd_list: "
347*7c478bd9Sstevel@tonic-gate 			    "QTD State = %d", state);
348*7c478bd9Sstevel@tonic-gate 		}
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 		/* Deallocate this transfer descriptor */
351*7c478bd9Sstevel@tonic-gate 		ehci_deallocate_qtd(ehcip, curr_qtd);
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 		/*
354*7c478bd9Sstevel@tonic-gate 		 * Deallocate the transfer wrapper if there are no more
355*7c478bd9Sstevel@tonic-gate 		 * QTD's for the transfer wrapper.  ehci_deallocate_tw()
356*7c478bd9Sstevel@tonic-gate 		 * will  not deallocate the tw for a periodic  endpoint
357*7c478bd9Sstevel@tonic-gate 		 * since it will always have a QTD attached to it.
358*7c478bd9Sstevel@tonic-gate 		 */
359*7c478bd9Sstevel@tonic-gate 		ehci_deallocate_tw(ehcip, pp, tw);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 		curr_qtd = next_qtd;
362*7c478bd9Sstevel@tonic-gate 	}
363*7c478bd9Sstevel@tonic-gate }
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate /*
367*7c478bd9Sstevel@tonic-gate  * ehci_create_done_qtd_list:
368*7c478bd9Sstevel@tonic-gate  *
369*7c478bd9Sstevel@tonic-gate  * Create done qtd list from active qtd list.
370*7c478bd9Sstevel@tonic-gate  */
371*7c478bd9Sstevel@tonic-gate ehci_qtd_t *
372*7c478bd9Sstevel@tonic-gate ehci_create_done_qtd_list(
373*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip)
374*7c478bd9Sstevel@tonic-gate {
375*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd = NULL, *next_qtd = NULL;
376*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*done_qtd_list = NULL, *last_done_qtd = NULL;
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
379*7c478bd9Sstevel@tonic-gate 	    "ehci_create_done_qtd_list:");
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	curr_qtd = ehcip->ehci_active_qtd_list;
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	while (curr_qtd) {
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 		/* Get next qtd from the active qtd list */
388*7c478bd9Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
389*7c478bd9Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 		/* Check this QTD has been processed by Host Controller */
392*7c478bd9Sstevel@tonic-gate 		if (!(Get_QTD(curr_qtd->qtd_ctrl) &
393*7c478bd9Sstevel@tonic-gate 		    EHCI_QTD_CTRL_ACTIVE_XACT)) {
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 			/* Remove this QTD from active QTD list */
396*7c478bd9Sstevel@tonic-gate 			ehci_remove_qtd_from_active_qtd_list(ehcip, curr_qtd);
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 			Set_QTD(curr_qtd->qtd_active_qtd_next, NULL);
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 			if (done_qtd_list) {
401*7c478bd9Sstevel@tonic-gate 				Set_QTD(last_done_qtd->qtd_active_qtd_next,
402*7c478bd9Sstevel@tonic-gate 				    ehci_qtd_cpu_to_iommu(ehcip, curr_qtd));
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 				last_done_qtd = curr_qtd;
405*7c478bd9Sstevel@tonic-gate 			} else {
406*7c478bd9Sstevel@tonic-gate 				done_qtd_list = curr_qtd;
407*7c478bd9Sstevel@tonic-gate 				last_done_qtd = curr_qtd;
408*7c478bd9Sstevel@tonic-gate 			}
409*7c478bd9Sstevel@tonic-gate 		}
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 		curr_qtd = next_qtd;
412*7c478bd9Sstevel@tonic-gate 	}
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	return (done_qtd_list);
415*7c478bd9Sstevel@tonic-gate }
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate /*
419*7c478bd9Sstevel@tonic-gate  * ehci_parse_error:
420*7c478bd9Sstevel@tonic-gate  *
421*7c478bd9Sstevel@tonic-gate  * Parse the result for any errors.
422*7c478bd9Sstevel@tonic-gate  */
423*7c478bd9Sstevel@tonic-gate static	usb_cr_t
424*7c478bd9Sstevel@tonic-gate ehci_parse_error(
425*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
426*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate 	uint_t			ctrl;
429*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
430*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
431*7c478bd9Sstevel@tonic-gate 	uint_t			flag;
432*7c478bd9Sstevel@tonic-gate 	usb_cr_t		error;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
435*7c478bd9Sstevel@tonic-gate 	    "ehci_parse_error:");
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	ASSERT(qtd != NULL);
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	/* Obtain the transfer wrapper from the QTD */
442*7c478bd9Sstevel@tonic-gate 	tw = (ehci_trans_wrapper_t *)
443*7c478bd9Sstevel@tonic-gate 	    EHCI_LOOKUP_ID((uint32_t)Get_QTD(qtd->qtd_trans_wrapper));
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	ASSERT(tw != NULL);
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	/* Obtain the pipe private structure */
448*7c478bd9Sstevel@tonic-gate 	pp = tw->tw_pipe_private;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
451*7c478bd9Sstevel@tonic-gate 	    "ehci_parse_error: PP 0x%p TW 0x%p", pp, tw);
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	ctrl = (uint_t)Get_QTD(qtd->qtd_ctrl);
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	/*
456*7c478bd9Sstevel@tonic-gate 	 * Check the condition code of completed QTD and report errors
457*7c478bd9Sstevel@tonic-gate 	 * if any. This checking will be done both for the general and
458*7c478bd9Sstevel@tonic-gate 	 * the isochronous QTDs.
459*7c478bd9Sstevel@tonic-gate 	 */
460*7c478bd9Sstevel@tonic-gate 	if ((error = ehci_check_for_error(ehcip, pp, tw, qtd, ctrl)) !=
461*7c478bd9Sstevel@tonic-gate 	    USB_CR_OK) {
462*7c478bd9Sstevel@tonic-gate 		flag = EHCI_REMOVE_XFER_ALWAYS;
463*7c478bd9Sstevel@tonic-gate 	} else {
464*7c478bd9Sstevel@tonic-gate 		flag  = EHCI_REMOVE_XFER_IFLAST;
465*7c478bd9Sstevel@tonic-gate 	}
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	/* Stop the transfer timer */
468*7c478bd9Sstevel@tonic-gate 	ehci_stop_xfer_timer(ehcip, tw, flag);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	return (error);
471*7c478bd9Sstevel@tonic-gate }
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate /*
475*7c478bd9Sstevel@tonic-gate  * ehci_check_for_error:
476*7c478bd9Sstevel@tonic-gate  *
477*7c478bd9Sstevel@tonic-gate  * Check for any errors.
478*7c478bd9Sstevel@tonic-gate  *
479*7c478bd9Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
480*7c478bd9Sstevel@tonic-gate  */
481*7c478bd9Sstevel@tonic-gate usb_cr_t
482*7c478bd9Sstevel@tonic-gate ehci_check_for_error(
483*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
484*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
485*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
486*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
487*7c478bd9Sstevel@tonic-gate 	uint_t			ctrl)
488*7c478bd9Sstevel@tonic-gate {
489*7c478bd9Sstevel@tonic-gate 	usb_cr_t		error = USB_CR_OK;
490*7c478bd9Sstevel@tonic-gate 	uint_t			status, speed, mask;
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
493*7c478bd9Sstevel@tonic-gate 	    "ehci_check_for_error: qtd = 0x%p ctrl = 0x%x",
494*7c478bd9Sstevel@tonic-gate 	    qtd, ctrl);
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	/*
497*7c478bd9Sstevel@tonic-gate 	 * Find the usb device speed and get the corresponding
498*7c478bd9Sstevel@tonic-gate 	 * error status mask.
499*7c478bd9Sstevel@tonic-gate 	 */
500*7c478bd9Sstevel@tonic-gate 	speed = Get_QH(pp->pp_qh->qh_ctrl) & EHCI_QH_CTRL_ED_SPEED;
501*7c478bd9Sstevel@tonic-gate 	mask = (speed == EHCI_QH_CTRL_ED_HIGH_SPEED)?
502*7c478bd9Sstevel@tonic-gate 	    EHCI_QTD_CTRL_HS_XACT_STATUS : EHCI_QTD_CTRL_NON_HS_XACT_STATUS;
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	/* Exclude halted transaction error condition */
505*7c478bd9Sstevel@tonic-gate 	status = ctrl & EHCI_QTD_CTRL_XACT_STATUS & ~EHCI_QTD_CTRL_HALTED_XACT;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	switch (status & mask) {
508*7c478bd9Sstevel@tonic-gate 	case EHCI_QTD_CTRL_NO_ERROR:
509*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
510*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_error: No Error");
511*7c478bd9Sstevel@tonic-gate 		error = USB_CR_OK;
512*7c478bd9Sstevel@tonic-gate 		break;
513*7c478bd9Sstevel@tonic-gate 	case EHCI_QTD_CTRL_ACTIVE_XACT:
514*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
515*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_error: Not accessed");
516*7c478bd9Sstevel@tonic-gate 		error = USB_CR_NOT_ACCESSED;
517*7c478bd9Sstevel@tonic-gate 		break;
518*7c478bd9Sstevel@tonic-gate 	case EHCI_QTD_CTRL_HALTED_XACT:
519*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
520*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_error: Halted");
521*7c478bd9Sstevel@tonic-gate 		error = USB_CR_STALL;
522*7c478bd9Sstevel@tonic-gate 		break;
523*7c478bd9Sstevel@tonic-gate 	case EHCI_QTD_CTRL_DATA_BUFFER_ERROR:
524*7c478bd9Sstevel@tonic-gate 		if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) {
525*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
526*7c478bd9Sstevel@tonic-gate 			    "ehci_check_for_error: Buffer Overrun");
527*7c478bd9Sstevel@tonic-gate 			error = USB_CR_BUFFER_OVERRUN;
528*7c478bd9Sstevel@tonic-gate 		} else	{
529*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
530*7c478bd9Sstevel@tonic-gate 			    "ehci_check_for_error: Buffer Underrun");
531*7c478bd9Sstevel@tonic-gate 			error = USB_CR_BUFFER_UNDERRUN;
532*7c478bd9Sstevel@tonic-gate 		}
533*7c478bd9Sstevel@tonic-gate 		break;
534*7c478bd9Sstevel@tonic-gate 	case EHCI_QTD_CTRL_BABBLE_DETECTED:
535*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
536*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_error: Babble Detected");
537*7c478bd9Sstevel@tonic-gate 		error = USB_CR_DATA_OVERRUN;
538*7c478bd9Sstevel@tonic-gate 		break;
539*7c478bd9Sstevel@tonic-gate 	case EHCI_QTD_CTRL_XACT_ERROR:
540*7c478bd9Sstevel@tonic-gate 		/*
541*7c478bd9Sstevel@tonic-gate 		 * An xacterr bit of one is not necessarily an error,
542*7c478bd9Sstevel@tonic-gate 		 * the transaction might have completed successfully
543*7c478bd9Sstevel@tonic-gate 		 * after some retries.
544*7c478bd9Sstevel@tonic-gate 		 *
545*7c478bd9Sstevel@tonic-gate 		 * Try to detect the case when the queue is halted,
546*7c478bd9Sstevel@tonic-gate 		 * because the error counter was decremented from one
547*7c478bd9Sstevel@tonic-gate 		 * down to zero after a transaction error.
548*7c478bd9Sstevel@tonic-gate 		 */
549*7c478bd9Sstevel@tonic-gate 		if (ctrl & EHCI_QTD_CTRL_HALTED_XACT && (ctrl &
550*7c478bd9Sstevel@tonic-gate 		    EHCI_QTD_CTRL_ERR_COUNT_MASK) == 0) {
551*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
552*7c478bd9Sstevel@tonic-gate 			    "ehci_check_for_error: Transaction Error");
553*7c478bd9Sstevel@tonic-gate 			error = USB_CR_DEV_NOT_RESP;
554*7c478bd9Sstevel@tonic-gate 		} else {
555*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
556*7c478bd9Sstevel@tonic-gate 			    "ehci_check_for_error: No Error");
557*7c478bd9Sstevel@tonic-gate 			error = USB_CR_OK;
558*7c478bd9Sstevel@tonic-gate 		}
559*7c478bd9Sstevel@tonic-gate 		break;
560*7c478bd9Sstevel@tonic-gate 	case EHCI_QTD_CTRL_MISSED_uFRAME:
561*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
562*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_error: Missed uFrame");
563*7c478bd9Sstevel@tonic-gate 		error = USB_CR_NOT_ACCESSED;
564*7c478bd9Sstevel@tonic-gate 		break;
565*7c478bd9Sstevel@tonic-gate 	case EHCI_QTD_CTRL_PRD_SPLIT_XACT_ERR:
566*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
567*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_error: Periodic split-transaction "
568*7c478bd9Sstevel@tonic-gate 		    "receives an error handshake");
569*7c478bd9Sstevel@tonic-gate 		error = USB_CR_UNSPECIFIED_ERR;
570*7c478bd9Sstevel@tonic-gate 		break;
571*7c478bd9Sstevel@tonic-gate 	default:
572*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
573*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_error: Unspecified Error");
574*7c478bd9Sstevel@tonic-gate 		error = USB_CR_UNSPECIFIED_ERR;
575*7c478bd9Sstevel@tonic-gate 		break;
576*7c478bd9Sstevel@tonic-gate 	}
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	/*
579*7c478bd9Sstevel@tonic-gate 	 * Check for halted transaction error condition.
580*7c478bd9Sstevel@tonic-gate 	 * Under short xfer conditions, EHCI HC will not return an error
581*7c478bd9Sstevel@tonic-gate 	 * or halt the QH.  This is done manually later in
582*7c478bd9Sstevel@tonic-gate 	 * ehci_check_for_short_xfer.
583*7c478bd9Sstevel@tonic-gate 	 */
584*7c478bd9Sstevel@tonic-gate 	if ((ctrl & EHCI_QTD_CTRL_HALTED_XACT) && (error == USB_CR_OK)) {
585*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
586*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_error: Halted");
587*7c478bd9Sstevel@tonic-gate 		error = USB_CR_STALL;
588*7c478bd9Sstevel@tonic-gate 	}
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	if (error == USB_CR_OK) {
591*7c478bd9Sstevel@tonic-gate 		error = ehci_check_for_short_xfer(ehcip, pp, tw, qtd);
592*7c478bd9Sstevel@tonic-gate 	}
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	if (error) {
595*7c478bd9Sstevel@tonic-gate 		uint_t qh_ctrl =  Get_QH(pp->pp_qh->qh_ctrl);
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
598*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_error: Error %d Device address %d "
599*7c478bd9Sstevel@tonic-gate 		    "Endpoint number %d", error,
600*7c478bd9Sstevel@tonic-gate 		    (qh_ctrl & EHCI_QH_CTRL_DEVICE_ADDRESS),
601*7c478bd9Sstevel@tonic-gate 		    ((qh_ctrl & EHCI_QH_CTRL_ED_NUMBER) >>
602*7c478bd9Sstevel@tonic-gate 		    EHCI_QH_CTRL_ED_NUMBER_SHIFT));
603*7c478bd9Sstevel@tonic-gate 	}
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	return (error);
606*7c478bd9Sstevel@tonic-gate }
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate /*
609*7c478bd9Sstevel@tonic-gate  * ehci_check_for_short_xfer:
610*7c478bd9Sstevel@tonic-gate  *
611*7c478bd9Sstevel@tonic-gate  * Check to see if there was a short xfer condition.
612*7c478bd9Sstevel@tonic-gate  *
613*7c478bd9Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
614*7c478bd9Sstevel@tonic-gate  *	 But it doesn't do anything.
615*7c478bd9Sstevel@tonic-gate  */
616*7c478bd9Sstevel@tonic-gate static usb_cr_t
617*7c478bd9Sstevel@tonic-gate ehci_check_for_short_xfer(
618*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
619*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
620*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
621*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
622*7c478bd9Sstevel@tonic-gate {
623*7c478bd9Sstevel@tonic-gate 	usb_cr_t		error = USB_CR_OK;
624*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd;
625*7c478bd9Sstevel@tonic-gate 	uchar_t			attributes;
626*7c478bd9Sstevel@tonic-gate 	uint32_t		residue = 0;
627*7c478bd9Sstevel@tonic-gate 	usb_req_attrs_t		xfer_attrs;
628*7c478bd9Sstevel@tonic-gate 	size_t			length;
629*7c478bd9Sstevel@tonic-gate 	mblk_t			*mp = NULL;
630*7c478bd9Sstevel@tonic-gate 	usb_opaque_t		xfer_reqp;
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
633*7c478bd9Sstevel@tonic-gate 	    "ehci_check_for_short_xfer:");
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	if (pp->pp_flag == EHCI_POLLED_MODE_FLAG) {
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 		return (error);
638*7c478bd9Sstevel@tonic-gate 	}
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	/*
641*7c478bd9Sstevel@tonic-gate 	 * Check for short xfer error.	If this is a control pipe, only check
642*7c478bd9Sstevel@tonic-gate 	 * if it is in the data phase.
643*7c478bd9Sstevel@tonic-gate 	 */
644*7c478bd9Sstevel@tonic-gate 	eptd = &pp->pp_pipe_handle->p_ep;
645*7c478bd9Sstevel@tonic-gate 	attributes = eptd->bmAttributes & USB_EP_ATTR_MASK;
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	switch (attributes) {
648*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
649*7c478bd9Sstevel@tonic-gate 		if (Get_QTD(qtd->qtd_ctrl_phase) !=
650*7c478bd9Sstevel@tonic-gate 		    EHCI_CTRL_DATA_PHASE) {
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 			break;
653*7c478bd9Sstevel@tonic-gate 		}
654*7c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
655*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
656*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
657*7c478bd9Sstevel@tonic-gate 		/*
658*7c478bd9Sstevel@tonic-gate 		 * If "Total bytes of xfer" in control field of
659*7c478bd9Sstevel@tonic-gate 		 * Transfer Descriptor (QTD) is not equal to zero,
660*7c478bd9Sstevel@tonic-gate 		 * then, we sent/received less data from the usb
661*7c478bd9Sstevel@tonic-gate 		 * device than requested. In that case, get the
662*7c478bd9Sstevel@tonic-gate 		 * actual received data size.
663*7c478bd9Sstevel@tonic-gate 		 */
664*7c478bd9Sstevel@tonic-gate 		residue = (Get_QTD(qtd->qtd_ctrl) &
665*7c478bd9Sstevel@tonic-gate 		    EHCI_QTD_CTRL_BYTES_TO_XFER) >>
666*7c478bd9Sstevel@tonic-gate 		    EHCI_QTD_CTRL_BYTES_TO_XFER_SHIFT;
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 		break;
669*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 		break;
672*7c478bd9Sstevel@tonic-gate 	}
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	if (residue) {
675*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
676*7c478bd9Sstevel@tonic-gate 		    "ehci_check_for_short_xfer: residue=%d direction=0x%x",
677*7c478bd9Sstevel@tonic-gate 		    residue, tw->tw_direction);
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 		length = (Get_QTD(qtd->qtd_xfer_addr) +
680*7c478bd9Sstevel@tonic-gate 		    Get_QTD(qtd->qtd_xfer_len) - residue) -
681*7c478bd9Sstevel@tonic-gate 		    tw->tw_cookie.dmac_address;
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 		if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) {
684*7c478bd9Sstevel@tonic-gate 			xfer_attrs = ehci_get_xfer_attrs(ehcip, pp, tw);
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 			if (xfer_attrs & USB_ATTRS_SHORT_XFER_OK) {
687*7c478bd9Sstevel@tonic-gate 				ehci_cleanup_data_underrun(ehcip, tw, qtd);
688*7c478bd9Sstevel@tonic-gate 			} else {
689*7c478bd9Sstevel@tonic-gate 				/* Halt the pipe to mirror OHCI behavior */
690*7c478bd9Sstevel@tonic-gate 				Set_QH(pp->pp_qh->qh_status,
691*7c478bd9Sstevel@tonic-gate 				    ((Get_QH(pp->pp_qh->qh_status) &
692*7c478bd9Sstevel@tonic-gate 					~EHCI_QH_STS_ACTIVE) |
693*7c478bd9Sstevel@tonic-gate 					EHCI_QH_STS_HALTED));
694*7c478bd9Sstevel@tonic-gate 				error = USB_CR_DATA_UNDERRUN;
695*7c478bd9Sstevel@tonic-gate 			}
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
698*7c478bd9Sstevel@tonic-gate 			    "ehci_check_for_short_xfer: requested data=%lu "
699*7c478bd9Sstevel@tonic-gate 			    "received data=%lu", tw->tw_length, length);
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 			switch (attributes) {
702*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
703*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
704*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
705*7c478bd9Sstevel@tonic-gate 				/* Save the actual received length */
706*7c478bd9Sstevel@tonic-gate 				tw->tw_length = length;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 				break;
709*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
710*7c478bd9Sstevel@tonic-gate 			default:
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 				break;
713*7c478bd9Sstevel@tonic-gate 			}
714*7c478bd9Sstevel@tonic-gate 		} else {
715*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
716*7c478bd9Sstevel@tonic-gate 			    "ehci_check_for_short_xfer: requested data=%lu "
717*7c478bd9Sstevel@tonic-gate 			    "sent data=%lu", tw->tw_length, length);
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 			xfer_reqp = tw->tw_curr_xfer_reqp;
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 			switch (attributes) {
722*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 				break;
725*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
726*7c478bd9Sstevel@tonic-gate 				mp = (mblk_t *)((usb_bulk_req_t *)
727*7c478bd9Sstevel@tonic-gate 				    (xfer_reqp))->bulk_data;
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 				/* Increment the read pointer */
730*7c478bd9Sstevel@tonic-gate 				mp->b_rptr = mp->b_rptr + length;
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 				break;
733*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
734*7c478bd9Sstevel@tonic-gate 				mp = (mblk_t *)((usb_intr_req_t *)
735*7c478bd9Sstevel@tonic-gate 				    (xfer_reqp))->intr_data;
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 				/* Increment the read pointer */
738*7c478bd9Sstevel@tonic-gate 				mp->b_rptr = mp->b_rptr + length;
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 				break;
741*7c478bd9Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
742*7c478bd9Sstevel@tonic-gate 			default:
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 				break;
745*7c478bd9Sstevel@tonic-gate 			}
746*7c478bd9Sstevel@tonic-gate 		}
747*7c478bd9Sstevel@tonic-gate 	}
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	return (error);
750*7c478bd9Sstevel@tonic-gate }
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate /*
753*7c478bd9Sstevel@tonic-gate  * ehci_handle_error:
754*7c478bd9Sstevel@tonic-gate  *
755*7c478bd9Sstevel@tonic-gate  * Inform USBA about occurred transaction errors by calling the USBA callback
756*7c478bd9Sstevel@tonic-gate  * routine.
757*7c478bd9Sstevel@tonic-gate  */
758*7c478bd9Sstevel@tonic-gate void
759*7c478bd9Sstevel@tonic-gate ehci_handle_error(
760*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
761*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
762*7c478bd9Sstevel@tonic-gate 	usb_cr_t		error)
763*7c478bd9Sstevel@tonic-gate {
764*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
765*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph;
766*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
767*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*tw_qtd = qtd;
768*7c478bd9Sstevel@tonic-gate 	uchar_t			attributes;
769*7c478bd9Sstevel@tonic-gate 	usb_intr_req_t		*curr_intr_reqp;
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
772*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_error: error = 0x%x", error);
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	ASSERT(qtd != NULL);
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	/* Print the values in the qtd */
779*7c478bd9Sstevel@tonic-gate 	ehci_print_qtd(ehcip, qtd);
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 	/* Obtain the transfer wrapper from the QTD */
782*7c478bd9Sstevel@tonic-gate 	tw = (ehci_trans_wrapper_t *)
783*7c478bd9Sstevel@tonic-gate 	    EHCI_LOOKUP_ID((uint32_t)Get_QTD(qtd->qtd_trans_wrapper));
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 	ASSERT(tw != NULL);
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 	/* Obtain the pipe private structure */
788*7c478bd9Sstevel@tonic-gate 	pp = tw->tw_pipe_private;
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	ph = tw->tw_pipe_private->pp_pipe_handle;
791*7c478bd9Sstevel@tonic-gate 	attributes = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 	/*
794*7c478bd9Sstevel@tonic-gate 	 * Mark all QTDs belongs to this TW as RECLAIM
795*7c478bd9Sstevel@tonic-gate 	 * so that we don't process them by mistake.
796*7c478bd9Sstevel@tonic-gate 	 */
797*7c478bd9Sstevel@tonic-gate 	while (tw_qtd) {
798*7c478bd9Sstevel@tonic-gate 		/* Set QTD state to RECLAIM */
799*7c478bd9Sstevel@tonic-gate 		Set_QTD(tw_qtd->qtd_state, EHCI_QTD_RECLAIM);
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 		/* Get the next QTD from the wrapper */
802*7c478bd9Sstevel@tonic-gate 		tw_qtd = ehci_qtd_iommu_to_cpu(ehcip,
803*7c478bd9Sstevel@tonic-gate 		    Get_QTD(tw_qtd->qtd_tw_next_qtd));
804*7c478bd9Sstevel@tonic-gate 	}
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	/*
807*7c478bd9Sstevel@tonic-gate 	 * Special error handling
808*7c478bd9Sstevel@tonic-gate 	 */
809*7c478bd9Sstevel@tonic-gate 	if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) {
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 		switch (attributes) {
812*7c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
813*7c478bd9Sstevel@tonic-gate 			if (((ph->p_ep.bmAttributes &
814*7c478bd9Sstevel@tonic-gate 			    USB_EP_ATTR_MASK) ==
815*7c478bd9Sstevel@tonic-gate 			    USB_EP_ATTR_CONTROL) &&
816*7c478bd9Sstevel@tonic-gate 			    (Get_QTD(qtd->qtd_ctrl_phase) ==
817*7c478bd9Sstevel@tonic-gate 			    EHCI_CTRL_SETUP_PHASE)) {
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 				break;
820*7c478bd9Sstevel@tonic-gate 			}
821*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
822*7c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
823*7c478bd9Sstevel@tonic-gate 			/*
824*7c478bd9Sstevel@tonic-gate 			 * Call ehci_sendup_qtd_message
825*7c478bd9Sstevel@tonic-gate 			 * to send message to upstream.
826*7c478bd9Sstevel@tonic-gate 			 */
827*7c478bd9Sstevel@tonic-gate 			ehci_sendup_qtd_message(ehcip, pp, tw, qtd, error);
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 			return;
830*7c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
831*7c478bd9Sstevel@tonic-gate 			curr_intr_reqp =
832*7c478bd9Sstevel@tonic-gate 			    (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 			if (curr_intr_reqp->intr_attributes &
835*7c478bd9Sstevel@tonic-gate 			    USB_ATTRS_ONE_XFER) {
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 				ehci_handle_one_xfer_completion(ehcip, tw);
838*7c478bd9Sstevel@tonic-gate 			}
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 			/* Decrement periodic in request count */
841*7c478bd9Sstevel@tonic-gate 			pp->pp_cur_periodic_req_cnt--;
842*7c478bd9Sstevel@tonic-gate 			break;
843*7c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
844*7c478bd9Sstevel@tonic-gate 			break;
845*7c478bd9Sstevel@tonic-gate 		}
846*7c478bd9Sstevel@tonic-gate 	}
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 	ehci_hcdi_callback(ph, tw, error);
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	/* Check anybody is waiting for transfers completion event */
851*7c478bd9Sstevel@tonic-gate 	ehci_check_for_transfers_completion(ehcip, pp);
852*7c478bd9Sstevel@tonic-gate }
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate /*
855*7c478bd9Sstevel@tonic-gate  * ehci_cleanup_data_underrun:
856*7c478bd9Sstevel@tonic-gate  *
857*7c478bd9Sstevel@tonic-gate  * Cleans up resources when a short xfer occurs.  Will only do cleanup if
858*7c478bd9Sstevel@tonic-gate  * this pipe supports alternate_qtds.
859*7c478bd9Sstevel@tonic-gate  *
860*7c478bd9Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
861*7c478bd9Sstevel@tonic-gate  */
862*7c478bd9Sstevel@tonic-gate static void
863*7c478bd9Sstevel@tonic-gate ehci_cleanup_data_underrun(
864*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
865*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
866*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
867*7c478bd9Sstevel@tonic-gate {
868*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*next_qtd, *temp_qtd;
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
871*7c478bd9Sstevel@tonic-gate 	    "ehci_cleanup_data_underrun: qtd=0x%p, tw=0x%p", qtd, tw);
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	/*
874*7c478bd9Sstevel@tonic-gate 	 * Check if this transfer doesn't supports short_xfer or
875*7c478bd9Sstevel@tonic-gate 	 * if this QTD is the last qtd in the tw.  If so there is
876*7c478bd9Sstevel@tonic-gate 	 * no need for cleanup.
877*7c478bd9Sstevel@tonic-gate 	 */
878*7c478bd9Sstevel@tonic-gate 	if ((tw->tw_alt_qtd == NULL) || (qtd == tw->tw_qtd_tail)) {
879*7c478bd9Sstevel@tonic-gate 		/* There is no need for cleanup */
880*7c478bd9Sstevel@tonic-gate 		return;
881*7c478bd9Sstevel@tonic-gate 	}
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 	/* Start removing all the unused QTDs from the TW */
884*7c478bd9Sstevel@tonic-gate 	next_qtd = (ehci_qtd_t *)ehci_qtd_iommu_to_cpu(ehcip,
885*7c478bd9Sstevel@tonic-gate 	    Get_QTD(qtd->qtd_tw_next_qtd));
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	while (next_qtd) {
888*7c478bd9Sstevel@tonic-gate 		tw->tw_num_qtds--;
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 		ehci_remove_qtd_from_active_qtd_list(ehcip, next_qtd);
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 		temp_qtd = next_qtd;
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
895*7c478bd9Sstevel@tonic-gate 		    Get_QTD(next_qtd->qtd_tw_next_qtd));
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 		ehci_deallocate_qtd(ehcip, temp_qtd);
898*7c478bd9Sstevel@tonic-gate 	}
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 	ASSERT(tw->tw_num_qtds == 1);
901*7c478bd9Sstevel@tonic-gate }
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate /*
904*7c478bd9Sstevel@tonic-gate  * ehci_handle_normal_qtd:
905*7c478bd9Sstevel@tonic-gate  */
906*7c478bd9Sstevel@tonic-gate static void
907*7c478bd9Sstevel@tonic-gate ehci_handle_normal_qtd(
908*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
909*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
910*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw)
911*7c478bd9Sstevel@tonic-gate {
912*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;	/* Pipe private field */
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
915*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_normal_qtd:");
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
918*7c478bd9Sstevel@tonic-gate 	ASSERT(tw != NULL);
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	/* Obtain the pipe private structure */
921*7c478bd9Sstevel@tonic-gate 	pp = tw->tw_pipe_private;
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	(*tw->tw_handle_qtd)(ehcip, pp, tw,
924*7c478bd9Sstevel@tonic-gate 	    qtd, tw->tw_handle_callback_value);
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	/* Check anybody is waiting for transfers completion event */
927*7c478bd9Sstevel@tonic-gate 	ehci_check_for_transfers_completion(ehcip, pp);
928*7c478bd9Sstevel@tonic-gate }
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate /*
932*7c478bd9Sstevel@tonic-gate  * ehci_handle_ctrl_qtd:
933*7c478bd9Sstevel@tonic-gate  *
934*7c478bd9Sstevel@tonic-gate  * Handle a control Transfer Descriptor (QTD).
935*7c478bd9Sstevel@tonic-gate  */
936*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
937*7c478bd9Sstevel@tonic-gate void
938*7c478bd9Sstevel@tonic-gate ehci_handle_ctrl_qtd(
939*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
940*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
941*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
942*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
943*7c478bd9Sstevel@tonic-gate 	void			*tw_handle_callback_value)
944*7c478bd9Sstevel@tonic-gate {
945*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
948*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_ctrl_qtd: pp = 0x%p tw = 0x%p qtd = 0x%p state = 0x%x",
949*7c478bd9Sstevel@tonic-gate 	    (void *)pp, (void *)tw, (void *)qtd, Get_QTD(qtd->qtd_ctrl_phase));
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	/*
954*7c478bd9Sstevel@tonic-gate 	 * A control transfer consists of three phases:
955*7c478bd9Sstevel@tonic-gate 	 *
956*7c478bd9Sstevel@tonic-gate 	 * Setup
957*7c478bd9Sstevel@tonic-gate 	 * Data (optional)
958*7c478bd9Sstevel@tonic-gate 	 * Status
959*7c478bd9Sstevel@tonic-gate 	 *
960*7c478bd9Sstevel@tonic-gate 	 * There is a QTD per phase. A QTD for a given phase isn't
961*7c478bd9Sstevel@tonic-gate 	 * enqueued until the previous phase is finished. EHCI
962*7c478bd9Sstevel@tonic-gate 	 * spec allows more than one  control transfer on a pipe
963*7c478bd9Sstevel@tonic-gate 	 * within a frame. However, we've found that some devices
964*7c478bd9Sstevel@tonic-gate 	 * can't handle this.
965*7c478bd9Sstevel@tonic-gate 	 */
966*7c478bd9Sstevel@tonic-gate 	tw->tw_num_qtds--;
967*7c478bd9Sstevel@tonic-gate 	switch (Get_QTD(qtd->qtd_ctrl_phase)) {
968*7c478bd9Sstevel@tonic-gate 	case EHCI_CTRL_SETUP_PHASE:
969*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
970*7c478bd9Sstevel@tonic-gate 		    "Setup complete: pp 0x%p qtd 0x%p",
971*7c478bd9Sstevel@tonic-gate 		    (void *)pp, (void *)qtd);
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 		break;
974*7c478bd9Sstevel@tonic-gate 	case EHCI_CTRL_DATA_PHASE:
975*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
976*7c478bd9Sstevel@tonic-gate 		    "Data complete: pp 0x%p qtd 0x%p",
977*7c478bd9Sstevel@tonic-gate 		    (void *)pp, (void *)qtd);
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 		break;
980*7c478bd9Sstevel@tonic-gate 	case EHCI_CTRL_STATUS_PHASE:
981*7c478bd9Sstevel@tonic-gate 		if ((tw->tw_length) &&
982*7c478bd9Sstevel@tonic-gate 		    (tw->tw_direction == EHCI_QTD_CTRL_IN_PID)) {
983*7c478bd9Sstevel@tonic-gate 			/*
984*7c478bd9Sstevel@tonic-gate 			 * Call ehci_sendup_qtd_message
985*7c478bd9Sstevel@tonic-gate 			 * to send message to upstream.
986*7c478bd9Sstevel@tonic-gate 			 */
987*7c478bd9Sstevel@tonic-gate 			ehci_sendup_qtd_message(ehcip,
988*7c478bd9Sstevel@tonic-gate 			    pp, tw, qtd, USB_CR_OK);
989*7c478bd9Sstevel@tonic-gate 		} else {
990*7c478bd9Sstevel@tonic-gate 			ehci_hcdi_callback(ph, tw, USB_CR_OK);
991*7c478bd9Sstevel@tonic-gate 		}
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
994*7c478bd9Sstevel@tonic-gate 		    "Status complete: pp 0x%p qtd 0x%p",
995*7c478bd9Sstevel@tonic-gate 		    (void *)pp, (void *)qtd);
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 		break;
998*7c478bd9Sstevel@tonic-gate 	}
999*7c478bd9Sstevel@tonic-gate }
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate /*
1003*7c478bd9Sstevel@tonic-gate  * ehci_handle_bulk_qtd:
1004*7c478bd9Sstevel@tonic-gate  *
1005*7c478bd9Sstevel@tonic-gate  * Handle a bulk Transfer Descriptor (QTD).
1006*7c478bd9Sstevel@tonic-gate  */
1007*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1008*7c478bd9Sstevel@tonic-gate void
1009*7c478bd9Sstevel@tonic-gate ehci_handle_bulk_qtd(
1010*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1011*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
1012*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
1013*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
1014*7c478bd9Sstevel@tonic-gate 	void			*tw_handle_callback_value)
1015*7c478bd9Sstevel@tonic-gate {
1016*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1017*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1020*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_bulk_qtd:");
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 	/*
1025*7c478bd9Sstevel@tonic-gate 	 * Decrement the QTDs counter and check whether all the bulk
1026*7c478bd9Sstevel@tonic-gate 	 * data has been send or received. If QTDs counter reaches
1027*7c478bd9Sstevel@tonic-gate 	 * zero then inform client driver about completion current
1028*7c478bd9Sstevel@tonic-gate 	 * bulk request. Other wise wait for completion of other bulk
1029*7c478bd9Sstevel@tonic-gate 	 * QTDs or transactions on this pipe.
1030*7c478bd9Sstevel@tonic-gate 	 */
1031*7c478bd9Sstevel@tonic-gate 	if (--tw->tw_num_qtds != 0) {
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1034*7c478bd9Sstevel@tonic-gate 		    "ehci_handle_bulk_qtd: Number of QTDs %d", tw->tw_num_qtds);
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 		return;
1037*7c478bd9Sstevel@tonic-gate 	}
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate 	/*
1040*7c478bd9Sstevel@tonic-gate 	 * If this is a bulk in pipe, return the data to the client.
1041*7c478bd9Sstevel@tonic-gate 	 * For a bulk out pipe, there is no need to do anything.
1042*7c478bd9Sstevel@tonic-gate 	 */
1043*7c478bd9Sstevel@tonic-gate 	if ((eptd->bEndpointAddress &
1044*7c478bd9Sstevel@tonic-gate 	    USB_EP_DIR_MASK) == USB_EP_DIR_OUT) {
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1047*7c478bd9Sstevel@tonic-gate 		    "ehci_handle_bulk_qtd: Bulk out pipe");
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 		/* Do the callback */
1050*7c478bd9Sstevel@tonic-gate 		ehci_hcdi_callback(ph, tw, USB_CR_OK);
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate 		return;
1053*7c478bd9Sstevel@tonic-gate 	}
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 	/* Call ehci_sendup_qtd_message to send message to upstream */
1056*7c478bd9Sstevel@tonic-gate 	ehci_sendup_qtd_message(ehcip, pp, tw, qtd, USB_CR_OK);
1057*7c478bd9Sstevel@tonic-gate }
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate /*
1061*7c478bd9Sstevel@tonic-gate  * ehci_handle_intr_qtd:
1062*7c478bd9Sstevel@tonic-gate  *
1063*7c478bd9Sstevel@tonic-gate  * Handle a interrupt Transfer Descriptor (QTD).
1064*7c478bd9Sstevel@tonic-gate  */
1065*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1066*7c478bd9Sstevel@tonic-gate void
1067*7c478bd9Sstevel@tonic-gate ehci_handle_intr_qtd(
1068*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1069*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
1070*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
1071*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
1072*7c478bd9Sstevel@tonic-gate 	void			*tw_handle_callback_value)
1073*7c478bd9Sstevel@tonic-gate {
1074*7c478bd9Sstevel@tonic-gate 	usb_intr_req_t		*curr_intr_reqp =
1075*7c478bd9Sstevel@tonic-gate 				    (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
1076*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1077*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
1078*7c478bd9Sstevel@tonic-gate 	usb_req_attrs_t		attrs;
1079*7c478bd9Sstevel@tonic-gate 	int			error = USB_SUCCESS;
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1082*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_intr_qtd:");
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 	/* Get the interrupt xfer attributes */
1087*7c478bd9Sstevel@tonic-gate 	attrs = curr_intr_reqp->intr_attributes;
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 	/*
1090*7c478bd9Sstevel@tonic-gate 	 * For a Interrupt OUT pipe, we just callback and we are done
1091*7c478bd9Sstevel@tonic-gate 	 */
1092*7c478bd9Sstevel@tonic-gate 	if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) {
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1095*7c478bd9Sstevel@tonic-gate 		    "ehci_handle_intr_qtd: Intr out pipe, intr_reqp=0x%p,"
1096*7c478bd9Sstevel@tonic-gate 		    "data=0x%p", curr_intr_reqp, curr_intr_reqp->intr_data);
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 		/* Do the callback */
1099*7c478bd9Sstevel@tonic-gate 		ehci_hcdi_callback(ph, tw, USB_CR_OK);
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate 		return;
1102*7c478bd9Sstevel@tonic-gate 	}
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 	/* Decrement number of interrupt request count */
1105*7c478bd9Sstevel@tonic-gate 	pp->pp_cur_periodic_req_cnt--;
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 	/*
1108*7c478bd9Sstevel@tonic-gate 	 * Check usb flag whether USB_FLAGS_ONE_XFER flag is set
1109*7c478bd9Sstevel@tonic-gate 	 * and if so, free duplicate request.
1110*7c478bd9Sstevel@tonic-gate 	 */
1111*7c478bd9Sstevel@tonic-gate 	if (attrs & USB_ATTRS_ONE_XFER) {
1112*7c478bd9Sstevel@tonic-gate 		ehci_handle_one_xfer_completion(ehcip, tw);
1113*7c478bd9Sstevel@tonic-gate 	}
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate 	/* Call ehci_sendup_qtd_message to callback into client */
1116*7c478bd9Sstevel@tonic-gate 	ehci_sendup_qtd_message(ehcip, pp, tw, qtd, USB_CR_OK);
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	/*
1119*7c478bd9Sstevel@tonic-gate 	 * If interrupt pipe state is still active, insert next Interrupt
1120*7c478bd9Sstevel@tonic-gate 	 * request into the Host Controller's Interrupt list.  Otherwise
1121*7c478bd9Sstevel@tonic-gate 	 * you are done.
1122*7c478bd9Sstevel@tonic-gate 	 */
1123*7c478bd9Sstevel@tonic-gate 	if ((pp->pp_state != EHCI_PIPE_STATE_ACTIVE) ||
1124*7c478bd9Sstevel@tonic-gate 	    (ehci_state_is_operational(ehcip) != USB_SUCCESS)) {
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 		return;
1127*7c478bd9Sstevel@tonic-gate 	}
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 	if ((error = ehci_allocate_intr_in_resource(ehcip, pp, tw, 0)) ==
1130*7c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
1131*7c478bd9Sstevel@tonic-gate 		curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
1132*7c478bd9Sstevel@tonic-gate 
1133*7c478bd9Sstevel@tonic-gate 		ASSERT(curr_intr_reqp != NULL);
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 		tw->tw_num_qtds = 1;
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate 		if (ehci_allocate_tds_for_tw(ehcip, pp, tw, tw->tw_num_qtds) !=
1138*7c478bd9Sstevel@tonic-gate 		    USB_SUCCESS) {
1139*7c478bd9Sstevel@tonic-gate 			ehci_deallocate_intr_in_resource(ehcip, pp, tw);
1140*7c478bd9Sstevel@tonic-gate 			error = USB_FAILURE;
1141*7c478bd9Sstevel@tonic-gate 		}
1142*7c478bd9Sstevel@tonic-gate 	}
1143*7c478bd9Sstevel@tonic-gate 
1144*7c478bd9Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
1145*7c478bd9Sstevel@tonic-gate 		/*
1146*7c478bd9Sstevel@tonic-gate 		 * Set pipe state to stop polling and error to no
1147*7c478bd9Sstevel@tonic-gate 		 * resource. Don't insert any more interrupt polling
1148*7c478bd9Sstevel@tonic-gate 		 * requests.
1149*7c478bd9Sstevel@tonic-gate 		 */
1150*7c478bd9Sstevel@tonic-gate 		pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING;
1151*7c478bd9Sstevel@tonic-gate 		pp->pp_error = USB_CR_NO_RESOURCES;
1152*7c478bd9Sstevel@tonic-gate 	} else {
1153*7c478bd9Sstevel@tonic-gate 		ehci_insert_intr_req(ehcip, pp, tw, 0);
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 		/* Increment number of interrupt request count */
1156*7c478bd9Sstevel@tonic-gate 		pp->pp_cur_periodic_req_cnt++;
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate 		ASSERT(pp->pp_cur_periodic_req_cnt ==
1159*7c478bd9Sstevel@tonic-gate 		    pp->pp_max_periodic_req_cnt);
1160*7c478bd9Sstevel@tonic-gate 	}
1161*7c478bd9Sstevel@tonic-gate }
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate 
1164*7c478bd9Sstevel@tonic-gate /*
1165*7c478bd9Sstevel@tonic-gate  * ehci_handle_one_xfer_completion:
1166*7c478bd9Sstevel@tonic-gate  */
1167*7c478bd9Sstevel@tonic-gate static void
1168*7c478bd9Sstevel@tonic-gate ehci_handle_one_xfer_completion(
1169*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1170*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw)
1171*7c478bd9Sstevel@tonic-gate {
1172*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = tw->tw_pipe_private->pp_pipe_handle;
1173*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = tw->tw_pipe_private;
1174*7c478bd9Sstevel@tonic-gate 	usb_intr_req_t		*curr_intr_reqp =
1175*7c478bd9Sstevel@tonic-gate 				    (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1178*7c478bd9Sstevel@tonic-gate 	    "ehci_handle_one_xfer_completion: tw = 0x%p", tw);
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1181*7c478bd9Sstevel@tonic-gate 	ASSERT(curr_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER);
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_IDLE;
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 	/*
1186*7c478bd9Sstevel@tonic-gate 	 * For one xfer, we need to copy back data ptr
1187*7c478bd9Sstevel@tonic-gate 	 * and free current request
1188*7c478bd9Sstevel@tonic-gate 	 */
1189*7c478bd9Sstevel@tonic-gate 	((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))->
1190*7c478bd9Sstevel@tonic-gate 	    intr_data = ((usb_intr_req_t *)
1191*7c478bd9Sstevel@tonic-gate 	    (tw->tw_curr_xfer_reqp))->intr_data;
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate 	((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL;
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate 	/* Now free duplicate current request */
1196*7c478bd9Sstevel@tonic-gate 	usb_free_intr_req((usb_intr_req_t *)tw-> tw_curr_xfer_reqp);
1197*7c478bd9Sstevel@tonic-gate 
1198*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
1199*7c478bd9Sstevel@tonic-gate 	ph->p_req_count--;
1200*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	/* Make client's request the current request */
1203*7c478bd9Sstevel@tonic-gate 	tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
1204*7c478bd9Sstevel@tonic-gate 	pp->pp_client_periodic_in_reqp = NULL;
1205*7c478bd9Sstevel@tonic-gate }
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate /*
1209*7c478bd9Sstevel@tonic-gate  * ehci_sendup_qtd_message:
1210*7c478bd9Sstevel@tonic-gate  *	copy data, if necessary and do callback
1211*7c478bd9Sstevel@tonic-gate  */
1212*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1213*7c478bd9Sstevel@tonic-gate static void
1214*7c478bd9Sstevel@tonic-gate ehci_sendup_qtd_message(
1215*7c478bd9Sstevel@tonic-gate 	ehci_state_t		*ehcip,
1216*7c478bd9Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
1217*7c478bd9Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
1218*7c478bd9Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
1219*7c478bd9Sstevel@tonic-gate 	usb_cr_t		error)
1220*7c478bd9Sstevel@tonic-gate {
1221*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &pp->pp_pipe_handle->p_ep;
1222*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1223*7c478bd9Sstevel@tonic-gate 	usb_opaque_t		curr_xfer_reqp = tw->tw_curr_xfer_reqp;
1224*7c478bd9Sstevel@tonic-gate 	size_t			skip_len = 0;
1225*7c478bd9Sstevel@tonic-gate 	size_t			length;
1226*7c478bd9Sstevel@tonic-gate 	uchar_t			*buf;
1227*7c478bd9Sstevel@tonic-gate 	mblk_t			*mp;
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1232*7c478bd9Sstevel@tonic-gate 	    "ehci_sendup_qtd_message:");
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate 	ASSERT(tw != NULL);
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate 	length = tw->tw_length;
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_CONTROL) {
1239*7c478bd9Sstevel@tonic-gate 		/* Get the correct length */
1240*7c478bd9Sstevel@tonic-gate 		length = length - SETUP_SIZE;
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 		/* Set the length of the buffer to skip */
1243*7c478bd9Sstevel@tonic-gate 		skip_len = SETUP_SIZE;
1244*7c478bd9Sstevel@tonic-gate 	}
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	/* Copy the data into the mblk_t */
1247*7c478bd9Sstevel@tonic-gate 	buf = (uchar_t *)tw->tw_buf + skip_len;
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1250*7c478bd9Sstevel@tonic-gate 	    "ehci_sendup_qtd_message: length %ld error %d", length, error);
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	/* Get the message block */
1253*7c478bd9Sstevel@tonic-gate 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
1254*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
1255*7c478bd9Sstevel@tonic-gate 		mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data;
1256*7c478bd9Sstevel@tonic-gate 		break;
1257*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
1258*7c478bd9Sstevel@tonic-gate 		mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data;
1259*7c478bd9Sstevel@tonic-gate 		break;
1260*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
1261*7c478bd9Sstevel@tonic-gate 		mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data;
1262*7c478bd9Sstevel@tonic-gate 		break;
1263*7c478bd9Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
1264*7c478bd9Sstevel@tonic-gate 		/* Isoc messages must not go through this path */
1265*7c478bd9Sstevel@tonic-gate 		mp = NULL;
1266*7c478bd9Sstevel@tonic-gate 		break;
1267*7c478bd9Sstevel@tonic-gate 	}
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	if (length) {
1272*7c478bd9Sstevel@tonic-gate 		/*
1273*7c478bd9Sstevel@tonic-gate 		 * Update kstat byte counts
1274*7c478bd9Sstevel@tonic-gate 		 * The control endpoints don't have direction bits so in
1275*7c478bd9Sstevel@tonic-gate 		 * order for control stats to be counted correctly an in
1276*7c478bd9Sstevel@tonic-gate 		 * bit must be faked on a control read.
1277*7c478bd9Sstevel@tonic-gate 		 */
1278*7c478bd9Sstevel@tonic-gate 		if ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
1279*7c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_CONTROL) {
1280*7c478bd9Sstevel@tonic-gate 			ehci_do_byte_stats(ehcip, length,
1281*7c478bd9Sstevel@tonic-gate 			    eptd->bmAttributes, USB_EP_DIR_IN);
1282*7c478bd9Sstevel@tonic-gate 		} else {
1283*7c478bd9Sstevel@tonic-gate 			ehci_do_byte_stats(ehcip, length,
1284*7c478bd9Sstevel@tonic-gate 			    eptd->bmAttributes, eptd->bEndpointAddress);
1285*7c478bd9Sstevel@tonic-gate 		}
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 		/* Sync IO buffer */
1288*7c478bd9Sstevel@tonic-gate 		Sync_IO_Buffer(tw->tw_dmahandle, length);
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 		/* since we specified NEVERSWAP, we can just use bcopy */
1291*7c478bd9Sstevel@tonic-gate 		bcopy(buf, mp->b_rptr, length);
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate 		/* Increment the write pointer */
1294*7c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_wptr + length;
1295*7c478bd9Sstevel@tonic-gate 	} else {
1296*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1297*7c478bd9Sstevel@tonic-gate 		    "ehci_sendup_qtd_message: Zero length packet");
1298*7c478bd9Sstevel@tonic-gate 	}
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 	ehci_hcdi_callback(ph, tw, error);
1301*7c478bd9Sstevel@tonic-gate }
1302