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  * USBA: Solaris USB Architecture support
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * all functions exposed to client drivers  have prefix usb_ while all USBA
33*7c478bd9Sstevel@tonic-gate  * internal functions or functions exposed to HCD or hubd only have prefix
34*7c478bd9Sstevel@tonic-gate  * usba_
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * this file contains all USBAI pipe management
37*7c478bd9Sstevel@tonic-gate  *	usb_pipe_open()
38*7c478bd9Sstevel@tonic-gate  *	usb_pipe_close()
39*7c478bd9Sstevel@tonic-gate  *	usb_pipe_set_private()
40*7c478bd9Sstevel@tonic-gate  *	usb_pipe_get_private()
41*7c478bd9Sstevel@tonic-gate  *	usb_pipe_abort()
42*7c478bd9Sstevel@tonic-gate  *	usb_pipe_reset()
43*7c478bd9Sstevel@tonic-gate  *	usb_pipe_drain_reqs()
44*7c478bd9Sstevel@tonic-gate  */
45*7c478bd9Sstevel@tonic-gate #define	USBA_FRAMEWORK
46*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate extern	pri_t	maxclsyspri;
51*7c478bd9Sstevel@tonic-gate extern	pri_t	minclsyspri;
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /* function prototypes */
54*7c478bd9Sstevel@tonic-gate static	void	usba_pipe_do_async_func_thread(void *arg);
55*7c478bd9Sstevel@tonic-gate static	int	usba_pipe_sync_close(dev_info_t *, usba_ph_impl_t *,
56*7c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
57*7c478bd9Sstevel@tonic-gate static	int	usba_pipe_sync_abort(dev_info_t *, usba_ph_impl_t *,
58*7c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
59*7c478bd9Sstevel@tonic-gate static	int	usba_pipe_sync_reset(dev_info_t *, usba_ph_impl_t *,
60*7c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
61*7c478bd9Sstevel@tonic-gate static	int	usba_pipe_sync_drain_reqs(dev_info_t *, usba_ph_impl_t *,
62*7c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /* local tunables */
65*7c478bd9Sstevel@tonic-gate static	int	usba_drain_timeout = 1000;	/* in ms */
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate /* return the default pipe for this device */
68*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t
69*7c478bd9Sstevel@tonic-gate usba_get_dflt_pipe_handle(dev_info_t *dip)
70*7c478bd9Sstevel@tonic-gate {
71*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
72*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = NULL;
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate 	if (dip) {
75*7c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(dip);
76*7c478bd9Sstevel@tonic-gate 		if (usba_device) {
77*7c478bd9Sstevel@tonic-gate 			pipe_handle =
78*7c478bd9Sstevel@tonic-gate 			    (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
79*7c478bd9Sstevel@tonic-gate 		}
80*7c478bd9Sstevel@tonic-gate 	}
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 	return (pipe_handle);
83*7c478bd9Sstevel@tonic-gate }
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate /* return dip owner of pipe_handle */
87*7c478bd9Sstevel@tonic-gate dev_info_t *
88*7c478bd9Sstevel@tonic-gate usba_get_dip(usb_pipe_handle_t pipe_handle)
89*7c478bd9Sstevel@tonic-gate {
90*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
91*7c478bd9Sstevel@tonic-gate 	dev_info_t		*dip = NULL;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	if (ph_impl) {
94*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
95*7c478bd9Sstevel@tonic-gate 		dip = ph_impl->usba_ph_dip;
96*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
97*7c478bd9Sstevel@tonic-gate 	}
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	return (dip);
100*7c478bd9Sstevel@tonic-gate }
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t
104*7c478bd9Sstevel@tonic-gate usba_usbdev_to_dflt_pipe_handle(usba_device_t *usba_device)
105*7c478bd9Sstevel@tonic-gate {
106*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = NULL;
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	if ((usba_device) &&
109*7c478bd9Sstevel@tonic-gate 	    (usba_device->usb_ph_list[0].usba_ph_data != NULL)) {
110*7c478bd9Sstevel@tonic-gate 		pipe_handle = (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
111*7c478bd9Sstevel@tonic-gate 	}
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	return (pipe_handle);
114*7c478bd9Sstevel@tonic-gate }
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *
118*7c478bd9Sstevel@tonic-gate usba_get_ph_data(usb_pipe_handle_t pipe_handle)
119*7c478bd9Sstevel@tonic-gate {
120*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
121*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = NULL;
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	if (ph_impl) {
124*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
125*7c478bd9Sstevel@tonic-gate 		ASSERT(ph_impl->usba_ph_ref_count >= 0);
126*7c478bd9Sstevel@tonic-gate 		ph_data = ph_impl->usba_ph_data;
127*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
128*7c478bd9Sstevel@tonic-gate 	}
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	return (ph_data);
131*7c478bd9Sstevel@tonic-gate }
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t
135*7c478bd9Sstevel@tonic-gate usba_get_pipe_handle(usba_pipe_handle_data_t *ph_data)
136*7c478bd9Sstevel@tonic-gate {
137*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph = NULL;
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	if (ph_data) {
140*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
141*7c478bd9Sstevel@tonic-gate 		ASSERT(ph_data->p_req_count >= 0);
142*7c478bd9Sstevel@tonic-gate 		ph = (usb_pipe_handle_t)ph_data->p_ph_impl;
143*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
144*7c478bd9Sstevel@tonic-gate 	}
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	return (ph);
147*7c478bd9Sstevel@tonic-gate }
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate /*
151*7c478bd9Sstevel@tonic-gate  * opaque to pipe handle impl translation with incr of ref count. The caller
152*7c478bd9Sstevel@tonic-gate  * must release ph_data when done. Increment the ref count ensures that
153*7c478bd9Sstevel@tonic-gate  * the ph_data will not be freed underneath us.
154*7c478bd9Sstevel@tonic-gate  */
155*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *
156*7c478bd9Sstevel@tonic-gate usba_hold_ph_data(usb_pipe_handle_t pipe_handle)
157*7c478bd9Sstevel@tonic-gate {
158*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
159*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = NULL;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	if (ph_impl) {
162*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 		switch (ph_impl->usba_ph_state) {
165*7c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_IDLE:
166*7c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_ACTIVE:
167*7c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_ERROR:
168*7c478bd9Sstevel@tonic-gate 			ph_data = ph_impl->usba_ph_data;
169*7c478bd9Sstevel@tonic-gate 			ph_impl->usba_ph_ref_count++;
170*7c478bd9Sstevel@tonic-gate 			break;
171*7c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_CLOSED:
172*7c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_CLOSING:
173*7c478bd9Sstevel@tonic-gate 		default:
174*7c478bd9Sstevel@tonic-gate 			break;
175*7c478bd9Sstevel@tonic-gate 		}
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
178*7c478bd9Sstevel@tonic-gate 		    "usba_hold_ph_data: ph_impl=0x%p state=%d ref=%d",
179*7c478bd9Sstevel@tonic-gate 		    ph_impl, ph_impl->usba_ph_state,
180*7c478bd9Sstevel@tonic-gate 		    ph_impl->usba_ph_ref_count);
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
183*7c478bd9Sstevel@tonic-gate 	}
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	return (ph_data);
186*7c478bd9Sstevel@tonic-gate }
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate void
190*7c478bd9Sstevel@tonic-gate usba_release_ph_data(usba_ph_impl_t *ph_impl)
191*7c478bd9Sstevel@tonic-gate {
192*7c478bd9Sstevel@tonic-gate 	if (ph_impl) {
193*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
196*7c478bd9Sstevel@tonic-gate 		    "usba_release_ph_data: "
197*7c478bd9Sstevel@tonic-gate 		    "ph_impl=0x%p state=%d ref=%d",
198*7c478bd9Sstevel@tonic-gate 		    ph_impl, ph_impl->usba_ph_state,
199*7c478bd9Sstevel@tonic-gate 		    ph_impl->usba_ph_ref_count);
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate #ifndef __lock_lint
202*7c478bd9Sstevel@tonic-gate 		if (ph_impl->usba_ph_data) {
203*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
204*7c478bd9Sstevel@tonic-gate 			    "usba_release_ph_data: req_count=%d",
205*7c478bd9Sstevel@tonic-gate 			    ph_impl->usba_ph_data->p_req_count);
206*7c478bd9Sstevel@tonic-gate 			ASSERT(ph_impl->usba_ph_data->p_req_count >= 0);
207*7c478bd9Sstevel@tonic-gate 		}
208*7c478bd9Sstevel@tonic-gate #endif
209*7c478bd9Sstevel@tonic-gate 		ph_impl->usba_ph_ref_count--;
210*7c478bd9Sstevel@tonic-gate 		ASSERT(ph_impl->usba_ph_ref_count >= 0);
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
213*7c478bd9Sstevel@tonic-gate 	}
214*7c478bd9Sstevel@tonic-gate }
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate /*
218*7c478bd9Sstevel@tonic-gate  * get pipe state from ph_data
219*7c478bd9Sstevel@tonic-gate  */
220*7c478bd9Sstevel@tonic-gate usb_pipe_state_t
221*7c478bd9Sstevel@tonic-gate usba_get_ph_state(usba_pipe_handle_data_t *ph_data)
222*7c478bd9Sstevel@tonic-gate {
223*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
224*7c478bd9Sstevel@tonic-gate 	usb_pipe_state_t	pipe_state;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ph_data->p_mutex));
227*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
228*7c478bd9Sstevel@tonic-gate 	pipe_state = ph_impl->usba_ph_state;
229*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	return (pipe_state);
232*7c478bd9Sstevel@tonic-gate }
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate /*
236*7c478bd9Sstevel@tonic-gate  * get ref_count from ph_data
237*7c478bd9Sstevel@tonic-gate  */
238*7c478bd9Sstevel@tonic-gate int
239*7c478bd9Sstevel@tonic-gate usba_get_ph_ref_count(usba_pipe_handle_data_t *ph_data)
240*7c478bd9Sstevel@tonic-gate {
241*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
242*7c478bd9Sstevel@tonic-gate 	int			ref_count;
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
245*7c478bd9Sstevel@tonic-gate 	ref_count = ph_impl->usba_ph_ref_count;
246*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	return (ref_count);
249*7c478bd9Sstevel@tonic-gate }
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate /*
253*7c478bd9Sstevel@tonic-gate  * new pipe state
254*7c478bd9Sstevel@tonic-gate  * We need to hold both pipe mutex and ph_impl mutex
255*7c478bd9Sstevel@tonic-gate  */
256*7c478bd9Sstevel@tonic-gate void
257*7c478bd9Sstevel@tonic-gate usba_pipe_new_state(usba_pipe_handle_data_t *ph_data, usb_pipe_state_t state)
258*7c478bd9Sstevel@tonic-gate {
259*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ph_data->p_mutex));
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
264*7c478bd9Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
265*7c478bd9Sstevel@tonic-gate 	ASSERT(ph_impl->usba_ph_ref_count >= 0);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
268*7c478bd9Sstevel@tonic-gate 	    "usba_pipe_new_state: "
269*7c478bd9Sstevel@tonic-gate 	    "ph_data=0x%p old=%s new=%s ref=%d req=%d",
270*7c478bd9Sstevel@tonic-gate 	    ph_data, usb_str_pipe_state(ph_impl->usba_ph_state),
271*7c478bd9Sstevel@tonic-gate 	    usb_str_pipe_state(state),
272*7c478bd9Sstevel@tonic-gate 	    ph_impl->usba_ph_ref_count, ph_data->p_req_count);
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	switch (ph_impl->usba_ph_state) {
275*7c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_IDLE:
276*7c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_ACTIVE:
277*7c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_ERROR:
278*7c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_CLOSED:
279*7c478bd9Sstevel@tonic-gate 		ph_impl->usba_ph_state = state;
280*7c478bd9Sstevel@tonic-gate 		break;
281*7c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_CLOSING:
282*7c478bd9Sstevel@tonic-gate 	default:
283*7c478bd9Sstevel@tonic-gate 		break;
284*7c478bd9Sstevel@tonic-gate 	}
285*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
286*7c478bd9Sstevel@tonic-gate }
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate /*
290*7c478bd9Sstevel@tonic-gate  * async function execution support
291*7c478bd9Sstevel@tonic-gate  * Arguments:
292*7c478bd9Sstevel@tonic-gate  *	dip		- devinfo pointer
293*7c478bd9Sstevel@tonic-gate  *	sync_func	- function to be executed
294*7c478bd9Sstevel@tonic-gate  *	ph_impl		- impl pipehandle
295*7c478bd9Sstevel@tonic-gate  *	arg		- opaque arg
296*7c478bd9Sstevel@tonic-gate  *	usb_flags	- none
297*7c478bd9Sstevel@tonic-gate  *	callback	- function to be called on completion, may be NULL
298*7c478bd9Sstevel@tonic-gate  *	callback_arg	- argument for callback function
299*7c478bd9Sstevel@tonic-gate  *
300*7c478bd9Sstevel@tonic-gate  * Note: The caller must do a hold on ph_data
301*7c478bd9Sstevel@tonic-gate  *	We sleep for memory resources and taskq_dispatch which will ensure
302*7c478bd9Sstevel@tonic-gate  *	that this function succeeds
303*7c478bd9Sstevel@tonic-gate  */
304*7c478bd9Sstevel@tonic-gate int
305*7c478bd9Sstevel@tonic-gate usba_pipe_setup_func_call(
306*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip,
307*7c478bd9Sstevel@tonic-gate 	int		(*sync_func)(dev_info_t *,
308*7c478bd9Sstevel@tonic-gate 			    usba_ph_impl_t *, usba_pipe_async_req_t *,
309*7c478bd9Sstevel@tonic-gate 			    usb_flags_t),
310*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t *ph_impl,
311*7c478bd9Sstevel@tonic-gate 	usb_opaque_t	arg,
312*7c478bd9Sstevel@tonic-gate 	usb_flags_t	usb_flags,
313*7c478bd9Sstevel@tonic-gate 	void		(*callback)(usb_pipe_handle_t,
314*7c478bd9Sstevel@tonic-gate 			    usb_opaque_t, int, usb_cb_flags_t),
315*7c478bd9Sstevel@tonic-gate 	usb_opaque_t	callback_arg)
316*7c478bd9Sstevel@tonic-gate {
317*7c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t	*request;
318*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = (usb_pipe_handle_t)ph_impl;
319*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
320*7c478bd9Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
321*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		callback_flags;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
324*7c478bd9Sstevel@tonic-gate 	    "usba_pipe_setup_func_call: ph_impl=0x%p, func=0x%p",
325*7c478bd9Sstevel@tonic-gate 	    ph_impl, sync_func);
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	if (((usb_flags & USB_FLAGS_SLEEP) == 0) && (callback == NULL)) {
328*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
329*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBAI, usbai_log_handle,
330*7c478bd9Sstevel@tonic-gate 		    "usba_pipe_setup_func_call: async request with "
331*7c478bd9Sstevel@tonic-gate 		    "no callback");
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	request = kmem_zalloc(sizeof (usba_pipe_async_req_t), KM_SLEEP);
337*7c478bd9Sstevel@tonic-gate 	request->dip		= dip;
338*7c478bd9Sstevel@tonic-gate 	request->ph_impl	= ph_impl;
339*7c478bd9Sstevel@tonic-gate 	request->arg		= arg;
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	/*
342*7c478bd9Sstevel@tonic-gate 	 * OR in sleep flag. regardless of calling sync_func directly
343*7c478bd9Sstevel@tonic-gate 	 * or in a new thread, we will always wait for completion
344*7c478bd9Sstevel@tonic-gate 	 */
345*7c478bd9Sstevel@tonic-gate 	request->usb_flags	= usb_flags | USB_FLAGS_SLEEP;
346*7c478bd9Sstevel@tonic-gate 	request->sync_func	= sync_func;
347*7c478bd9Sstevel@tonic-gate 	request->callback	= callback;
348*7c478bd9Sstevel@tonic-gate 	request->callback_arg	= callback_arg;
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	if (usb_flags & USB_FLAGS_SLEEP) {
351*7c478bd9Sstevel@tonic-gate 		rval = sync_func(dip, ph_impl, request, usb_flags);
352*7c478bd9Sstevel@tonic-gate 		kmem_free(request, sizeof (usba_pipe_async_req_t));
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	} else if (usba_async_ph_req(ph_data,
355*7c478bd9Sstevel@tonic-gate 	    usba_pipe_do_async_func_thread,
356*7c478bd9Sstevel@tonic-gate 	    (void *)request, USB_FLAGS_SLEEP) != USB_SUCCESS) {
357*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
358*7c478bd9Sstevel@tonic-gate 		    "usb_async_req failed: ph_impl=0x%p, func=0x%p",
359*7c478bd9Sstevel@tonic-gate 		    ph_impl, sync_func);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 		if (callback) {
362*7c478bd9Sstevel@tonic-gate 			callback_flags =
363*7c478bd9Sstevel@tonic-gate 			    usba_check_intr_context(USB_CB_ASYNC_REQ_FAILED);
364*7c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg, USB_FAILURE,
365*7c478bd9Sstevel@tonic-gate 			    callback_flags);
366*7c478bd9Sstevel@tonic-gate 		}
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 		kmem_free(request, sizeof (usba_pipe_async_req_t));
369*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
370*7c478bd9Sstevel@tonic-gate 	}
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	return (rval);
373*7c478bd9Sstevel@tonic-gate }
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate /*
377*7c478bd9Sstevel@tonic-gate  * taskq thread function to execute function synchronously
378*7c478bd9Sstevel@tonic-gate  * Note: caller must have done a hold on ph_data
379*7c478bd9Sstevel@tonic-gate  */
380*7c478bd9Sstevel@tonic-gate static void
381*7c478bd9Sstevel@tonic-gate usba_pipe_do_async_func_thread(void *arg)
382*7c478bd9Sstevel@tonic-gate {
383*7c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t	*request = (usba_pipe_async_req_t *)arg;
384*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = request->ph_impl;
385*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = (usb_pipe_handle_t)ph_impl;
386*7c478bd9Sstevel@tonic-gate 	int			rval;
387*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags = USB_CB_NO_INFO;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	if ((rval = request->sync_func(request->dip, ph_impl,
390*7c478bd9Sstevel@tonic-gate 	    request, request->usb_flags | USB_FLAGS_SLEEP)) !=
391*7c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
392*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
393*7c478bd9Sstevel@tonic-gate 		    "sync func failed (%d)", rval);
394*7c478bd9Sstevel@tonic-gate 	}
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	if (request->callback) {
397*7c478bd9Sstevel@tonic-gate 		request->callback(pipe_handle, request->callback_arg, rval,
398*7c478bd9Sstevel@tonic-gate 		    cb_flags);
399*7c478bd9Sstevel@tonic-gate 	}
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	kmem_free(request, sizeof (usba_pipe_async_req_t));
402*7c478bd9Sstevel@tonic-gate }
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate /*
406*7c478bd9Sstevel@tonic-gate  * default endpoint descriptor and pipe policy
407*7c478bd9Sstevel@tonic-gate  */
408*7c478bd9Sstevel@tonic-gate usb_ep_descr_t	usba_default_ep_descr =
409*7c478bd9Sstevel@tonic-gate 	{7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0};
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate /* set some meaningful defaults */
412*7c478bd9Sstevel@tonic-gate static usb_pipe_policy_t usba_default_ep_pipe_policy = {3};
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate /*
416*7c478bd9Sstevel@tonic-gate  * usb_get_ep_index: create an index from endpoint address that can
417*7c478bd9Sstevel@tonic-gate  * be used to index into endpoint pipe lists
418*7c478bd9Sstevel@tonic-gate  */
419*7c478bd9Sstevel@tonic-gate uchar_t
420*7c478bd9Sstevel@tonic-gate usb_get_ep_index(uint8_t ep_addr)
421*7c478bd9Sstevel@tonic-gate {
422*7c478bd9Sstevel@tonic-gate 	return ((ep_addr & USB_EP_NUM_MASK) +
423*7c478bd9Sstevel@tonic-gate 	    ((ep_addr & USB_EP_DIR_MASK) ? 16 : 0));
424*7c478bd9Sstevel@tonic-gate }
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate /*
428*7c478bd9Sstevel@tonic-gate  * pipe management
429*7c478bd9Sstevel@tonic-gate  *	utility functions to init and destroy a pipehandle
430*7c478bd9Sstevel@tonic-gate  */
431*7c478bd9Sstevel@tonic-gate static int
432*7c478bd9Sstevel@tonic-gate usba_init_pipe_handle(dev_info_t *dip,
433*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device,
434*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*ep,
435*7c478bd9Sstevel@tonic-gate 	usb_pipe_policy_t	*pipe_policy,
436*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl)
437*7c478bd9Sstevel@tonic-gate {
438*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
439*7c478bd9Sstevel@tonic-gate 	unsigned int def_instance = instance;
440*7c478bd9Sstevel@tonic-gate 	static unsigned int anon_instance = 0;
441*7c478bd9Sstevel@tonic-gate 	char tq_name[TASKQ_NAMELEN];
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
444*7c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t	iblock_cookie =
445*7c478bd9Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
446*7c478bd9Sstevel@tonic-gate 	    hcdi_iblock_cookie;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
449*7c478bd9Sstevel@tonic-gate 	    "usba_init_pipe_handle: "
450*7c478bd9Sstevel@tonic-gate 	    "usba_device=0x%p ep=0x%x", usba_device, ep->bEndpointAddress);
451*7c478bd9Sstevel@tonic-gate 	mutex_init(&ph_data->p_mutex, NULL, MUTEX_DRIVER, iblock_cookie);
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	/* just to keep warlock happy, there is no contention yet */
454*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
455*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	ASSERT(pipe_policy->pp_max_async_reqs);
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	if (instance != -1) {
460*7c478bd9Sstevel@tonic-gate 		(void) snprintf(tq_name, sizeof (tq_name),
461*7c478bd9Sstevel@tonic-gate 		    "USB_%s_%x_pipehndl_tq_%d",
462*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ep->bEndpointAddress, instance);
463*7c478bd9Sstevel@tonic-gate 	} else {
464*7c478bd9Sstevel@tonic-gate 		def_instance = atomic_add_32_nv(&anon_instance, 1);
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 		(void) snprintf(tq_name, sizeof (tq_name),
467*7c478bd9Sstevel@tonic-gate 		    "USB_%s_%x_pipehndl_tq_%d_",
468*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ep->bEndpointAddress, def_instance);
469*7c478bd9Sstevel@tonic-gate 	}
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	ph_data->p_taskq = taskq_create(tq_name,
472*7c478bd9Sstevel@tonic-gate 		    pipe_policy->pp_max_async_reqs + 1,
473*7c478bd9Sstevel@tonic-gate 		    ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
474*7c478bd9Sstevel@tonic-gate 			USB_EP_ATTR_ISOCH) ?
475*7c478bd9Sstevel@tonic-gate 			(maxclsyspri - 5) : minclsyspri,
476*7c478bd9Sstevel@tonic-gate 		    2 * (pipe_policy->pp_max_async_reqs + 1),
477*7c478bd9Sstevel@tonic-gate 		    8 * (pipe_policy->pp_max_async_reqs + 1),
478*7c478bd9Sstevel@tonic-gate 		    TASKQ_PREPOPULATE);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	/*
481*7c478bd9Sstevel@tonic-gate 	 * Create a shared taskq.
482*7c478bd9Sstevel@tonic-gate 	 */
483*7c478bd9Sstevel@tonic-gate 	if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
484*7c478bd9Sstevel@tonic-gate 		int iface = usb_get_if_number(dip);
485*7c478bd9Sstevel@tonic-gate 		if (iface < 0) {
486*7c478bd9Sstevel@tonic-gate 			/* we own the device, use first entry */
487*7c478bd9Sstevel@tonic-gate 			iface = 0;
488*7c478bd9Sstevel@tonic-gate 		}
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 		if (instance != -1) {
491*7c478bd9Sstevel@tonic-gate 			(void) snprintf(tq_name, sizeof (tq_name),
492*7c478bd9Sstevel@tonic-gate 			    "USB_%s_%x_shared_tq_%d",
493*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ep->bEndpointAddress,
494*7c478bd9Sstevel@tonic-gate 			    instance);
495*7c478bd9Sstevel@tonic-gate 		} else {
496*7c478bd9Sstevel@tonic-gate 			(void) snprintf(tq_name, sizeof (tq_name),
497*7c478bd9Sstevel@tonic-gate 			    "USB_%s_%x_shared_tq_%d_",
498*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ep->bEndpointAddress,
499*7c478bd9Sstevel@tonic-gate 			    def_instance);
500*7c478bd9Sstevel@tonic-gate 		}
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 		if (usba_device->usb_shared_taskq_ref_count[iface] == 0) {
503*7c478bd9Sstevel@tonic-gate 			usba_device->usb_shared_taskq[iface] =
504*7c478bd9Sstevel@tonic-gate 			    taskq_create(tq_name,
505*7c478bd9Sstevel@tonic-gate 			    1,				/* Number threads. */
506*7c478bd9Sstevel@tonic-gate 			    maxclsyspri - 5,		/* Priority */
507*7c478bd9Sstevel@tonic-gate 			    1,				/* minalloc */
508*7c478bd9Sstevel@tonic-gate 			    USBA_N_ENDPOINTS + 4,	/* maxalloc */
509*7c478bd9Sstevel@tonic-gate 			    TASKQ_PREPOPULATE);
510*7c478bd9Sstevel@tonic-gate 			ASSERT(usba_device->usb_shared_taskq[iface] != NULL);
511*7c478bd9Sstevel@tonic-gate 		}
512*7c478bd9Sstevel@tonic-gate 		usba_device->usb_shared_taskq_ref_count[iface]++;
513*7c478bd9Sstevel@tonic-gate 	}
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	ph_data->p_dip		= dip;
516*7c478bd9Sstevel@tonic-gate 	ph_data->p_usba_device	= usba_device;
517*7c478bd9Sstevel@tonic-gate 	ph_data->p_ep		= *ep;
518*7c478bd9Sstevel@tonic-gate 	ph_data->p_ph_impl	= ph_impl;
519*7c478bd9Sstevel@tonic-gate 	if ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
520*7c478bd9Sstevel@tonic-gate 	    USB_EP_ATTR_ISOCH) {
521*7c478bd9Sstevel@tonic-gate 		ph_data->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
522*7c478bd9Sstevel@tonic-gate 	}
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	/* fix up the MaxPacketSize if it is the default endpoint descr */
525*7c478bd9Sstevel@tonic-gate 	if ((ep == &usba_default_ep_descr) && usba_device) {
526*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
527*7c478bd9Sstevel@tonic-gate 		    "adjusting max packet size from %d to %d",
528*7c478bd9Sstevel@tonic-gate 		    ph_data->p_ep.wMaxPacketSize,
529*7c478bd9Sstevel@tonic-gate 		    usba_device->usb_dev_descr->bMaxPacketSize0);
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 		ph_data->p_ep.wMaxPacketSize = usba_device->usb_dev_descr->
532*7c478bd9Sstevel@tonic-gate 							bMaxPacketSize0;
533*7c478bd9Sstevel@tonic-gate 	}
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	/* now update usba_ph_impl structure */
536*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
537*7c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_dip = dip;
538*7c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_ep = ph_data->p_ep;
539*7c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_policy = ph_data->p_policy = *pipe_policy;
540*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	usba_init_list(&ph_data->p_queue, (usb_opaque_t)ph_data, iblock_cookie);
543*7c478bd9Sstevel@tonic-gate 	usba_init_list(&ph_data->p_cb_queue, (usb_opaque_t)ph_data,
544*7c478bd9Sstevel@tonic-gate 								iblock_cookie);
545*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
546*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
549*7c478bd9Sstevel@tonic-gate }
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate static void
553*7c478bd9Sstevel@tonic-gate usba_taskq_destroy(void *arg)
554*7c478bd9Sstevel@tonic-gate {
555*7c478bd9Sstevel@tonic-gate 	taskq_destroy((taskq_t *)arg);
556*7c478bd9Sstevel@tonic-gate }
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate static void
560*7c478bd9Sstevel@tonic-gate usba_destroy_pipe_handle(usba_pipe_handle_data_t *ph_data)
561*7c478bd9Sstevel@tonic-gate {
562*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
563*7c478bd9Sstevel@tonic-gate 	int			timeout;
564*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
567*7c478bd9Sstevel@tonic-gate 	    "usba_destroy_pipe_handle: ph_data=0x%p", ph_data);
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
570*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	/* check for all activity to drain */
573*7c478bd9Sstevel@tonic-gate 	for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
574*7c478bd9Sstevel@tonic-gate 		if ((ph_impl->usba_ph_ref_count <= 1) &&
575*7c478bd9Sstevel@tonic-gate 		    (ph_data->p_req_count == 0)) {
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 			break;
578*7c478bd9Sstevel@tonic-gate 		}
579*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
580*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
581*7c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000));
582*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
583*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
584*7c478bd9Sstevel@tonic-gate 	}
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	/*
587*7c478bd9Sstevel@tonic-gate 	 * set state to closed here so any other thread
588*7c478bd9Sstevel@tonic-gate 	 * that is waiting for the CLOSED state will
589*7c478bd9Sstevel@tonic-gate 	 * continue. Otherwise, taskq_destroy might deadlock
590*7c478bd9Sstevel@tonic-gate 	 */
591*7c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_data = NULL;
592*7c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_ref_count = 0;
593*7c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSED;
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	if (ph_data->p_taskq) {
596*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
597*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
598*7c478bd9Sstevel@tonic-gate 		if (taskq_member(ph_data->p_taskq, curthread)) {
599*7c478bd9Sstevel@tonic-gate 			/*
600*7c478bd9Sstevel@tonic-gate 			 * use system taskq to destroy ph's taskq to avoid
601*7c478bd9Sstevel@tonic-gate 			 * deadlock
602*7c478bd9Sstevel@tonic-gate 			 */
603*7c478bd9Sstevel@tonic-gate 			(void) taskq_dispatch(system_taskq,
604*7c478bd9Sstevel@tonic-gate 			    usba_taskq_destroy, ph_data->p_taskq, TQ_SLEEP);
605*7c478bd9Sstevel@tonic-gate 		} else {
606*7c478bd9Sstevel@tonic-gate 			taskq_destroy(ph_data->p_taskq);
607*7c478bd9Sstevel@tonic-gate 		}
608*7c478bd9Sstevel@tonic-gate 	} else {
609*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
610*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
614*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
615*7c478bd9Sstevel@tonic-gate 	if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
616*7c478bd9Sstevel@tonic-gate 		int iface = usb_get_if_number(ph_data->p_dip);
617*7c478bd9Sstevel@tonic-gate 		if (iface < 0) {
618*7c478bd9Sstevel@tonic-gate 			/* we own the device, use the first entry */
619*7c478bd9Sstevel@tonic-gate 			iface = 0;
620*7c478bd9Sstevel@tonic-gate 		}
621*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
622*7c478bd9Sstevel@tonic-gate 		if (--usba_device->usb_shared_taskq_ref_count[iface] == 0) {
623*7c478bd9Sstevel@tonic-gate 			ph_data->p_spec_flag &= ~USBA_PH_FLAG_TQ_SHARE;
624*7c478bd9Sstevel@tonic-gate 			if (taskq_member(usba_device->usb_shared_taskq[iface],
625*7c478bd9Sstevel@tonic-gate 			    curthread)) {
626*7c478bd9Sstevel@tonic-gate 				(void) taskq_dispatch(
627*7c478bd9Sstevel@tonic-gate 				    system_taskq,
628*7c478bd9Sstevel@tonic-gate 				    usba_taskq_destroy,
629*7c478bd9Sstevel@tonic-gate 				    usba_device->usb_shared_taskq[iface],
630*7c478bd9Sstevel@tonic-gate 				    TQ_SLEEP);
631*7c478bd9Sstevel@tonic-gate 			} else {
632*7c478bd9Sstevel@tonic-gate 				taskq_destroy(
633*7c478bd9Sstevel@tonic-gate 				    usba_device->usb_shared_taskq[iface]);
634*7c478bd9Sstevel@tonic-gate 			}
635*7c478bd9Sstevel@tonic-gate 		}
636*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
637*7c478bd9Sstevel@tonic-gate 	}
638*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
642*7c478bd9Sstevel@tonic-gate 	    "usba_destroy_pipe_handle: destroying ph_data=0x%p", ph_data);
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 	usba_destroy_list(&ph_data->p_queue);
645*7c478bd9Sstevel@tonic-gate 	usba_destroy_list(&ph_data->p_cb_queue);
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	/* destroy mutexes */
648*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&ph_data->p_mutex);
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 	kmem_free(ph_data, sizeof (usba_pipe_handle_data_t));
651*7c478bd9Sstevel@tonic-gate }
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate /*
655*7c478bd9Sstevel@tonic-gate  * usba_drain_cbs:
656*7c478bd9Sstevel@tonic-gate  *	Drain the request callbacks on the pipe handle
657*7c478bd9Sstevel@tonic-gate  */
658*7c478bd9Sstevel@tonic-gate int
659*7c478bd9Sstevel@tonic-gate usba_drain_cbs(usba_pipe_handle_data_t *ph_data, usb_cb_flags_t cb_flags,
660*7c478bd9Sstevel@tonic-gate 	usb_cr_t cr)
661*7c478bd9Sstevel@tonic-gate {
662*7c478bd9Sstevel@tonic-gate 	usba_req_wrapper_t	*req_wrp;
663*7c478bd9Sstevel@tonic-gate 	int			flush_requests = 1;
664*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
665*7c478bd9Sstevel@tonic-gate 	int			timeout;
666*7c478bd9Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ph_data->p_mutex));
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
671*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
672*7c478bd9Sstevel@tonic-gate 	    "usba_drain_cbs: ph_data=0x%p ref=%d req=%d cb=0x%x cr=%d",
673*7c478bd9Sstevel@tonic-gate 	    ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count,
674*7c478bd9Sstevel@tonic-gate 	    cb_flags, cr);
675*7c478bd9Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
676*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	if (ph_data->p_dip) {
679*7c478bd9Sstevel@tonic-gate 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
680*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
681*7c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
682*7c478bd9Sstevel@tonic-gate 			    "no flushing on default pipe!");
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 			flush_requests = 0;
685*7c478bd9Sstevel@tonic-gate 		}
686*7c478bd9Sstevel@tonic-gate 	}
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	if (flush_requests) {
689*7c478bd9Sstevel@tonic-gate 		/* flush all requests in the pipehandle queue */
690*7c478bd9Sstevel@tonic-gate 		while ((req_wrp = (usba_req_wrapper_t *)
691*7c478bd9Sstevel@tonic-gate 		    usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
692*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
693*7c478bd9Sstevel@tonic-gate 			usba_do_req_exc_cb(req_wrp, cr, cb_flags);
694*7c478bd9Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
695*7c478bd9Sstevel@tonic-gate 		}
696*7c478bd9Sstevel@tonic-gate 	}
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	/*
699*7c478bd9Sstevel@tonic-gate 	 * wait for any callbacks in progress but don't wait for
700*7c478bd9Sstevel@tonic-gate 	 * for queued requests on the default pipe
701*7c478bd9Sstevel@tonic-gate 	 */
702*7c478bd9Sstevel@tonic-gate 	for (timeout = 0; (timeout < usba_drain_timeout) &&
703*7c478bd9Sstevel@tonic-gate 	    (ph_data->p_req_count >
704*7c478bd9Sstevel@tonic-gate 	    usba_list_entry_count(&ph_data->p_queue));
705*7c478bd9Sstevel@tonic-gate 	    timeout++) {
706*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
707*7c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000));
708*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
709*7c478bd9Sstevel@tonic-gate 	}
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
712*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
713*7c478bd9Sstevel@tonic-gate 	    "usba_drain_cbs done: ph_data=0x%p ref=%d req=%d",
714*7c478bd9Sstevel@tonic-gate 	    ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count);
715*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 	if (timeout == usba_drain_timeout) {
718*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
719*7c478bd9Sstevel@tonic-gate 		    "draining callbacks timed out!");
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
722*7c478bd9Sstevel@tonic-gate 	}
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 	return (rval);
725*7c478bd9Sstevel@tonic-gate }
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate /*
729*7c478bd9Sstevel@tonic-gate  * usb_pipe_open():
730*7c478bd9Sstevel@tonic-gate  *
731*7c478bd9Sstevel@tonic-gate  * Before using any pipe including the default pipe, it should be opened
732*7c478bd9Sstevel@tonic-gate  * using usb_pipe_open(). On a successful open, a pipe handle is returned
733*7c478bd9Sstevel@tonic-gate  * for use in other usb_pipe_*() functions
734*7c478bd9Sstevel@tonic-gate  *
735*7c478bd9Sstevel@tonic-gate  * The default pipe can only be opened by the hub driver
736*7c478bd9Sstevel@tonic-gate  *
737*7c478bd9Sstevel@tonic-gate  * The bandwidth has been allocated and guaranteed on successful
738*7c478bd9Sstevel@tonic-gate  * opening of an isoc/intr pipes.
739*7c478bd9Sstevel@tonic-gate  *
740*7c478bd9Sstevel@tonic-gate  * Only the default pipe can be shared. all other control pipes
741*7c478bd9Sstevel@tonic-gate  * are excusively opened by default.
742*7c478bd9Sstevel@tonic-gate  * A pipe policy and endpoint descriptor must always be provided
743*7c478bd9Sstevel@tonic-gate  * except for default pipe
744*7c478bd9Sstevel@tonic-gate  *
745*7c478bd9Sstevel@tonic-gate  * Arguments:
746*7c478bd9Sstevel@tonic-gate  *	dip		- devinfo ptr
747*7c478bd9Sstevel@tonic-gate  *	ep		- endpoint descriptor pointer
748*7c478bd9Sstevel@tonic-gate  *	pipe_policy	- pointer to pipe policy which provides hints on how
749*7c478bd9Sstevel@tonic-gate  *			  the pipe will be used.
750*7c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP wait for resources
751*7c478bd9Sstevel@tonic-gate  *			  to become available
752*7c478bd9Sstevel@tonic-gate  *	pipe_handle	- a pipe handle pointer. On a successful open,
753*7c478bd9Sstevel@tonic-gate  *			  a pipe_handle is returned in this pointer.
754*7c478bd9Sstevel@tonic-gate  *
755*7c478bd9Sstevel@tonic-gate  * Return values:
756*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	 - open succeeded
757*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	 - unspecified open failure or pipe is already open
758*7c478bd9Sstevel@tonic-gate  *	USB_NO_RESOURCES - no resources were available to complete the open
759*7c478bd9Sstevel@tonic-gate  *	USB_NO_BANDWIDTH - no bandwidth available (isoc/intr pipes)
760*7c478bd9Sstevel@tonic-gate  *	USB_*		 - refer to usbai.h
761*7c478bd9Sstevel@tonic-gate  */
762*7c478bd9Sstevel@tonic-gate int
763*7c478bd9Sstevel@tonic-gate usb_pipe_open(
764*7c478bd9Sstevel@tonic-gate 	dev_info_t		*dip,
765*7c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*ep,
766*7c478bd9Sstevel@tonic-gate 	usb_pipe_policy_t	*pipe_policy,
767*7c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags,
768*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	*pipe_handle)
769*7c478bd9Sstevel@tonic-gate {
770*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
771*7c478bd9Sstevel@tonic-gate 	int			rval;
772*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data;
773*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl;
774*7c478bd9Sstevel@tonic-gate 	uchar_t			ep_index;
775*7c478bd9Sstevel@tonic-gate 	int			kmflag;
776*7c478bd9Sstevel@tonic-gate 	size_t			size;
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
779*7c478bd9Sstevel@tonic-gate 	    "usb_pipe_open:\n\t"
780*7c478bd9Sstevel@tonic-gate 	    "dip=0x%p ep=0x%p pp=0x%p uf=0x%x ph=0x%p",
781*7c478bd9Sstevel@tonic-gate 	    dip, ep, pipe_policy, usb_flags, pipe_handle);
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (pipe_handle == NULL)) {
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
786*7c478bd9Sstevel@tonic-gate 	}
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 	if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
791*7c478bd9Sstevel@tonic-gate 	}
792*7c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	if ((ep != NULL) && (pipe_policy == NULL)) {
795*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
796*7c478bd9Sstevel@tonic-gate 		    "usb_pipe_open: null pipe policy");
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
799*7c478bd9Sstevel@tonic-gate 	}
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	/* is the device still connected? */
802*7c478bd9Sstevel@tonic-gate 	if ((ep != NULL) & DEVI_IS_DEVICE_REMOVED(dip)) {
803*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
804*7c478bd9Sstevel@tonic-gate 		    "usb_pipe_open: device has been removed");
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
807*7c478bd9Sstevel@tonic-gate 	}
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	/*
811*7c478bd9Sstevel@tonic-gate 	 * if a null endpoint pointer was passed, use the default
812*7c478bd9Sstevel@tonic-gate 	 * endpoint descriptor
813*7c478bd9Sstevel@tonic-gate 	 */
814*7c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
815*7c478bd9Sstevel@tonic-gate 		if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
816*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
817*7c478bd9Sstevel@tonic-gate 			    "usb_pipe_open: not allowed to open def pipe");
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 			return (USB_INVALID_PERM);
820*7c478bd9Sstevel@tonic-gate 		}
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate 		ep = &usba_default_ep_descr;
823*7c478bd9Sstevel@tonic-gate 		pipe_policy = &usba_default_ep_pipe_policy;
824*7c478bd9Sstevel@tonic-gate 	}
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 	if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
827*7c478bd9Sstevel@tonic-gate 		if (((ep->bmAttributes & USB_EP_ATTR_MASK) ==
828*7c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_CONTROL) ||
829*7c478bd9Sstevel@tonic-gate 		    ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
830*7c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_ISOCH)) {
831*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
832*7c478bd9Sstevel@tonic-gate 			    "usb_pipe_open: shared taskq not allowed with "
833*7c478bd9Sstevel@tonic-gate 			    "ctrl or isoch pipe");
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 			return (USB_INVALID_ARGS);
836*7c478bd9Sstevel@tonic-gate 		}
837*7c478bd9Sstevel@tonic-gate 	}
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	kmflag	= (usb_flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
840*7c478bd9Sstevel@tonic-gate 	size	= sizeof (usba_pipe_handle_data_t);
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	if ((ph_data = kmem_zalloc(size, kmflag)) == NULL) {
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
845*7c478bd9Sstevel@tonic-gate 	}
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	/* check if pipe is already open and if so fail */
848*7c478bd9Sstevel@tonic-gate 	ep_index = usb_get_ep_index(ep->bEndpointAddress);
849*7c478bd9Sstevel@tonic-gate 	ph_impl = &usba_device->usb_ph_list[ep_index];
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
852*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	if (ph_impl->usba_ph_data) {
855*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
856*7c478bd9Sstevel@tonic-gate 		    "usb_pipe_open: pipe to ep %d already open", ep_index);
857*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
858*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
859*7c478bd9Sstevel@tonic-gate 		kmem_free(ph_data, size);
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 		return (USB_BUSY);
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_data = ph_data;
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
867*7c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
870*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
871*7c478bd9Sstevel@tonic-gate 		ph_data->p_spec_flag |= USBA_PH_FLAG_TQ_SHARE;
872*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
873*7c478bd9Sstevel@tonic-gate 	}
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 	/*
876*7c478bd9Sstevel@tonic-gate 	 * allocate and initialize the pipe handle
877*7c478bd9Sstevel@tonic-gate 	 */
878*7c478bd9Sstevel@tonic-gate 	if ((rval = usba_init_pipe_handle(dip, usba_device,
879*7c478bd9Sstevel@tonic-gate 	    ep, pipe_policy, ph_impl)) != USB_SUCCESS) {
880*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
881*7c478bd9Sstevel@tonic-gate 		    "usb_pipe_open: pipe init failed (%d)", rval);
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 		return (rval);
884*7c478bd9Sstevel@tonic-gate 	}
885*7c478bd9Sstevel@tonic-gate 	ph_data = ph_impl->usba_ph_data;
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	/*
888*7c478bd9Sstevel@tonic-gate 	 * ask the hcd to open the pipe
889*7c478bd9Sstevel@tonic-gate 	 */
890*7c478bd9Sstevel@tonic-gate 	if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_open(ph_data,
891*7c478bd9Sstevel@tonic-gate 	    usb_flags)) != USB_SUCCESS) {
892*7c478bd9Sstevel@tonic-gate 		usba_destroy_pipe_handle(ph_data);
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 		*pipe_handle = NULL;
895*7c478bd9Sstevel@tonic-gate 	} else {
896*7c478bd9Sstevel@tonic-gate 		*pipe_handle = (usb_pipe_handle_t)ph_impl;
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 		/* set the pipe state after a successful hcd open */
899*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
900*7c478bd9Sstevel@tonic-gate 		usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
901*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
902*7c478bd9Sstevel@tonic-gate 	}
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
905*7c478bd9Sstevel@tonic-gate 	    "usb_pipe_open: ph_impl=0x%p (0x%p)", ph_impl, ph_data);
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	return (rval);
908*7c478bd9Sstevel@tonic-gate }
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate /*
912*7c478bd9Sstevel@tonic-gate  * usb_pipe_close/sync_close:
913*7c478bd9Sstevel@tonic-gate  *
914*7c478bd9Sstevel@tonic-gate  * Close a pipe and release all resources and free the pipe_handle.
915*7c478bd9Sstevel@tonic-gate  * Automatic polling, if active,  will be terminated
916*7c478bd9Sstevel@tonic-gate  *
917*7c478bd9Sstevel@tonic-gate  * Arguments:
918*7c478bd9Sstevel@tonic-gate  *	dip		- devinfo ptr
919*7c478bd9Sstevel@tonic-gate  *	pipehandle	- pointer to pipehandle. The pipehandle will be
920*7c478bd9Sstevel@tonic-gate  *			  zeroed on successful completion
921*7c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
922*7c478bd9Sstevel@tonic-gate  *				wait for resources, pipe
923*7c478bd9Sstevel@tonic-gate  *				to become free, all callbacks completed
924*7c478bd9Sstevel@tonic-gate  *	callback	- If USB_FLAGS_SLEEP has not been specified, a
925*7c478bd9Sstevel@tonic-gate  *			  callback will be performed.
926*7c478bd9Sstevel@tonic-gate  *	callback_arg	- the first argument of the callback. Note that
927*7c478bd9Sstevel@tonic-gate  *			  the pipehandle will be zeroed and not passed
928*7c478bd9Sstevel@tonic-gate  *
929*7c478bd9Sstevel@tonic-gate  * Notes:
930*7c478bd9Sstevel@tonic-gate  * Pipe close will always succeed regardless whether USB_FLAGS_SLEEP has been
931*7c478bd9Sstevel@tonic-gate  * specified or not.
932*7c478bd9Sstevel@tonic-gate  * An async close will always succeed if the hint in the pipe policy
933*7c478bd9Sstevel@tonic-gate  * has been correct about the max number of async taskq requests required.
934*7c478bd9Sstevel@tonic-gate  * If there are really no resources, the pipe handle will be linked into
935*7c478bd9Sstevel@tonic-gate  * a garbage pipe list and periodically checked by USBA until it can be
936*7c478bd9Sstevel@tonic-gate  * closed. This may cause a hang in the detach of the driver.
937*7c478bd9Sstevel@tonic-gate  * USBA will prevent the client from submitting more requests to a pipe
938*7c478bd9Sstevel@tonic-gate  * that is being closed
939*7c478bd9Sstevel@tonic-gate  * Subsequent usb_pipe_close() requests on the same pipe to USBA will
940*7c478bd9Sstevel@tonic-gate  * wait for the previous close(s) to finish.
941*7c478bd9Sstevel@tonic-gate  *
942*7c478bd9Sstevel@tonic-gate  * Note that once we start closing a pipe, we cannot go back anymore
943*7c478bd9Sstevel@tonic-gate  * to a normal pipe state
944*7c478bd9Sstevel@tonic-gate  */
945*7c478bd9Sstevel@tonic-gate void
946*7c478bd9Sstevel@tonic-gate usb_pipe_close(dev_info_t	*dip,
947*7c478bd9Sstevel@tonic-gate 		usb_pipe_handle_t pipe_handle,
948*7c478bd9Sstevel@tonic-gate 		usb_flags_t	usb_flags,
949*7c478bd9Sstevel@tonic-gate 		void		(*callback)(
950*7c478bd9Sstevel@tonic-gate 				    usb_pipe_handle_t	pipe_handle,
951*7c478bd9Sstevel@tonic-gate 				    usb_opaque_t	arg,
952*7c478bd9Sstevel@tonic-gate 				    int			rval,
953*7c478bd9Sstevel@tonic-gate 				    usb_cb_flags_t	flags),
954*7c478bd9Sstevel@tonic-gate 		usb_opaque_t	callback_arg)
955*7c478bd9Sstevel@tonic-gate {
956*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data;
957*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t	*ph_impl = (usba_ph_impl_t *)pipe_handle;
958*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	callback_flags;
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
961*7c478bd9Sstevel@tonic-gate 	    "usb_pipe_close: ph=0x%p", pipe_handle);
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate 	callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
964*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (pipe_handle == NULL)) {
965*7c478bd9Sstevel@tonic-gate 		if (callback) {
966*7c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
967*7c478bd9Sstevel@tonic-gate 			    USB_INVALID_ARGS, callback_flags);
968*7c478bd9Sstevel@tonic-gate 		} else {
969*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBAI,
970*7c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
971*7c478bd9Sstevel@tonic-gate 			    "usb_pipe_close: invalid arguments");
972*7c478bd9Sstevel@tonic-gate 		}
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 		return;
975*7c478bd9Sstevel@tonic-gate 	}
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
978*7c478bd9Sstevel@tonic-gate 		/*
979*7c478bd9Sstevel@tonic-gate 		 * It is the client driver doing the pipe close,
980*7c478bd9Sstevel@tonic-gate 		 * the pipe is no longer persistent then.
981*7c478bd9Sstevel@tonic-gate 		 */
982*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
983*7c478bd9Sstevel@tonic-gate 		ph_impl->usba_ph_flags &= ~USBA_PH_DATA_PERSISTENT;
984*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
985*7c478bd9Sstevel@tonic-gate 	}
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
988*7c478bd9Sstevel@tonic-gate 		if (callback) {
989*7c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
990*7c478bd9Sstevel@tonic-gate 			    USB_INVALID_CONTEXT, callback_flags);
991*7c478bd9Sstevel@tonic-gate 		} else {
992*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBAI,
993*7c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
994*7c478bd9Sstevel@tonic-gate 			    "usb_pipe_close: invalid context");
995*7c478bd9Sstevel@tonic-gate 		}
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 		return;
998*7c478bd9Sstevel@tonic-gate 	}
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 		/* hold pipehandle anyways since we will decrement later */
1003*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
1004*7c478bd9Sstevel@tonic-gate 		ph_impl->usba_ph_ref_count++;
1005*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate 		(void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
1008*7c478bd9Sstevel@tonic-gate 		    ph_impl, NULL, usb_flags, callback, callback_arg);
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 		return;
1011*7c478bd9Sstevel@tonic-gate 	}
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data) &&
1016*7c478bd9Sstevel@tonic-gate 	    ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0)) {
1017*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBAI, usbai_log_handle,
1018*7c478bd9Sstevel@tonic-gate 		    "usb_pipe_close: not allowed to close def pipe");
1019*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 		if (callback) {
1024*7c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
1025*7c478bd9Sstevel@tonic-gate 			    USB_INVALID_PIPE, callback_flags);
1026*7c478bd9Sstevel@tonic-gate 		} else {
1027*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBAI,
1028*7c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
1029*7c478bd9Sstevel@tonic-gate 			    "usb_pipe_close: invalid pipe");
1030*7c478bd9Sstevel@tonic-gate 		}
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 		return;
1033*7c478bd9Sstevel@tonic-gate 	}
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
1038*7c478bd9Sstevel@tonic-gate 	    ph_impl, NULL, usb_flags, callback, callback_arg);
1039*7c478bd9Sstevel@tonic-gate }
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1043*7c478bd9Sstevel@tonic-gate static int
1044*7c478bd9Sstevel@tonic-gate usba_pipe_sync_close(dev_info_t *dip, usba_ph_impl_t *ph_impl,
1045*7c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t *request, usb_flags_t usb_flags)
1046*7c478bd9Sstevel@tonic-gate {
1047*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
1048*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
1049*7c478bd9Sstevel@tonic-gate 					(usb_pipe_handle_t)ph_impl);
1050*7c478bd9Sstevel@tonic-gate 	int			attribute;
1051*7c478bd9Sstevel@tonic-gate 	uchar_t			dir;
1052*7c478bd9Sstevel@tonic-gate 	int			timeout;
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 	if (ph_impl == NULL) {
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
1057*7c478bd9Sstevel@tonic-gate 	}
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
1060*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1061*7c478bd9Sstevel@tonic-gate 	    "usba_pipe_sync_close: dip=0x%p ph_data=0x%p state=%d ref=%d",
1062*7c478bd9Sstevel@tonic-gate 	    dip, ph_data, ph_impl->usba_ph_state, ph_impl->usba_ph_ref_count);
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 	/*
1065*7c478bd9Sstevel@tonic-gate 	 * if another thread opens the pipe again, this loop could
1066*7c478bd9Sstevel@tonic-gate 	 * be truly forever
1067*7c478bd9Sstevel@tonic-gate 	 */
1068*7c478bd9Sstevel@tonic-gate 	if ((ph_data == NULL) ||
1069*7c478bd9Sstevel@tonic-gate 	    (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSING) ||
1070*7c478bd9Sstevel@tonic-gate 	    (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSED)) {
1071*7c478bd9Sstevel@tonic-gate 		/* wait forever till really closed */
1072*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
1073*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 		while (usba_get_ph_data((usb_pipe_handle_t)ph_impl)) {
1076*7c478bd9Sstevel@tonic-gate 			delay(1);
1077*7c478bd9Sstevel@tonic-gate 		}
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
1080*7c478bd9Sstevel@tonic-gate 	}
1081*7c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSING;
1082*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1085*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 	attribute = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
1088*7c478bd9Sstevel@tonic-gate 	dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	/*
1093*7c478bd9Sstevel@tonic-gate 	 * For control and bulk, we will drain till ref_count <= 1 and
1094*7c478bd9Sstevel@tonic-gate 	 * req_count == 0 but for isoc and intr IN, we can only wait
1095*7c478bd9Sstevel@tonic-gate 	 * till the ref_count === 1 as the req_count will never go to 0
1096*7c478bd9Sstevel@tonic-gate 	 */
1097*7c478bd9Sstevel@tonic-gate 	for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
1098*7c478bd9Sstevel@tonic-gate 		switch (attribute) {
1099*7c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
1100*7c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
1101*7c478bd9Sstevel@tonic-gate 			if ((ph_data->p_req_count == 0) &&
1102*7c478bd9Sstevel@tonic-gate 			    (ph_impl->usba_ph_ref_count <= 1)) {
1103*7c478bd9Sstevel@tonic-gate 				goto done;
1104*7c478bd9Sstevel@tonic-gate 			}
1105*7c478bd9Sstevel@tonic-gate 			break;
1106*7c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
1107*7c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
1108*7c478bd9Sstevel@tonic-gate 			if (dir == USB_EP_DIR_IN) {
1109*7c478bd9Sstevel@tonic-gate 				if (ph_impl->usba_ph_ref_count <= 1) {
1110*7c478bd9Sstevel@tonic-gate 					goto done;
1111*7c478bd9Sstevel@tonic-gate 				}
1112*7c478bd9Sstevel@tonic-gate 			} else if ((ph_data->p_req_count == 0) &&
1113*7c478bd9Sstevel@tonic-gate 			    (ph_impl->usba_ph_ref_count <= 1)) {
1114*7c478bd9Sstevel@tonic-gate 				goto done;
1115*7c478bd9Sstevel@tonic-gate 			}
1116*7c478bd9Sstevel@tonic-gate 			break;
1117*7c478bd9Sstevel@tonic-gate 		}
1118*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
1119*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
1120*7c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000));
1121*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
1122*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
1123*7c478bd9Sstevel@tonic-gate 	}
1124*7c478bd9Sstevel@tonic-gate done:
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
1127*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 	if (timeout >= usba_drain_timeout) {
1130*7c478bd9Sstevel@tonic-gate 		int draining_succeeded;
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1133*7c478bd9Sstevel@tonic-gate 		    "timeout on draining requests, resetting pipe 0x%p",
1134*7c478bd9Sstevel@tonic-gate 		    ph_impl);
1135*7c478bd9Sstevel@tonic-gate 
1136*7c478bd9Sstevel@tonic-gate 		(void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1137*7c478bd9Sstevel@tonic-gate 		    USB_FLAGS_SLEEP);
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
1140*7c478bd9Sstevel@tonic-gate 		draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
1141*7c478bd9Sstevel@tonic-gate 						USB_CR_PIPE_RESET);
1142*7c478bd9Sstevel@tonic-gate 		/* this MUST have succeeded */
1143*7c478bd9Sstevel@tonic-gate 		ASSERT(draining_succeeded == USB_SUCCESS);
1144*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
1145*7c478bd9Sstevel@tonic-gate 
1146*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1147*7c478bd9Sstevel@tonic-gate 		    "draining requests done");
1148*7c478bd9Sstevel@tonic-gate 	}
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 	if (usba_device->usb_hcdi_ops->usba_hcdi_pipe_close(ph_data,
1151*7c478bd9Sstevel@tonic-gate 	    usb_flags) != USB_SUCCESS) {
1152*7c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L1(DPRINT_MASK_USBAI, usbai_log_handle,
1153*7c478bd9Sstevel@tonic-gate 		    "usba_pipe_sync_close: hcd close failed");
1154*7c478bd9Sstevel@tonic-gate 		/* carry on regardless! */
1155*7c478bd9Sstevel@tonic-gate 	}
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	usba_destroy_pipe_handle(ph_data);
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1160*7c478bd9Sstevel@tonic-gate }
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate /*
1164*7c478bd9Sstevel@tonic-gate  * usb_pipe_set_private:
1165*7c478bd9Sstevel@tonic-gate  *	set private client date in the pipe handle
1166*7c478bd9Sstevel@tonic-gate  */
1167*7c478bd9Sstevel@tonic-gate int
1168*7c478bd9Sstevel@tonic-gate usb_pipe_set_private(usb_pipe_handle_t	pipe_handle, usb_opaque_t data)
1169*7c478bd9Sstevel@tonic-gate {
1170*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1173*7c478bd9Sstevel@tonic-gate 	    "usb_pipe_set_private: ");
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
1178*7c478bd9Sstevel@tonic-gate 	}
1179*7c478bd9Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1180*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PERM);
1183*7c478bd9Sstevel@tonic-gate 	}
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1186*7c478bd9Sstevel@tonic-gate 	ph_data->p_client_private = data;
1187*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
1190*7c478bd9Sstevel@tonic-gate 
1191*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1192*7c478bd9Sstevel@tonic-gate }
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate /*
1196*7c478bd9Sstevel@tonic-gate  * usb_pipe_get_private:
1197*7c478bd9Sstevel@tonic-gate  *	get private client date from the pipe handle
1198*7c478bd9Sstevel@tonic-gate  */
1199*7c478bd9Sstevel@tonic-gate usb_opaque_t
1200*7c478bd9Sstevel@tonic-gate usb_pipe_get_private(usb_pipe_handle_t	pipe_handle)
1201*7c478bd9Sstevel@tonic-gate {
1202*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1203*7c478bd9Sstevel@tonic-gate 	usb_opaque_t		data;
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1206*7c478bd9Sstevel@tonic-gate 	    "usb_pipe_get_private:");
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 		return (NULL);
1211*7c478bd9Sstevel@tonic-gate 	}
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1214*7c478bd9Sstevel@tonic-gate 	data = ph_data->p_client_private;
1215*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 	return (data);
1220*7c478bd9Sstevel@tonic-gate }
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 
1223*7c478bd9Sstevel@tonic-gate /*
1224*7c478bd9Sstevel@tonic-gate  * usb_pipe_reset
1225*7c478bd9Sstevel@tonic-gate  * Arguments:
1226*7c478bd9Sstevel@tonic-gate  *	dip		- devinfo pointer
1227*7c478bd9Sstevel@tonic-gate  *	pipe_handle	- opaque pipe handle
1228*7c478bd9Sstevel@tonic-gate  * Returns:
1229*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- pipe successfully reset or request queued
1230*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- undetermined failure
1231*7c478bd9Sstevel@tonic-gate  *	USB_INVALID_PIPE - pipe is invalid or already closed
1232*7c478bd9Sstevel@tonic-gate  */
1233*7c478bd9Sstevel@tonic-gate void
1234*7c478bd9Sstevel@tonic-gate usb_pipe_reset(dev_info_t		*dip,
1235*7c478bd9Sstevel@tonic-gate 		usb_pipe_handle_t	pipe_handle,
1236*7c478bd9Sstevel@tonic-gate 		usb_flags_t		usb_flags,
1237*7c478bd9Sstevel@tonic-gate 		void			(*callback)(
1238*7c478bd9Sstevel@tonic-gate 					    usb_pipe_handle_t	ph,
1239*7c478bd9Sstevel@tonic-gate 					    usb_opaque_t	arg,
1240*7c478bd9Sstevel@tonic-gate 					    int			rval,
1241*7c478bd9Sstevel@tonic-gate 					    usb_cb_flags_t	flags),
1242*7c478bd9Sstevel@tonic-gate 		usb_opaque_t		callback_arg)
1243*7c478bd9Sstevel@tonic-gate {
1244*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
1245*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1246*7c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		callback_flags;
1247*7c478bd9Sstevel@tonic-gate 
1248*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1249*7c478bd9Sstevel@tonic-gate 	    "usb_pipe_reset: dip=0x%p ph=0x%p uf=0x%x",
1250*7c478bd9Sstevel@tonic-gate 	    dip, pipe_handle, usb_flags);
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
1253*7c478bd9Sstevel@tonic-gate 
1254*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (ph_data == NULL)) {
1255*7c478bd9Sstevel@tonic-gate 		if (callback) {
1256*7c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
1257*7c478bd9Sstevel@tonic-gate 			    USB_INVALID_ARGS, callback_flags);
1258*7c478bd9Sstevel@tonic-gate 		} else {
1259*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBAI,
1260*7c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
1261*7c478bd9Sstevel@tonic-gate 			    "usb_pipe_reset: invalid arguments");
1262*7c478bd9Sstevel@tonic-gate 		}
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 		return;
1267*7c478bd9Sstevel@tonic-gate 	}
1268*7c478bd9Sstevel@tonic-gate 	if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
1269*7c478bd9Sstevel@tonic-gate 		if (callback) {
1270*7c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
1271*7c478bd9Sstevel@tonic-gate 			    USB_INVALID_CONTEXT, callback_flags);
1272*7c478bd9Sstevel@tonic-gate 		} else {
1273*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBAI,
1274*7c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
1275*7c478bd9Sstevel@tonic-gate 			    "usb_pipe_reset: invalid context");
1276*7c478bd9Sstevel@tonic-gate 		}
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 		return;
1281*7c478bd9Sstevel@tonic-gate 	}
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate 	/* is this the default pipe? */
1286*7c478bd9Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1287*7c478bd9Sstevel@tonic-gate 		if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
1288*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L1(DPRINT_MASK_USBAI, usbai_log_handle,
1289*7c478bd9Sstevel@tonic-gate 			    "usb_pipe_reset: not allowed to reset def pipe");
1290*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 			if (callback) {
1293*7c478bd9Sstevel@tonic-gate 				callback(pipe_handle, callback_arg,
1294*7c478bd9Sstevel@tonic-gate 				    USB_INVALID_PIPE, callback_flags);
1295*7c478bd9Sstevel@tonic-gate 			} else {
1296*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L1(DPRINT_MASK_USBAI,
1297*7c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
1298*7c478bd9Sstevel@tonic-gate 				    "usb_pipe_reset: invalid pipe");
1299*7c478bd9Sstevel@tonic-gate 			}
1300*7c478bd9Sstevel@tonic-gate 			usba_release_ph_data(ph_impl);
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate 			return;
1303*7c478bd9Sstevel@tonic-gate 		}
1304*7c478bd9Sstevel@tonic-gate 	}
1305*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1306*7c478bd9Sstevel@tonic-gate 
1307*7c478bd9Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(dip,
1308*7c478bd9Sstevel@tonic-gate 	    usba_pipe_sync_reset, ph_impl, NULL, usb_flags, callback,
1309*7c478bd9Sstevel@tonic-gate 	    callback_arg);
1310*7c478bd9Sstevel@tonic-gate }
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1314*7c478bd9Sstevel@tonic-gate int
1315*7c478bd9Sstevel@tonic-gate usba_pipe_sync_reset(dev_info_t	*dip,
1316*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl,
1317*7c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t	*request,
1318*7c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags)
1319*7c478bd9Sstevel@tonic-gate {
1320*7c478bd9Sstevel@tonic-gate 	int rval, draining_succeeded;
1321*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
1322*7c478bd9Sstevel@tonic-gate 								ph_impl);
1323*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
1324*7c478bd9Sstevel@tonic-gate 
1325*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1326*7c478bd9Sstevel@tonic-gate 	    "usba_pipe_sync_reset: dip=0x%p ph_data=0x%p uf=0x%x",
1327*7c478bd9Sstevel@tonic-gate 	    dip, ph_data, usb_flags);
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1330*7c478bd9Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
1331*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1332*7c478bd9Sstevel@tonic-gate 
1333*7c478bd9Sstevel@tonic-gate 	rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1334*7c478bd9Sstevel@tonic-gate 								usb_flags);
1335*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate 	/*
1338*7c478bd9Sstevel@tonic-gate 	 * The host controller has stopped polling of the endpoint.
1339*7c478bd9Sstevel@tonic-gate 	 */
1340*7c478bd9Sstevel@tonic-gate 	draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
1341*7c478bd9Sstevel@tonic-gate 							USB_CR_PIPE_RESET);
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate 	/* this MUST have succeeded */
1344*7c478bd9Sstevel@tonic-gate 	ASSERT(draining_succeeded == USB_SUCCESS);
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 	usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1347*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1348*7c478bd9Sstevel@tonic-gate 
1349*7c478bd9Sstevel@tonic-gate 	/*
1350*7c478bd9Sstevel@tonic-gate 	 * if there are requests still queued on the default pipe,
1351*7c478bd9Sstevel@tonic-gate 	 * start them now
1352*7c478bd9Sstevel@tonic-gate 	 */
1353*7c478bd9Sstevel@tonic-gate 	usba_start_next_req(ph_data);
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 	return (rval);
1358*7c478bd9Sstevel@tonic-gate }
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate /*
1362*7c478bd9Sstevel@tonic-gate  * usba_pipe_clear:
1363*7c478bd9Sstevel@tonic-gate  *	call hcd to clear pipe but don't wait for draining
1364*7c478bd9Sstevel@tonic-gate  */
1365*7c478bd9Sstevel@tonic-gate void
1366*7c478bd9Sstevel@tonic-gate usba_pipe_clear(usb_pipe_handle_t pipe_handle)
1367*7c478bd9Sstevel@tonic-gate {
1368*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(pipe_handle);
1369*7c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
1370*7c478bd9Sstevel@tonic-gate 	usba_req_wrapper_t	*req_wrp;
1371*7c478bd9Sstevel@tonic-gate 	int			flush_requests = 1;
1372*7c478bd9Sstevel@tonic-gate 
1373*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1374*7c478bd9Sstevel@tonic-gate 	    "usba_pipe_clear: ph_data=0x%p", ph_data);
1375*7c478bd9Sstevel@tonic-gate 
1376*7c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
1377*7c478bd9Sstevel@tonic-gate 
1378*7c478bd9Sstevel@tonic-gate 		return;
1379*7c478bd9Sstevel@tonic-gate 	}
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1382*7c478bd9Sstevel@tonic-gate 	if (USBA_PIPE_CLOSING(usba_get_ph_state(ph_data))) {
1383*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 		return;
1386*7c478bd9Sstevel@tonic-gate 	}
1387*7c478bd9Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
1388*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1389*7c478bd9Sstevel@tonic-gate 
1390*7c478bd9Sstevel@tonic-gate 	(void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1391*7c478bd9Sstevel@tonic-gate 							USB_FLAGS_SLEEP);
1392*7c478bd9Sstevel@tonic-gate 
1393*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1394*7c478bd9Sstevel@tonic-gate 	if (ph_data->p_dip) {
1395*7c478bd9Sstevel@tonic-gate 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1396*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
1397*7c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
1398*7c478bd9Sstevel@tonic-gate 			    "no flushing on default pipe!");
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate 			flush_requests = 0;
1401*7c478bd9Sstevel@tonic-gate 		}
1402*7c478bd9Sstevel@tonic-gate 	}
1403*7c478bd9Sstevel@tonic-gate 
1404*7c478bd9Sstevel@tonic-gate 	if (flush_requests) {
1405*7c478bd9Sstevel@tonic-gate 		/* flush all requests in the pipehandle queue */
1406*7c478bd9Sstevel@tonic-gate 		while ((req_wrp = (usba_req_wrapper_t *)
1407*7c478bd9Sstevel@tonic-gate 		    usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
1408*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
1409*7c478bd9Sstevel@tonic-gate 			usba_do_req_exc_cb(req_wrp, USB_CR_FLUSHED,
1410*7c478bd9Sstevel@tonic-gate 					USB_CB_RESET_PIPE);
1411*7c478bd9Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
1412*7c478bd9Sstevel@tonic-gate 		}
1413*7c478bd9Sstevel@tonic-gate 	}
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 	usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1416*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1417*7c478bd9Sstevel@tonic-gate }
1418*7c478bd9Sstevel@tonic-gate 
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate /*
1421*7c478bd9Sstevel@tonic-gate  *
1422*7c478bd9Sstevel@tonic-gate  * usb_pipe_drain_reqs
1423*7c478bd9Sstevel@tonic-gate  *	this function blocks until there are no more requests
1424*7c478bd9Sstevel@tonic-gate  *	owned by this dip on the pipe
1425*7c478bd9Sstevel@tonic-gate  *
1426*7c478bd9Sstevel@tonic-gate  * Arguments:
1427*7c478bd9Sstevel@tonic-gate  *	dip		- devinfo pointer
1428*7c478bd9Sstevel@tonic-gate  *	pipe_handle	- opaque pipe handle
1429*7c478bd9Sstevel@tonic-gate  *	timeout 	- timeout in seconds
1430*7c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
1431*7c478bd9Sstevel@tonic-gate  *				wait for completion.
1432*7c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
1433*7c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
1434*7c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
1435*7c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
1436*7c478bd9Sstevel@tonic-gate  *			  be provided.
1437*7c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
1438*7c478bd9Sstevel@tonic-gate  *
1439*7c478bd9Sstevel@tonic-gate  * callback and callback_arg should be NULL if USB_FLAGS_SLEEP has
1440*7c478bd9Sstevel@tonic-gate  * been specified
1441*7c478bd9Sstevel@tonic-gate  *
1442*7c478bd9Sstevel@tonic-gate  * Returns:
1443*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- pipe successfully reset or request queued
1444*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- timeout
1445*7c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
1446*7c478bd9Sstevel@tonic-gate  */
1447*7c478bd9Sstevel@tonic-gate int
1448*7c478bd9Sstevel@tonic-gate usb_pipe_drain_reqs(dev_info_t	*dip,
1449*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle,
1450*7c478bd9Sstevel@tonic-gate 	uint_t			time,
1451*7c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags,
1452*7c478bd9Sstevel@tonic-gate 	void			(*cb)(
1453*7c478bd9Sstevel@tonic-gate 				    usb_pipe_handle_t	ph,
1454*7c478bd9Sstevel@tonic-gate 				    usb_opaque_t	arg,   /* cb arg */
1455*7c478bd9Sstevel@tonic-gate 				    int			rval,
1456*7c478bd9Sstevel@tonic-gate 				    usb_cb_flags_t	flags),
1457*7c478bd9Sstevel@tonic-gate 	usb_opaque_t		cb_arg)
1458*7c478bd9Sstevel@tonic-gate {
1459*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
1460*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1461*7c478bd9Sstevel@tonic-gate 
1462*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1463*7c478bd9Sstevel@tonic-gate 	    "usb_pipe_drain_reqs: dip=0x%p ph_data=0x%p tm=%d uf=0x%x",
1464*7c478bd9Sstevel@tonic-gate 	    dip, ph_data, time, usb_flags);
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
1469*7c478bd9Sstevel@tonic-gate 	}
1470*7c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
1471*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
1474*7c478bd9Sstevel@tonic-gate 	}
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
1477*7c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
1480*7c478bd9Sstevel@tonic-gate 	}
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(dip, usba_pipe_sync_drain_reqs,
1483*7c478bd9Sstevel@tonic-gate 	    ph_impl, (usb_opaque_t)((uintptr_t)time), usb_flags, cb, cb_arg);
1484*7c478bd9Sstevel@tonic-gate 
1485*7c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
1486*7c478bd9Sstevel@tonic-gate }
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate /*
1490*7c478bd9Sstevel@tonic-gate  * usba_pipe_sync_drain_reqs
1491*7c478bd9Sstevel@tonic-gate  *	this function blocks until there are no more requests
1492*7c478bd9Sstevel@tonic-gate  *	owned by this dip on the pipe
1493*7c478bd9Sstevel@tonic-gate  *
1494*7c478bd9Sstevel@tonic-gate  * Arguments:
1495*7c478bd9Sstevel@tonic-gate  *	dip		- devinfo pointer
1496*7c478bd9Sstevel@tonic-gate  *	ph_impl		- pipe impl handle
1497*7c478bd9Sstevel@tonic-gate  *	timeout		- timeout in seconds
1498*7c478bd9Sstevel@tonic-gate  * Returns:
1499*7c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- pipe successfully reset or request queued
1500*7c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- timeout
1501*7c478bd9Sstevel@tonic-gate  *	USB_*		- see usbai.h
1502*7c478bd9Sstevel@tonic-gate  */
1503*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1504*7c478bd9Sstevel@tonic-gate int
1505*7c478bd9Sstevel@tonic-gate usba_pipe_sync_drain_reqs(dev_info_t	*dip,
1506*7c478bd9Sstevel@tonic-gate 		usba_ph_impl_t		*ph_impl,
1507*7c478bd9Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
1508*7c478bd9Sstevel@tonic-gate 		usb_flags_t		usb_flags)
1509*7c478bd9Sstevel@tonic-gate {
1510*7c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
1511*7c478bd9Sstevel@tonic-gate 								ph_impl);
1512*7c478bd9Sstevel@tonic-gate 	int		i;
1513*7c478bd9Sstevel@tonic-gate 	int		timeout = 100 * (int)((uintptr_t)(request->arg));
1514*7c478bd9Sstevel@tonic-gate 						/* delay will be 10 ms */
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1519*7c478bd9Sstevel@tonic-gate 	    "usba_pipe_sync_drain_reqs: "
1520*7c478bd9Sstevel@tonic-gate 	    "dip=0x%p ph_data=0x%p timeout=%d ref=%d req=%d",
1521*7c478bd9Sstevel@tonic-gate 	    dip, ph_data, timeout, usba_get_ph_ref_count(ph_data),
1522*7c478bd9Sstevel@tonic-gate 	    ph_data->p_req_count);
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 	/*
1527*7c478bd9Sstevel@tonic-gate 	 * for default pipe, we need to check the active request
1528*7c478bd9Sstevel@tonic-gate 	 * and the queue
1529*7c478bd9Sstevel@tonic-gate 	 * Note that a pipe reset on the default pipe doesn't flush
1530*7c478bd9Sstevel@tonic-gate 	 * the queue
1531*7c478bd9Sstevel@tonic-gate 	 * for all other pipes we just check ref and req count since
1532*7c478bd9Sstevel@tonic-gate 	 * these pipes are unshared
1533*7c478bd9Sstevel@tonic-gate 	 */
1534*7c478bd9Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1535*7c478bd9Sstevel@tonic-gate 		for (i = 0; (i < timeout) || (request->arg == 0); i++) {
1536*7c478bd9Sstevel@tonic-gate 			usba_list_entry_t *next, *tmpnext;
1537*7c478bd9Sstevel@tonic-gate 			usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *)
1538*7c478bd9Sstevel@tonic-gate 					    ph_data->p_active_cntrl_req_wrp;
1539*7c478bd9Sstevel@tonic-gate 			int found = 0;
1540*7c478bd9Sstevel@tonic-gate 			int count = 0;
1541*7c478bd9Sstevel@tonic-gate 
1542*7c478bd9Sstevel@tonic-gate 			/* active_req_wrp is only for control pipes */
1543*7c478bd9Sstevel@tonic-gate 			if ((req_wrp == NULL) || (req_wrp->wr_dip != dip)) {
1544*7c478bd9Sstevel@tonic-gate 				/* walk the queue */
1545*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_data->p_queue.list_mutex);
1546*7c478bd9Sstevel@tonic-gate 				next = ph_data->p_queue.next;
1547*7c478bd9Sstevel@tonic-gate 				while (next != NULL) {
1548*7c478bd9Sstevel@tonic-gate 					mutex_enter(&next->list_mutex);
1549*7c478bd9Sstevel@tonic-gate 					req_wrp = (usba_req_wrapper_t *)
1550*7c478bd9Sstevel@tonic-gate 							next->private;
1551*7c478bd9Sstevel@tonic-gate 					found = (req_wrp->wr_dip == dip);
1552*7c478bd9Sstevel@tonic-gate 					if (found) {
1553*7c478bd9Sstevel@tonic-gate 						mutex_exit(&next->list_mutex);
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate 						break;
1556*7c478bd9Sstevel@tonic-gate 					}
1557*7c478bd9Sstevel@tonic-gate 					tmpnext = next->next;
1558*7c478bd9Sstevel@tonic-gate 					mutex_exit(&next->list_mutex);
1559*7c478bd9Sstevel@tonic-gate 					next = tmpnext;
1560*7c478bd9Sstevel@tonic-gate 					count++;
1561*7c478bd9Sstevel@tonic-gate 				}
1562*7c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_data->p_queue.list_mutex);
1563*7c478bd9Sstevel@tonic-gate 				if (found == 0) {
1564*7c478bd9Sstevel@tonic-gate 					break;
1565*7c478bd9Sstevel@tonic-gate 				}
1566*7c478bd9Sstevel@tonic-gate 			}
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1569*7c478bd9Sstevel@tonic-gate 			    "usb_pipe_sync_drain_reqs: "
1570*7c478bd9Sstevel@tonic-gate 			    "cnt=%d active_req_wrp=0x%p",
1571*7c478bd9Sstevel@tonic-gate 			    count, ph_data->p_active_cntrl_req_wrp);
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
1574*7c478bd9Sstevel@tonic-gate 			delay(drv_usectohz(10000));
1575*7c478bd9Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
1576*7c478bd9Sstevel@tonic-gate 		}
1577*7c478bd9Sstevel@tonic-gate 	} else {
1578*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
1579*7c478bd9Sstevel@tonic-gate 		for (i = 0; (i < timeout) || (request->arg == 0); i++) {
1580*7c478bd9Sstevel@tonic-gate 			ASSERT(ph_data->p_req_count >= 0);
1581*7c478bd9Sstevel@tonic-gate 			if (ph_data->p_req_count ||
1582*7c478bd9Sstevel@tonic-gate 			    (ph_data->p_ph_impl->usba_ph_ref_count > 1)) {
1583*7c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
1584*7c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_data->p_mutex);
1585*7c478bd9Sstevel@tonic-gate 				delay(drv_usectohz(10000));
1586*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_data->p_mutex);
1587*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
1588*7c478bd9Sstevel@tonic-gate 			} else {
1589*7c478bd9Sstevel@tonic-gate 				break;
1590*7c478bd9Sstevel@tonic-gate 			}
1591*7c478bd9Sstevel@tonic-gate 		}
1592*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
1593*7c478bd9Sstevel@tonic-gate 	}
1594*7c478bd9Sstevel@tonic-gate 
1595*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1596*7c478bd9Sstevel@tonic-gate 	    "usb_pipe_sync_drain_reqs: timeout=%d active_req_wrp=0x%p req=%d",
1597*7c478bd9Sstevel@tonic-gate 	    i, ph_data->p_active_cntrl_req_wrp, ph_data->p_req_count);
1598*7c478bd9Sstevel@tonic-gate 
1599*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
1600*7c478bd9Sstevel@tonic-gate 
1601*7c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
1602*7c478bd9Sstevel@tonic-gate 
1603*7c478bd9Sstevel@tonic-gate 	return (i >= timeout ? USB_FAILURE : USB_SUCCESS);
1604*7c478bd9Sstevel@tonic-gate }
1605*7c478bd9Sstevel@tonic-gate 
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate /*
1608*7c478bd9Sstevel@tonic-gate  * usba_persistent_pipe_open
1609*7c478bd9Sstevel@tonic-gate  *	Open all the pipes marked persistent for this device
1610*7c478bd9Sstevel@tonic-gate  */
1611*7c478bd9Sstevel@tonic-gate int
1612*7c478bd9Sstevel@tonic-gate usba_persistent_pipe_open(usba_device_t *usba_device)
1613*7c478bd9Sstevel@tonic-gate {
1614*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl;
1615*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle;
1616*7c478bd9Sstevel@tonic-gate 	int			i;
1617*7c478bd9Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1620*7c478bd9Sstevel@tonic-gate 	    "usba_persistent_pipe_open: usba_device=0x%p", usba_device);
1621*7c478bd9Sstevel@tonic-gate 
1622*7c478bd9Sstevel@tonic-gate 	if (usba_device != NULL) {
1623*7c478bd9Sstevel@tonic-gate 		/* default pipe is the first one to be opened */
1624*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
1625*7c478bd9Sstevel@tonic-gate 		for (i = 0; (rval == USB_SUCCESS) &&
1626*7c478bd9Sstevel@tonic-gate 		    (i < USBA_N_ENDPOINTS); i++) {
1627*7c478bd9Sstevel@tonic-gate 
1628*7c478bd9Sstevel@tonic-gate 			ph_impl = &usba_device->usb_ph_list[i];
1629*7c478bd9Sstevel@tonic-gate 			mutex_enter(&ph_impl->usba_ph_mutex);
1630*7c478bd9Sstevel@tonic-gate 			if (ph_impl->usba_ph_flags & USBA_PH_DATA_PERSISTENT) {
1631*7c478bd9Sstevel@tonic-gate 				ph_impl->usba_ph_flags &=
1632*7c478bd9Sstevel@tonic-gate 						~USBA_PH_DATA_PERSISTENT;
1633*7c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_impl->usba_ph_mutex);
1634*7c478bd9Sstevel@tonic-gate 				mutex_exit(&usba_device->usb_mutex);
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate 				rval = usb_pipe_open(ph_impl->usba_ph_dip,
1637*7c478bd9Sstevel@tonic-gate 				    &ph_impl->usba_ph_ep,
1638*7c478bd9Sstevel@tonic-gate 				    &ph_impl->usba_ph_policy,
1639*7c478bd9Sstevel@tonic-gate 				    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
1640*7c478bd9Sstevel@tonic-gate 				    &pipe_handle);
1641*7c478bd9Sstevel@tonic-gate 
1642*7c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(DPRINT_MASK_USBAI,
1643*7c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
1644*7c478bd9Sstevel@tonic-gate 				    "usba_persistent_pipe_open: "
1645*7c478bd9Sstevel@tonic-gate 				    "ep_index=%d, rval=%d", i, rval);
1646*7c478bd9Sstevel@tonic-gate 				mutex_enter(&usba_device->usb_mutex);
1647*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_impl->usba_ph_mutex);
1648*7c478bd9Sstevel@tonic-gate 			}
1649*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_impl->usba_ph_mutex);
1650*7c478bd9Sstevel@tonic-gate 		}
1651*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
1652*7c478bd9Sstevel@tonic-gate 	}
1653*7c478bd9Sstevel@tonic-gate 
1654*7c478bd9Sstevel@tonic-gate 	return (rval);
1655*7c478bd9Sstevel@tonic-gate }
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate /*
1659*7c478bd9Sstevel@tonic-gate  * usba_persistent_pipe_close
1660*7c478bd9Sstevel@tonic-gate  *	Close all pipes of this device and mark them persistent
1661*7c478bd9Sstevel@tonic-gate  */
1662*7c478bd9Sstevel@tonic-gate void
1663*7c478bd9Sstevel@tonic-gate usba_persistent_pipe_close(usba_device_t *usba_device)
1664*7c478bd9Sstevel@tonic-gate {
1665*7c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl;
1666*7c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle;
1667*7c478bd9Sstevel@tonic-gate 	int			i;
1668*7c478bd9Sstevel@tonic-gate 
1669*7c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1670*7c478bd9Sstevel@tonic-gate 	    "usba_persistent_pipe_close: usba_device=0x%p", usba_device);
1671*7c478bd9Sstevel@tonic-gate 
1672*7c478bd9Sstevel@tonic-gate 	if (usba_device != NULL) {
1673*7c478bd9Sstevel@tonic-gate 		/* default pipe is the last one to be closed */
1674*7c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
1675*7c478bd9Sstevel@tonic-gate 
1676*7c478bd9Sstevel@tonic-gate 		for (i = (USBA_N_ENDPOINTS - 1); i >= 0; i--) {
1677*7c478bd9Sstevel@tonic-gate 			ph_impl = &usba_device->usb_ph_list[i];
1678*7c478bd9Sstevel@tonic-gate 			if (ph_impl->usba_ph_data != NULL) {
1679*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_impl->usba_ph_mutex);
1680*7c478bd9Sstevel@tonic-gate 				ph_impl->usba_ph_flags |=
1681*7c478bd9Sstevel@tonic-gate 						USBA_PH_DATA_PERSISTENT;
1682*7c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_impl->usba_ph_mutex);
1683*7c478bd9Sstevel@tonic-gate 				mutex_exit(&usba_device->usb_mutex);
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate 				pipe_handle = (usb_pipe_handle_t)ph_impl;
1686*7c478bd9Sstevel@tonic-gate 
1687*7c478bd9Sstevel@tonic-gate 				usb_pipe_close(ph_impl->usba_ph_dip,
1688*7c478bd9Sstevel@tonic-gate 				    pipe_handle,
1689*7c478bd9Sstevel@tonic-gate 				    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
1690*7c478bd9Sstevel@tonic-gate 				    NULL, NULL);
1691*7c478bd9Sstevel@tonic-gate 				mutex_enter(&usba_device->usb_mutex);
1692*7c478bd9Sstevel@tonic-gate 				ASSERT(ph_impl->usba_ph_data == NULL);
1693*7c478bd9Sstevel@tonic-gate 			}
1694*7c478bd9Sstevel@tonic-gate 		}
1695*7c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
1696*7c478bd9Sstevel@tonic-gate 	}
1697*7c478bd9Sstevel@tonic-gate }
1698