17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
234610e4a0Sfrits  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * all functions exposed to client drivers  have prefix usb_ while all USBA
337c478bd9Sstevel@tonic-gate  * internal functions or functions exposed to HCD or hubd only have prefix
347c478bd9Sstevel@tonic-gate  * usba_
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * this file contains all USBAI pipe management
377c478bd9Sstevel@tonic-gate  *	usb_pipe_open()
387c478bd9Sstevel@tonic-gate  *	usb_pipe_close()
397c478bd9Sstevel@tonic-gate  *	usb_pipe_set_private()
407c478bd9Sstevel@tonic-gate  *	usb_pipe_get_private()
417c478bd9Sstevel@tonic-gate  *	usb_pipe_abort()
427c478bd9Sstevel@tonic-gate  *	usb_pipe_reset()
437c478bd9Sstevel@tonic-gate  *	usb_pipe_drain_reqs()
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate #define	USBA_FRAMEWORK
467c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
477c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
487c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate extern	pri_t	maxclsyspri;
517c478bd9Sstevel@tonic-gate extern	pri_t	minclsyspri;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /* function prototypes */
547c478bd9Sstevel@tonic-gate static	void	usba_pipe_do_async_func_thread(void *arg);
557c478bd9Sstevel@tonic-gate static	int	usba_pipe_sync_close(dev_info_t *, usba_ph_impl_t *,
567c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
577c478bd9Sstevel@tonic-gate static	int	usba_pipe_sync_abort(dev_info_t *, usba_ph_impl_t *,
587c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
597c478bd9Sstevel@tonic-gate static	int	usba_pipe_sync_reset(dev_info_t *, usba_ph_impl_t *,
607c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
617c478bd9Sstevel@tonic-gate static	int	usba_pipe_sync_drain_reqs(dev_info_t *, usba_ph_impl_t *,
627c478bd9Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /* local tunables */
654610e4a0Sfrits int	usba_drain_timeout = 1000;	/* in ms */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /* return the default pipe for this device */
687c478bd9Sstevel@tonic-gate usb_pipe_handle_t
697c478bd9Sstevel@tonic-gate usba_get_dflt_pipe_handle(dev_info_t *dip)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
727c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = NULL;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	if (dip) {
757c478bd9Sstevel@tonic-gate 		usba_device = usba_get_usba_device(dip);
767c478bd9Sstevel@tonic-gate 		if (usba_device) {
777c478bd9Sstevel@tonic-gate 			pipe_handle =
787c478bd9Sstevel@tonic-gate 			    (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
797c478bd9Sstevel@tonic-gate 		}
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	return (pipe_handle);
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /* return dip owner of pipe_handle */
877c478bd9Sstevel@tonic-gate dev_info_t *
887c478bd9Sstevel@tonic-gate usba_get_dip(usb_pipe_handle_t pipe_handle)
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
917c478bd9Sstevel@tonic-gate 	dev_info_t		*dip = NULL;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	if (ph_impl) {
947c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
957c478bd9Sstevel@tonic-gate 		dip = ph_impl->usba_ph_dip;
967c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
977c478bd9Sstevel@tonic-gate 	}
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	return (dip);
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate usb_pipe_handle_t
1047c478bd9Sstevel@tonic-gate usba_usbdev_to_dflt_pipe_handle(usba_device_t *usba_device)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = NULL;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	if ((usba_device) &&
1097c478bd9Sstevel@tonic-gate 	    (usba_device->usb_ph_list[0].usba_ph_data != NULL)) {
1107c478bd9Sstevel@tonic-gate 		pipe_handle = (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	return (pipe_handle);
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *
1187c478bd9Sstevel@tonic-gate usba_get_ph_data(usb_pipe_handle_t pipe_handle)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
1217c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = NULL;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	if (ph_impl) {
1247c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
1257c478bd9Sstevel@tonic-gate 		ASSERT(ph_impl->usba_ph_ref_count >= 0);
1267c478bd9Sstevel@tonic-gate 		ph_data = ph_impl->usba_ph_data;
1277c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
1287c478bd9Sstevel@tonic-gate 	}
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	return (ph_data);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate usb_pipe_handle_t
1357c478bd9Sstevel@tonic-gate usba_get_pipe_handle(usba_pipe_handle_data_t *ph_data)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t ph = NULL;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	if (ph_data) {
1407c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
1417c478bd9Sstevel@tonic-gate 		ASSERT(ph_data->p_req_count >= 0);
1427c478bd9Sstevel@tonic-gate 		ph = (usb_pipe_handle_t)ph_data->p_ph_impl;
1437c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	return (ph);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate /*
1517c478bd9Sstevel@tonic-gate  * opaque to pipe handle impl translation with incr of ref count. The caller
1527c478bd9Sstevel@tonic-gate  * must release ph_data when done. Increment the ref count ensures that
1537c478bd9Sstevel@tonic-gate  * the ph_data will not be freed underneath us.
1547c478bd9Sstevel@tonic-gate  */
1557c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *
1567c478bd9Sstevel@tonic-gate usba_hold_ph_data(usb_pipe_handle_t pipe_handle)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
1597c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = NULL;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	if (ph_impl) {
1627c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 		switch (ph_impl->usba_ph_state) {
1657c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_IDLE:
1667c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_ACTIVE:
1677c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_ERROR:
1687c478bd9Sstevel@tonic-gate 			ph_data = ph_impl->usba_ph_data;
1697c478bd9Sstevel@tonic-gate 			ph_impl->usba_ph_ref_count++;
1707c478bd9Sstevel@tonic-gate 			break;
1717c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_CLOSED:
1727c478bd9Sstevel@tonic-gate 		case USB_PIPE_STATE_CLOSING:
1737c478bd9Sstevel@tonic-gate 		default:
1747c478bd9Sstevel@tonic-gate 			break;
1757c478bd9Sstevel@tonic-gate 		}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1787c478bd9Sstevel@tonic-gate 		    "usba_hold_ph_data: ph_impl=0x%p state=%d ref=%d",
1797c478bd9Sstevel@tonic-gate 		    ph_impl, ph_impl->usba_ph_state,
1807c478bd9Sstevel@tonic-gate 		    ph_impl->usba_ph_ref_count);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	return (ph_data);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate void
1907c478bd9Sstevel@tonic-gate usba_release_ph_data(usba_ph_impl_t *ph_impl)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	if (ph_impl) {
1937c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1967c478bd9Sstevel@tonic-gate 		    "usba_release_ph_data: "
1977c478bd9Sstevel@tonic-gate 		    "ph_impl=0x%p state=%d ref=%d",
1987c478bd9Sstevel@tonic-gate 		    ph_impl, ph_impl->usba_ph_state,
1997c478bd9Sstevel@tonic-gate 		    ph_impl->usba_ph_ref_count);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate #ifndef __lock_lint
2027c478bd9Sstevel@tonic-gate 		if (ph_impl->usba_ph_data) {
2037c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2047c478bd9Sstevel@tonic-gate 			    "usba_release_ph_data: req_count=%d",
2057c478bd9Sstevel@tonic-gate 			    ph_impl->usba_ph_data->p_req_count);
2067c478bd9Sstevel@tonic-gate 			ASSERT(ph_impl->usba_ph_data->p_req_count >= 0);
2077c478bd9Sstevel@tonic-gate 		}
2087c478bd9Sstevel@tonic-gate #endif
2097c478bd9Sstevel@tonic-gate 		ph_impl->usba_ph_ref_count--;
2107c478bd9Sstevel@tonic-gate 		ASSERT(ph_impl->usba_ph_ref_count >= 0);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate /*
2187c478bd9Sstevel@tonic-gate  * get pipe state from ph_data
2197c478bd9Sstevel@tonic-gate  */
2207c478bd9Sstevel@tonic-gate usb_pipe_state_t
2217c478bd9Sstevel@tonic-gate usba_get_ph_state(usba_pipe_handle_data_t *ph_data)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
2247c478bd9Sstevel@tonic-gate 	usb_pipe_state_t	pipe_state;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ph_data->p_mutex));
2277c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
2287c478bd9Sstevel@tonic-gate 	pipe_state = ph_impl->usba_ph_state;
2297c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	return (pipe_state);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate  * get ref_count from ph_data
2377c478bd9Sstevel@tonic-gate  */
2387c478bd9Sstevel@tonic-gate int
2397c478bd9Sstevel@tonic-gate usba_get_ph_ref_count(usba_pipe_handle_data_t *ph_data)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
2427c478bd9Sstevel@tonic-gate 	int			ref_count;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
2457c478bd9Sstevel@tonic-gate 	ref_count = ph_impl->usba_ph_ref_count;
2467c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	return (ref_count);
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate  * new pipe state
2547c478bd9Sstevel@tonic-gate  * We need to hold both pipe mutex and ph_impl mutex
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate void
2577c478bd9Sstevel@tonic-gate usba_pipe_new_state(usba_pipe_handle_data_t *ph_data, usb_pipe_state_t state)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ph_data->p_mutex));
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
2647c478bd9Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
2657c478bd9Sstevel@tonic-gate 	ASSERT(ph_impl->usba_ph_ref_count >= 0);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2687c478bd9Sstevel@tonic-gate 	    "usba_pipe_new_state: "
2697c478bd9Sstevel@tonic-gate 	    "ph_data=0x%p old=%s new=%s ref=%d req=%d",
2707c478bd9Sstevel@tonic-gate 	    ph_data, usb_str_pipe_state(ph_impl->usba_ph_state),
2717c478bd9Sstevel@tonic-gate 	    usb_str_pipe_state(state),
2727c478bd9Sstevel@tonic-gate 	    ph_impl->usba_ph_ref_count, ph_data->p_req_count);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	switch (ph_impl->usba_ph_state) {
2757c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_IDLE:
2767c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_ACTIVE:
2777c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_ERROR:
2787c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_CLOSED:
2797c478bd9Sstevel@tonic-gate 		ph_impl->usba_ph_state = state;
2807c478bd9Sstevel@tonic-gate 		break;
2817c478bd9Sstevel@tonic-gate 	case USB_PIPE_STATE_CLOSING:
2827c478bd9Sstevel@tonic-gate 	default:
2837c478bd9Sstevel@tonic-gate 		break;
2847c478bd9Sstevel@tonic-gate 	}
2857c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate /*
2907c478bd9Sstevel@tonic-gate  * async function execution support
2917c478bd9Sstevel@tonic-gate  * Arguments:
2927c478bd9Sstevel@tonic-gate  *	dip		- devinfo pointer
2937c478bd9Sstevel@tonic-gate  *	sync_func	- function to be executed
2947c478bd9Sstevel@tonic-gate  *	ph_impl		- impl pipehandle
2957c478bd9Sstevel@tonic-gate  *	arg		- opaque arg
2967c478bd9Sstevel@tonic-gate  *	usb_flags	- none
2977c478bd9Sstevel@tonic-gate  *	callback	- function to be called on completion, may be NULL
2987c478bd9Sstevel@tonic-gate  *	callback_arg	- argument for callback function
2997c478bd9Sstevel@tonic-gate  *
3007c478bd9Sstevel@tonic-gate  * Note: The caller must do a hold on ph_data
3017c478bd9Sstevel@tonic-gate  *	We sleep for memory resources and taskq_dispatch which will ensure
3027c478bd9Sstevel@tonic-gate  *	that this function succeeds
3037c478bd9Sstevel@tonic-gate  */
3047c478bd9Sstevel@tonic-gate int
3057c478bd9Sstevel@tonic-gate usba_pipe_setup_func_call(
3067c478bd9Sstevel@tonic-gate 	dev_info_t	*dip,
3077c478bd9Sstevel@tonic-gate 	int		(*sync_func)(dev_info_t *,
3087c478bd9Sstevel@tonic-gate 			    usba_ph_impl_t *, usba_pipe_async_req_t *,
3097c478bd9Sstevel@tonic-gate 			    usb_flags_t),
3107c478bd9Sstevel@tonic-gate 	usba_ph_impl_t *ph_impl,
3117c478bd9Sstevel@tonic-gate 	usb_opaque_t	arg,
3127c478bd9Sstevel@tonic-gate 	usb_flags_t	usb_flags,
3137c478bd9Sstevel@tonic-gate 	void		(*callback)(usb_pipe_handle_t,
3147c478bd9Sstevel@tonic-gate 			    usb_opaque_t, int, usb_cb_flags_t),
3157c478bd9Sstevel@tonic-gate 	usb_opaque_t	callback_arg)
3167c478bd9Sstevel@tonic-gate {
3177c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t	*request;
3187c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = (usb_pipe_handle_t)ph_impl;
3197c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
3207c478bd9Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
3217c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		callback_flags;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
3247c478bd9Sstevel@tonic-gate 	    "usba_pipe_setup_func_call: ph_impl=0x%p, func=0x%p",
3257c478bd9Sstevel@tonic-gate 	    ph_impl, sync_func);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	if (((usb_flags & USB_FLAGS_SLEEP) == 0) && (callback == NULL)) {
3287c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
329*d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
3307c478bd9Sstevel@tonic-gate 		    "usba_pipe_setup_func_call: async request with "
3317c478bd9Sstevel@tonic-gate 		    "no callback");
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	request = kmem_zalloc(sizeof (usba_pipe_async_req_t), KM_SLEEP);
3377c478bd9Sstevel@tonic-gate 	request->dip		= dip;
3387c478bd9Sstevel@tonic-gate 	request->ph_impl	= ph_impl;
3397c478bd9Sstevel@tonic-gate 	request->arg		= arg;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	/*
3427c478bd9Sstevel@tonic-gate 	 * OR in sleep flag. regardless of calling sync_func directly
3437c478bd9Sstevel@tonic-gate 	 * or in a new thread, we will always wait for completion
3447c478bd9Sstevel@tonic-gate 	 */
3457c478bd9Sstevel@tonic-gate 	request->usb_flags	= usb_flags | USB_FLAGS_SLEEP;
3467c478bd9Sstevel@tonic-gate 	request->sync_func	= sync_func;
3477c478bd9Sstevel@tonic-gate 	request->callback	= callback;
3487c478bd9Sstevel@tonic-gate 	request->callback_arg	= callback_arg;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (usb_flags & USB_FLAGS_SLEEP) {
3517c478bd9Sstevel@tonic-gate 		rval = sync_func(dip, ph_impl, request, usb_flags);
3527c478bd9Sstevel@tonic-gate 		kmem_free(request, sizeof (usba_pipe_async_req_t));
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	} else if (usba_async_ph_req(ph_data,
3557c478bd9Sstevel@tonic-gate 	    usba_pipe_do_async_func_thread,
3567c478bd9Sstevel@tonic-gate 	    (void *)request, USB_FLAGS_SLEEP) != USB_SUCCESS) {
3577c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
3587c478bd9Sstevel@tonic-gate 		    "usb_async_req failed: ph_impl=0x%p, func=0x%p",
3597c478bd9Sstevel@tonic-gate 		    ph_impl, sync_func);
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		if (callback) {
3627c478bd9Sstevel@tonic-gate 			callback_flags =
3637c478bd9Sstevel@tonic-gate 			    usba_check_intr_context(USB_CB_ASYNC_REQ_FAILED);
3647c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg, USB_FAILURE,
3657c478bd9Sstevel@tonic-gate 			    callback_flags);
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		kmem_free(request, sizeof (usba_pipe_async_req_t));
3697c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	return (rval);
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  * taskq thread function to execute function synchronously
3787c478bd9Sstevel@tonic-gate  * Note: caller must have done a hold on ph_data
3797c478bd9Sstevel@tonic-gate  */
3807c478bd9Sstevel@tonic-gate static void
3817c478bd9Sstevel@tonic-gate usba_pipe_do_async_func_thread(void *arg)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t	*request = (usba_pipe_async_req_t *)arg;
3847c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = request->ph_impl;
3857c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = (usb_pipe_handle_t)ph_impl;
3867c478bd9Sstevel@tonic-gate 	int			rval;
3877c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags = USB_CB_NO_INFO;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	if ((rval = request->sync_func(request->dip, ph_impl,
3907c478bd9Sstevel@tonic-gate 	    request, request->usb_flags | USB_FLAGS_SLEEP)) !=
3917c478bd9Sstevel@tonic-gate 	    USB_SUCCESS) {
3927c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
3937c478bd9Sstevel@tonic-gate 		    "sync func failed (%d)", rval);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if (request->callback) {
3977c478bd9Sstevel@tonic-gate 		request->callback(pipe_handle, request->callback_arg, rval,
3987c478bd9Sstevel@tonic-gate 		    cb_flags);
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	kmem_free(request, sizeof (usba_pipe_async_req_t));
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate /*
4067c478bd9Sstevel@tonic-gate  * default endpoint descriptor and pipe policy
4077c478bd9Sstevel@tonic-gate  */
4087c478bd9Sstevel@tonic-gate usb_ep_descr_t	usba_default_ep_descr =
4097c478bd9Sstevel@tonic-gate 	{7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0};
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate /* set some meaningful defaults */
4127c478bd9Sstevel@tonic-gate static usb_pipe_policy_t usba_default_ep_pipe_policy = {3};
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate  * usb_get_ep_index: create an index from endpoint address that can
4177c478bd9Sstevel@tonic-gate  * be used to index into endpoint pipe lists
4187c478bd9Sstevel@tonic-gate  */
4197c478bd9Sstevel@tonic-gate uchar_t
4207c478bd9Sstevel@tonic-gate usb_get_ep_index(uint8_t ep_addr)
4217c478bd9Sstevel@tonic-gate {
4227c478bd9Sstevel@tonic-gate 	return ((ep_addr & USB_EP_NUM_MASK) +
4237c478bd9Sstevel@tonic-gate 	    ((ep_addr & USB_EP_DIR_MASK) ? 16 : 0));
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate /*
4287c478bd9Sstevel@tonic-gate  * pipe management
4297c478bd9Sstevel@tonic-gate  *	utility functions to init and destroy a pipehandle
4307c478bd9Sstevel@tonic-gate  */
4317c478bd9Sstevel@tonic-gate static int
4327c478bd9Sstevel@tonic-gate usba_init_pipe_handle(dev_info_t *dip,
4337c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device,
4347c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*ep,
4357c478bd9Sstevel@tonic-gate 	usb_pipe_policy_t	*pipe_policy,
4367c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl)
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
4397c478bd9Sstevel@tonic-gate 	unsigned int def_instance = instance;
4407c478bd9Sstevel@tonic-gate 	static unsigned int anon_instance = 0;
4417c478bd9Sstevel@tonic-gate 	char tq_name[TASKQ_NAMELEN];
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
4447c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t	iblock_cookie =
4457c478bd9Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
4467c478bd9Sstevel@tonic-gate 	    hcdi_iblock_cookie;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
4497c478bd9Sstevel@tonic-gate 	    "usba_init_pipe_handle: "
4507c478bd9Sstevel@tonic-gate 	    "usba_device=0x%p ep=0x%x", usba_device, ep->bEndpointAddress);
4517c478bd9Sstevel@tonic-gate 	mutex_init(&ph_data->p_mutex, NULL, MUTEX_DRIVER, iblock_cookie);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	/* just to keep warlock happy, there is no contention yet */
4547c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
4557c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	ASSERT(pipe_policy->pp_max_async_reqs);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if (instance != -1) {
4607c478bd9Sstevel@tonic-gate 		(void) snprintf(tq_name, sizeof (tq_name),
4617c478bd9Sstevel@tonic-gate 		    "USB_%s_%x_pipehndl_tq_%d",
4627c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ep->bEndpointAddress, instance);
4637c478bd9Sstevel@tonic-gate 	} else {
4647c478bd9Sstevel@tonic-gate 		def_instance = atomic_add_32_nv(&anon_instance, 1);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		(void) snprintf(tq_name, sizeof (tq_name),
4677c478bd9Sstevel@tonic-gate 		    "USB_%s_%x_pipehndl_tq_%d_",
4687c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ep->bEndpointAddress, def_instance);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	ph_data->p_taskq = taskq_create(tq_name,
4727c478bd9Sstevel@tonic-gate 		    pipe_policy->pp_max_async_reqs + 1,
4737c478bd9Sstevel@tonic-gate 		    ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
4747c478bd9Sstevel@tonic-gate 			USB_EP_ATTR_ISOCH) ?
4757c478bd9Sstevel@tonic-gate 			(maxclsyspri - 5) : minclsyspri,
4767c478bd9Sstevel@tonic-gate 		    2 * (pipe_policy->pp_max_async_reqs + 1),
4777c478bd9Sstevel@tonic-gate 		    8 * (pipe_policy->pp_max_async_reqs + 1),
4787c478bd9Sstevel@tonic-gate 		    TASKQ_PREPOPULATE);
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	/*
4817c478bd9Sstevel@tonic-gate 	 * Create a shared taskq.
4827c478bd9Sstevel@tonic-gate 	 */
4837c478bd9Sstevel@tonic-gate 	if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
4847c478bd9Sstevel@tonic-gate 		int iface = usb_get_if_number(dip);
4857c478bd9Sstevel@tonic-gate 		if (iface < 0) {
4867c478bd9Sstevel@tonic-gate 			/* we own the device, use first entry */
4877c478bd9Sstevel@tonic-gate 			iface = 0;
4887c478bd9Sstevel@tonic-gate 		}
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		if (instance != -1) {
4917c478bd9Sstevel@tonic-gate 			(void) snprintf(tq_name, sizeof (tq_name),
4927c478bd9Sstevel@tonic-gate 			    "USB_%s_%x_shared_tq_%d",
4937c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ep->bEndpointAddress,
4947c478bd9Sstevel@tonic-gate 			    instance);
4957c478bd9Sstevel@tonic-gate 		} else {
4967c478bd9Sstevel@tonic-gate 			(void) snprintf(tq_name, sizeof (tq_name),
4977c478bd9Sstevel@tonic-gate 			    "USB_%s_%x_shared_tq_%d_",
4987c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ep->bEndpointAddress,
4997c478bd9Sstevel@tonic-gate 			    def_instance);
5007c478bd9Sstevel@tonic-gate 		}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		if (usba_device->usb_shared_taskq_ref_count[iface] == 0) {
5037c478bd9Sstevel@tonic-gate 			usba_device->usb_shared_taskq[iface] =
5047c478bd9Sstevel@tonic-gate 			    taskq_create(tq_name,
5057c478bd9Sstevel@tonic-gate 			    1,				/* Number threads. */
5067c478bd9Sstevel@tonic-gate 			    maxclsyspri - 5,		/* Priority */
5077c478bd9Sstevel@tonic-gate 			    1,				/* minalloc */
5087c478bd9Sstevel@tonic-gate 			    USBA_N_ENDPOINTS + 4,	/* maxalloc */
5097c478bd9Sstevel@tonic-gate 			    TASKQ_PREPOPULATE);
5107c478bd9Sstevel@tonic-gate 			ASSERT(usba_device->usb_shared_taskq[iface] != NULL);
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 		usba_device->usb_shared_taskq_ref_count[iface]++;
5137c478bd9Sstevel@tonic-gate 	}
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	ph_data->p_dip		= dip;
5167c478bd9Sstevel@tonic-gate 	ph_data->p_usba_device	= usba_device;
5177c478bd9Sstevel@tonic-gate 	ph_data->p_ep		= *ep;
5187c478bd9Sstevel@tonic-gate 	ph_data->p_ph_impl	= ph_impl;
5197c478bd9Sstevel@tonic-gate 	if ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
5207c478bd9Sstevel@tonic-gate 	    USB_EP_ATTR_ISOCH) {
5217c478bd9Sstevel@tonic-gate 		ph_data->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	/* fix up the MaxPacketSize if it is the default endpoint descr */
5257c478bd9Sstevel@tonic-gate 	if ((ep == &usba_default_ep_descr) && usba_device) {
5267c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
5277c478bd9Sstevel@tonic-gate 		    "adjusting max packet size from %d to %d",
5287c478bd9Sstevel@tonic-gate 		    ph_data->p_ep.wMaxPacketSize,
5297c478bd9Sstevel@tonic-gate 		    usba_device->usb_dev_descr->bMaxPacketSize0);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 		ph_data->p_ep.wMaxPacketSize = usba_device->usb_dev_descr->
5327c478bd9Sstevel@tonic-gate 							bMaxPacketSize0;
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	/* now update usba_ph_impl structure */
5367c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
5377c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_dip = dip;
5387c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_ep = ph_data->p_ep;
5397c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_policy = ph_data->p_policy = *pipe_policy;
5407c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	usba_init_list(&ph_data->p_queue, (usb_opaque_t)ph_data, iblock_cookie);
5437c478bd9Sstevel@tonic-gate 	usba_init_list(&ph_data->p_cb_queue, (usb_opaque_t)ph_data,
5447c478bd9Sstevel@tonic-gate 								iblock_cookie);
5457c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5467c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate static void
5537c478bd9Sstevel@tonic-gate usba_taskq_destroy(void *arg)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate 	taskq_destroy((taskq_t *)arg);
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate static void
5607c478bd9Sstevel@tonic-gate usba_destroy_pipe_handle(usba_pipe_handle_data_t *ph_data)
5617c478bd9Sstevel@tonic-gate {
5627c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
5637c478bd9Sstevel@tonic-gate 	int			timeout;
5647c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
5677c478bd9Sstevel@tonic-gate 	    "usba_destroy_pipe_handle: ph_data=0x%p", ph_data);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
5707c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	/* check for all activity to drain */
5737c478bd9Sstevel@tonic-gate 	for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
5747c478bd9Sstevel@tonic-gate 		if ((ph_impl->usba_ph_ref_count <= 1) &&
5757c478bd9Sstevel@tonic-gate 		    (ph_data->p_req_count == 0)) {
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 			break;
5787c478bd9Sstevel@tonic-gate 		}
5797c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
5807c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
5817c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000));
5827c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
5837c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	/*
5877c478bd9Sstevel@tonic-gate 	 * set state to closed here so any other thread
5887c478bd9Sstevel@tonic-gate 	 * that is waiting for the CLOSED state will
5897c478bd9Sstevel@tonic-gate 	 * continue. Otherwise, taskq_destroy might deadlock
5907c478bd9Sstevel@tonic-gate 	 */
5917c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_data = NULL;
5927c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_ref_count = 0;
5937c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSED;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	if (ph_data->p_taskq) {
5967c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
5977c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
5987c478bd9Sstevel@tonic-gate 		if (taskq_member(ph_data->p_taskq, curthread)) {
5997c478bd9Sstevel@tonic-gate 			/*
6007c478bd9Sstevel@tonic-gate 			 * use system taskq to destroy ph's taskq to avoid
6017c478bd9Sstevel@tonic-gate 			 * deadlock
6027c478bd9Sstevel@tonic-gate 			 */
6037c478bd9Sstevel@tonic-gate 			(void) taskq_dispatch(system_taskq,
6047c478bd9Sstevel@tonic-gate 			    usba_taskq_destroy, ph_data->p_taskq, TQ_SLEEP);
6057c478bd9Sstevel@tonic-gate 		} else {
6067c478bd9Sstevel@tonic-gate 			taskq_destroy(ph_data->p_taskq);
6077c478bd9Sstevel@tonic-gate 		}
6087c478bd9Sstevel@tonic-gate 	} else {
6097c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
6107c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
6147c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
6157c478bd9Sstevel@tonic-gate 	if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
6167c478bd9Sstevel@tonic-gate 		int iface = usb_get_if_number(ph_data->p_dip);
6177c478bd9Sstevel@tonic-gate 		if (iface < 0) {
6187c478bd9Sstevel@tonic-gate 			/* we own the device, use the first entry */
6197c478bd9Sstevel@tonic-gate 			iface = 0;
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
6227c478bd9Sstevel@tonic-gate 		if (--usba_device->usb_shared_taskq_ref_count[iface] == 0) {
6237c478bd9Sstevel@tonic-gate 			ph_data->p_spec_flag &= ~USBA_PH_FLAG_TQ_SHARE;
6247c478bd9Sstevel@tonic-gate 			if (taskq_member(usba_device->usb_shared_taskq[iface],
6257c478bd9Sstevel@tonic-gate 			    curthread)) {
6267c478bd9Sstevel@tonic-gate 				(void) taskq_dispatch(
6277c478bd9Sstevel@tonic-gate 				    system_taskq,
6287c478bd9Sstevel@tonic-gate 				    usba_taskq_destroy,
6297c478bd9Sstevel@tonic-gate 				    usba_device->usb_shared_taskq[iface],
6307c478bd9Sstevel@tonic-gate 				    TQ_SLEEP);
6317c478bd9Sstevel@tonic-gate 			} else {
6327c478bd9Sstevel@tonic-gate 				taskq_destroy(
6337c478bd9Sstevel@tonic-gate 				    usba_device->usb_shared_taskq[iface]);
6347c478bd9Sstevel@tonic-gate 			}
6357c478bd9Sstevel@tonic-gate 		}
6367c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6427c478bd9Sstevel@tonic-gate 	    "usba_destroy_pipe_handle: destroying ph_data=0x%p", ph_data);
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	usba_destroy_list(&ph_data->p_queue);
6457c478bd9Sstevel@tonic-gate 	usba_destroy_list(&ph_data->p_cb_queue);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	/* destroy mutexes */
6487c478bd9Sstevel@tonic-gate 	mutex_destroy(&ph_data->p_mutex);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	kmem_free(ph_data, sizeof (usba_pipe_handle_data_t));
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate /*
6557c478bd9Sstevel@tonic-gate  * usba_drain_cbs:
6567c478bd9Sstevel@tonic-gate  *	Drain the request callbacks on the pipe handle
6577c478bd9Sstevel@tonic-gate  */
6587c478bd9Sstevel@tonic-gate int
6597c478bd9Sstevel@tonic-gate usba_drain_cbs(usba_pipe_handle_data_t *ph_data, usb_cb_flags_t cb_flags,
6607c478bd9Sstevel@tonic-gate 	usb_cr_t cr)
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate 	usba_req_wrapper_t	*req_wrp;
6637c478bd9Sstevel@tonic-gate 	int			flush_requests = 1;
6647c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
6657c478bd9Sstevel@tonic-gate 	int			timeout;
6667c478bd9Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&ph_data->p_mutex));
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
6717c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6727c478bd9Sstevel@tonic-gate 	    "usba_drain_cbs: ph_data=0x%p ref=%d req=%d cb=0x%x cr=%d",
6737c478bd9Sstevel@tonic-gate 	    ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count,
6747c478bd9Sstevel@tonic-gate 	    cb_flags, cr);
6757c478bd9Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
6767c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	if (ph_data->p_dip) {
6797c478bd9Sstevel@tonic-gate 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
6807c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
6817c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
6827c478bd9Sstevel@tonic-gate 			    "no flushing on default pipe!");
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 			flush_requests = 0;
6857c478bd9Sstevel@tonic-gate 		}
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	if (flush_requests) {
6897c478bd9Sstevel@tonic-gate 		/* flush all requests in the pipehandle queue */
6907c478bd9Sstevel@tonic-gate 		while ((req_wrp = (usba_req_wrapper_t *)
6917c478bd9Sstevel@tonic-gate 		    usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
6927c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
6937c478bd9Sstevel@tonic-gate 			usba_do_req_exc_cb(req_wrp, cr, cb_flags);
6947c478bd9Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
6957c478bd9Sstevel@tonic-gate 		}
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	/*
6997c478bd9Sstevel@tonic-gate 	 * wait for any callbacks in progress but don't wait for
7007c478bd9Sstevel@tonic-gate 	 * for queued requests on the default pipe
7017c478bd9Sstevel@tonic-gate 	 */
7027c478bd9Sstevel@tonic-gate 	for (timeout = 0; (timeout < usba_drain_timeout) &&
7037c478bd9Sstevel@tonic-gate 	    (ph_data->p_req_count >
7047c478bd9Sstevel@tonic-gate 	    usba_list_entry_count(&ph_data->p_queue));
7057c478bd9Sstevel@tonic-gate 	    timeout++) {
7067c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
7077c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000));
7087c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
7127c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
7137c478bd9Sstevel@tonic-gate 	    "usba_drain_cbs done: ph_data=0x%p ref=%d req=%d",
7147c478bd9Sstevel@tonic-gate 	    ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count);
7157c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	if (timeout == usba_drain_timeout) {
7187c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
7197c478bd9Sstevel@tonic-gate 		    "draining callbacks timed out!");
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 		rval = USB_FAILURE;
7227c478bd9Sstevel@tonic-gate 	}
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	return (rval);
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate  * usb_pipe_open():
7307c478bd9Sstevel@tonic-gate  *
7317c478bd9Sstevel@tonic-gate  * Before using any pipe including the default pipe, it should be opened
7327c478bd9Sstevel@tonic-gate  * using usb_pipe_open(). On a successful open, a pipe handle is returned
7337c478bd9Sstevel@tonic-gate  * for use in other usb_pipe_*() functions
7347c478bd9Sstevel@tonic-gate  *
7357c478bd9Sstevel@tonic-gate  * The default pipe can only be opened by the hub driver
7367c478bd9Sstevel@tonic-gate  *
7377c478bd9Sstevel@tonic-gate  * The bandwidth has been allocated and guaranteed on successful
7387c478bd9Sstevel@tonic-gate  * opening of an isoc/intr pipes.
7397c478bd9Sstevel@tonic-gate  *
7407c478bd9Sstevel@tonic-gate  * Only the default pipe can be shared. all other control pipes
7417c478bd9Sstevel@tonic-gate  * are excusively opened by default.
7427c478bd9Sstevel@tonic-gate  * A pipe policy and endpoint descriptor must always be provided
7437c478bd9Sstevel@tonic-gate  * except for default pipe
7447c478bd9Sstevel@tonic-gate  *
7457c478bd9Sstevel@tonic-gate  * Arguments:
7467c478bd9Sstevel@tonic-gate  *	dip		- devinfo ptr
7477c478bd9Sstevel@tonic-gate  *	ep		- endpoint descriptor pointer
7487c478bd9Sstevel@tonic-gate  *	pipe_policy	- pointer to pipe policy which provides hints on how
7497c478bd9Sstevel@tonic-gate  *			  the pipe will be used.
7507c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP wait for resources
7517c478bd9Sstevel@tonic-gate  *			  to become available
7527c478bd9Sstevel@tonic-gate  *	pipe_handle	- a pipe handle pointer. On a successful open,
7537c478bd9Sstevel@tonic-gate  *			  a pipe_handle is returned in this pointer.
7547c478bd9Sstevel@tonic-gate  *
7557c478bd9Sstevel@tonic-gate  * Return values:
7567c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	 - open succeeded
7577c478bd9Sstevel@tonic-gate  *	USB_FAILURE	 - unspecified open failure or pipe is already open
7587c478bd9Sstevel@tonic-gate  *	USB_NO_RESOURCES - no resources were available to complete the open
7597c478bd9Sstevel@tonic-gate  *	USB_NO_BANDWIDTH - no bandwidth available (isoc/intr pipes)
7607c478bd9Sstevel@tonic-gate  *	USB_*		 - refer to usbai.h
7617c478bd9Sstevel@tonic-gate  */
7627c478bd9Sstevel@tonic-gate int
7637c478bd9Sstevel@tonic-gate usb_pipe_open(
7647c478bd9Sstevel@tonic-gate 	dev_info_t		*dip,
7657c478bd9Sstevel@tonic-gate 	usb_ep_descr_t		*ep,
7667c478bd9Sstevel@tonic-gate 	usb_pipe_policy_t	*pipe_policy,
7677c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags,
7687c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	*pipe_handle)
7697c478bd9Sstevel@tonic-gate {
7707c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
7717c478bd9Sstevel@tonic-gate 	int			rval;
7727c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data;
7737c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl;
7747c478bd9Sstevel@tonic-gate 	uchar_t			ep_index;
7757c478bd9Sstevel@tonic-gate 	int			kmflag;
7767c478bd9Sstevel@tonic-gate 	size_t			size;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
7797c478bd9Sstevel@tonic-gate 	    "usb_pipe_open:\n\t"
7807c478bd9Sstevel@tonic-gate 	    "dip=0x%p ep=0x%p pp=0x%p uf=0x%x ph=0x%p",
7817c478bd9Sstevel@tonic-gate 	    dip, ep, pipe_policy, usb_flags, pipe_handle);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (pipe_handle == NULL)) {
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	if ((ep != NULL) && (pipe_policy == NULL)) {
7957c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
7967c478bd9Sstevel@tonic-gate 		    "usb_pipe_open: null pipe policy");
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	/* is the device still connected? */
8027c478bd9Sstevel@tonic-gate 	if ((ep != NULL) & DEVI_IS_DEVICE_REMOVED(dip)) {
8037c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8047c478bd9Sstevel@tonic-gate 		    "usb_pipe_open: device has been removed");
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 		return (USB_FAILURE);
8077c478bd9Sstevel@tonic-gate 	}
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	/*
8117c478bd9Sstevel@tonic-gate 	 * if a null endpoint pointer was passed, use the default
8127c478bd9Sstevel@tonic-gate 	 * endpoint descriptor
8137c478bd9Sstevel@tonic-gate 	 */
8147c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
8157c478bd9Sstevel@tonic-gate 		if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
8167c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8177c478bd9Sstevel@tonic-gate 			    "usb_pipe_open: not allowed to open def pipe");
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 			return (USB_INVALID_PERM);
8207c478bd9Sstevel@tonic-gate 		}
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 		ep = &usba_default_ep_descr;
8237c478bd9Sstevel@tonic-gate 		pipe_policy = &usba_default_ep_pipe_policy;
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
8277c478bd9Sstevel@tonic-gate 		if (((ep->bmAttributes & USB_EP_ATTR_MASK) ==
8287c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_CONTROL) ||
8297c478bd9Sstevel@tonic-gate 		    ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
8307c478bd9Sstevel@tonic-gate 		    USB_EP_ATTR_ISOCH)) {
8317c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8327c478bd9Sstevel@tonic-gate 			    "usb_pipe_open: shared taskq not allowed with "
8337c478bd9Sstevel@tonic-gate 			    "ctrl or isoch pipe");
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 			return (USB_INVALID_ARGS);
8367c478bd9Sstevel@tonic-gate 		}
8377c478bd9Sstevel@tonic-gate 	}
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	kmflag	= (usb_flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
8407c478bd9Sstevel@tonic-gate 	size	= sizeof (usba_pipe_handle_data_t);
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	if ((ph_data = kmem_zalloc(size, kmflag)) == NULL) {
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	/* check if pipe is already open and if so fail */
8487c478bd9Sstevel@tonic-gate 	ep_index = usb_get_ep_index(ep->bEndpointAddress);
8497c478bd9Sstevel@tonic-gate 	ph_impl = &usba_device->usb_ph_list[ep_index];
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
8527c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	if (ph_impl->usba_ph_data) {
8557c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8567c478bd9Sstevel@tonic-gate 		    "usb_pipe_open: pipe to ep %d already open", ep_index);
8577c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
8587c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
8597c478bd9Sstevel@tonic-gate 		kmem_free(ph_data, size);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 		return (USB_BUSY);
8627c478bd9Sstevel@tonic-gate 	}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_data = ph_data;
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
8677c478bd9Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
8707c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
8717c478bd9Sstevel@tonic-gate 		ph_data->p_spec_flag |= USBA_PH_FLAG_TQ_SHARE;
8727c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	/*
8767c478bd9Sstevel@tonic-gate 	 * allocate and initialize the pipe handle
8777c478bd9Sstevel@tonic-gate 	 */
8787c478bd9Sstevel@tonic-gate 	if ((rval = usba_init_pipe_handle(dip, usba_device,
8797c478bd9Sstevel@tonic-gate 	    ep, pipe_policy, ph_impl)) != USB_SUCCESS) {
8807c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8817c478bd9Sstevel@tonic-gate 		    "usb_pipe_open: pipe init failed (%d)", rval);
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 		return (rval);
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 	ph_data = ph_impl->usba_ph_data;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	/*
8887c478bd9Sstevel@tonic-gate 	 * ask the hcd to open the pipe
8897c478bd9Sstevel@tonic-gate 	 */
8907c478bd9Sstevel@tonic-gate 	if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_open(ph_data,
8917c478bd9Sstevel@tonic-gate 	    usb_flags)) != USB_SUCCESS) {
8927c478bd9Sstevel@tonic-gate 		usba_destroy_pipe_handle(ph_data);
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 		*pipe_handle = NULL;
8957c478bd9Sstevel@tonic-gate 	} else {
8967c478bd9Sstevel@tonic-gate 		*pipe_handle = (usb_pipe_handle_t)ph_impl;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 		/* set the pipe state after a successful hcd open */
8997c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
9007c478bd9Sstevel@tonic-gate 		usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
9017c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
9027c478bd9Sstevel@tonic-gate 	}
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
9057c478bd9Sstevel@tonic-gate 	    "usb_pipe_open: ph_impl=0x%p (0x%p)", ph_impl, ph_data);
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	return (rval);
9087c478bd9Sstevel@tonic-gate }
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate  * usb_pipe_close/sync_close:
9137c478bd9Sstevel@tonic-gate  *
9147c478bd9Sstevel@tonic-gate  * Close a pipe and release all resources and free the pipe_handle.
9157c478bd9Sstevel@tonic-gate  * Automatic polling, if active,  will be terminated
9167c478bd9Sstevel@tonic-gate  *
9177c478bd9Sstevel@tonic-gate  * Arguments:
9187c478bd9Sstevel@tonic-gate  *	dip		- devinfo ptr
9197c478bd9Sstevel@tonic-gate  *	pipehandle	- pointer to pipehandle. The pipehandle will be
9207c478bd9Sstevel@tonic-gate  *			  zeroed on successful completion
9217c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
9227c478bd9Sstevel@tonic-gate  *				wait for resources, pipe
9237c478bd9Sstevel@tonic-gate  *				to become free, all callbacks completed
9247c478bd9Sstevel@tonic-gate  *	callback	- If USB_FLAGS_SLEEP has not been specified, a
9257c478bd9Sstevel@tonic-gate  *			  callback will be performed.
9267c478bd9Sstevel@tonic-gate  *	callback_arg	- the first argument of the callback. Note that
9277c478bd9Sstevel@tonic-gate  *			  the pipehandle will be zeroed and not passed
9287c478bd9Sstevel@tonic-gate  *
9297c478bd9Sstevel@tonic-gate  * Notes:
9307c478bd9Sstevel@tonic-gate  * Pipe close will always succeed regardless whether USB_FLAGS_SLEEP has been
9317c478bd9Sstevel@tonic-gate  * specified or not.
9327c478bd9Sstevel@tonic-gate  * An async close will always succeed if the hint in the pipe policy
9337c478bd9Sstevel@tonic-gate  * has been correct about the max number of async taskq requests required.
9347c478bd9Sstevel@tonic-gate  * If there are really no resources, the pipe handle will be linked into
9357c478bd9Sstevel@tonic-gate  * a garbage pipe list and periodically checked by USBA until it can be
9367c478bd9Sstevel@tonic-gate  * closed. This may cause a hang in the detach of the driver.
9377c478bd9Sstevel@tonic-gate  * USBA will prevent the client from submitting more requests to a pipe
9387c478bd9Sstevel@tonic-gate  * that is being closed
9397c478bd9Sstevel@tonic-gate  * Subsequent usb_pipe_close() requests on the same pipe to USBA will
9407c478bd9Sstevel@tonic-gate  * wait for the previous close(s) to finish.
9417c478bd9Sstevel@tonic-gate  *
9427c478bd9Sstevel@tonic-gate  * Note that once we start closing a pipe, we cannot go back anymore
9437c478bd9Sstevel@tonic-gate  * to a normal pipe state
9447c478bd9Sstevel@tonic-gate  */
9457c478bd9Sstevel@tonic-gate void
9467c478bd9Sstevel@tonic-gate usb_pipe_close(dev_info_t	*dip,
9477c478bd9Sstevel@tonic-gate 		usb_pipe_handle_t pipe_handle,
9487c478bd9Sstevel@tonic-gate 		usb_flags_t	usb_flags,
9497c478bd9Sstevel@tonic-gate 		void		(*callback)(
9507c478bd9Sstevel@tonic-gate 				    usb_pipe_handle_t	pipe_handle,
9517c478bd9Sstevel@tonic-gate 				    usb_opaque_t	arg,
9527c478bd9Sstevel@tonic-gate 				    int			rval,
9537c478bd9Sstevel@tonic-gate 				    usb_cb_flags_t	flags),
9547c478bd9Sstevel@tonic-gate 		usb_opaque_t	callback_arg)
9557c478bd9Sstevel@tonic-gate {
9567c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data;
9577c478bd9Sstevel@tonic-gate 	usba_ph_impl_t	*ph_impl = (usba_ph_impl_t *)pipe_handle;
9587c478bd9Sstevel@tonic-gate 	usb_cb_flags_t	callback_flags;
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
9617c478bd9Sstevel@tonic-gate 	    "usb_pipe_close: ph=0x%p", pipe_handle);
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
9647c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (pipe_handle == NULL)) {
9657c478bd9Sstevel@tonic-gate 		if (callback) {
9667c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
9677c478bd9Sstevel@tonic-gate 			    USB_INVALID_ARGS, callback_flags);
9687c478bd9Sstevel@tonic-gate 		} else {
969*d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
9707c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
9717c478bd9Sstevel@tonic-gate 			    "usb_pipe_close: invalid arguments");
9727c478bd9Sstevel@tonic-gate 		}
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 		return;
9757c478bd9Sstevel@tonic-gate 	}
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
9787c478bd9Sstevel@tonic-gate 		/*
9797c478bd9Sstevel@tonic-gate 		 * It is the client driver doing the pipe close,
9807c478bd9Sstevel@tonic-gate 		 * the pipe is no longer persistent then.
9817c478bd9Sstevel@tonic-gate 		 */
9827c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
9837c478bd9Sstevel@tonic-gate 		ph_impl->usba_ph_flags &= ~USBA_PH_DATA_PERSISTENT;
9847c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
9887c478bd9Sstevel@tonic-gate 		if (callback) {
9897c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
9907c478bd9Sstevel@tonic-gate 			    USB_INVALID_CONTEXT, callback_flags);
9917c478bd9Sstevel@tonic-gate 		} else {
992*d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
9937c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
9947c478bd9Sstevel@tonic-gate 			    "usb_pipe_close: invalid context");
9957c478bd9Sstevel@tonic-gate 		}
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 		return;
9987c478bd9Sstevel@tonic-gate 	}
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 		/* hold pipehandle anyways since we will decrement later */
10037c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
10047c478bd9Sstevel@tonic-gate 		ph_impl->usba_ph_ref_count++;
10057c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 		(void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
10087c478bd9Sstevel@tonic-gate 		    ph_impl, NULL, usb_flags, callback, callback_arg);
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 		return;
10117c478bd9Sstevel@tonic-gate 	}
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data) &&
10167c478bd9Sstevel@tonic-gate 	    ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0)) {
1017*d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
10187c478bd9Sstevel@tonic-gate 		    "usb_pipe_close: not allowed to close def pipe");
10197c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 		if (callback) {
10247c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
10257c478bd9Sstevel@tonic-gate 			    USB_INVALID_PIPE, callback_flags);
10267c478bd9Sstevel@tonic-gate 		} else {
1027*d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
10287c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
10297c478bd9Sstevel@tonic-gate 			    "usb_pipe_close: invalid pipe");
10307c478bd9Sstevel@tonic-gate 		}
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 		return;
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
10387c478bd9Sstevel@tonic-gate 	    ph_impl, NULL, usb_flags, callback, callback_arg);
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10437c478bd9Sstevel@tonic-gate static int
10447c478bd9Sstevel@tonic-gate usba_pipe_sync_close(dev_info_t *dip, usba_ph_impl_t *ph_impl,
10457c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t *request, usb_flags_t usb_flags)
10467c478bd9Sstevel@tonic-gate {
10477c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
10487c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
10497c478bd9Sstevel@tonic-gate 					(usb_pipe_handle_t)ph_impl);
10507c478bd9Sstevel@tonic-gate 	int			attribute;
10517c478bd9Sstevel@tonic-gate 	uchar_t			dir;
10527c478bd9Sstevel@tonic-gate 	int			timeout;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	if (ph_impl == NULL) {
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
10577c478bd9Sstevel@tonic-gate 	}
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
10607c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10617c478bd9Sstevel@tonic-gate 	    "usba_pipe_sync_close: dip=0x%p ph_data=0x%p state=%d ref=%d",
10627c478bd9Sstevel@tonic-gate 	    dip, ph_data, ph_impl->usba_ph_state, ph_impl->usba_ph_ref_count);
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	/*
10657c478bd9Sstevel@tonic-gate 	 * if another thread opens the pipe again, this loop could
10667c478bd9Sstevel@tonic-gate 	 * be truly forever
10677c478bd9Sstevel@tonic-gate 	 */
10687c478bd9Sstevel@tonic-gate 	if ((ph_data == NULL) ||
10697c478bd9Sstevel@tonic-gate 	    (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSING) ||
10707c478bd9Sstevel@tonic-gate 	    (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSED)) {
10717c478bd9Sstevel@tonic-gate 		/* wait forever till really closed */
10727c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
10737c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 		while (usba_get_ph_data((usb_pipe_handle_t)ph_impl)) {
10767c478bd9Sstevel@tonic-gate 			delay(1);
10777c478bd9Sstevel@tonic-gate 		}
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 		return (USB_SUCCESS);
10807c478bd9Sstevel@tonic-gate 	}
10817c478bd9Sstevel@tonic-gate 	ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSING;
10827c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
10857c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	attribute = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
10887c478bd9Sstevel@tonic-gate 	dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	/*
10937c478bd9Sstevel@tonic-gate 	 * For control and bulk, we will drain till ref_count <= 1 and
10947c478bd9Sstevel@tonic-gate 	 * req_count == 0 but for isoc and intr IN, we can only wait
10957c478bd9Sstevel@tonic-gate 	 * till the ref_count === 1 as the req_count will never go to 0
10967c478bd9Sstevel@tonic-gate 	 */
10977c478bd9Sstevel@tonic-gate 	for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
10987c478bd9Sstevel@tonic-gate 		switch (attribute) {
10997c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
11007c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
11017c478bd9Sstevel@tonic-gate 			if ((ph_data->p_req_count == 0) &&
11027c478bd9Sstevel@tonic-gate 			    (ph_impl->usba_ph_ref_count <= 1)) {
11037c478bd9Sstevel@tonic-gate 				goto done;
11047c478bd9Sstevel@tonic-gate 			}
11057c478bd9Sstevel@tonic-gate 			break;
11067c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
11077c478bd9Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
11087c478bd9Sstevel@tonic-gate 			if (dir == USB_EP_DIR_IN) {
11097c478bd9Sstevel@tonic-gate 				if (ph_impl->usba_ph_ref_count <= 1) {
11107c478bd9Sstevel@tonic-gate 					goto done;
11117c478bd9Sstevel@tonic-gate 				}
11127c478bd9Sstevel@tonic-gate 			} else if ((ph_data->p_req_count == 0) &&
11137c478bd9Sstevel@tonic-gate 			    (ph_impl->usba_ph_ref_count <= 1)) {
11147c478bd9Sstevel@tonic-gate 				goto done;
11157c478bd9Sstevel@tonic-gate 			}
11167c478bd9Sstevel@tonic-gate 			break;
11177c478bd9Sstevel@tonic-gate 		}
11187c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
11197c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
11207c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000));
11217c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
11227c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
11237c478bd9Sstevel@tonic-gate 	}
11247c478bd9Sstevel@tonic-gate done:
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
11277c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	if (timeout >= usba_drain_timeout) {
11307c478bd9Sstevel@tonic-gate 		int draining_succeeded;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
11337c478bd9Sstevel@tonic-gate 		    "timeout on draining requests, resetting pipe 0x%p",
11347c478bd9Sstevel@tonic-gate 		    ph_impl);
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 		(void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
11377c478bd9Sstevel@tonic-gate 		    USB_FLAGS_SLEEP);
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
11407c478bd9Sstevel@tonic-gate 		draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
11417c478bd9Sstevel@tonic-gate 						USB_CR_PIPE_RESET);
11427c478bd9Sstevel@tonic-gate 		/* this MUST have succeeded */
11437c478bd9Sstevel@tonic-gate 		ASSERT(draining_succeeded == USB_SUCCESS);
11447c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
11477c478bd9Sstevel@tonic-gate 		    "draining requests done");
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	if (usba_device->usb_hcdi_ops->usba_hcdi_pipe_close(ph_data,
11517c478bd9Sstevel@tonic-gate 	    usb_flags) != USB_SUCCESS) {
1152*d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
11537c478bd9Sstevel@tonic-gate 		    "usba_pipe_sync_close: hcd close failed");
11547c478bd9Sstevel@tonic-gate 		/* carry on regardless! */
11557c478bd9Sstevel@tonic-gate 	}
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	usba_destroy_pipe_handle(ph_data);
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
11607c478bd9Sstevel@tonic-gate }
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate /*
11647c478bd9Sstevel@tonic-gate  * usb_pipe_set_private:
11657c478bd9Sstevel@tonic-gate  *	set private client date in the pipe handle
11667c478bd9Sstevel@tonic-gate  */
11677c478bd9Sstevel@tonic-gate int
11687c478bd9Sstevel@tonic-gate usb_pipe_set_private(usb_pipe_handle_t	pipe_handle, usb_opaque_t data)
11697c478bd9Sstevel@tonic-gate {
11707c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
11737c478bd9Sstevel@tonic-gate 	    "usb_pipe_set_private: ");
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
11787c478bd9Sstevel@tonic-gate 	}
11797c478bd9Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data)) {
11807c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PERM);
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
11867c478bd9Sstevel@tonic-gate 	ph_data->p_client_private = data;
11877c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
11927c478bd9Sstevel@tonic-gate }
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate /*
11967c478bd9Sstevel@tonic-gate  * usb_pipe_get_private:
11977c478bd9Sstevel@tonic-gate  *	get private client date from the pipe handle
11987c478bd9Sstevel@tonic-gate  */
11997c478bd9Sstevel@tonic-gate usb_opaque_t
12007c478bd9Sstevel@tonic-gate usb_pipe_get_private(usb_pipe_handle_t	pipe_handle)
12017c478bd9Sstevel@tonic-gate {
12027c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
12037c478bd9Sstevel@tonic-gate 	usb_opaque_t		data;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12067c478bd9Sstevel@tonic-gate 	    "usb_pipe_get_private:");
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 		return (NULL);
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
12147c478bd9Sstevel@tonic-gate 	data = ph_data->p_client_private;
12157c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	return (data);
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate /*
12247c478bd9Sstevel@tonic-gate  * usb_pipe_reset
12257c478bd9Sstevel@tonic-gate  * Arguments:
12267c478bd9Sstevel@tonic-gate  *	dip		- devinfo pointer
12277c478bd9Sstevel@tonic-gate  *	pipe_handle	- opaque pipe handle
12287c478bd9Sstevel@tonic-gate  * Returns:
12297c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- pipe successfully reset or request queued
12307c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- undetermined failure
12317c478bd9Sstevel@tonic-gate  *	USB_INVALID_PIPE - pipe is invalid or already closed
12327c478bd9Sstevel@tonic-gate  */
12337c478bd9Sstevel@tonic-gate void
12347c478bd9Sstevel@tonic-gate usb_pipe_reset(dev_info_t		*dip,
12357c478bd9Sstevel@tonic-gate 		usb_pipe_handle_t	pipe_handle,
12367c478bd9Sstevel@tonic-gate 		usb_flags_t		usb_flags,
12377c478bd9Sstevel@tonic-gate 		void			(*callback)(
12387c478bd9Sstevel@tonic-gate 					    usb_pipe_handle_t	ph,
12397c478bd9Sstevel@tonic-gate 					    usb_opaque_t	arg,
12407c478bd9Sstevel@tonic-gate 					    int			rval,
12417c478bd9Sstevel@tonic-gate 					    usb_cb_flags_t	flags),
12427c478bd9Sstevel@tonic-gate 		usb_opaque_t		callback_arg)
12437c478bd9Sstevel@tonic-gate {
12447c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
12457c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
12467c478bd9Sstevel@tonic-gate 	usb_cb_flags_t		callback_flags;
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12497c478bd9Sstevel@tonic-gate 	    "usb_pipe_reset: dip=0x%p ph=0x%p uf=0x%x",
12507c478bd9Sstevel@tonic-gate 	    dip, pipe_handle, usb_flags);
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (ph_data == NULL)) {
12557c478bd9Sstevel@tonic-gate 		if (callback) {
12567c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
12577c478bd9Sstevel@tonic-gate 			    USB_INVALID_ARGS, callback_flags);
12587c478bd9Sstevel@tonic-gate 		} else {
1259*d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
12607c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
12617c478bd9Sstevel@tonic-gate 			    "usb_pipe_reset: invalid arguments");
12627c478bd9Sstevel@tonic-gate 		}
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		return;
12677c478bd9Sstevel@tonic-gate 	}
12687c478bd9Sstevel@tonic-gate 	if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
12697c478bd9Sstevel@tonic-gate 		if (callback) {
12707c478bd9Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
12717c478bd9Sstevel@tonic-gate 			    USB_INVALID_CONTEXT, callback_flags);
12727c478bd9Sstevel@tonic-gate 		} else {
1273*d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
12747c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
12757c478bd9Sstevel@tonic-gate 			    "usb_pipe_reset: invalid context");
12767c478bd9Sstevel@tonic-gate 		}
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 		return;
12817c478bd9Sstevel@tonic-gate 	}
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	/* is this the default pipe? */
12867c478bd9Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data)) {
12877c478bd9Sstevel@tonic-gate 		if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
1288*d291d9f2Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
12897c478bd9Sstevel@tonic-gate 			    "usb_pipe_reset: not allowed to reset def pipe");
12907c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 			if (callback) {
12937c478bd9Sstevel@tonic-gate 				callback(pipe_handle, callback_arg,
12947c478bd9Sstevel@tonic-gate 				    USB_INVALID_PIPE, callback_flags);
12957c478bd9Sstevel@tonic-gate 			} else {
1296*d291d9f2Sfrits 				USB_DPRINTF_L2(DPRINT_MASK_USBAI,
12977c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
12987c478bd9Sstevel@tonic-gate 				    "usb_pipe_reset: invalid pipe");
12997c478bd9Sstevel@tonic-gate 			}
13007c478bd9Sstevel@tonic-gate 			usba_release_ph_data(ph_impl);
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 			return;
13037c478bd9Sstevel@tonic-gate 		}
13047c478bd9Sstevel@tonic-gate 	}
13057c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(dip,
13087c478bd9Sstevel@tonic-gate 	    usba_pipe_sync_reset, ph_impl, NULL, usb_flags, callback,
13097c478bd9Sstevel@tonic-gate 	    callback_arg);
13107c478bd9Sstevel@tonic-gate }
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
13147c478bd9Sstevel@tonic-gate int
13157c478bd9Sstevel@tonic-gate usba_pipe_sync_reset(dev_info_t	*dip,
13167c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl,
13177c478bd9Sstevel@tonic-gate 	usba_pipe_async_req_t	*request,
13187c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags)
13197c478bd9Sstevel@tonic-gate {
13207c478bd9Sstevel@tonic-gate 	int rval, draining_succeeded;
13217c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
13227c478bd9Sstevel@tonic-gate 								ph_impl);
13237c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
13267c478bd9Sstevel@tonic-gate 	    "usba_pipe_sync_reset: dip=0x%p ph_data=0x%p uf=0x%x",
13277c478bd9Sstevel@tonic-gate 	    dip, ph_data, usb_flags);
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
13307c478bd9Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
13317c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
13347c478bd9Sstevel@tonic-gate 								usb_flags);
13357c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 	/*
13387c478bd9Sstevel@tonic-gate 	 * The host controller has stopped polling of the endpoint.
13397c478bd9Sstevel@tonic-gate 	 */
13407c478bd9Sstevel@tonic-gate 	draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
13417c478bd9Sstevel@tonic-gate 							USB_CR_PIPE_RESET);
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	/* this MUST have succeeded */
13447c478bd9Sstevel@tonic-gate 	ASSERT(draining_succeeded == USB_SUCCESS);
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 	usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
13477c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 	/*
13507c478bd9Sstevel@tonic-gate 	 * if there are requests still queued on the default pipe,
13517c478bd9Sstevel@tonic-gate 	 * start them now
13527c478bd9Sstevel@tonic-gate 	 */
13537c478bd9Sstevel@tonic-gate 	usba_start_next_req(ph_data);
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 	return (rval);
13587c478bd9Sstevel@tonic-gate }
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate /*
13627c478bd9Sstevel@tonic-gate  * usba_pipe_clear:
13637c478bd9Sstevel@tonic-gate  *	call hcd to clear pipe but don't wait for draining
13647c478bd9Sstevel@tonic-gate  */
13657c478bd9Sstevel@tonic-gate void
13667c478bd9Sstevel@tonic-gate usba_pipe_clear(usb_pipe_handle_t pipe_handle)
13677c478bd9Sstevel@tonic-gate {
13687c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(pipe_handle);
13697c478bd9Sstevel@tonic-gate 	usba_device_t		*usba_device;
13707c478bd9Sstevel@tonic-gate 	usba_req_wrapper_t	*req_wrp;
13717c478bd9Sstevel@tonic-gate 	int			flush_requests = 1;
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
13747c478bd9Sstevel@tonic-gate 	    "usba_pipe_clear: ph_data=0x%p", ph_data);
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 		return;
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
13827c478bd9Sstevel@tonic-gate 	if (USBA_PIPE_CLOSING(usba_get_ph_state(ph_data))) {
13837c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 		return;
13867c478bd9Sstevel@tonic-gate 	}
13877c478bd9Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
13887c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	(void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
13917c478bd9Sstevel@tonic-gate 							USB_FLAGS_SLEEP);
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
13947c478bd9Sstevel@tonic-gate 	if (ph_data->p_dip) {
13957c478bd9Sstevel@tonic-gate 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
13967c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
13977c478bd9Sstevel@tonic-gate 			    usbai_log_handle,
13987c478bd9Sstevel@tonic-gate 			    "no flushing on default pipe!");
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 			flush_requests = 0;
14017c478bd9Sstevel@tonic-gate 		}
14027c478bd9Sstevel@tonic-gate 	}
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	if (flush_requests) {
14057c478bd9Sstevel@tonic-gate 		/* flush all requests in the pipehandle queue */
14067c478bd9Sstevel@tonic-gate 		while ((req_wrp = (usba_req_wrapper_t *)
14077c478bd9Sstevel@tonic-gate 		    usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
14087c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
14097c478bd9Sstevel@tonic-gate 			usba_do_req_exc_cb(req_wrp, USB_CR_FLUSHED,
14107c478bd9Sstevel@tonic-gate 					USB_CB_RESET_PIPE);
14117c478bd9Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
14127c478bd9Sstevel@tonic-gate 		}
14137c478bd9Sstevel@tonic-gate 	}
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 	usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
14167c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
14177c478bd9Sstevel@tonic-gate }
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate /*
14217c478bd9Sstevel@tonic-gate  *
14227c478bd9Sstevel@tonic-gate  * usb_pipe_drain_reqs
14237c478bd9Sstevel@tonic-gate  *	this function blocks until there are no more requests
14247c478bd9Sstevel@tonic-gate  *	owned by this dip on the pipe
14257c478bd9Sstevel@tonic-gate  *
14267c478bd9Sstevel@tonic-gate  * Arguments:
14277c478bd9Sstevel@tonic-gate  *	dip		- devinfo pointer
14287c478bd9Sstevel@tonic-gate  *	pipe_handle	- opaque pipe handle
14297c478bd9Sstevel@tonic-gate  *	timeout 	- timeout in seconds
14307c478bd9Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
14317c478bd9Sstevel@tonic-gate  *				wait for completion.
14327c478bd9Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
14337c478bd9Sstevel@tonic-gate  *			  this callback function will be called on
14347c478bd9Sstevel@tonic-gate  *			  completion. This callback may be NULL
14357c478bd9Sstevel@tonic-gate  *			  and no notification of completion will then
14367c478bd9Sstevel@tonic-gate  *			  be provided.
14377c478bd9Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
14387c478bd9Sstevel@tonic-gate  *
14397c478bd9Sstevel@tonic-gate  * callback and callback_arg should be NULL if USB_FLAGS_SLEEP has
14407c478bd9Sstevel@tonic-gate  * been specified
14417c478bd9Sstevel@tonic-gate  *
14427c478bd9Sstevel@tonic-gate  * Returns:
14437c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- pipe successfully reset or request queued
14447c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- timeout
14457c478bd9Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
14467c478bd9Sstevel@tonic-gate  */
14477c478bd9Sstevel@tonic-gate int
14487c478bd9Sstevel@tonic-gate usb_pipe_drain_reqs(dev_info_t	*dip,
14497c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle,
14507c478bd9Sstevel@tonic-gate 	uint_t			time,
14517c478bd9Sstevel@tonic-gate 	usb_flags_t		usb_flags,
14527c478bd9Sstevel@tonic-gate 	void			(*cb)(
14537c478bd9Sstevel@tonic-gate 				    usb_pipe_handle_t	ph,
14547c478bd9Sstevel@tonic-gate 				    usb_opaque_t	arg,   /* cb arg */
14557c478bd9Sstevel@tonic-gate 				    int			rval,
14567c478bd9Sstevel@tonic-gate 				    usb_cb_flags_t	flags),
14577c478bd9Sstevel@tonic-gate 	usb_opaque_t		cb_arg)
14587c478bd9Sstevel@tonic-gate {
14597c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
14607c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
14637c478bd9Sstevel@tonic-gate 	    "usb_pipe_drain_reqs: dip=0x%p ph_data=0x%p tm=%d uf=0x%x",
14647c478bd9Sstevel@tonic-gate 	    dip, ph_data, time, usb_flags);
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	if (ph_data == NULL) {
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
14697c478bd9Sstevel@tonic-gate 	}
14707c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
14717c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
14747c478bd9Sstevel@tonic-gate 	}
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
14777c478bd9Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
14807c478bd9Sstevel@tonic-gate 	}
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(dip, usba_pipe_sync_drain_reqs,
14837c478bd9Sstevel@tonic-gate 	    ph_impl, (usb_opaque_t)((uintptr_t)time), usb_flags, cb, cb_arg);
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	return (USB_SUCCESS);
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate /*
14907c478bd9Sstevel@tonic-gate  * usba_pipe_sync_drain_reqs
14917c478bd9Sstevel@tonic-gate  *	this function blocks until there are no more requests
14927c478bd9Sstevel@tonic-gate  *	owned by this dip on the pipe
14937c478bd9Sstevel@tonic-gate  *
14947c478bd9Sstevel@tonic-gate  * Arguments:
14957c478bd9Sstevel@tonic-gate  *	dip		- devinfo pointer
14967c478bd9Sstevel@tonic-gate  *	ph_impl		- pipe impl handle
14977c478bd9Sstevel@tonic-gate  *	timeout		- timeout in seconds
14987c478bd9Sstevel@tonic-gate  * Returns:
14997c478bd9Sstevel@tonic-gate  *	USB_SUCCESS	- pipe successfully reset or request queued
15007c478bd9Sstevel@tonic-gate  *	USB_FAILURE	- timeout
15017c478bd9Sstevel@tonic-gate  *	USB_*		- see usbai.h
15027c478bd9Sstevel@tonic-gate  */
15037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15047c478bd9Sstevel@tonic-gate int
15057c478bd9Sstevel@tonic-gate usba_pipe_sync_drain_reqs(dev_info_t	*dip,
15067c478bd9Sstevel@tonic-gate 		usba_ph_impl_t		*ph_impl,
15077c478bd9Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
15087c478bd9Sstevel@tonic-gate 		usb_flags_t		usb_flags)
15097c478bd9Sstevel@tonic-gate {
15107c478bd9Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
15117c478bd9Sstevel@tonic-gate 								ph_impl);
15127c478bd9Sstevel@tonic-gate 	int		i;
15137c478bd9Sstevel@tonic-gate 	int		timeout = 100 * (int)((uintptr_t)(request->arg));
15147c478bd9Sstevel@tonic-gate 						/* delay will be 10 ms */
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15197c478bd9Sstevel@tonic-gate 	    "usba_pipe_sync_drain_reqs: "
15207c478bd9Sstevel@tonic-gate 	    "dip=0x%p ph_data=0x%p timeout=%d ref=%d req=%d",
15217c478bd9Sstevel@tonic-gate 	    dip, ph_data, timeout, usba_get_ph_ref_count(ph_data),
15227c478bd9Sstevel@tonic-gate 	    ph_data->p_req_count);
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	/*
15277c478bd9Sstevel@tonic-gate 	 * for default pipe, we need to check the active request
15287c478bd9Sstevel@tonic-gate 	 * and the queue
15297c478bd9Sstevel@tonic-gate 	 * Note that a pipe reset on the default pipe doesn't flush
15307c478bd9Sstevel@tonic-gate 	 * the queue
15317c478bd9Sstevel@tonic-gate 	 * for all other pipes we just check ref and req count since
15327c478bd9Sstevel@tonic-gate 	 * these pipes are unshared
15337c478bd9Sstevel@tonic-gate 	 */
15347c478bd9Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data)) {
15357c478bd9Sstevel@tonic-gate 		for (i = 0; (i < timeout) || (request->arg == 0); i++) {
15367c478bd9Sstevel@tonic-gate 			usba_list_entry_t *next, *tmpnext;
15377c478bd9Sstevel@tonic-gate 			usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *)
15387c478bd9Sstevel@tonic-gate 					    ph_data->p_active_cntrl_req_wrp;
15397c478bd9Sstevel@tonic-gate 			int found = 0;
15407c478bd9Sstevel@tonic-gate 			int count = 0;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 			/* active_req_wrp is only for control pipes */
15437c478bd9Sstevel@tonic-gate 			if ((req_wrp == NULL) || (req_wrp->wr_dip != dip)) {
15447c478bd9Sstevel@tonic-gate 				/* walk the queue */
15457c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_data->p_queue.list_mutex);
15467c478bd9Sstevel@tonic-gate 				next = ph_data->p_queue.next;
15477c478bd9Sstevel@tonic-gate 				while (next != NULL) {
15487c478bd9Sstevel@tonic-gate 					mutex_enter(&next->list_mutex);
15497c478bd9Sstevel@tonic-gate 					req_wrp = (usba_req_wrapper_t *)
15507c478bd9Sstevel@tonic-gate 							next->private;
15517c478bd9Sstevel@tonic-gate 					found = (req_wrp->wr_dip == dip);
15527c478bd9Sstevel@tonic-gate 					if (found) {
15537c478bd9Sstevel@tonic-gate 						mutex_exit(&next->list_mutex);
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 						break;
15567c478bd9Sstevel@tonic-gate 					}
15577c478bd9Sstevel@tonic-gate 					tmpnext = next->next;
15587c478bd9Sstevel@tonic-gate 					mutex_exit(&next->list_mutex);
15597c478bd9Sstevel@tonic-gate 					next = tmpnext;
15607c478bd9Sstevel@tonic-gate 					count++;
15617c478bd9Sstevel@tonic-gate 				}
15627c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_data->p_queue.list_mutex);
15637c478bd9Sstevel@tonic-gate 				if (found == 0) {
15647c478bd9Sstevel@tonic-gate 					break;
15657c478bd9Sstevel@tonic-gate 				}
15667c478bd9Sstevel@tonic-gate 			}
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15697c478bd9Sstevel@tonic-gate 			    "usb_pipe_sync_drain_reqs: "
15707c478bd9Sstevel@tonic-gate 			    "cnt=%d active_req_wrp=0x%p",
15717c478bd9Sstevel@tonic-gate 			    count, ph_data->p_active_cntrl_req_wrp);
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
15747c478bd9Sstevel@tonic-gate 			delay(drv_usectohz(10000));
15757c478bd9Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
15767c478bd9Sstevel@tonic-gate 		}
15777c478bd9Sstevel@tonic-gate 	} else {
15787c478bd9Sstevel@tonic-gate 		mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
15797c478bd9Sstevel@tonic-gate 		for (i = 0; (i < timeout) || (request->arg == 0); i++) {
15807c478bd9Sstevel@tonic-gate 			ASSERT(ph_data->p_req_count >= 0);
15817c478bd9Sstevel@tonic-gate 			if (ph_data->p_req_count ||
15827c478bd9Sstevel@tonic-gate 			    (ph_data->p_ph_impl->usba_ph_ref_count > 1)) {
15837c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
15847c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_data->p_mutex);
15857c478bd9Sstevel@tonic-gate 				delay(drv_usectohz(10000));
15867c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_data->p_mutex);
15877c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
15887c478bd9Sstevel@tonic-gate 			} else {
15897c478bd9Sstevel@tonic-gate 				break;
15907c478bd9Sstevel@tonic-gate 			}
15917c478bd9Sstevel@tonic-gate 		}
15927c478bd9Sstevel@tonic-gate 		mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
15937c478bd9Sstevel@tonic-gate 	}
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15967c478bd9Sstevel@tonic-gate 	    "usb_pipe_sync_drain_reqs: timeout=%d active_req_wrp=0x%p req=%d",
15977c478bd9Sstevel@tonic-gate 	    i, ph_data->p_active_cntrl_req_wrp, ph_data->p_req_count);
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 	return (i >= timeout ? USB_FAILURE : USB_SUCCESS);
16047c478bd9Sstevel@tonic-gate }
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate /*
16087c478bd9Sstevel@tonic-gate  * usba_persistent_pipe_open
16097c478bd9Sstevel@tonic-gate  *	Open all the pipes marked persistent for this device
16107c478bd9Sstevel@tonic-gate  */
16117c478bd9Sstevel@tonic-gate int
16127c478bd9Sstevel@tonic-gate usba_persistent_pipe_open(usba_device_t *usba_device)
16137c478bd9Sstevel@tonic-gate {
16147c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl;
16157c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle;
16167c478bd9Sstevel@tonic-gate 	int			i;
16177c478bd9Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16207c478bd9Sstevel@tonic-gate 	    "usba_persistent_pipe_open: usba_device=0x%p", usba_device);
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	if (usba_device != NULL) {
16237c478bd9Sstevel@tonic-gate 		/* default pipe is the first one to be opened */
16247c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
16257c478bd9Sstevel@tonic-gate 		for (i = 0; (rval == USB_SUCCESS) &&
16267c478bd9Sstevel@tonic-gate 		    (i < USBA_N_ENDPOINTS); i++) {
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 			ph_impl = &usba_device->usb_ph_list[i];
16297c478bd9Sstevel@tonic-gate 			mutex_enter(&ph_impl->usba_ph_mutex);
16307c478bd9Sstevel@tonic-gate 			if (ph_impl->usba_ph_flags & USBA_PH_DATA_PERSISTENT) {
16317c478bd9Sstevel@tonic-gate 				ph_impl->usba_ph_flags &=
16327c478bd9Sstevel@tonic-gate 						~USBA_PH_DATA_PERSISTENT;
16337c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_impl->usba_ph_mutex);
16347c478bd9Sstevel@tonic-gate 				mutex_exit(&usba_device->usb_mutex);
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 				rval = usb_pipe_open(ph_impl->usba_ph_dip,
16377c478bd9Sstevel@tonic-gate 				    &ph_impl->usba_ph_ep,
16387c478bd9Sstevel@tonic-gate 				    &ph_impl->usba_ph_policy,
16397c478bd9Sstevel@tonic-gate 				    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
16407c478bd9Sstevel@tonic-gate 				    &pipe_handle);
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 				USB_DPRINTF_L3(DPRINT_MASK_USBAI,
16437c478bd9Sstevel@tonic-gate 				    usbai_log_handle,
16447c478bd9Sstevel@tonic-gate 				    "usba_persistent_pipe_open: "
16457c478bd9Sstevel@tonic-gate 				    "ep_index=%d, rval=%d", i, rval);
16467c478bd9Sstevel@tonic-gate 				mutex_enter(&usba_device->usb_mutex);
16477c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_impl->usba_ph_mutex);
16487c478bd9Sstevel@tonic-gate 			}
16497c478bd9Sstevel@tonic-gate 			mutex_exit(&ph_impl->usba_ph_mutex);
16507c478bd9Sstevel@tonic-gate 		}
16517c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
16527c478bd9Sstevel@tonic-gate 	}
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	return (rval);
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate /*
16597c478bd9Sstevel@tonic-gate  * usba_persistent_pipe_close
16607c478bd9Sstevel@tonic-gate  *	Close all pipes of this device and mark them persistent
16617c478bd9Sstevel@tonic-gate  */
16627c478bd9Sstevel@tonic-gate void
16637c478bd9Sstevel@tonic-gate usba_persistent_pipe_close(usba_device_t *usba_device)
16647c478bd9Sstevel@tonic-gate {
16657c478bd9Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl;
16667c478bd9Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle;
16677c478bd9Sstevel@tonic-gate 	int			i;
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16707c478bd9Sstevel@tonic-gate 	    "usba_persistent_pipe_close: usba_device=0x%p", usba_device);
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 	if (usba_device != NULL) {
16737c478bd9Sstevel@tonic-gate 		/* default pipe is the last one to be closed */
16747c478bd9Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 		for (i = (USBA_N_ENDPOINTS - 1); i >= 0; i--) {
16777c478bd9Sstevel@tonic-gate 			ph_impl = &usba_device->usb_ph_list[i];
16787c478bd9Sstevel@tonic-gate 			if (ph_impl->usba_ph_data != NULL) {
16797c478bd9Sstevel@tonic-gate 				mutex_enter(&ph_impl->usba_ph_mutex);
16807c478bd9Sstevel@tonic-gate 				ph_impl->usba_ph_flags |=
16817c478bd9Sstevel@tonic-gate 						USBA_PH_DATA_PERSISTENT;
16827c478bd9Sstevel@tonic-gate 				mutex_exit(&ph_impl->usba_ph_mutex);
16837c478bd9Sstevel@tonic-gate 				mutex_exit(&usba_device->usb_mutex);
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 				pipe_handle = (usb_pipe_handle_t)ph_impl;
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 				usb_pipe_close(ph_impl->usba_ph_dip,
16887c478bd9Sstevel@tonic-gate 				    pipe_handle,
16897c478bd9Sstevel@tonic-gate 				    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
16907c478bd9Sstevel@tonic-gate 				    NULL, NULL);
16917c478bd9Sstevel@tonic-gate 				mutex_enter(&usba_device->usb_mutex);
16927c478bd9Sstevel@tonic-gate 				ASSERT(ph_impl->usba_ph_data == NULL);
16937c478bd9Sstevel@tonic-gate 			}
16947c478bd9Sstevel@tonic-gate 		}
16957c478bd9Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
16967c478bd9Sstevel@tonic-gate 	}
16977c478bd9Sstevel@tonic-gate }
1698