xref: /onnv-gate/usr/src/uts/common/io/usb/usba/usbai_pipe_mgmt.c (revision 9430:637732b28916)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56898Sfb209375  * Common Development and Distribution License (the "License").
66898Sfb209375  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*9430SRaymond.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * USBA: Solaris USB Architecture support
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * all functions exposed to client drivers  have prefix usb_ while all USBA
310Sstevel@tonic-gate  * internal functions or functions exposed to HCD or hubd only have prefix
320Sstevel@tonic-gate  * usba_
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * this file contains all USBAI pipe management
350Sstevel@tonic-gate  *	usb_pipe_open()
360Sstevel@tonic-gate  *	usb_pipe_close()
370Sstevel@tonic-gate  *	usb_pipe_set_private()
380Sstevel@tonic-gate  *	usb_pipe_get_private()
390Sstevel@tonic-gate  *	usb_pipe_abort()
400Sstevel@tonic-gate  *	usb_pipe_reset()
410Sstevel@tonic-gate  *	usb_pipe_drain_reqs()
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate #define	USBA_FRAMEWORK
440Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
450Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
460Sstevel@tonic-gate #include <sys/atomic.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate extern	pri_t	maxclsyspri;
490Sstevel@tonic-gate extern	pri_t	minclsyspri;
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /* function prototypes */
520Sstevel@tonic-gate static	void	usba_pipe_do_async_func_thread(void *arg);
530Sstevel@tonic-gate static	int	usba_pipe_sync_close(dev_info_t *, usba_ph_impl_t *,
540Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
550Sstevel@tonic-gate static	int	usba_pipe_sync_reset(dev_info_t *, usba_ph_impl_t *,
560Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
570Sstevel@tonic-gate static	int	usba_pipe_sync_drain_reqs(dev_info_t *, usba_ph_impl_t *,
580Sstevel@tonic-gate 			usba_pipe_async_req_t *, usb_flags_t);
590Sstevel@tonic-gate 
600Sstevel@tonic-gate /* local tunables */
61880Sfrits int	usba_drain_timeout = 1000;	/* in ms */
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /* return the default pipe for this device */
640Sstevel@tonic-gate usb_pipe_handle_t
usba_get_dflt_pipe_handle(dev_info_t * dip)650Sstevel@tonic-gate usba_get_dflt_pipe_handle(dev_info_t *dip)
660Sstevel@tonic-gate {
670Sstevel@tonic-gate 	usba_device_t		*usba_device;
680Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = NULL;
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	if (dip) {
710Sstevel@tonic-gate 		usba_device = usba_get_usba_device(dip);
720Sstevel@tonic-gate 		if (usba_device) {
730Sstevel@tonic-gate 			pipe_handle =
740Sstevel@tonic-gate 			    (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
750Sstevel@tonic-gate 		}
760Sstevel@tonic-gate 	}
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	return (pipe_handle);
790Sstevel@tonic-gate }
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /* return dip owner of pipe_handle */
830Sstevel@tonic-gate dev_info_t *
usba_get_dip(usb_pipe_handle_t pipe_handle)840Sstevel@tonic-gate usba_get_dip(usb_pipe_handle_t pipe_handle)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
870Sstevel@tonic-gate 	dev_info_t		*dip = NULL;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	if (ph_impl) {
900Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
910Sstevel@tonic-gate 		dip = ph_impl->usba_ph_dip;
920Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
930Sstevel@tonic-gate 	}
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	return (dip);
960Sstevel@tonic-gate }
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 
990Sstevel@tonic-gate usb_pipe_handle_t
usba_usbdev_to_dflt_pipe_handle(usba_device_t * usba_device)1000Sstevel@tonic-gate usba_usbdev_to_dflt_pipe_handle(usba_device_t *usba_device)
1010Sstevel@tonic-gate {
1020Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = NULL;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	if ((usba_device) &&
1050Sstevel@tonic-gate 	    (usba_device->usb_ph_list[0].usba_ph_data != NULL)) {
1060Sstevel@tonic-gate 		pipe_handle = (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
1070Sstevel@tonic-gate 	}
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	return (pipe_handle);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate usba_pipe_handle_data_t *
usba_get_ph_data(usb_pipe_handle_t pipe_handle)1140Sstevel@tonic-gate usba_get_ph_data(usb_pipe_handle_t pipe_handle)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
1170Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = NULL;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	if (ph_impl) {
1200Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
1210Sstevel@tonic-gate 		ASSERT(ph_impl->usba_ph_ref_count >= 0);
1220Sstevel@tonic-gate 		ph_data = ph_impl->usba_ph_data;
1230Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
1240Sstevel@tonic-gate 	}
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	return (ph_data);
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate usb_pipe_handle_t
usba_get_pipe_handle(usba_pipe_handle_data_t * ph_data)1310Sstevel@tonic-gate usba_get_pipe_handle(usba_pipe_handle_data_t *ph_data)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	usb_pipe_handle_t ph = NULL;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	if (ph_data) {
1360Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
1370Sstevel@tonic-gate 		ASSERT(ph_data->p_req_count >= 0);
1380Sstevel@tonic-gate 		ph = (usb_pipe_handle_t)ph_data->p_ph_impl;
1390Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	return (ph);
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate  * opaque to pipe handle impl translation with incr of ref count. The caller
1480Sstevel@tonic-gate  * must release ph_data when done. Increment the ref count ensures that
1490Sstevel@tonic-gate  * the ph_data will not be freed underneath us.
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate usba_pipe_handle_data_t *
usba_hold_ph_data(usb_pipe_handle_t pipe_handle)1520Sstevel@tonic-gate usba_hold_ph_data(usb_pipe_handle_t pipe_handle)
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
1550Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = NULL;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	if (ph_impl) {
1580Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 		switch (ph_impl->usba_ph_state) {
1610Sstevel@tonic-gate 		case USB_PIPE_STATE_IDLE:
1620Sstevel@tonic-gate 		case USB_PIPE_STATE_ACTIVE:
1630Sstevel@tonic-gate 		case USB_PIPE_STATE_ERROR:
1640Sstevel@tonic-gate 			ph_data = ph_impl->usba_ph_data;
1650Sstevel@tonic-gate 			ph_impl->usba_ph_ref_count++;
1660Sstevel@tonic-gate 			break;
1670Sstevel@tonic-gate 		case USB_PIPE_STATE_CLOSED:
1680Sstevel@tonic-gate 		case USB_PIPE_STATE_CLOSING:
1690Sstevel@tonic-gate 		default:
1700Sstevel@tonic-gate 			break;
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1740Sstevel@tonic-gate 		    "usba_hold_ph_data: ph_impl=0x%p state=%d ref=%d",
1756898Sfb209375 		    (void *)ph_impl, ph_impl->usba_ph_state,
1760Sstevel@tonic-gate 		    ph_impl->usba_ph_ref_count);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	return (ph_data);
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate void
usba_release_ph_data(usba_ph_impl_t * ph_impl)1860Sstevel@tonic-gate usba_release_ph_data(usba_ph_impl_t *ph_impl)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	if (ph_impl) {
1890Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 		USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1920Sstevel@tonic-gate 		    "usba_release_ph_data: "
1930Sstevel@tonic-gate 		    "ph_impl=0x%p state=%d ref=%d",
1946898Sfb209375 		    (void *)ph_impl, ph_impl->usba_ph_state,
1950Sstevel@tonic-gate 		    ph_impl->usba_ph_ref_count);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate #ifndef __lock_lint
1980Sstevel@tonic-gate 		if (ph_impl->usba_ph_data) {
1990Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2000Sstevel@tonic-gate 			    "usba_release_ph_data: req_count=%d",
2010Sstevel@tonic-gate 			    ph_impl->usba_ph_data->p_req_count);
2020Sstevel@tonic-gate 			ASSERT(ph_impl->usba_ph_data->p_req_count >= 0);
2030Sstevel@tonic-gate 		}
2040Sstevel@tonic-gate #endif
2050Sstevel@tonic-gate 		ph_impl->usba_ph_ref_count--;
2060Sstevel@tonic-gate 		ASSERT(ph_impl->usba_ph_ref_count >= 0);
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate  * get pipe state from ph_data
2150Sstevel@tonic-gate  */
2160Sstevel@tonic-gate usb_pipe_state_t
usba_get_ph_state(usba_pipe_handle_data_t * ph_data)2170Sstevel@tonic-gate usba_get_ph_state(usba_pipe_handle_data_t *ph_data)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
2200Sstevel@tonic-gate 	usb_pipe_state_t	pipe_state;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	ASSERT(mutex_owned(&ph_data->p_mutex));
2230Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
2240Sstevel@tonic-gate 	pipe_state = ph_impl->usba_ph_state;
2250Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	return (pipe_state);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate  * get ref_count from ph_data
2330Sstevel@tonic-gate  */
2340Sstevel@tonic-gate int
usba_get_ph_ref_count(usba_pipe_handle_data_t * ph_data)2350Sstevel@tonic-gate usba_get_ph_ref_count(usba_pipe_handle_data_t *ph_data)
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
2380Sstevel@tonic-gate 	int			ref_count;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
2410Sstevel@tonic-gate 	ref_count = ph_impl->usba_ph_ref_count;
2420Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	return (ref_count);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * new pipe state
2500Sstevel@tonic-gate  * We need to hold both pipe mutex and ph_impl mutex
2510Sstevel@tonic-gate  */
2520Sstevel@tonic-gate void
usba_pipe_new_state(usba_pipe_handle_data_t * ph_data,usb_pipe_state_t state)2530Sstevel@tonic-gate usba_pipe_new_state(usba_pipe_handle_data_t *ph_data, usb_pipe_state_t state)
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	ASSERT(mutex_owned(&ph_data->p_mutex));
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
2600Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
2610Sstevel@tonic-gate 	ASSERT(ph_impl->usba_ph_ref_count >= 0);
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2640Sstevel@tonic-gate 	    "usba_pipe_new_state: "
2650Sstevel@tonic-gate 	    "ph_data=0x%p old=%s new=%s ref=%d req=%d",
2666898Sfb209375 	    (void *)ph_data, usb_str_pipe_state(ph_impl->usba_ph_state),
2670Sstevel@tonic-gate 	    usb_str_pipe_state(state),
2680Sstevel@tonic-gate 	    ph_impl->usba_ph_ref_count, ph_data->p_req_count);
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	switch (ph_impl->usba_ph_state) {
2710Sstevel@tonic-gate 	case USB_PIPE_STATE_IDLE:
2720Sstevel@tonic-gate 	case USB_PIPE_STATE_ACTIVE:
2730Sstevel@tonic-gate 	case USB_PIPE_STATE_ERROR:
2740Sstevel@tonic-gate 	case USB_PIPE_STATE_CLOSED:
2750Sstevel@tonic-gate 		ph_impl->usba_ph_state = state;
2760Sstevel@tonic-gate 		break;
2770Sstevel@tonic-gate 	case USB_PIPE_STATE_CLOSING:
2780Sstevel@tonic-gate 	default:
2790Sstevel@tonic-gate 		break;
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate  * async function execution support
2870Sstevel@tonic-gate  * Arguments:
2880Sstevel@tonic-gate  *	dip		- devinfo pointer
2890Sstevel@tonic-gate  *	sync_func	- function to be executed
2900Sstevel@tonic-gate  *	ph_impl		- impl pipehandle
2910Sstevel@tonic-gate  *	arg		- opaque arg
2920Sstevel@tonic-gate  *	usb_flags	- none
2930Sstevel@tonic-gate  *	callback	- function to be called on completion, may be NULL
2940Sstevel@tonic-gate  *	callback_arg	- argument for callback function
2950Sstevel@tonic-gate  *
2960Sstevel@tonic-gate  * Note: The caller must do a hold on ph_data
2970Sstevel@tonic-gate  *	We sleep for memory resources and taskq_dispatch which will ensure
2980Sstevel@tonic-gate  *	that this function succeeds
2990Sstevel@tonic-gate  */
3000Sstevel@tonic-gate int
usba_pipe_setup_func_call(dev_info_t * dip,int (* sync_func)(dev_info_t *,usba_ph_impl_t *,usba_pipe_async_req_t *,usb_flags_t),usba_ph_impl_t * ph_impl,usb_opaque_t arg,usb_flags_t usb_flags,void (* callback)(usb_pipe_handle_t,usb_opaque_t,int,usb_cb_flags_t),usb_opaque_t callback_arg)3010Sstevel@tonic-gate usba_pipe_setup_func_call(
3020Sstevel@tonic-gate 	dev_info_t	*dip,
3030Sstevel@tonic-gate 	int		(*sync_func)(dev_info_t *,
3040Sstevel@tonic-gate 			    usba_ph_impl_t *, usba_pipe_async_req_t *,
3050Sstevel@tonic-gate 			    usb_flags_t),
3060Sstevel@tonic-gate 	usba_ph_impl_t *ph_impl,
3070Sstevel@tonic-gate 	usb_opaque_t	arg,
3080Sstevel@tonic-gate 	usb_flags_t	usb_flags,
3090Sstevel@tonic-gate 	void		(*callback)(usb_pipe_handle_t,
3100Sstevel@tonic-gate 			    usb_opaque_t, int, usb_cb_flags_t),
3110Sstevel@tonic-gate 	usb_opaque_t	callback_arg)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate 	usba_pipe_async_req_t	*request;
3140Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = (usb_pipe_handle_t)ph_impl;
3150Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
3160Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
3170Sstevel@tonic-gate 	usb_cb_flags_t		callback_flags;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
3200Sstevel@tonic-gate 	    "usba_pipe_setup_func_call: ph_impl=0x%p, func=0x%p",
3216898Sfb209375 	    (void *)ph_impl, (void *)sync_func);
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	if (((usb_flags & USB_FLAGS_SLEEP) == 0) && (callback == NULL)) {
3240Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
325978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
3260Sstevel@tonic-gate 		    "usba_pipe_setup_func_call: async request with "
3270Sstevel@tonic-gate 		    "no callback");
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	request = kmem_zalloc(sizeof (usba_pipe_async_req_t), KM_SLEEP);
3330Sstevel@tonic-gate 	request->dip		= dip;
3340Sstevel@tonic-gate 	request->ph_impl	= ph_impl;
3350Sstevel@tonic-gate 	request->arg		= arg;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	/*
3380Sstevel@tonic-gate 	 * OR in sleep flag. regardless of calling sync_func directly
3390Sstevel@tonic-gate 	 * or in a new thread, we will always wait for completion
3400Sstevel@tonic-gate 	 */
3410Sstevel@tonic-gate 	request->usb_flags	= usb_flags | USB_FLAGS_SLEEP;
3420Sstevel@tonic-gate 	request->sync_func	= sync_func;
3430Sstevel@tonic-gate 	request->callback	= callback;
3440Sstevel@tonic-gate 	request->callback_arg	= callback_arg;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	if (usb_flags & USB_FLAGS_SLEEP) {
3470Sstevel@tonic-gate 		rval = sync_func(dip, ph_impl, request, usb_flags);
3480Sstevel@tonic-gate 		kmem_free(request, sizeof (usba_pipe_async_req_t));
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	} else if (usba_async_ph_req(ph_data,
3510Sstevel@tonic-gate 	    usba_pipe_do_async_func_thread,
3520Sstevel@tonic-gate 	    (void *)request, USB_FLAGS_SLEEP) != USB_SUCCESS) {
3530Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
3540Sstevel@tonic-gate 		    "usb_async_req failed: ph_impl=0x%p, func=0x%p",
3556898Sfb209375 		    (void *)ph_impl, (void *)sync_func);
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 		if (callback) {
3580Sstevel@tonic-gate 			callback_flags =
3590Sstevel@tonic-gate 			    usba_check_intr_context(USB_CB_ASYNC_REQ_FAILED);
3600Sstevel@tonic-gate 			callback(pipe_handle, callback_arg, USB_FAILURE,
3610Sstevel@tonic-gate 			    callback_flags);
3620Sstevel@tonic-gate 		}
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 		kmem_free(request, sizeof (usba_pipe_async_req_t));
3650Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
3660Sstevel@tonic-gate 	}
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	return (rval);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate /*
3730Sstevel@tonic-gate  * taskq thread function to execute function synchronously
3740Sstevel@tonic-gate  * Note: caller must have done a hold on ph_data
3750Sstevel@tonic-gate  */
3760Sstevel@tonic-gate static void
usba_pipe_do_async_func_thread(void * arg)3770Sstevel@tonic-gate usba_pipe_do_async_func_thread(void *arg)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate 	usba_pipe_async_req_t	*request = (usba_pipe_async_req_t *)arg;
3800Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = request->ph_impl;
3810Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle = (usb_pipe_handle_t)ph_impl;
3820Sstevel@tonic-gate 	int			rval;
3830Sstevel@tonic-gate 	usb_cb_flags_t		cb_flags = USB_CB_NO_INFO;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	if ((rval = request->sync_func(request->dip, ph_impl,
3860Sstevel@tonic-gate 	    request, request->usb_flags | USB_FLAGS_SLEEP)) !=
3870Sstevel@tonic-gate 	    USB_SUCCESS) {
3880Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
3890Sstevel@tonic-gate 		    "sync func failed (%d)", rval);
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	if (request->callback) {
3930Sstevel@tonic-gate 		request->callback(pipe_handle, request->callback_arg, rval,
3940Sstevel@tonic-gate 		    cb_flags);
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	kmem_free(request, sizeof (usba_pipe_async_req_t));
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate /*
4020Sstevel@tonic-gate  * default endpoint descriptor and pipe policy
4030Sstevel@tonic-gate  */
4040Sstevel@tonic-gate usb_ep_descr_t	usba_default_ep_descr =
4050Sstevel@tonic-gate 	{7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0};
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate /* set some meaningful defaults */
4080Sstevel@tonic-gate static usb_pipe_policy_t usba_default_ep_pipe_policy = {3};
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate  * usb_get_ep_index: create an index from endpoint address that can
4130Sstevel@tonic-gate  * be used to index into endpoint pipe lists
4140Sstevel@tonic-gate  */
4150Sstevel@tonic-gate uchar_t
usb_get_ep_index(uint8_t ep_addr)4160Sstevel@tonic-gate usb_get_ep_index(uint8_t ep_addr)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	return ((ep_addr & USB_EP_NUM_MASK) +
4190Sstevel@tonic-gate 	    ((ep_addr & USB_EP_DIR_MASK) ? 16 : 0));
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate /*
4240Sstevel@tonic-gate  * pipe management
4250Sstevel@tonic-gate  *	utility functions to init and destroy a pipehandle
4260Sstevel@tonic-gate  */
4270Sstevel@tonic-gate static int
usba_init_pipe_handle(dev_info_t * dip,usba_device_t * usba_device,usb_ep_descr_t * ep,usb_pipe_policy_t * pipe_policy,usba_ph_impl_t * ph_impl)4280Sstevel@tonic-gate usba_init_pipe_handle(dev_info_t *dip,
4290Sstevel@tonic-gate 	usba_device_t		*usba_device,
4300Sstevel@tonic-gate 	usb_ep_descr_t		*ep,
4310Sstevel@tonic-gate 	usb_pipe_policy_t	*pipe_policy,
4320Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl)
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
4350Sstevel@tonic-gate 	unsigned int def_instance = instance;
4360Sstevel@tonic-gate 	static unsigned int anon_instance = 0;
4370Sstevel@tonic-gate 	char tq_name[TASKQ_NAMELEN];
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
4400Sstevel@tonic-gate 	ddi_iblock_cookie_t	iblock_cookie =
4410Sstevel@tonic-gate 	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
4420Sstevel@tonic-gate 	    hcdi_iblock_cookie;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
4450Sstevel@tonic-gate 	    "usba_init_pipe_handle: "
4466898Sfb209375 	    "usba_device=0x%p ep=0x%x", (void *)usba_device,
4476898Sfb209375 	    ep->bEndpointAddress);
4480Sstevel@tonic-gate 	mutex_init(&ph_data->p_mutex, NULL, MUTEX_DRIVER, iblock_cookie);
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	/* just to keep warlock happy, there is no contention yet */
4510Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
4520Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	ASSERT(pipe_policy->pp_max_async_reqs);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	if (instance != -1) {
4570Sstevel@tonic-gate 		(void) snprintf(tq_name, sizeof (tq_name),
4580Sstevel@tonic-gate 		    "USB_%s_%x_pipehndl_tq_%d",
4590Sstevel@tonic-gate 		    ddi_driver_name(dip), ep->bEndpointAddress, instance);
4600Sstevel@tonic-gate 	} else {
4610Sstevel@tonic-gate 		def_instance = atomic_add_32_nv(&anon_instance, 1);
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		(void) snprintf(tq_name, sizeof (tq_name),
4640Sstevel@tonic-gate 		    "USB_%s_%x_pipehndl_tq_%d_",
4650Sstevel@tonic-gate 		    ddi_driver_name(dip), ep->bEndpointAddress, def_instance);
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	ph_data->p_taskq = taskq_create(tq_name,
4696898Sfb209375 	    pipe_policy->pp_max_async_reqs + 1,
4706898Sfb209375 	    ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
4716898Sfb209375 	    USB_EP_ATTR_ISOCH) ?
4726898Sfb209375 	    (maxclsyspri - 5) : minclsyspri,
4736898Sfb209375 	    2 * (pipe_policy->pp_max_async_reqs + 1),
4746898Sfb209375 	    8 * (pipe_policy->pp_max_async_reqs + 1),
4756898Sfb209375 	    TASKQ_PREPOPULATE);
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	/*
4780Sstevel@tonic-gate 	 * Create a shared taskq.
4790Sstevel@tonic-gate 	 */
4800Sstevel@tonic-gate 	if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
4810Sstevel@tonic-gate 		int iface = usb_get_if_number(dip);
4820Sstevel@tonic-gate 		if (iface < 0) {
4830Sstevel@tonic-gate 			/* we own the device, use first entry */
4840Sstevel@tonic-gate 			iface = 0;
4850Sstevel@tonic-gate 		}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 		if (instance != -1) {
4880Sstevel@tonic-gate 			(void) snprintf(tq_name, sizeof (tq_name),
4890Sstevel@tonic-gate 			    "USB_%s_%x_shared_tq_%d",
4900Sstevel@tonic-gate 			    ddi_driver_name(dip), ep->bEndpointAddress,
4910Sstevel@tonic-gate 			    instance);
4920Sstevel@tonic-gate 		} else {
4930Sstevel@tonic-gate 			(void) snprintf(tq_name, sizeof (tq_name),
4940Sstevel@tonic-gate 			    "USB_%s_%x_shared_tq_%d_",
4950Sstevel@tonic-gate 			    ddi_driver_name(dip), ep->bEndpointAddress,
4960Sstevel@tonic-gate 			    def_instance);
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 		if (usba_device->usb_shared_taskq_ref_count[iface] == 0) {
5000Sstevel@tonic-gate 			usba_device->usb_shared_taskq[iface] =
5010Sstevel@tonic-gate 			    taskq_create(tq_name,
5020Sstevel@tonic-gate 			    1,				/* Number threads. */
5030Sstevel@tonic-gate 			    maxclsyspri - 5,		/* Priority */
5040Sstevel@tonic-gate 			    1,				/* minalloc */
5050Sstevel@tonic-gate 			    USBA_N_ENDPOINTS + 4,	/* maxalloc */
5060Sstevel@tonic-gate 			    TASKQ_PREPOPULATE);
5070Sstevel@tonic-gate 			ASSERT(usba_device->usb_shared_taskq[iface] != NULL);
5080Sstevel@tonic-gate 		}
5090Sstevel@tonic-gate 		usba_device->usb_shared_taskq_ref_count[iface]++;
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	ph_data->p_dip		= dip;
5130Sstevel@tonic-gate 	ph_data->p_usba_device	= usba_device;
5140Sstevel@tonic-gate 	ph_data->p_ep		= *ep;
5150Sstevel@tonic-gate 	ph_data->p_ph_impl	= ph_impl;
5160Sstevel@tonic-gate 	if ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
5170Sstevel@tonic-gate 	    USB_EP_ATTR_ISOCH) {
5180Sstevel@tonic-gate 		ph_data->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	/* fix up the MaxPacketSize if it is the default endpoint descr */
5220Sstevel@tonic-gate 	if ((ep == &usba_default_ep_descr) && usba_device) {
523*9430SRaymond.Chen@Sun.COM 		uint16_t	maxpktsize;
524*9430SRaymond.Chen@Sun.COM 
525*9430SRaymond.Chen@Sun.COM 		maxpktsize = usba_device->usb_dev_descr->bMaxPacketSize0;
526*9430SRaymond.Chen@Sun.COM 		if (usba_device->usb_is_wireless) {
527*9430SRaymond.Chen@Sun.COM 			/*
528*9430SRaymond.Chen@Sun.COM 			 * according to wusb 1.0 spec 4.8.1, the host must
529*9430SRaymond.Chen@Sun.COM 			 * assume a wMaxPacketSize of 512 for the default
530*9430SRaymond.Chen@Sun.COM 			 * control pipe of a wusb device
531*9430SRaymond.Chen@Sun.COM 			 */
532*9430SRaymond.Chen@Sun.COM 			maxpktsize = 0x200;
533*9430SRaymond.Chen@Sun.COM 		}
5340Sstevel@tonic-gate 		USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
5350Sstevel@tonic-gate 		    "adjusting max packet size from %d to %d",
536*9430SRaymond.Chen@Sun.COM 		    ph_data->p_ep.wMaxPacketSize, maxpktsize);
5370Sstevel@tonic-gate 
538*9430SRaymond.Chen@Sun.COM 		ph_data->p_ep.wMaxPacketSize = maxpktsize;
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	/* now update usba_ph_impl structure */
5420Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
5430Sstevel@tonic-gate 	ph_impl->usba_ph_dip = dip;
5440Sstevel@tonic-gate 	ph_impl->usba_ph_ep = ph_data->p_ep;
5450Sstevel@tonic-gate 	ph_impl->usba_ph_policy = ph_data->p_policy = *pipe_policy;
5460Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	usba_init_list(&ph_data->p_queue, (usb_opaque_t)ph_data, iblock_cookie);
5490Sstevel@tonic-gate 	usba_init_list(&ph_data->p_cb_queue, (usb_opaque_t)ph_data,
5506898Sfb209375 	    iblock_cookie);
5510Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
5520Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	return (USB_SUCCESS);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate static void
usba_taskq_destroy(void * arg)5590Sstevel@tonic-gate usba_taskq_destroy(void *arg)
5600Sstevel@tonic-gate {
5610Sstevel@tonic-gate 	taskq_destroy((taskq_t *)arg);
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate static void
usba_destroy_pipe_handle(usba_pipe_handle_data_t * ph_data)5660Sstevel@tonic-gate usba_destroy_pipe_handle(usba_pipe_handle_data_t *ph_data)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
5690Sstevel@tonic-gate 	int			timeout;
5700Sstevel@tonic-gate 	usba_device_t		*usba_device;
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
5736898Sfb209375 	    "usba_destroy_pipe_handle: ph_data=0x%p", (void *)ph_data);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
5760Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	/* check for all activity to drain */
5790Sstevel@tonic-gate 	for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
5800Sstevel@tonic-gate 		if ((ph_impl->usba_ph_ref_count <= 1) &&
5810Sstevel@tonic-gate 		    (ph_data->p_req_count == 0)) {
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 			break;
5840Sstevel@tonic-gate 		}
5850Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
5860Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
5870Sstevel@tonic-gate 		delay(drv_usectohz(1000));
5880Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
5890Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
5900Sstevel@tonic-gate 	}
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	/*
5930Sstevel@tonic-gate 	 * set state to closed here so any other thread
5940Sstevel@tonic-gate 	 * that is waiting for the CLOSED state will
5950Sstevel@tonic-gate 	 * continue. Otherwise, taskq_destroy might deadlock
5960Sstevel@tonic-gate 	 */
5970Sstevel@tonic-gate 	ph_impl->usba_ph_data = NULL;
5980Sstevel@tonic-gate 	ph_impl->usba_ph_ref_count = 0;
5990Sstevel@tonic-gate 	ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSED;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	if (ph_data->p_taskq) {
6020Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
6030Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
6040Sstevel@tonic-gate 		if (taskq_member(ph_data->p_taskq, curthread)) {
6050Sstevel@tonic-gate 			/*
6060Sstevel@tonic-gate 			 * use system taskq to destroy ph's taskq to avoid
6070Sstevel@tonic-gate 			 * deadlock
6080Sstevel@tonic-gate 			 */
6090Sstevel@tonic-gate 			(void) taskq_dispatch(system_taskq,
6100Sstevel@tonic-gate 			    usba_taskq_destroy, ph_data->p_taskq, TQ_SLEEP);
6110Sstevel@tonic-gate 		} else {
6120Sstevel@tonic-gate 			taskq_destroy(ph_data->p_taskq);
6130Sstevel@tonic-gate 		}
6140Sstevel@tonic-gate 	} else {
6150Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
6160Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
6200Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
6210Sstevel@tonic-gate 	if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
6220Sstevel@tonic-gate 		int iface = usb_get_if_number(ph_data->p_dip);
6230Sstevel@tonic-gate 		if (iface < 0) {
6240Sstevel@tonic-gate 			/* we own the device, use the first entry */
6250Sstevel@tonic-gate 			iface = 0;
6260Sstevel@tonic-gate 		}
6270Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
6280Sstevel@tonic-gate 		if (--usba_device->usb_shared_taskq_ref_count[iface] == 0) {
6290Sstevel@tonic-gate 			ph_data->p_spec_flag &= ~USBA_PH_FLAG_TQ_SHARE;
6300Sstevel@tonic-gate 			if (taskq_member(usba_device->usb_shared_taskq[iface],
6310Sstevel@tonic-gate 			    curthread)) {
6320Sstevel@tonic-gate 				(void) taskq_dispatch(
6330Sstevel@tonic-gate 				    system_taskq,
6340Sstevel@tonic-gate 				    usba_taskq_destroy,
6350Sstevel@tonic-gate 				    usba_device->usb_shared_taskq[iface],
6360Sstevel@tonic-gate 				    TQ_SLEEP);
6370Sstevel@tonic-gate 			} else {
6380Sstevel@tonic-gate 				taskq_destroy(
6390Sstevel@tonic-gate 				    usba_device->usb_shared_taskq[iface]);
6400Sstevel@tonic-gate 			}
6410Sstevel@tonic-gate 		}
6420Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6486898Sfb209375 	    "usba_destroy_pipe_handle: destroying ph_data=0x%p",
6496898Sfb209375 	    (void *)ph_data);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	usba_destroy_list(&ph_data->p_queue);
6520Sstevel@tonic-gate 	usba_destroy_list(&ph_data->p_cb_queue);
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/* destroy mutexes */
6550Sstevel@tonic-gate 	mutex_destroy(&ph_data->p_mutex);
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	kmem_free(ph_data, sizeof (usba_pipe_handle_data_t));
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate /*
6620Sstevel@tonic-gate  * usba_drain_cbs:
6630Sstevel@tonic-gate  *	Drain the request callbacks on the pipe handle
6640Sstevel@tonic-gate  */
6650Sstevel@tonic-gate int
usba_drain_cbs(usba_pipe_handle_data_t * ph_data,usb_cb_flags_t cb_flags,usb_cr_t cr)6660Sstevel@tonic-gate usba_drain_cbs(usba_pipe_handle_data_t *ph_data, usb_cb_flags_t cb_flags,
6670Sstevel@tonic-gate 	usb_cr_t cr)
6680Sstevel@tonic-gate {
6690Sstevel@tonic-gate 	usba_req_wrapper_t	*req_wrp;
6700Sstevel@tonic-gate 	int			flush_requests = 1;
6710Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = ph_data->p_ph_impl;
6720Sstevel@tonic-gate 	int			timeout;
6730Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	ASSERT(mutex_owned(&ph_data->p_mutex));
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
6780Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6790Sstevel@tonic-gate 	    "usba_drain_cbs: ph_data=0x%p ref=%d req=%d cb=0x%x cr=%d",
6806898Sfb209375 	    (void *)ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count,
6810Sstevel@tonic-gate 	    cb_flags, cr);
6820Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
6830Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	if (ph_data->p_dip) {
6860Sstevel@tonic-gate 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
6870Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
6880Sstevel@tonic-gate 			    usbai_log_handle,
6890Sstevel@tonic-gate 			    "no flushing on default pipe!");
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 			flush_requests = 0;
6920Sstevel@tonic-gate 		}
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	if (flush_requests) {
6960Sstevel@tonic-gate 		/* flush all requests in the pipehandle queue */
6970Sstevel@tonic-gate 		while ((req_wrp = (usba_req_wrapper_t *)
6980Sstevel@tonic-gate 		    usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
6990Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
7000Sstevel@tonic-gate 			usba_do_req_exc_cb(req_wrp, cr, cb_flags);
7010Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
7020Sstevel@tonic-gate 		}
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	/*
7060Sstevel@tonic-gate 	 * wait for any callbacks in progress but don't wait for
7070Sstevel@tonic-gate 	 * for queued requests on the default pipe
7080Sstevel@tonic-gate 	 */
7090Sstevel@tonic-gate 	for (timeout = 0; (timeout < usba_drain_timeout) &&
7100Sstevel@tonic-gate 	    (ph_data->p_req_count >
7110Sstevel@tonic-gate 	    usba_list_entry_count(&ph_data->p_queue));
7120Sstevel@tonic-gate 	    timeout++) {
7130Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
7140Sstevel@tonic-gate 		delay(drv_usectohz(1000));
7150Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
7160Sstevel@tonic-gate 	}
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
7190Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
7200Sstevel@tonic-gate 	    "usba_drain_cbs done: ph_data=0x%p ref=%d req=%d",
7216898Sfb209375 	    (void *)ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count);
7220Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	if (timeout == usba_drain_timeout) {
7250Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
7260Sstevel@tonic-gate 		    "draining callbacks timed out!");
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 		rval = USB_FAILURE;
7290Sstevel@tonic-gate 	}
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	return (rval);
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate  * usb_pipe_open():
7370Sstevel@tonic-gate  *
7380Sstevel@tonic-gate  * Before using any pipe including the default pipe, it should be opened
7390Sstevel@tonic-gate  * using usb_pipe_open(). On a successful open, a pipe handle is returned
7400Sstevel@tonic-gate  * for use in other usb_pipe_*() functions
7410Sstevel@tonic-gate  *
7420Sstevel@tonic-gate  * The default pipe can only be opened by the hub driver
7430Sstevel@tonic-gate  *
7440Sstevel@tonic-gate  * The bandwidth has been allocated and guaranteed on successful
7450Sstevel@tonic-gate  * opening of an isoc/intr pipes.
7460Sstevel@tonic-gate  *
7470Sstevel@tonic-gate  * Only the default pipe can be shared. all other control pipes
7480Sstevel@tonic-gate  * are excusively opened by default.
7490Sstevel@tonic-gate  * A pipe policy and endpoint descriptor must always be provided
7500Sstevel@tonic-gate  * except for default pipe
7510Sstevel@tonic-gate  *
7520Sstevel@tonic-gate  * Arguments:
7530Sstevel@tonic-gate  *	dip		- devinfo ptr
7540Sstevel@tonic-gate  *	ep		- endpoint descriptor pointer
7550Sstevel@tonic-gate  *	pipe_policy	- pointer to pipe policy which provides hints on how
7560Sstevel@tonic-gate  *			  the pipe will be used.
7570Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP wait for resources
7580Sstevel@tonic-gate  *			  to become available
7590Sstevel@tonic-gate  *	pipe_handle	- a pipe handle pointer. On a successful open,
7600Sstevel@tonic-gate  *			  a pipe_handle is returned in this pointer.
7610Sstevel@tonic-gate  *
7620Sstevel@tonic-gate  * Return values:
7630Sstevel@tonic-gate  *	USB_SUCCESS	 - open succeeded
7640Sstevel@tonic-gate  *	USB_FAILURE	 - unspecified open failure or pipe is already open
7650Sstevel@tonic-gate  *	USB_NO_RESOURCES - no resources were available to complete the open
7660Sstevel@tonic-gate  *	USB_NO_BANDWIDTH - no bandwidth available (isoc/intr pipes)
7670Sstevel@tonic-gate  *	USB_*		 - refer to usbai.h
7680Sstevel@tonic-gate  */
7690Sstevel@tonic-gate int
usb_pipe_open(dev_info_t * dip,usb_ep_descr_t * ep,usb_pipe_policy_t * pipe_policy,usb_flags_t usb_flags,usb_pipe_handle_t * pipe_handle)7700Sstevel@tonic-gate usb_pipe_open(
7710Sstevel@tonic-gate 	dev_info_t		*dip,
7720Sstevel@tonic-gate 	usb_ep_descr_t		*ep,
7730Sstevel@tonic-gate 	usb_pipe_policy_t	*pipe_policy,
7740Sstevel@tonic-gate 	usb_flags_t		usb_flags,
7750Sstevel@tonic-gate 	usb_pipe_handle_t	*pipe_handle)
7760Sstevel@tonic-gate {
7770Sstevel@tonic-gate 	usba_device_t		*usba_device;
7780Sstevel@tonic-gate 	int			rval;
7790Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data;
7800Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl;
7810Sstevel@tonic-gate 	uchar_t			ep_index;
7820Sstevel@tonic-gate 	int			kmflag;
7830Sstevel@tonic-gate 	size_t			size;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
7860Sstevel@tonic-gate 	    "usb_pipe_open:\n\t"
7870Sstevel@tonic-gate 	    "dip=0x%p ep=0x%p pp=0x%p uf=0x%x ph=0x%p",
7886898Sfb209375 	    (void *)dip, (void *)ep, (void *)pipe_policy, usb_flags,
7896898Sfb209375 	    (void *)pipe_handle);
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	if ((dip == NULL) || (pipe_handle == NULL)) {
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
7940Sstevel@tonic-gate 	}
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 	usba_device = usba_get_usba_device(dip);
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	if ((ep != NULL) && (pipe_policy == NULL)) {
8030Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8040Sstevel@tonic-gate 		    "usb_pipe_open: null pipe policy");
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
8070Sstevel@tonic-gate 	}
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	/* is the device still connected? */
8100Sstevel@tonic-gate 	if ((ep != NULL) & DEVI_IS_DEVICE_REMOVED(dip)) {
8110Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8120Sstevel@tonic-gate 		    "usb_pipe_open: device has been removed");
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 		return (USB_FAILURE);
8150Sstevel@tonic-gate 	}
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	/*
8190Sstevel@tonic-gate 	 * if a null endpoint pointer was passed, use the default
8200Sstevel@tonic-gate 	 * endpoint descriptor
8210Sstevel@tonic-gate 	 */
8220Sstevel@tonic-gate 	if (ep == NULL) {
8230Sstevel@tonic-gate 		if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
8240Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8250Sstevel@tonic-gate 			    "usb_pipe_open: not allowed to open def pipe");
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 			return (USB_INVALID_PERM);
8280Sstevel@tonic-gate 		}
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 		ep = &usba_default_ep_descr;
8310Sstevel@tonic-gate 		pipe_policy = &usba_default_ep_pipe_policy;
8320Sstevel@tonic-gate 	}
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
8350Sstevel@tonic-gate 		if (((ep->bmAttributes & USB_EP_ATTR_MASK) ==
8360Sstevel@tonic-gate 		    USB_EP_ATTR_CONTROL) ||
8370Sstevel@tonic-gate 		    ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
8380Sstevel@tonic-gate 		    USB_EP_ATTR_ISOCH)) {
8390Sstevel@tonic-gate 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8400Sstevel@tonic-gate 			    "usb_pipe_open: shared taskq not allowed with "
8410Sstevel@tonic-gate 			    "ctrl or isoch pipe");
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 			return (USB_INVALID_ARGS);
8440Sstevel@tonic-gate 		}
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	kmflag	= (usb_flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
8480Sstevel@tonic-gate 	size	= sizeof (usba_pipe_handle_data_t);
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	if ((ph_data = kmem_zalloc(size, kmflag)) == NULL) {
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 		return (USB_NO_RESOURCES);
8530Sstevel@tonic-gate 	}
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	/* check if pipe is already open and if so fail */
8560Sstevel@tonic-gate 	ep_index = usb_get_ep_index(ep->bEndpointAddress);
8570Sstevel@tonic-gate 	ph_impl = &usba_device->usb_ph_list[ep_index];
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	mutex_enter(&usba_device->usb_mutex);
8600Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	if (ph_impl->usba_ph_data) {
8630Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8640Sstevel@tonic-gate 		    "usb_pipe_open: pipe to ep %d already open", ep_index);
8650Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
8660Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
8670Sstevel@tonic-gate 		kmem_free(ph_data, size);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 		return (USB_BUSY);
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	ph_impl->usba_ph_data = ph_data;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
8750Sstevel@tonic-gate 	mutex_exit(&usba_device->usb_mutex);
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
8780Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
8790Sstevel@tonic-gate 		ph_data->p_spec_flag |= USBA_PH_FLAG_TQ_SHARE;
8800Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	/*
8840Sstevel@tonic-gate 	 * allocate and initialize the pipe handle
8850Sstevel@tonic-gate 	 */
8860Sstevel@tonic-gate 	if ((rval = usba_init_pipe_handle(dip, usba_device,
8870Sstevel@tonic-gate 	    ep, pipe_policy, ph_impl)) != USB_SUCCESS) {
8880Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8890Sstevel@tonic-gate 		    "usb_pipe_open: pipe init failed (%d)", rval);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 		return (rval);
8920Sstevel@tonic-gate 	}
8930Sstevel@tonic-gate 	ph_data = ph_impl->usba_ph_data;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	/*
8960Sstevel@tonic-gate 	 * ask the hcd to open the pipe
8970Sstevel@tonic-gate 	 */
8980Sstevel@tonic-gate 	if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_open(ph_data,
8990Sstevel@tonic-gate 	    usb_flags)) != USB_SUCCESS) {
9000Sstevel@tonic-gate 		usba_destroy_pipe_handle(ph_data);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		*pipe_handle = NULL;
9030Sstevel@tonic-gate 	} else {
9040Sstevel@tonic-gate 		*pipe_handle = (usb_pipe_handle_t)ph_impl;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 		/* set the pipe state after a successful hcd open */
9070Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
9080Sstevel@tonic-gate 		usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
9090Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
9100Sstevel@tonic-gate 	}
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
9136898Sfb209375 	    "usb_pipe_open: ph_impl=0x%p (0x%p)",
9146898Sfb209375 	    (void *)ph_impl, (void *)ph_data);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	return (rval);
9170Sstevel@tonic-gate }
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate /*
9210Sstevel@tonic-gate  * usb_pipe_close/sync_close:
9220Sstevel@tonic-gate  *
9230Sstevel@tonic-gate  * Close a pipe and release all resources and free the pipe_handle.
9240Sstevel@tonic-gate  * Automatic polling, if active,  will be terminated
9250Sstevel@tonic-gate  *
9260Sstevel@tonic-gate  * Arguments:
9270Sstevel@tonic-gate  *	dip		- devinfo ptr
9280Sstevel@tonic-gate  *	pipehandle	- pointer to pipehandle. The pipehandle will be
9290Sstevel@tonic-gate  *			  zeroed on successful completion
9300Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
9310Sstevel@tonic-gate  *				wait for resources, pipe
9320Sstevel@tonic-gate  *				to become free, all callbacks completed
9330Sstevel@tonic-gate  *	callback	- If USB_FLAGS_SLEEP has not been specified, a
9340Sstevel@tonic-gate  *			  callback will be performed.
9350Sstevel@tonic-gate  *	callback_arg	- the first argument of the callback. Note that
9360Sstevel@tonic-gate  *			  the pipehandle will be zeroed and not passed
9370Sstevel@tonic-gate  *
9380Sstevel@tonic-gate  * Notes:
9390Sstevel@tonic-gate  * Pipe close will always succeed regardless whether USB_FLAGS_SLEEP has been
9400Sstevel@tonic-gate  * specified or not.
9410Sstevel@tonic-gate  * An async close will always succeed if the hint in the pipe policy
9420Sstevel@tonic-gate  * has been correct about the max number of async taskq requests required.
9430Sstevel@tonic-gate  * If there are really no resources, the pipe handle will be linked into
9440Sstevel@tonic-gate  * a garbage pipe list and periodically checked by USBA until it can be
9450Sstevel@tonic-gate  * closed. This may cause a hang in the detach of the driver.
9460Sstevel@tonic-gate  * USBA will prevent the client from submitting more requests to a pipe
9470Sstevel@tonic-gate  * that is being closed
9480Sstevel@tonic-gate  * Subsequent usb_pipe_close() requests on the same pipe to USBA will
9490Sstevel@tonic-gate  * wait for the previous close(s) to finish.
9500Sstevel@tonic-gate  *
9510Sstevel@tonic-gate  * Note that once we start closing a pipe, we cannot go back anymore
9520Sstevel@tonic-gate  * to a normal pipe state
9530Sstevel@tonic-gate  */
9540Sstevel@tonic-gate void
usb_pipe_close(dev_info_t * dip,usb_pipe_handle_t pipe_handle,usb_flags_t usb_flags,void (* callback)(usb_pipe_handle_t pipe_handle,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t callback_arg)9550Sstevel@tonic-gate usb_pipe_close(dev_info_t	*dip,
9560Sstevel@tonic-gate 		usb_pipe_handle_t pipe_handle,
9570Sstevel@tonic-gate 		usb_flags_t	usb_flags,
9580Sstevel@tonic-gate 		void		(*callback)(
9590Sstevel@tonic-gate 				    usb_pipe_handle_t	pipe_handle,
9600Sstevel@tonic-gate 				    usb_opaque_t	arg,
9610Sstevel@tonic-gate 				    int			rval,
9620Sstevel@tonic-gate 				    usb_cb_flags_t	flags),
9630Sstevel@tonic-gate 		usb_opaque_t	callback_arg)
9640Sstevel@tonic-gate {
9650Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data;
9660Sstevel@tonic-gate 	usba_ph_impl_t	*ph_impl = (usba_ph_impl_t *)pipe_handle;
9670Sstevel@tonic-gate 	usb_cb_flags_t	callback_flags;
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
9706898Sfb209375 	    "usb_pipe_close: ph=0x%p", (void *)pipe_handle);
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
9730Sstevel@tonic-gate 	if ((dip == NULL) || (pipe_handle == NULL)) {
9740Sstevel@tonic-gate 		if (callback) {
9750Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
9760Sstevel@tonic-gate 			    USB_INVALID_ARGS, callback_flags);
9770Sstevel@tonic-gate 		} else {
978978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
9790Sstevel@tonic-gate 			    usbai_log_handle,
9800Sstevel@tonic-gate 			    "usb_pipe_close: invalid arguments");
9810Sstevel@tonic-gate 		}
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 		return;
9840Sstevel@tonic-gate 	}
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
9870Sstevel@tonic-gate 		/*
9880Sstevel@tonic-gate 		 * It is the client driver doing the pipe close,
9890Sstevel@tonic-gate 		 * the pipe is no longer persistent then.
9900Sstevel@tonic-gate 		 */
9910Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
9920Sstevel@tonic-gate 		ph_impl->usba_ph_flags &= ~USBA_PH_DATA_PERSISTENT;
9930Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
9940Sstevel@tonic-gate 	}
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
9970Sstevel@tonic-gate 		if (callback) {
9980Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
9990Sstevel@tonic-gate 			    USB_INVALID_CONTEXT, callback_flags);
10000Sstevel@tonic-gate 		} else {
1001978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
10020Sstevel@tonic-gate 			    usbai_log_handle,
10030Sstevel@tonic-gate 			    "usb_pipe_close: invalid context");
10040Sstevel@tonic-gate 		}
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 		return;
10070Sstevel@tonic-gate 	}
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 		/* hold pipehandle anyways since we will decrement later */
10120Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
10130Sstevel@tonic-gate 		ph_impl->usba_ph_ref_count++;
10140Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 		(void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
10170Sstevel@tonic-gate 		    ph_impl, NULL, usb_flags, callback, callback_arg);
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 		return;
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data) &&
10250Sstevel@tonic-gate 	    ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0)) {
1026978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
10270Sstevel@tonic-gate 		    "usb_pipe_close: not allowed to close def pipe");
10280Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 		if (callback) {
10330Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
10340Sstevel@tonic-gate 			    USB_INVALID_PIPE, callback_flags);
10350Sstevel@tonic-gate 		} else {
1036978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
10370Sstevel@tonic-gate 			    usbai_log_handle,
10380Sstevel@tonic-gate 			    "usb_pipe_close: invalid pipe");
10390Sstevel@tonic-gate 		}
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 		return;
10420Sstevel@tonic-gate 	}
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
10470Sstevel@tonic-gate 	    ph_impl, NULL, usb_flags, callback, callback_arg);
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate /*ARGSUSED*/
10520Sstevel@tonic-gate static int
usba_pipe_sync_close(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t usb_flags)10530Sstevel@tonic-gate usba_pipe_sync_close(dev_info_t *dip, usba_ph_impl_t *ph_impl,
10540Sstevel@tonic-gate 	usba_pipe_async_req_t *request, usb_flags_t usb_flags)
10550Sstevel@tonic-gate {
10560Sstevel@tonic-gate 	usba_device_t		*usba_device;
10570Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
10586898Sfb209375 	    (usb_pipe_handle_t)ph_impl);
10590Sstevel@tonic-gate 	int			attribute;
10600Sstevel@tonic-gate 	uchar_t			dir;
10610Sstevel@tonic-gate 	int			timeout;
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	if (ph_impl == NULL) {
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 		return (USB_SUCCESS);
10660Sstevel@tonic-gate 	}
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
10690Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10700Sstevel@tonic-gate 	    "usba_pipe_sync_close: dip=0x%p ph_data=0x%p state=%d ref=%d",
10716898Sfb209375 	    (void *)dip, (void *)ph_data, ph_impl->usba_ph_state,
10726898Sfb209375 	    ph_impl->usba_ph_ref_count);
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	/*
10750Sstevel@tonic-gate 	 * if another thread opens the pipe again, this loop could
10760Sstevel@tonic-gate 	 * be truly forever
10770Sstevel@tonic-gate 	 */
10780Sstevel@tonic-gate 	if ((ph_data == NULL) ||
10790Sstevel@tonic-gate 	    (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSING) ||
10800Sstevel@tonic-gate 	    (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSED)) {
10810Sstevel@tonic-gate 		/* wait forever till really closed */
10820Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
10830Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 		while (usba_get_ph_data((usb_pipe_handle_t)ph_impl)) {
10860Sstevel@tonic-gate 			delay(1);
10870Sstevel@tonic-gate 		}
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 		return (USB_SUCCESS);
10900Sstevel@tonic-gate 	}
10910Sstevel@tonic-gate 	ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSING;
10920Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
10950Sstevel@tonic-gate 	mutex_enter(&ph_impl->usba_ph_mutex);
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	attribute = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
10980Sstevel@tonic-gate 	dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	/*
11030Sstevel@tonic-gate 	 * For control and bulk, we will drain till ref_count <= 1 and
11040Sstevel@tonic-gate 	 * req_count == 0 but for isoc and intr IN, we can only wait
11050Sstevel@tonic-gate 	 * till the ref_count === 1 as the req_count will never go to 0
11060Sstevel@tonic-gate 	 */
11070Sstevel@tonic-gate 	for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
11080Sstevel@tonic-gate 		switch (attribute) {
11090Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
11100Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
11110Sstevel@tonic-gate 			if ((ph_data->p_req_count == 0) &&
11120Sstevel@tonic-gate 			    (ph_impl->usba_ph_ref_count <= 1)) {
11130Sstevel@tonic-gate 				goto done;
11140Sstevel@tonic-gate 			}
11150Sstevel@tonic-gate 			break;
11160Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
11170Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
11180Sstevel@tonic-gate 			if (dir == USB_EP_DIR_IN) {
11190Sstevel@tonic-gate 				if (ph_impl->usba_ph_ref_count <= 1) {
11200Sstevel@tonic-gate 					goto done;
11210Sstevel@tonic-gate 				}
11220Sstevel@tonic-gate 			} else if ((ph_data->p_req_count == 0) &&
11230Sstevel@tonic-gate 			    (ph_impl->usba_ph_ref_count <= 1)) {
11240Sstevel@tonic-gate 				goto done;
11250Sstevel@tonic-gate 			}
11260Sstevel@tonic-gate 			break;
11270Sstevel@tonic-gate 		}
11280Sstevel@tonic-gate 		mutex_exit(&ph_impl->usba_ph_mutex);
11290Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
11300Sstevel@tonic-gate 		delay(drv_usectohz(1000));
11310Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
11320Sstevel@tonic-gate 		mutex_enter(&ph_impl->usba_ph_mutex);
11330Sstevel@tonic-gate 	}
11340Sstevel@tonic-gate done:
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	mutex_exit(&ph_impl->usba_ph_mutex);
11370Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	if (timeout >= usba_drain_timeout) {
11400Sstevel@tonic-gate 		int draining_succeeded;
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
11430Sstevel@tonic-gate 		    "timeout on draining requests, resetting pipe 0x%p",
11446898Sfb209375 		    (void *)ph_impl);
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 		(void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
11470Sstevel@tonic-gate 		    USB_FLAGS_SLEEP);
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 		mutex_enter(&ph_data->p_mutex);
11500Sstevel@tonic-gate 		draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
11516898Sfb209375 		    USB_CR_PIPE_RESET);
11520Sstevel@tonic-gate 		/* this MUST have succeeded */
11530Sstevel@tonic-gate 		ASSERT(draining_succeeded == USB_SUCCESS);
11540Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
11570Sstevel@tonic-gate 		    "draining requests done");
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	if (usba_device->usb_hcdi_ops->usba_hcdi_pipe_close(ph_data,
11610Sstevel@tonic-gate 	    usb_flags) != USB_SUCCESS) {
1162978Sfrits 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
11630Sstevel@tonic-gate 		    "usba_pipe_sync_close: hcd close failed");
11640Sstevel@tonic-gate 		/* carry on regardless! */
11650Sstevel@tonic-gate 	}
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	usba_destroy_pipe_handle(ph_data);
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	return (USB_SUCCESS);
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate /*
11740Sstevel@tonic-gate  * usb_pipe_set_private:
11750Sstevel@tonic-gate  *	set private client date in the pipe handle
11760Sstevel@tonic-gate  */
11770Sstevel@tonic-gate int
usb_pipe_set_private(usb_pipe_handle_t pipe_handle,usb_opaque_t data)11780Sstevel@tonic-gate usb_pipe_set_private(usb_pipe_handle_t	pipe_handle, usb_opaque_t data)
11790Sstevel@tonic-gate {
11800Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
11830Sstevel@tonic-gate 	    "usb_pipe_set_private: ");
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	if (ph_data == NULL) {
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
11880Sstevel@tonic-gate 	}
11890Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data)) {
11900Sstevel@tonic-gate 		usba_release_ph_data(ph_data->p_ph_impl);
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 		return (USB_INVALID_PERM);
11930Sstevel@tonic-gate 	}
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
11960Sstevel@tonic-gate 	ph_data->p_client_private = data;
11970Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	return (USB_SUCCESS);
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate /*
12060Sstevel@tonic-gate  * usb_pipe_get_private:
12070Sstevel@tonic-gate  *	get private client date from the pipe handle
12080Sstevel@tonic-gate  */
12090Sstevel@tonic-gate usb_opaque_t
usb_pipe_get_private(usb_pipe_handle_t pipe_handle)12100Sstevel@tonic-gate usb_pipe_get_private(usb_pipe_handle_t	pipe_handle)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
12130Sstevel@tonic-gate 	usb_opaque_t		data;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12160Sstevel@tonic-gate 	    "usb_pipe_get_private:");
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	if (ph_data == NULL) {
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 		return (NULL);
12210Sstevel@tonic-gate 	}
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
12240Sstevel@tonic-gate 	data = ph_data->p_client_private;
12250Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	usba_release_ph_data(ph_data->p_ph_impl);
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	return (data);
12300Sstevel@tonic-gate }
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate /*
12340Sstevel@tonic-gate  * usb_pipe_reset
12350Sstevel@tonic-gate  * Arguments:
12360Sstevel@tonic-gate  *	dip		- devinfo pointer
12370Sstevel@tonic-gate  *	pipe_handle	- opaque pipe handle
12380Sstevel@tonic-gate  * Returns:
12390Sstevel@tonic-gate  *	USB_SUCCESS	- pipe successfully reset or request queued
12400Sstevel@tonic-gate  *	USB_FAILURE	- undetermined failure
12410Sstevel@tonic-gate  *	USB_INVALID_PIPE - pipe is invalid or already closed
12420Sstevel@tonic-gate  */
12430Sstevel@tonic-gate void
usb_pipe_reset(dev_info_t * dip,usb_pipe_handle_t pipe_handle,usb_flags_t usb_flags,void (* callback)(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t callback_arg)12440Sstevel@tonic-gate usb_pipe_reset(dev_info_t		*dip,
12450Sstevel@tonic-gate 		usb_pipe_handle_t	pipe_handle,
12460Sstevel@tonic-gate 		usb_flags_t		usb_flags,
12470Sstevel@tonic-gate 		void			(*callback)(
12480Sstevel@tonic-gate 					    usb_pipe_handle_t	ph,
12490Sstevel@tonic-gate 					    usb_opaque_t	arg,
12500Sstevel@tonic-gate 					    int			rval,
12510Sstevel@tonic-gate 					    usb_cb_flags_t	flags),
12520Sstevel@tonic-gate 		usb_opaque_t		callback_arg)
12530Sstevel@tonic-gate {
12540Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
12550Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
12560Sstevel@tonic-gate 	usb_cb_flags_t		callback_flags;
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12590Sstevel@tonic-gate 	    "usb_pipe_reset: dip=0x%p ph=0x%p uf=0x%x",
12606898Sfb209375 	    (void *)dip, (void *)pipe_handle, usb_flags);
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	if ((dip == NULL) || (ph_data == NULL)) {
12650Sstevel@tonic-gate 		if (callback) {
12660Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
12670Sstevel@tonic-gate 			    USB_INVALID_ARGS, callback_flags);
12680Sstevel@tonic-gate 		} else {
1269978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
12700Sstevel@tonic-gate 			    usbai_log_handle,
12710Sstevel@tonic-gate 			    "usb_pipe_reset: invalid arguments");
12720Sstevel@tonic-gate 		}
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 		return;
12770Sstevel@tonic-gate 	}
12780Sstevel@tonic-gate 	if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
12790Sstevel@tonic-gate 		if (callback) {
12800Sstevel@tonic-gate 			callback(pipe_handle, callback_arg,
12810Sstevel@tonic-gate 			    USB_INVALID_CONTEXT, callback_flags);
12820Sstevel@tonic-gate 		} else {
1283978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI,
12840Sstevel@tonic-gate 			    usbai_log_handle,
12850Sstevel@tonic-gate 			    "usb_pipe_reset: invalid context");
12860Sstevel@tonic-gate 		}
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 		return;
12910Sstevel@tonic-gate 	}
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 	/* is this the default pipe? */
12960Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data)) {
12970Sstevel@tonic-gate 		if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
1298978Sfrits 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
12990Sstevel@tonic-gate 			    "usb_pipe_reset: not allowed to reset def pipe");
13000Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 			if (callback) {
13030Sstevel@tonic-gate 				callback(pipe_handle, callback_arg,
13040Sstevel@tonic-gate 				    USB_INVALID_PIPE, callback_flags);
13050Sstevel@tonic-gate 			} else {
1306978Sfrits 				USB_DPRINTF_L2(DPRINT_MASK_USBAI,
13070Sstevel@tonic-gate 				    usbai_log_handle,
13080Sstevel@tonic-gate 				    "usb_pipe_reset: invalid pipe");
13090Sstevel@tonic-gate 			}
13100Sstevel@tonic-gate 			usba_release_ph_data(ph_impl);
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 			return;
13130Sstevel@tonic-gate 		}
13140Sstevel@tonic-gate 	}
13150Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(dip,
13180Sstevel@tonic-gate 	    usba_pipe_sync_reset, ph_impl, NULL, usb_flags, callback,
13190Sstevel@tonic-gate 	    callback_arg);
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate /*ARGSUSED*/
13240Sstevel@tonic-gate int
usba_pipe_sync_reset(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t usb_flags)13250Sstevel@tonic-gate usba_pipe_sync_reset(dev_info_t	*dip,
13260Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl,
13270Sstevel@tonic-gate 	usba_pipe_async_req_t	*request,
13280Sstevel@tonic-gate 	usb_flags_t		usb_flags)
13290Sstevel@tonic-gate {
13300Sstevel@tonic-gate 	int rval, draining_succeeded;
13310Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
13326898Sfb209375 	    ph_impl);
13330Sstevel@tonic-gate 	usba_device_t		*usba_device;
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
13360Sstevel@tonic-gate 	    "usba_pipe_sync_reset: dip=0x%p ph_data=0x%p uf=0x%x",
13376898Sfb209375 	    (void *)dip, (void *)ph_data, usb_flags);
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
13400Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
13410Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
13446898Sfb209375 	    usb_flags);
13450Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	/*
13480Sstevel@tonic-gate 	 * The host controller has stopped polling of the endpoint.
13490Sstevel@tonic-gate 	 */
13500Sstevel@tonic-gate 	draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
13516898Sfb209375 	    USB_CR_PIPE_RESET);
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	/* this MUST have succeeded */
13540Sstevel@tonic-gate 	ASSERT(draining_succeeded == USB_SUCCESS);
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
13570Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	/*
13600Sstevel@tonic-gate 	 * if there are requests still queued on the default pipe,
13610Sstevel@tonic-gate 	 * start them now
13620Sstevel@tonic-gate 	 */
13630Sstevel@tonic-gate 	usba_start_next_req(ph_data);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	return (rval);
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate /*
13720Sstevel@tonic-gate  * usba_pipe_clear:
13730Sstevel@tonic-gate  *	call hcd to clear pipe but don't wait for draining
13740Sstevel@tonic-gate  */
13750Sstevel@tonic-gate void
usba_pipe_clear(usb_pipe_handle_t pipe_handle)13760Sstevel@tonic-gate usba_pipe_clear(usb_pipe_handle_t pipe_handle)
13770Sstevel@tonic-gate {
13780Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(pipe_handle);
13790Sstevel@tonic-gate 	usba_device_t		*usba_device;
13800Sstevel@tonic-gate 	usba_req_wrapper_t	*req_wrp;
13810Sstevel@tonic-gate 	int			flush_requests = 1;
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
13846898Sfb209375 	    "usba_pipe_clear: ph_data=0x%p", (void *)ph_data);
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	if (ph_data == NULL) {
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 		return;
13890Sstevel@tonic-gate 	}
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
13920Sstevel@tonic-gate 	if (USBA_PIPE_CLOSING(usba_get_ph_state(ph_data))) {
13930Sstevel@tonic-gate 		mutex_exit(&ph_data->p_mutex);
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 		return;
13960Sstevel@tonic-gate 	}
13970Sstevel@tonic-gate 	usba_device = ph_data->p_usba_device;
13980Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 	(void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
14016898Sfb209375 	    USB_FLAGS_SLEEP);
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
14040Sstevel@tonic-gate 	if (ph_data->p_dip) {
14050Sstevel@tonic-gate 		if (USBA_IS_DEFAULT_PIPE(ph_data)) {
14060Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI,
14070Sstevel@tonic-gate 			    usbai_log_handle,
14080Sstevel@tonic-gate 			    "no flushing on default pipe!");
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 			flush_requests = 0;
14110Sstevel@tonic-gate 		}
14120Sstevel@tonic-gate 	}
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	if (flush_requests) {
14150Sstevel@tonic-gate 		/* flush all requests in the pipehandle queue */
14160Sstevel@tonic-gate 		while ((req_wrp = (usba_req_wrapper_t *)
14170Sstevel@tonic-gate 		    usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
14180Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
14190Sstevel@tonic-gate 			usba_do_req_exc_cb(req_wrp, USB_CR_FLUSHED,
14206898Sfb209375 			    USB_CB_RESET_PIPE);
14210Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
14220Sstevel@tonic-gate 		}
14230Sstevel@tonic-gate 	}
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 	usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
14260Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
14270Sstevel@tonic-gate }
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate /*
14310Sstevel@tonic-gate  *
14320Sstevel@tonic-gate  * usb_pipe_drain_reqs
14330Sstevel@tonic-gate  *	this function blocks until there are no more requests
14340Sstevel@tonic-gate  *	owned by this dip on the pipe
14350Sstevel@tonic-gate  *
14360Sstevel@tonic-gate  * Arguments:
14370Sstevel@tonic-gate  *	dip		- devinfo pointer
14380Sstevel@tonic-gate  *	pipe_handle	- opaque pipe handle
14390Sstevel@tonic-gate  *	timeout 	- timeout in seconds
14400Sstevel@tonic-gate  *	flags		- USB_FLAGS_SLEEP:
14410Sstevel@tonic-gate  *				wait for completion.
14420Sstevel@tonic-gate  *	cb		- if USB_FLAGS_SLEEP has not been specified
14430Sstevel@tonic-gate  *			  this callback function will be called on
14440Sstevel@tonic-gate  *			  completion. This callback may be NULL
14450Sstevel@tonic-gate  *			  and no notification of completion will then
14460Sstevel@tonic-gate  *			  be provided.
14470Sstevel@tonic-gate  *	cb_arg		- 2nd argument to callback function.
14480Sstevel@tonic-gate  *
14490Sstevel@tonic-gate  * callback and callback_arg should be NULL if USB_FLAGS_SLEEP has
14500Sstevel@tonic-gate  * been specified
14510Sstevel@tonic-gate  *
14520Sstevel@tonic-gate  * Returns:
14530Sstevel@tonic-gate  *	USB_SUCCESS	- pipe successfully reset or request queued
14540Sstevel@tonic-gate  *	USB_FAILURE	- timeout
14550Sstevel@tonic-gate  *	USB_*		- refer to usbai.h
14560Sstevel@tonic-gate  */
14570Sstevel@tonic-gate int
usb_pipe_drain_reqs(dev_info_t * dip,usb_pipe_handle_t pipe_handle,uint_t time,usb_flags_t usb_flags,void (* cb)(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t cb_arg)14580Sstevel@tonic-gate usb_pipe_drain_reqs(dev_info_t	*dip,
14590Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle,
14600Sstevel@tonic-gate 	uint_t			time,
14610Sstevel@tonic-gate 	usb_flags_t		usb_flags,
14620Sstevel@tonic-gate 	void			(*cb)(
14630Sstevel@tonic-gate 				    usb_pipe_handle_t	ph,
14640Sstevel@tonic-gate 				    usb_opaque_t	arg,   /* cb arg */
14650Sstevel@tonic-gate 				    int			rval,
14660Sstevel@tonic-gate 				    usb_cb_flags_t	flags),
14670Sstevel@tonic-gate 	usb_opaque_t		cb_arg)
14680Sstevel@tonic-gate {
14690Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl = (usba_ph_impl_t *)pipe_handle;
14700Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
14730Sstevel@tonic-gate 	    "usb_pipe_drain_reqs: dip=0x%p ph_data=0x%p tm=%d uf=0x%x",
14746898Sfb209375 	    (void *)dip, (void *)ph_data, time, usb_flags);
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	if (ph_data == NULL) {
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 		return (USB_INVALID_PIPE);
14790Sstevel@tonic-gate 	}
14800Sstevel@tonic-gate 	if (dip == NULL) {
14810Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 		return (USB_INVALID_ARGS);
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
14870Sstevel@tonic-gate 		usba_release_ph_data(ph_impl);
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 		return (USB_INVALID_CONTEXT);
14900Sstevel@tonic-gate 	}
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	(void) usba_pipe_setup_func_call(dip, usba_pipe_sync_drain_reqs,
14930Sstevel@tonic-gate 	    ph_impl, (usb_opaque_t)((uintptr_t)time), usb_flags, cb, cb_arg);
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 	return (USB_SUCCESS);
14960Sstevel@tonic-gate }
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate /*
15000Sstevel@tonic-gate  * usba_pipe_sync_drain_reqs
15010Sstevel@tonic-gate  *	this function blocks until there are no more requests
15020Sstevel@tonic-gate  *	owned by this dip on the pipe
15030Sstevel@tonic-gate  *
15040Sstevel@tonic-gate  * Arguments:
15050Sstevel@tonic-gate  *	dip		- devinfo pointer
15060Sstevel@tonic-gate  *	ph_impl		- pipe impl handle
15070Sstevel@tonic-gate  *	timeout		- timeout in seconds
15080Sstevel@tonic-gate  * Returns:
15090Sstevel@tonic-gate  *	USB_SUCCESS	- pipe successfully reset or request queued
15100Sstevel@tonic-gate  *	USB_FAILURE	- timeout
15110Sstevel@tonic-gate  *	USB_*		- see usbai.h
15120Sstevel@tonic-gate  */
15130Sstevel@tonic-gate /*ARGSUSED*/
15140Sstevel@tonic-gate int
usba_pipe_sync_drain_reqs(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t usb_flags)15150Sstevel@tonic-gate usba_pipe_sync_drain_reqs(dev_info_t	*dip,
15160Sstevel@tonic-gate 		usba_ph_impl_t		*ph_impl,
15170Sstevel@tonic-gate 		usba_pipe_async_req_t	*request,
15180Sstevel@tonic-gate 		usb_flags_t		usb_flags)
15190Sstevel@tonic-gate {
15200Sstevel@tonic-gate 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
15216898Sfb209375 	    ph_impl);
15220Sstevel@tonic-gate 	int		i;
15230Sstevel@tonic-gate 	int		timeout = 100 * (int)((uintptr_t)(request->arg));
15240Sstevel@tonic-gate 						/* delay will be 10 ms */
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	mutex_enter(&ph_data->p_mutex);
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15290Sstevel@tonic-gate 	    "usba_pipe_sync_drain_reqs: "
15300Sstevel@tonic-gate 	    "dip=0x%p ph_data=0x%p timeout=%d ref=%d req=%d",
15316898Sfb209375 	    (void *)dip, (void *)ph_data, timeout,
15326898Sfb209375 	    usba_get_ph_ref_count(ph_data),
15330Sstevel@tonic-gate 	    ph_data->p_req_count);
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 	ASSERT(ph_data->p_req_count >= 0);
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	/*
15380Sstevel@tonic-gate 	 * for default pipe, we need to check the active request
15390Sstevel@tonic-gate 	 * and the queue
15400Sstevel@tonic-gate 	 * Note that a pipe reset on the default pipe doesn't flush
15410Sstevel@tonic-gate 	 * the queue
15420Sstevel@tonic-gate 	 * for all other pipes we just check ref and req count since
15430Sstevel@tonic-gate 	 * these pipes are unshared
15440Sstevel@tonic-gate 	 */
15450Sstevel@tonic-gate 	if (USBA_IS_DEFAULT_PIPE(ph_data)) {
15460Sstevel@tonic-gate 		for (i = 0; (i < timeout) || (request->arg == 0); i++) {
15470Sstevel@tonic-gate 			usba_list_entry_t *next, *tmpnext;
15480Sstevel@tonic-gate 			usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *)
15496898Sfb209375 			    ph_data->p_active_cntrl_req_wrp;
15500Sstevel@tonic-gate 			int found = 0;
15510Sstevel@tonic-gate 			int count = 0;
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate 			/* active_req_wrp is only for control pipes */
15540Sstevel@tonic-gate 			if ((req_wrp == NULL) || (req_wrp->wr_dip != dip)) {
15550Sstevel@tonic-gate 				/* walk the queue */
15560Sstevel@tonic-gate 				mutex_enter(&ph_data->p_queue.list_mutex);
15570Sstevel@tonic-gate 				next = ph_data->p_queue.next;
15580Sstevel@tonic-gate 				while (next != NULL) {
15590Sstevel@tonic-gate 					mutex_enter(&next->list_mutex);
15600Sstevel@tonic-gate 					req_wrp = (usba_req_wrapper_t *)
15616898Sfb209375 					    next->private;
15620Sstevel@tonic-gate 					found = (req_wrp->wr_dip == dip);
15630Sstevel@tonic-gate 					if (found) {
15640Sstevel@tonic-gate 						mutex_exit(&next->list_mutex);
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 						break;
15670Sstevel@tonic-gate 					}
15680Sstevel@tonic-gate 					tmpnext = next->next;
15690Sstevel@tonic-gate 					mutex_exit(&next->list_mutex);
15700Sstevel@tonic-gate 					next = tmpnext;
15710Sstevel@tonic-gate 					count++;
15720Sstevel@tonic-gate 				}
15730Sstevel@tonic-gate 				mutex_exit(&ph_data->p_queue.list_mutex);
15740Sstevel@tonic-gate 				if (found == 0) {
15750Sstevel@tonic-gate 					break;
15760Sstevel@tonic-gate 				}
15770Sstevel@tonic-gate 			}
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 			USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15800Sstevel@tonic-gate 			    "usb_pipe_sync_drain_reqs: "
15810Sstevel@tonic-gate 			    "cnt=%d active_req_wrp=0x%p",
15826898Sfb209375 			    count, (void *)ph_data->p_active_cntrl_req_wrp);
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 			mutex_exit(&ph_data->p_mutex);
15850Sstevel@tonic-gate 			delay(drv_usectohz(10000));
15860Sstevel@tonic-gate 			mutex_enter(&ph_data->p_mutex);
15870Sstevel@tonic-gate 		}
15880Sstevel@tonic-gate 	} else {
15890Sstevel@tonic-gate 		mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
15900Sstevel@tonic-gate 		for (i = 0; (i < timeout) || (request->arg == 0); i++) {
15910Sstevel@tonic-gate 			ASSERT(ph_data->p_req_count >= 0);
15920Sstevel@tonic-gate 			if (ph_data->p_req_count ||
15930Sstevel@tonic-gate 			    (ph_data->p_ph_impl->usba_ph_ref_count > 1)) {
15940Sstevel@tonic-gate 				mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
15950Sstevel@tonic-gate 				mutex_exit(&ph_data->p_mutex);
15960Sstevel@tonic-gate 				delay(drv_usectohz(10000));
15970Sstevel@tonic-gate 				mutex_enter(&ph_data->p_mutex);
15980Sstevel@tonic-gate 				mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
15990Sstevel@tonic-gate 			} else {
16000Sstevel@tonic-gate 				break;
16010Sstevel@tonic-gate 			}
16020Sstevel@tonic-gate 		}
16030Sstevel@tonic-gate 		mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
16040Sstevel@tonic-gate 	}
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16070Sstevel@tonic-gate 	    "usb_pipe_sync_drain_reqs: timeout=%d active_req_wrp=0x%p req=%d",
16086898Sfb209375 	    i, (void *)ph_data->p_active_cntrl_req_wrp, ph_data->p_req_count);
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	mutex_exit(&ph_data->p_mutex);
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	usba_release_ph_data(ph_impl);
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 	return (i >= timeout ? USB_FAILURE : USB_SUCCESS);
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate /*
16190Sstevel@tonic-gate  * usba_persistent_pipe_open
16200Sstevel@tonic-gate  *	Open all the pipes marked persistent for this device
16210Sstevel@tonic-gate  */
16220Sstevel@tonic-gate int
usba_persistent_pipe_open(usba_device_t * usba_device)16230Sstevel@tonic-gate usba_persistent_pipe_open(usba_device_t *usba_device)
16240Sstevel@tonic-gate {
16250Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl;
16260Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle;
16270Sstevel@tonic-gate 	int			i;
16280Sstevel@tonic-gate 	int			rval = USB_SUCCESS;
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16316898Sfb209375 	    "usba_persistent_pipe_open: usba_device=0x%p", (void *)usba_device);
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	if (usba_device != NULL) {
16340Sstevel@tonic-gate 		/* default pipe is the first one to be opened */
16350Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
16360Sstevel@tonic-gate 		for (i = 0; (rval == USB_SUCCESS) &&
16370Sstevel@tonic-gate 		    (i < USBA_N_ENDPOINTS); i++) {
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 			ph_impl = &usba_device->usb_ph_list[i];
16400Sstevel@tonic-gate 			mutex_enter(&ph_impl->usba_ph_mutex);
16410Sstevel@tonic-gate 			if (ph_impl->usba_ph_flags & USBA_PH_DATA_PERSISTENT) {
16420Sstevel@tonic-gate 				ph_impl->usba_ph_flags &=
16436898Sfb209375 				    ~USBA_PH_DATA_PERSISTENT;
16440Sstevel@tonic-gate 				mutex_exit(&ph_impl->usba_ph_mutex);
16450Sstevel@tonic-gate 				mutex_exit(&usba_device->usb_mutex);
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 				rval = usb_pipe_open(ph_impl->usba_ph_dip,
16480Sstevel@tonic-gate 				    &ph_impl->usba_ph_ep,
16490Sstevel@tonic-gate 				    &ph_impl->usba_ph_policy,
16500Sstevel@tonic-gate 				    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
16510Sstevel@tonic-gate 				    &pipe_handle);
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 				USB_DPRINTF_L3(DPRINT_MASK_USBAI,
16540Sstevel@tonic-gate 				    usbai_log_handle,
16550Sstevel@tonic-gate 				    "usba_persistent_pipe_open: "
16560Sstevel@tonic-gate 				    "ep_index=%d, rval=%d", i, rval);
16570Sstevel@tonic-gate 				mutex_enter(&usba_device->usb_mutex);
16580Sstevel@tonic-gate 				mutex_enter(&ph_impl->usba_ph_mutex);
16590Sstevel@tonic-gate 			}
16600Sstevel@tonic-gate 			mutex_exit(&ph_impl->usba_ph_mutex);
16610Sstevel@tonic-gate 		}
16620Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
16630Sstevel@tonic-gate 	}
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 	return (rval);
16660Sstevel@tonic-gate }
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate /*
16700Sstevel@tonic-gate  * usba_persistent_pipe_close
16710Sstevel@tonic-gate  *	Close all pipes of this device and mark them persistent
16720Sstevel@tonic-gate  */
16730Sstevel@tonic-gate void
usba_persistent_pipe_close(usba_device_t * usba_device)16740Sstevel@tonic-gate usba_persistent_pipe_close(usba_device_t *usba_device)
16750Sstevel@tonic-gate {
16760Sstevel@tonic-gate 	usba_ph_impl_t		*ph_impl;
16770Sstevel@tonic-gate 	usb_pipe_handle_t	pipe_handle;
16780Sstevel@tonic-gate 	int			i;
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16816898Sfb209375 	    "usba_persistent_pipe_close: usba_device=0x%p",
16826898Sfb209375 	    (void *)usba_device);
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	if (usba_device != NULL) {
16850Sstevel@tonic-gate 		/* default pipe is the last one to be closed */
16860Sstevel@tonic-gate 		mutex_enter(&usba_device->usb_mutex);
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 		for (i = (USBA_N_ENDPOINTS - 1); i >= 0; i--) {
16890Sstevel@tonic-gate 			ph_impl = &usba_device->usb_ph_list[i];
16900Sstevel@tonic-gate 			if (ph_impl->usba_ph_data != NULL) {
16910Sstevel@tonic-gate 				mutex_enter(&ph_impl->usba_ph_mutex);
16920Sstevel@tonic-gate 				ph_impl->usba_ph_flags |=
16936898Sfb209375 				    USBA_PH_DATA_PERSISTENT;
16940Sstevel@tonic-gate 				mutex_exit(&ph_impl->usba_ph_mutex);
16950Sstevel@tonic-gate 				mutex_exit(&usba_device->usb_mutex);
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 				pipe_handle = (usb_pipe_handle_t)ph_impl;
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 				usb_pipe_close(ph_impl->usba_ph_dip,
17000Sstevel@tonic-gate 				    pipe_handle,
17010Sstevel@tonic-gate 				    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
17020Sstevel@tonic-gate 				    NULL, NULL);
17030Sstevel@tonic-gate 				mutex_enter(&usba_device->usb_mutex);
17040Sstevel@tonic-gate 				ASSERT(ph_impl->usba_ph_data == NULL);
17050Sstevel@tonic-gate 			}
17060Sstevel@tonic-gate 		}
17070Sstevel@tonic-gate 		mutex_exit(&usba_device->usb_mutex);
17080Sstevel@tonic-gate 	}
17090Sstevel@tonic-gate }
1710