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