xref: /onnv-gate/usr/src/uts/common/io/usb/usba/wa.c (revision 11066:cebb50cbe4f9)
19430SRaymond.Chen@Sun.COM /*
29430SRaymond.Chen@Sun.COM  * CDDL HEADER START
39430SRaymond.Chen@Sun.COM  *
49430SRaymond.Chen@Sun.COM  * The contents of this file are subject to the terms of the
59430SRaymond.Chen@Sun.COM  * Common Development and Distribution License (the "License").
69430SRaymond.Chen@Sun.COM  * You may not use this file except in compliance with the License.
79430SRaymond.Chen@Sun.COM  *
89430SRaymond.Chen@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99430SRaymond.Chen@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109430SRaymond.Chen@Sun.COM  * See the License for the specific language governing permissions
119430SRaymond.Chen@Sun.COM  * and limitations under the License.
129430SRaymond.Chen@Sun.COM  *
139430SRaymond.Chen@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149430SRaymond.Chen@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159430SRaymond.Chen@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169430SRaymond.Chen@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179430SRaymond.Chen@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189430SRaymond.Chen@Sun.COM  *
199430SRaymond.Chen@Sun.COM  * CDDL HEADER END
209430SRaymond.Chen@Sun.COM  */
219430SRaymond.Chen@Sun.COM /*
229430SRaymond.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
239430SRaymond.Chen@Sun.COM  * Use is subject to license terms.
249430SRaymond.Chen@Sun.COM  */
259430SRaymond.Chen@Sun.COM 
269430SRaymond.Chen@Sun.COM /*
279430SRaymond.Chen@Sun.COM  * Wire Adapter Operations
289430SRaymond.Chen@Sun.COM  * Both DWA and HWA have the same kind of functional components, the
299430SRaymond.Chen@Sun.COM  * Wire Adapter. Functions defined in this file are to handle WA's
309430SRaymond.Chen@Sun.COM  * class specific Descriptors, Requests, Notifications and Transfers.
319430SRaymond.Chen@Sun.COM  * DWA or HWA specific descriptors, requests are not handled here.
329430SRaymond.Chen@Sun.COM  */
339430SRaymond.Chen@Sun.COM 
349430SRaymond.Chen@Sun.COM #include <sys/usb/hwa/hwahc/hwahc.h>
359430SRaymond.Chen@Sun.COM #include <sys/usb/hwa/hwahc/hwahc_util.h>
369430SRaymond.Chen@Sun.COM #include <sys/usb/usba/wa.h>
379430SRaymond.Chen@Sun.COM #include <sys/usb/usba/wusba.h>
389430SRaymond.Chen@Sun.COM #include <sys/usb/usba/whcdi.h>
399430SRaymond.Chen@Sun.COM #include <sys/usb/usba.h>
409430SRaymond.Chen@Sun.COM #include <sys/usb/usba/usba_impl.h>
419430SRaymond.Chen@Sun.COM #include <sys/usb/usba/usba_devdb.h>	/* usba_devdb_refresh */
429430SRaymond.Chen@Sun.COM #include <sys/usb/hubd/hubdvar.h>
439430SRaymond.Chen@Sun.COM #include <sys/usb/hubd/hubd_impl.h>	/* hubd_ioctl_data_t */
449430SRaymond.Chen@Sun.COM #include <sys/strsubr.h>	/* allocb_wait */
459430SRaymond.Chen@Sun.COM #include <sys/strsun.h>		/* MBLKL macro */
469430SRaymond.Chen@Sun.COM 
479430SRaymond.Chen@Sun.COM extern usb_log_handle_t whcdi_log_handle;
489430SRaymond.Chen@Sun.COM 
499430SRaymond.Chen@Sun.COM /* default rpipe PHY transfer speed */
509430SRaymond.Chen@Sun.COM static uint8_t rp_default_speed = WUSB_PHY_TX_RATE_106;
519430SRaymond.Chen@Sun.COM 
529430SRaymond.Chen@Sun.COM /* function prototypes */
539430SRaymond.Chen@Sun.COM static void wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl,
549430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *tw);
559430SRaymond.Chen@Sun.COM static void wusb_wa_handle_error(wusb_wa_data_t *wa_data,
569430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *wr, usb_cr_t cr);
579430SRaymond.Chen@Sun.COM 
589430SRaymond.Chen@Sun.COM /*
599430SRaymond.Chen@Sun.COM  * Parse Wire Adapter class desriptor.
609430SRaymond.Chen@Sun.COM  *	- see 8.4.3.7 & 8.5.2.7
619430SRaymond.Chen@Sun.COM  *
629430SRaymond.Chen@Sun.COM  *	wa_descr - the parsed descriptors.
639430SRaymond.Chen@Sun.COM  *	altif_data - the passed in raw descriptor data.
649430SRaymond.Chen@Sun.COM  */
659430SRaymond.Chen@Sun.COM int
wusb_parse_wa_descr(usb_wa_descr_t * wa_descr,usb_alt_if_data_t * altif_data)669430SRaymond.Chen@Sun.COM wusb_parse_wa_descr(usb_wa_descr_t *wa_descr, usb_alt_if_data_t *altif_data)
679430SRaymond.Chen@Sun.COM {
689430SRaymond.Chen@Sun.COM 	usb_cvs_data_t	*cvs_data;
699430SRaymond.Chen@Sun.COM 	int		i;
709430SRaymond.Chen@Sun.COM 	size_t		count;
719430SRaymond.Chen@Sun.COM 
729430SRaymond.Chen@Sun.COM 	if ((wa_descr == NULL) || (altif_data == NULL)) {
739430SRaymond.Chen@Sun.COM 		return (USB_INVALID_ARGS);
749430SRaymond.Chen@Sun.COM 	}
759430SRaymond.Chen@Sun.COM 
769430SRaymond.Chen@Sun.COM 	for (i = 0; i < altif_data->altif_n_cvs; i++) {
779430SRaymond.Chen@Sun.COM 		cvs_data = &altif_data->altif_cvs[i];
789430SRaymond.Chen@Sun.COM 		if (cvs_data->cvs_buf == NULL) {
799430SRaymond.Chen@Sun.COM 			continue;
809430SRaymond.Chen@Sun.COM 		}
819430SRaymond.Chen@Sun.COM 		if (cvs_data->cvs_buf[1] == USB_DESCR_TYPE_WA) {
829430SRaymond.Chen@Sun.COM 			count = usb_parse_data("ccsccsscccc",
839430SRaymond.Chen@Sun.COM 			    cvs_data->cvs_buf, cvs_data->cvs_buf_len,
849430SRaymond.Chen@Sun.COM 			    (void *)wa_descr,
859430SRaymond.Chen@Sun.COM 			    (size_t)USB_WA_DESCR_SIZE);
869430SRaymond.Chen@Sun.COM 			if (count != USB_WA_DESCR_SIZE) {
879430SRaymond.Chen@Sun.COM 				return (USB_FAILURE);
889430SRaymond.Chen@Sun.COM 			} else {
899430SRaymond.Chen@Sun.COM 				return (USB_SUCCESS);
909430SRaymond.Chen@Sun.COM 			}
919430SRaymond.Chen@Sun.COM 		}
929430SRaymond.Chen@Sun.COM 	}
939430SRaymond.Chen@Sun.COM 
949430SRaymond.Chen@Sun.COM 	return (USB_FAILURE);
959430SRaymond.Chen@Sun.COM }
969430SRaymond.Chen@Sun.COM 
979430SRaymond.Chen@Sun.COM /* initialize rpipe structures */
989430SRaymond.Chen@Sun.COM void
wusb_wa_rpipes_init(wusb_wa_data_t * wa_data)999430SRaymond.Chen@Sun.COM wusb_wa_rpipes_init(wusb_wa_data_t *wa_data)
1009430SRaymond.Chen@Sun.COM {
1019430SRaymond.Chen@Sun.COM 	int			i;
1029430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t	*hdl;
1039430SRaymond.Chen@Sun.COM 
1049430SRaymond.Chen@Sun.COM 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
1059430SRaymond.Chen@Sun.COM 		hdl = &wa_data->wa_rpipe_hdl[i];
1069430SRaymond.Chen@Sun.COM 		mutex_init(&hdl->rp_mutex, NULL, MUTEX_DRIVER, NULL);
1079430SRaymond.Chen@Sun.COM 		cv_init(&hdl->rp_cv, NULL, CV_DRIVER, NULL);
1089430SRaymond.Chen@Sun.COM 
1099797SRaymond.Chen@Sun.COM 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdl));
1109430SRaymond.Chen@Sun.COM 		hdl->rp_state = WA_RPIPE_STATE_FREE;
1119430SRaymond.Chen@Sun.COM 		hdl->rp_refcnt = 0;
1129430SRaymond.Chen@Sun.COM 		hdl->rp_timeout_list = NULL;
1139797SRaymond.Chen@Sun.COM 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*hdl));
1149430SRaymond.Chen@Sun.COM 	}
1159430SRaymond.Chen@Sun.COM }
1169430SRaymond.Chen@Sun.COM 
1179430SRaymond.Chen@Sun.COM /* deinitialize rpipe structures */
1189430SRaymond.Chen@Sun.COM void
wusb_wa_rpipes_fini(wusb_wa_data_t * wa_data)1199430SRaymond.Chen@Sun.COM wusb_wa_rpipes_fini(wusb_wa_data_t *wa_data)
1209430SRaymond.Chen@Sun.COM {
1219430SRaymond.Chen@Sun.COM 	int			i;
1229430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t	*hdl;
1239430SRaymond.Chen@Sun.COM 
1249430SRaymond.Chen@Sun.COM 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
1259430SRaymond.Chen@Sun.COM 		hdl = &wa_data->wa_rpipe_hdl[i];
1269430SRaymond.Chen@Sun.COM 		mutex_destroy(&hdl->rp_mutex);
1279430SRaymond.Chen@Sun.COM 		cv_destroy(&hdl->rp_cv);
1289430SRaymond.Chen@Sun.COM 	}
1299430SRaymond.Chen@Sun.COM }
1309430SRaymond.Chen@Sun.COM 
1319430SRaymond.Chen@Sun.COM 
1329430SRaymond.Chen@Sun.COM /*
1339430SRaymond.Chen@Sun.COM  * wusb_wa_data_init:
1349430SRaymond.Chen@Sun.COM  *	WA interface validation
1359430SRaymond.Chen@Sun.COM  *	Parse WA class descriptors
1369430SRaymond.Chen@Sun.COM  *	Set up RPipes
1379430SRaymond.Chen@Sun.COM  *	Set up callbacks
1389430SRaymond.Chen@Sun.COM  */
1399430SRaymond.Chen@Sun.COM int
wusb_wa_data_init(dev_info_t * dip,wusb_wa_data_t * wa_data,wusb_wa_cb_t * cbs,usb_client_dev_data_t * dev_data,uint_t mask,usb_log_handle_t handle)1409430SRaymond.Chen@Sun.COM wusb_wa_data_init(dev_info_t *dip, wusb_wa_data_t *wa_data, wusb_wa_cb_t *cbs,
1419430SRaymond.Chen@Sun.COM 	usb_client_dev_data_t *dev_data,
1429430SRaymond.Chen@Sun.COM 	uint_t mask, usb_log_handle_t handle)
1439430SRaymond.Chen@Sun.COM {
1449430SRaymond.Chen@Sun.COM 	usb_alt_if_data_t	*altif_data;
1459430SRaymond.Chen@Sun.COM 	usb_ep_data_t		*ep_data;
1469430SRaymond.Chen@Sun.COM 	int			ifno;
1479430SRaymond.Chen@Sun.COM 	int			rval;
1489430SRaymond.Chen@Sun.COM 
1499430SRaymond.Chen@Sun.COM 	if ((wa_data == NULL) || (dev_data == NULL)) {
1509430SRaymond.Chen@Sun.COM 
1519430SRaymond.Chen@Sun.COM 		return (USB_INVALID_ARGS);
1529430SRaymond.Chen@Sun.COM 	}
1539430SRaymond.Chen@Sun.COM 
1549797SRaymond.Chen@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data));
1559797SRaymond.Chen@Sun.COM 
1569430SRaymond.Chen@Sun.COM 	/* get inf descr and ept descrs from altif data */
1579430SRaymond.Chen@Sun.COM 	altif_data = &dev_data->dev_curr_cfg->
1589430SRaymond.Chen@Sun.COM 	    cfg_if[dev_data->dev_curr_if].if_alt[0];
1599430SRaymond.Chen@Sun.COM 
1609430SRaymond.Chen@Sun.COM 	/* T.8-44. Wire Adapter */
1619430SRaymond.Chen@Sun.COM 	if (altif_data->altif_descr.bInterfaceSubClass !=
1629430SRaymond.Chen@Sun.COM 	    USB_SUBCLS_WUSB_2) {
1639430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(mask, handle,
1649430SRaymond.Chen@Sun.COM 		    "wusb_init_wa_data: invalid interface subclass (0x%x)",
1659430SRaymond.Chen@Sun.COM 		    altif_data->altif_descr.bInterfaceSubClass);
1669430SRaymond.Chen@Sun.COM 
1679430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
1689430SRaymond.Chen@Sun.COM 	}
1699430SRaymond.Chen@Sun.COM 
1709430SRaymond.Chen@Sun.COM 	/* at least 3 EPs, INTR IN + BULK IN + BULK OUT */
1719430SRaymond.Chen@Sun.COM 	if (altif_data->altif_n_ep < 3) {
1729430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(mask, handle,
1739430SRaymond.Chen@Sun.COM 		    "wusb_init_wa_data: invalid alt 0 for interface %d",
1749430SRaymond.Chen@Sun.COM 		    dev_data->dev_curr_if);
1759430SRaymond.Chen@Sun.COM 
1769430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
1779430SRaymond.Chen@Sun.COM 	}
1789430SRaymond.Chen@Sun.COM 
1799430SRaymond.Chen@Sun.COM 	wa_data->wa_ifno = ifno = dev_data->dev_curr_if;
1809430SRaymond.Chen@Sun.COM 	wa_data->wa_if_descr = altif_data->altif_descr;
1819430SRaymond.Chen@Sun.COM 
1829430SRaymond.Chen@Sun.COM 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
1839430SRaymond.Chen@Sun.COM 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
1849430SRaymond.Chen@Sun.COM 		wa_data->wa_bulkout_ept = ep_data->ep_descr;
1859430SRaymond.Chen@Sun.COM 	}
1869430SRaymond.Chen@Sun.COM 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
1879430SRaymond.Chen@Sun.COM 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
1889430SRaymond.Chen@Sun.COM 		wa_data->wa_bulkin_ept = ep_data->ep_descr;
1899430SRaymond.Chen@Sun.COM 	}
1909430SRaymond.Chen@Sun.COM 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
1919430SRaymond.Chen@Sun.COM 	    USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
1929430SRaymond.Chen@Sun.COM 		wa_data->wa_intr_ept = ep_data->ep_descr;
1939430SRaymond.Chen@Sun.COM 	}
1949430SRaymond.Chen@Sun.COM 
1959430SRaymond.Chen@Sun.COM 	if ((wa_data->wa_bulkout_ept.bLength == 0) ||
1969430SRaymond.Chen@Sun.COM 	    (wa_data->wa_bulkin_ept.bLength == 0) ||
1979430SRaymond.Chen@Sun.COM 	    (wa_data->wa_intr_ept.bLength == 0)) {
1989430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(mask, handle,
1999430SRaymond.Chen@Sun.COM 		    "wusb_init_wa_data: the minimum endpoint set is not "
2009430SRaymond.Chen@Sun.COM 		    "supported");
2019430SRaymond.Chen@Sun.COM 
2029430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
2039430SRaymond.Chen@Sun.COM 	}
2049430SRaymond.Chen@Sun.COM 
2059430SRaymond.Chen@Sun.COM 	/* parse the WA descriptor */
2069430SRaymond.Chen@Sun.COM 	if ((rval = wusb_parse_wa_descr(&wa_data->wa_descr, altif_data)) !=
2079430SRaymond.Chen@Sun.COM 	    USB_SUCCESS) {
2089430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(mask, handle,
2099430SRaymond.Chen@Sun.COM 		    "wusb_init_wa_data: parse wire adapter class descr failed");
2109430SRaymond.Chen@Sun.COM 
2119430SRaymond.Chen@Sun.COM 		return (rval);
2129430SRaymond.Chen@Sun.COM 	}
2139430SRaymond.Chen@Sun.COM 	wa_data->wa_avail_blocks = wa_data->wa_descr.wRPipeMaxBlock;
2149430SRaymond.Chen@Sun.COM 
2159430SRaymond.Chen@Sun.COM 	wa_data->wa_dip = dip;
2169430SRaymond.Chen@Sun.COM 
2179430SRaymond.Chen@Sun.COM 	/* initialize rpipe handlers */
2189430SRaymond.Chen@Sun.COM 	wa_data->wa_num_rpipes = wa_data->wa_descr.wNumRPipes;
2199430SRaymond.Chen@Sun.COM 
2209430SRaymond.Chen@Sun.COM 	wa_data->wa_rpipe_hdl = kmem_zalloc((wa_data->wa_num_rpipes *
2219430SRaymond.Chen@Sun.COM 	    sizeof (wusb_wa_rpipe_hdl_t)), KM_SLEEP);
2229430SRaymond.Chen@Sun.COM 
2239430SRaymond.Chen@Sun.COM 	/* init rpipes */
2249430SRaymond.Chen@Sun.COM 	wusb_wa_rpipes_init(wa_data);
2259430SRaymond.Chen@Sun.COM 
2269430SRaymond.Chen@Sun.COM 	/* register callbacks */
2279430SRaymond.Chen@Sun.COM 	wa_data->pipe_periodic_req = cbs->pipe_periodic_req;
2289430SRaymond.Chen@Sun.COM 	wa_data->intr_cb = cbs->intr_cb;
2299430SRaymond.Chen@Sun.COM 	wa_data->intr_exc_cb = cbs->intr_exc_cb;
2309430SRaymond.Chen@Sun.COM 	wa_data->rpipe_xfer_cb = cbs->rpipe_xfer_cb;
2319430SRaymond.Chen@Sun.COM 
2329430SRaymond.Chen@Sun.COM 	mutex_init(&wa_data->wa_mutex, NULL, MUTEX_DRIVER, NULL);
2339430SRaymond.Chen@Sun.COM 
2349797SRaymond.Chen@Sun.COM 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data));
2359797SRaymond.Chen@Sun.COM 
2369430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
2379430SRaymond.Chen@Sun.COM }
2389430SRaymond.Chen@Sun.COM 
2399430SRaymond.Chen@Sun.COM /* deinitialize data transfer related resources */
2409430SRaymond.Chen@Sun.COM void
wusb_wa_data_fini(wusb_wa_data_t * wa_data)2419430SRaymond.Chen@Sun.COM wusb_wa_data_fini(wusb_wa_data_t *wa_data)
2429430SRaymond.Chen@Sun.COM {
2439797SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
2449430SRaymond.Chen@Sun.COM 	if (wa_data->wa_rpipe_hdl) {
2459430SRaymond.Chen@Sun.COM 		wusb_wa_rpipes_fini(wa_data);
2469430SRaymond.Chen@Sun.COM 		kmem_free(wa_data->wa_rpipe_hdl, wa_data->wa_num_rpipes *
2479430SRaymond.Chen@Sun.COM 		    sizeof (wusb_wa_rpipe_hdl_t));
2489430SRaymond.Chen@Sun.COM 	}
2499797SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
2509430SRaymond.Chen@Sun.COM 	mutex_destroy(&wa_data->wa_mutex);
2519430SRaymond.Chen@Sun.COM }
2529430SRaymond.Chen@Sun.COM 
wusb_wa_dump_rpipe_descr(usb_wa_rpipe_descr_t * pd,uint_t mask,usb_log_handle_t handle)2539430SRaymond.Chen@Sun.COM void wusb_wa_dump_rpipe_descr(usb_wa_rpipe_descr_t *pd, uint_t mask,
2549430SRaymond.Chen@Sun.COM     usb_log_handle_t handle)
2559430SRaymond.Chen@Sun.COM {
2569430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(mask, handle, "RPipe Descriptor:\n"
2579430SRaymond.Chen@Sun.COM 	    "\tWRPipeIndex=%d wRequests=%d wBlocks=%d\n"
2589430SRaymond.Chen@Sun.COM 	    "\twMaxPacketSize=%d bHSHubAddress=%d\n"
2599430SRaymond.Chen@Sun.COM 	    "\tbHSHubPort=%d bSpeed=%d bDeviceAddress=%d\n"
2609430SRaymond.Chen@Sun.COM 	    "\tbEndpointAddress=0x%02x bDataSequence=%d\n"
2619430SRaymond.Chen@Sun.COM 	    "\tdwCurrentWindow=0x%08x bMaxDataSequence=%d",
2629430SRaymond.Chen@Sun.COM 	    pd->wRPipeIndex, pd->wRequests, pd->wBlocks, pd->wMaxPacketSize,
2639430SRaymond.Chen@Sun.COM 	    pd->wa_value.hwa_value.bMaxBurst,
2649430SRaymond.Chen@Sun.COM 	    pd->wa_value.hwa_value.bDeviceInfoIndex,
2659430SRaymond.Chen@Sun.COM 	    pd->bSpeed, pd->bDeviceAddress,
2669430SRaymond.Chen@Sun.COM 	    pd->bEndpointAddress, pd->bDataSequence, pd->dwCurrentWindow,
2679430SRaymond.Chen@Sun.COM 	    pd->bMaxDataSequence);
2689430SRaymond.Chen@Sun.COM 
2699430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(mask, handle,
2709430SRaymond.Chen@Sun.COM 	    "(cont'ed)bInterval=%d bOverTheAirInterval=%d\n"
2719430SRaymond.Chen@Sun.COM 	    "\tbmAttribute=0x%02x bmCharacter=0x%02x\n"
2729430SRaymond.Chen@Sun.COM 	    "\tbmRetryOptions=0x%02x wNumTransactionErrors=%d\n",
2739430SRaymond.Chen@Sun.COM 	    pd->bInterval, pd->bOverTheAirInterval,
2749430SRaymond.Chen@Sun.COM 	    pd->bmAttribute, pd->bmCharacteristics, pd->bmRetryOptions,
2759430SRaymond.Chen@Sun.COM 	    pd->wNumTransactionErrors);
2769430SRaymond.Chen@Sun.COM 
2779430SRaymond.Chen@Sun.COM }
2789430SRaymond.Chen@Sun.COM 
2799430SRaymond.Chen@Sun.COM /* get rpipe descr of a certain index, refer to WUSB 1.0/8.3.1.4 */
2809430SRaymond.Chen@Sun.COM int
wusb_wa_get_rpipe_descr(dev_info_t * dip,usb_pipe_handle_t ph,uint16_t idx,usb_wa_rpipe_descr_t * descr,uint_t mask,usb_log_handle_t handle)2819430SRaymond.Chen@Sun.COM wusb_wa_get_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph,
2829430SRaymond.Chen@Sun.COM 	uint16_t idx, usb_wa_rpipe_descr_t *descr,
2839430SRaymond.Chen@Sun.COM 	uint_t mask, usb_log_handle_t handle)
2849430SRaymond.Chen@Sun.COM {
2859430SRaymond.Chen@Sun.COM 	mblk_t		*data = NULL;
2869430SRaymond.Chen@Sun.COM 	usb_cr_t	completion_reason;
2879430SRaymond.Chen@Sun.COM 	usb_cb_flags_t	cb_flags;
2889430SRaymond.Chen@Sun.COM 	size_t		count;
2899430SRaymond.Chen@Sun.COM 	int		rval;
2909430SRaymond.Chen@Sun.COM 
2919430SRaymond.Chen@Sun.COM 	/*
2929430SRaymond.Chen@Sun.COM 	 * This descriptor is critical for later operations to succeed.
2939430SRaymond.Chen@Sun.COM 	 * So, we must wait here.
2949430SRaymond.Chen@Sun.COM 	 */
2959430SRaymond.Chen@Sun.COM 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
2969430SRaymond.Chen@Sun.COM 	    WA_CLASS_RPIPE_REQ_IN_TYPE,
2979430SRaymond.Chen@Sun.COM 	    USB_REQ_GET_DESCR,
2989430SRaymond.Chen@Sun.COM 	    USB_DESCR_TYPE_RPIPE << 8,
2999430SRaymond.Chen@Sun.COM 	    idx,
3009430SRaymond.Chen@Sun.COM 	    USB_RPIPE_DESCR_SIZE,
3019430SRaymond.Chen@Sun.COM 	    &data, 0,
3029430SRaymond.Chen@Sun.COM 	    &completion_reason, &cb_flags, 0);
3039430SRaymond.Chen@Sun.COM 
3049430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
3059430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(mask, handle,
3069430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_rpipe_descr: rval=%d, cr=%d, "
3079430SRaymond.Chen@Sun.COM 		    "cb=0x%x", rval, completion_reason, cb_flags);
3089430SRaymond.Chen@Sun.COM 
3099430SRaymond.Chen@Sun.COM 		goto done;
3109430SRaymond.Chen@Sun.COM 	}
3119430SRaymond.Chen@Sun.COM 
3129430SRaymond.Chen@Sun.COM 	if (MBLKL(data) != USB_RPIPE_DESCR_SIZE) {
3139430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(mask, handle,
3149430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_rpipe_descr: return size %d",
3159430SRaymond.Chen@Sun.COM 		    (int)MBLKL(data));
3169430SRaymond.Chen@Sun.COM 		rval = USB_FAILURE;
3179430SRaymond.Chen@Sun.COM 
3189430SRaymond.Chen@Sun.COM 		goto done;
3199430SRaymond.Chen@Sun.COM 	}
3209430SRaymond.Chen@Sun.COM 
3219430SRaymond.Chen@Sun.COM 	count = usb_parse_data("2c4s6cl6cs", data->b_rptr,
3229430SRaymond.Chen@Sun.COM 	    USB_RPIPE_DESCR_SIZE, descr, sizeof (usb_wa_rpipe_descr_t));
3239430SRaymond.Chen@Sun.COM 
3249430SRaymond.Chen@Sun.COM 	if (count == USB_PARSE_ERROR) {
3259430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(mask, handle,
3269430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_rpipe_descr: parse error");
3279430SRaymond.Chen@Sun.COM 		rval = USB_FAILURE;
3289430SRaymond.Chen@Sun.COM 
3299430SRaymond.Chen@Sun.COM 		goto done;
3309430SRaymond.Chen@Sun.COM 	}
3319430SRaymond.Chen@Sun.COM 
3329430SRaymond.Chen@Sun.COM 	wusb_wa_dump_rpipe_descr(descr, mask, handle);
3339430SRaymond.Chen@Sun.COM 
3349430SRaymond.Chen@Sun.COM 	freemsg(data);
3359430SRaymond.Chen@Sun.COM 	data = NULL;
3369430SRaymond.Chen@Sun.COM 
3379430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
3389430SRaymond.Chen@Sun.COM 
3399430SRaymond.Chen@Sun.COM done:
3409430SRaymond.Chen@Sun.COM 	if (data) {
3419430SRaymond.Chen@Sun.COM 		freemsg(data);
3429430SRaymond.Chen@Sun.COM 	}
3439430SRaymond.Chen@Sun.COM 
3449430SRaymond.Chen@Sun.COM 	return (rval);
3459430SRaymond.Chen@Sun.COM }
3469430SRaymond.Chen@Sun.COM 
3479430SRaymond.Chen@Sun.COM /*
3489430SRaymond.Chen@Sun.COM  * Get All the RPipes' descriptors of an HWA
3499430SRaymond.Chen@Sun.COM  *	- WA RPipe descriptor are not returned as part of the
3509430SRaymond.Chen@Sun.COM  *	cofiguration descriptor. We have to get it separately.
3519430SRaymond.Chen@Sun.COM  *	- See section 8.4.3.19 and 8.5.2.11
3529430SRaymond.Chen@Sun.COM  */
3539430SRaymond.Chen@Sun.COM int
wusb_wa_get_rpipe_descrs(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph,uint_t mask,usb_log_handle_t handle)3549430SRaymond.Chen@Sun.COM wusb_wa_get_rpipe_descrs(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
3559430SRaymond.Chen@Sun.COM 	uint_t mask, usb_log_handle_t handle)
3569430SRaymond.Chen@Sun.COM {
3579430SRaymond.Chen@Sun.COM 	dev_info_t	*dip = wa_data->wa_dip;
3589430SRaymond.Chen@Sun.COM 	int		i, rval;
3599430SRaymond.Chen@Sun.COM 
3609430SRaymond.Chen@Sun.COM 	if ((dip == NULL) || (ph == NULL)) {
3619430SRaymond.Chen@Sun.COM 
3629430SRaymond.Chen@Sun.COM 		return (USB_INVALID_ARGS);
3639430SRaymond.Chen@Sun.COM 	}
3649430SRaymond.Chen@Sun.COM 
3659797SRaymond.Chen@Sun.COM 	/* called at initialization, no other threads yet */
3669797SRaymond.Chen@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data));
3679797SRaymond.Chen@Sun.COM 
3689430SRaymond.Chen@Sun.COM 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
3699430SRaymond.Chen@Sun.COM 		rval = wusb_wa_get_rpipe_descr(dip, ph, i,
3709430SRaymond.Chen@Sun.COM 		    &wa_data->wa_rpipe_hdl[i].rp_descr, mask, handle);
3719430SRaymond.Chen@Sun.COM 
3729430SRaymond.Chen@Sun.COM 		if (rval != USB_SUCCESS) {
3739430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L2(mask, handle,
3749430SRaymond.Chen@Sun.COM 			    "wusb_wa_get_rpipe_descrs: fail to get rpipe "
3759430SRaymond.Chen@Sun.COM 			    "descr for idx %d", i);
3769430SRaymond.Chen@Sun.COM 
3779430SRaymond.Chen@Sun.COM 			return (rval);
3789430SRaymond.Chen@Sun.COM 		}
3799430SRaymond.Chen@Sun.COM 	}
3809797SRaymond.Chen@Sun.COM 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data));
3819430SRaymond.Chen@Sun.COM 
3829430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
3839430SRaymond.Chen@Sun.COM }
3849430SRaymond.Chen@Sun.COM 
3859430SRaymond.Chen@Sun.COM /*
3869430SRaymond.Chen@Sun.COM  * Get Wire Adapter's Status
3879430SRaymond.Chen@Sun.COM  *	See section 8.3.1.6
3889430SRaymond.Chen@Sun.COM  */
3899430SRaymond.Chen@Sun.COM int
wusb_get_wa_status(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph,uint32_t * status)3909430SRaymond.Chen@Sun.COM wusb_get_wa_status(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
3919430SRaymond.Chen@Sun.COM 	uint32_t *status)
3929430SRaymond.Chen@Sun.COM {
3939430SRaymond.Chen@Sun.COM 	dev_info_t	*dip = wa_data->wa_dip;
3949430SRaymond.Chen@Sun.COM 	int		rval = USB_SUCCESS;
3959430SRaymond.Chen@Sun.COM 	mblk_t		*data = NULL;
3969430SRaymond.Chen@Sun.COM 	usb_cr_t	completion_reason;
3979430SRaymond.Chen@Sun.COM 	usb_cb_flags_t	cb_flags;
3989430SRaymond.Chen@Sun.COM 
3999430SRaymond.Chen@Sun.COM 	if ((dip == NULL) || (ph == NULL)) {
4009430SRaymond.Chen@Sun.COM 
4019430SRaymond.Chen@Sun.COM 		return (USB_INVALID_ARGS);
4029430SRaymond.Chen@Sun.COM 	}
4039430SRaymond.Chen@Sun.COM 
4049430SRaymond.Chen@Sun.COM 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
4059430SRaymond.Chen@Sun.COM 	    WUSB_CLASS_IF_REQ_IN_TYPE,
4069430SRaymond.Chen@Sun.COM 	    USB_REQ_GET_STATUS,
4079430SRaymond.Chen@Sun.COM 	    0,
4089430SRaymond.Chen@Sun.COM 	    wa_data->wa_ifno,
4099430SRaymond.Chen@Sun.COM 	    WA_GET_WA_STATUS_LEN,
4109430SRaymond.Chen@Sun.COM 	    &data, 0,
4119430SRaymond.Chen@Sun.COM 	    &completion_reason, &cb_flags, 0);
4129430SRaymond.Chen@Sun.COM 
4139430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
4149430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
4159430SRaymond.Chen@Sun.COM 		    "wusb_get_wa_status: can't retrieve status");
4169430SRaymond.Chen@Sun.COM 
4179430SRaymond.Chen@Sun.COM 		goto done;
4189430SRaymond.Chen@Sun.COM 	}
4199430SRaymond.Chen@Sun.COM 
4209430SRaymond.Chen@Sun.COM 	*status = (*(data->b_rptr + 3) << 24) | (*(data->b_rptr + 2) << 16) |
4219430SRaymond.Chen@Sun.COM 	    (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
4229430SRaymond.Chen@Sun.COM 
4239430SRaymond.Chen@Sun.COM done:
4249430SRaymond.Chen@Sun.COM 	if (data) {
4259430SRaymond.Chen@Sun.COM 		freemsg(data);
4269430SRaymond.Chen@Sun.COM 	}
4279430SRaymond.Chen@Sun.COM 
4289430SRaymond.Chen@Sun.COM 	return (rval);
4299430SRaymond.Chen@Sun.COM }
4309430SRaymond.Chen@Sun.COM 
4319430SRaymond.Chen@Sun.COM /*
4329430SRaymond.Chen@Sun.COM  * Reset WA
4339430SRaymond.Chen@Sun.COM  *	See 8.3.1.9
4349430SRaymond.Chen@Sun.COM  */
4359430SRaymond.Chen@Sun.COM int
wusb_wa_reset(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph)4369430SRaymond.Chen@Sun.COM wusb_wa_reset(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
4379430SRaymond.Chen@Sun.COM {
4389430SRaymond.Chen@Sun.COM 	dev_info_t	*dip = wa_data->wa_dip;
4399430SRaymond.Chen@Sun.COM 	usb_cr_t	completion_reason;
4409430SRaymond.Chen@Sun.COM 	usb_cb_flags_t	cb_flags;
4419430SRaymond.Chen@Sun.COM 	int		rval, i;
4429430SRaymond.Chen@Sun.COM 	uint32_t	status;
4439430SRaymond.Chen@Sun.COM 
4449430SRaymond.Chen@Sun.COM 	if ((dip == NULL) || (ph == NULL)) {
4459430SRaymond.Chen@Sun.COM 
4469430SRaymond.Chen@Sun.COM 		return (USB_INVALID_ARGS);
4479430SRaymond.Chen@Sun.COM 	}
4489430SRaymond.Chen@Sun.COM 
4499430SRaymond.Chen@Sun.COM 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
4509430SRaymond.Chen@Sun.COM 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
4519430SRaymond.Chen@Sun.COM 	    USB_REQ_SET_FEATURE,
4529430SRaymond.Chen@Sun.COM 	    WA_DEV_RESET,
4539430SRaymond.Chen@Sun.COM 	    wa_data->wa_ifno,
4549430SRaymond.Chen@Sun.COM 	    0,
4559430SRaymond.Chen@Sun.COM 	    NULL, 0,
4569430SRaymond.Chen@Sun.COM 	    &completion_reason, &cb_flags, 0);
4579430SRaymond.Chen@Sun.COM 
4589430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
4599430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
4609430SRaymond.Chen@Sun.COM 		    "wusb_wa_reset: can't reset wa, rval = %d, cr=%d", rval,
4619430SRaymond.Chen@Sun.COM 		    completion_reason);
4629430SRaymond.Chen@Sun.COM 
4639430SRaymond.Chen@Sun.COM 		return (rval);
4649430SRaymond.Chen@Sun.COM 	}
4659430SRaymond.Chen@Sun.COM 
4669430SRaymond.Chen@Sun.COM 	for (i = 0; i < 10; i++) {
4679430SRaymond.Chen@Sun.COM 		delay(drv_usectohz(50000));
4689430SRaymond.Chen@Sun.COM 
4699430SRaymond.Chen@Sun.COM 		rval = wusb_get_wa_status(wa_data, ph, &status);
4709430SRaymond.Chen@Sun.COM 		if (rval != USB_SUCCESS) {
4719430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
4729430SRaymond.Chen@Sun.COM 			    "wusb_wa_reset: can't get status, rval = %d",
4739430SRaymond.Chen@Sun.COM 			    rval);
4749430SRaymond.Chen@Sun.COM 
4759430SRaymond.Chen@Sun.COM 			return (rval);
4769430SRaymond.Chen@Sun.COM 		}
4779430SRaymond.Chen@Sun.COM 
4789430SRaymond.Chen@Sun.COM 		if (!(status & WA_HC_RESET_IN_PROGRESS)) {
4799430SRaymond.Chen@Sun.COM 
4809430SRaymond.Chen@Sun.COM 			return (USB_SUCCESS);
4819430SRaymond.Chen@Sun.COM 		}
4829430SRaymond.Chen@Sun.COM 	}
4839430SRaymond.Chen@Sun.COM 
4849430SRaymond.Chen@Sun.COM 	return (USB_FAILURE);
4859430SRaymond.Chen@Sun.COM }
4869430SRaymond.Chen@Sun.COM 
4879430SRaymond.Chen@Sun.COM /*
4889430SRaymond.Chen@Sun.COM  * Enable wire adapter.
4899430SRaymond.Chen@Sun.COM  *	See 8.3.1.9
4909430SRaymond.Chen@Sun.COM  */
4919430SRaymond.Chen@Sun.COM int
wusb_wa_enable(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph)4929430SRaymond.Chen@Sun.COM wusb_wa_enable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
4939430SRaymond.Chen@Sun.COM {
4949430SRaymond.Chen@Sun.COM 	dev_info_t	*dip = wa_data->wa_dip;
4959430SRaymond.Chen@Sun.COM 	usb_cr_t	completion_reason;
4969430SRaymond.Chen@Sun.COM 	usb_cb_flags_t	cb_flags;
4979430SRaymond.Chen@Sun.COM 	int		rval, i;
4989430SRaymond.Chen@Sun.COM 	uint32_t	status;
4999430SRaymond.Chen@Sun.COM 
5009430SRaymond.Chen@Sun.COM 	if ((dip == NULL) || (ph == NULL)) {
5019430SRaymond.Chen@Sun.COM 
5029430SRaymond.Chen@Sun.COM 		return (USB_INVALID_ARGS);
5039430SRaymond.Chen@Sun.COM 	}
5049430SRaymond.Chen@Sun.COM 
5059430SRaymond.Chen@Sun.COM 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
5069430SRaymond.Chen@Sun.COM 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
5079430SRaymond.Chen@Sun.COM 	    USB_REQ_SET_FEATURE,
5089430SRaymond.Chen@Sun.COM 	    WA_DEV_ENABLE,
5099430SRaymond.Chen@Sun.COM 	    wa_data->wa_ifno,
5109430SRaymond.Chen@Sun.COM 	    0,
5119430SRaymond.Chen@Sun.COM 	    NULL, 0,
5129430SRaymond.Chen@Sun.COM 	    &completion_reason, &cb_flags, 0);
5139430SRaymond.Chen@Sun.COM 
5149430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
5159430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
5169430SRaymond.Chen@Sun.COM 		    "wusb_wa_enable: can't enable WA, rval = %d, cr=%d",
5179430SRaymond.Chen@Sun.COM 		    rval, completion_reason);
5189430SRaymond.Chen@Sun.COM 
5199430SRaymond.Chen@Sun.COM 		return (rval);
5209430SRaymond.Chen@Sun.COM 	}
5219430SRaymond.Chen@Sun.COM 
5229430SRaymond.Chen@Sun.COM 	for (i = 0; i < 10; i++) {
5239430SRaymond.Chen@Sun.COM 		delay(drv_usectohz(50000));
5249430SRaymond.Chen@Sun.COM 
5259430SRaymond.Chen@Sun.COM 		rval = wusb_get_wa_status(wa_data, ph, &status);
5269430SRaymond.Chen@Sun.COM 		if (rval != USB_SUCCESS) {
5279430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
5289430SRaymond.Chen@Sun.COM 			    "wusb_wa_enable: can't get status, rval = %d",
5299430SRaymond.Chen@Sun.COM 			    rval);
5309430SRaymond.Chen@Sun.COM 
5319430SRaymond.Chen@Sun.COM 			return (rval);
5329430SRaymond.Chen@Sun.COM 		}
5339430SRaymond.Chen@Sun.COM 
5349430SRaymond.Chen@Sun.COM 		if (status & WA_HC_ENABLED) {
5359430SRaymond.Chen@Sun.COM 
5369430SRaymond.Chen@Sun.COM 			return (USB_SUCCESS);
5379430SRaymond.Chen@Sun.COM 		}
5389430SRaymond.Chen@Sun.COM 	}
5399430SRaymond.Chen@Sun.COM 
5409430SRaymond.Chen@Sun.COM 	return (USB_FAILURE);
5419430SRaymond.Chen@Sun.COM }
5429430SRaymond.Chen@Sun.COM 
5439430SRaymond.Chen@Sun.COM /*
5449430SRaymond.Chen@Sun.COM  * Disable WA. Clear a fearture.
5459430SRaymond.Chen@Sun.COM  *	See Section 8.3.1.3
5469430SRaymond.Chen@Sun.COM  */
5479430SRaymond.Chen@Sun.COM int
wusb_wa_disable(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph)5489430SRaymond.Chen@Sun.COM wusb_wa_disable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
5499430SRaymond.Chen@Sun.COM {
5509430SRaymond.Chen@Sun.COM 	dev_info_t	*dip = wa_data->wa_dip;
5519430SRaymond.Chen@Sun.COM 	usb_cr_t	completion_reason;
5529430SRaymond.Chen@Sun.COM 	usb_cb_flags_t	cb_flags;
5539430SRaymond.Chen@Sun.COM 	int		rval, i;
5549430SRaymond.Chen@Sun.COM 	uint32_t	status;
5559430SRaymond.Chen@Sun.COM 
5569430SRaymond.Chen@Sun.COM 	if ((dip == NULL) || (ph == NULL)) {
5579430SRaymond.Chen@Sun.COM 
5589430SRaymond.Chen@Sun.COM 		return (USB_INVALID_ARGS);
5599430SRaymond.Chen@Sun.COM 	}
5609430SRaymond.Chen@Sun.COM 
5619430SRaymond.Chen@Sun.COM 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
5629430SRaymond.Chen@Sun.COM 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
5639430SRaymond.Chen@Sun.COM 	    USB_REQ_CLEAR_FEATURE,
5649430SRaymond.Chen@Sun.COM 	    WA_DEV_ENABLE,
5659430SRaymond.Chen@Sun.COM 	    wa_data->wa_ifno,
5669430SRaymond.Chen@Sun.COM 	    0,
5679430SRaymond.Chen@Sun.COM 	    NULL, 0,
5689430SRaymond.Chen@Sun.COM 	    &completion_reason, &cb_flags, 0);
5699430SRaymond.Chen@Sun.COM 
5709430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
5719430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
5729430SRaymond.Chen@Sun.COM 		    "wusb_wa_disable: can't disable wa, rval = %d, cr = %d",
5739430SRaymond.Chen@Sun.COM 		    rval, completion_reason);
5749430SRaymond.Chen@Sun.COM 
5759430SRaymond.Chen@Sun.COM 		return (rval);
5769430SRaymond.Chen@Sun.COM 	}
5779430SRaymond.Chen@Sun.COM 
5789430SRaymond.Chen@Sun.COM 	for (i = 0; i < 10; i++) {
5799430SRaymond.Chen@Sun.COM 		delay(drv_usectohz(50000));
5809430SRaymond.Chen@Sun.COM 
5819430SRaymond.Chen@Sun.COM 		rval = wusb_get_wa_status(wa_data, ph, &status);
5829430SRaymond.Chen@Sun.COM 		if (rval != USB_SUCCESS) {
5839430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
5849430SRaymond.Chen@Sun.COM 			    "wusb_wa_disable: can't get status, rval = %d",
5859430SRaymond.Chen@Sun.COM 			    rval);
5869430SRaymond.Chen@Sun.COM 
5879430SRaymond.Chen@Sun.COM 			return (rval);
5889430SRaymond.Chen@Sun.COM 		}
5899430SRaymond.Chen@Sun.COM 
5909430SRaymond.Chen@Sun.COM 		if (!(status & WA_HC_ENABLED)) {
5919430SRaymond.Chen@Sun.COM 
5929430SRaymond.Chen@Sun.COM 			return (USB_SUCCESS);
5939430SRaymond.Chen@Sun.COM 		}
5949430SRaymond.Chen@Sun.COM 	}
5959430SRaymond.Chen@Sun.COM 
5969430SRaymond.Chen@Sun.COM 	return (USB_FAILURE);
5979430SRaymond.Chen@Sun.COM }
5989430SRaymond.Chen@Sun.COM 
5999430SRaymond.Chen@Sun.COM /*
6009430SRaymond.Chen@Sun.COM  * Open the two bulk endpoints and one interrupt IN endpoint, defined in
6019430SRaymond.Chen@Sun.COM  * a WA's data transfer interface. See 8.1.2
6029430SRaymond.Chen@Sun.COM  */
6039430SRaymond.Chen@Sun.COM int
wusb_wa_open_pipes(wusb_wa_data_t * wa_data)6049430SRaymond.Chen@Sun.COM wusb_wa_open_pipes(wusb_wa_data_t *wa_data)
6059430SRaymond.Chen@Sun.COM {
6069430SRaymond.Chen@Sun.COM 	int	rval;
6079430SRaymond.Chen@Sun.COM 
6089430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
6099430SRaymond.Chen@Sun.COM 	if (wa_data->wa_state & WA_PIPES_OPENED) {
6109430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
6119430SRaymond.Chen@Sun.COM 
6129430SRaymond.Chen@Sun.COM 		return (USB_SUCCESS);
6139430SRaymond.Chen@Sun.COM 	}
6149430SRaymond.Chen@Sun.COM 	wa_data->wa_pipe_policy.pp_max_async_reqs = 1;
6159430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
6169430SRaymond.Chen@Sun.COM 
6179430SRaymond.Chen@Sun.COM 	rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_intr_ept,
6189430SRaymond.Chen@Sun.COM 	    &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
6199430SRaymond.Chen@Sun.COM 	    &wa_data->wa_intr_ph);
6209430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
6219430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
6229430SRaymond.Chen@Sun.COM 		    "wusb_wa_open_pipes: can't open intr pipe, rval = %d",
6239430SRaymond.Chen@Sun.COM 		    rval);
6249430SRaymond.Chen@Sun.COM 
6259430SRaymond.Chen@Sun.COM 		return (rval);
6269430SRaymond.Chen@Sun.COM 	}
6279430SRaymond.Chen@Sun.COM 
6289430SRaymond.Chen@Sun.COM 	rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkin_ept,
6299430SRaymond.Chen@Sun.COM 	    &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
6309430SRaymond.Chen@Sun.COM 	    &wa_data->wa_bulkin_ph);
6319430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
6329430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
6339430SRaymond.Chen@Sun.COM 		    "wusb_wa_open_pipes: can't open bulkin pipe, rval = %d",
6349430SRaymond.Chen@Sun.COM 		    rval);
6359430SRaymond.Chen@Sun.COM 
6369430SRaymond.Chen@Sun.COM 		usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
6379430SRaymond.Chen@Sun.COM 		    USB_FLAGS_SLEEP, NULL, NULL);
6389430SRaymond.Chen@Sun.COM 		mutex_enter(&wa_data->wa_mutex);
6399430SRaymond.Chen@Sun.COM 		wa_data->wa_intr_ph = NULL;
6409430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
6419430SRaymond.Chen@Sun.COM 
6429430SRaymond.Chen@Sun.COM 		return (rval);
6439430SRaymond.Chen@Sun.COM 	}
6449430SRaymond.Chen@Sun.COM 
6459430SRaymond.Chen@Sun.COM 	rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkout_ept,
6469430SRaymond.Chen@Sun.COM 	    &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
6479430SRaymond.Chen@Sun.COM 	    &wa_data->wa_bulkout_ph);
6489430SRaymond.Chen@Sun.COM 
6499430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
6509430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
6519430SRaymond.Chen@Sun.COM 		    "wusb_wa_open_pipes: can't open bulkout pipe, rval = %d",
6529430SRaymond.Chen@Sun.COM 		    rval);
6539430SRaymond.Chen@Sun.COM 
6549430SRaymond.Chen@Sun.COM 		usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
6559430SRaymond.Chen@Sun.COM 		    USB_FLAGS_SLEEP, NULL, NULL);
6569430SRaymond.Chen@Sun.COM 		usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph,
6579430SRaymond.Chen@Sun.COM 		    USB_FLAGS_SLEEP, NULL, NULL);
6589430SRaymond.Chen@Sun.COM 		mutex_enter(&wa_data->wa_mutex);
6599430SRaymond.Chen@Sun.COM 		wa_data->wa_intr_ph = NULL;
6609430SRaymond.Chen@Sun.COM 		wa_data->wa_bulkin_ph = NULL;
6619430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
6629430SRaymond.Chen@Sun.COM 
6639430SRaymond.Chen@Sun.COM 		return (rval);
6649430SRaymond.Chen@Sun.COM 	}
6659430SRaymond.Chen@Sun.COM 
6669430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
6679430SRaymond.Chen@Sun.COM 	/* mark the state stopped until listening is started on the pipes */
6689430SRaymond.Chen@Sun.COM 	wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED;
6699430SRaymond.Chen@Sun.COM 	wa_data->wa_bulkin_pipe_state = WA_PIPE_STOPPED;
6709430SRaymond.Chen@Sun.COM 	/* no listening on this pipe, just mark it active */
6719430SRaymond.Chen@Sun.COM 	wa_data->wa_bulkout_pipe_state = WA_PIPE_ACTIVE;
6729430SRaymond.Chen@Sun.COM 	wa_data->wa_state |= WA_PIPES_OPENED;
6739430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
6749430SRaymond.Chen@Sun.COM 
6759430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
6769430SRaymond.Chen@Sun.COM }
6779430SRaymond.Chen@Sun.COM 
6789430SRaymond.Chen@Sun.COM /*
6799430SRaymond.Chen@Sun.COM  * Close WA's pipes.
6809430SRaymond.Chen@Sun.COM  */
6819430SRaymond.Chen@Sun.COM void
wusb_wa_close_pipes(wusb_wa_data_t * wa_data)6829430SRaymond.Chen@Sun.COM wusb_wa_close_pipes(wusb_wa_data_t *wa_data)
6839430SRaymond.Chen@Sun.COM {
6849430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
6859430SRaymond.Chen@Sun.COM 	if ((wa_data->wa_state & WA_PIPES_OPENED) == 0) {
6869430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
6879430SRaymond.Chen@Sun.COM 
6889430SRaymond.Chen@Sun.COM 		return;
6899430SRaymond.Chen@Sun.COM 	}
6909430SRaymond.Chen@Sun.COM 
6919430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
6929430SRaymond.Chen@Sun.COM 
6939430SRaymond.Chen@Sun.COM 	usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
6949430SRaymond.Chen@Sun.COM 	    USB_FLAGS_SLEEP, NULL, NULL);
6959430SRaymond.Chen@Sun.COM 
6969430SRaymond.Chen@Sun.COM 	if (wa_data->wa_bulkin_ph != NULL) {
6979430SRaymond.Chen@Sun.COM 		usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph,
6989430SRaymond.Chen@Sun.COM 		    USB_FLAGS_SLEEP, NULL, NULL);
6999430SRaymond.Chen@Sun.COM 	}
7009430SRaymond.Chen@Sun.COM 
7019430SRaymond.Chen@Sun.COM 	usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkout_ph,
7029430SRaymond.Chen@Sun.COM 	    USB_FLAGS_SLEEP, NULL, NULL);
7039430SRaymond.Chen@Sun.COM 
7049430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
7059430SRaymond.Chen@Sun.COM 	wa_data->wa_intr_ph = NULL;
7069430SRaymond.Chen@Sun.COM 	wa_data->wa_bulkin_ph = NULL;
7079430SRaymond.Chen@Sun.COM 	wa_data->wa_bulkout_ph = NULL;
7089430SRaymond.Chen@Sun.COM 	wa_data->wa_intr_pipe_state = WA_PIPE_CLOSED;
7099430SRaymond.Chen@Sun.COM 	wa_data->wa_bulkin_pipe_state = WA_PIPE_CLOSED;
7109430SRaymond.Chen@Sun.COM 	wa_data->wa_bulkout_pipe_state = WA_PIPE_CLOSED;
7119430SRaymond.Chen@Sun.COM 	wa_data->wa_state &= ~WA_PIPES_OPENED;
7129430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
7139430SRaymond.Chen@Sun.COM }
7149430SRaymond.Chen@Sun.COM 
7159430SRaymond.Chen@Sun.COM /*
7169430SRaymond.Chen@Sun.COM  * start listening for transfer completion notifications or device
7179430SRaymond.Chen@Sun.COM  * notifications on the notification ept
7189430SRaymond.Chen@Sun.COM  */
7199430SRaymond.Chen@Sun.COM int
wusb_wa_start_nep(wusb_wa_data_t * wa_data,usb_flags_t flag)7209430SRaymond.Chen@Sun.COM wusb_wa_start_nep(wusb_wa_data_t *wa_data, usb_flags_t flag)
7219430SRaymond.Chen@Sun.COM {
7229430SRaymond.Chen@Sun.COM 	int		rval;
7239430SRaymond.Chen@Sun.COM 	usb_intr_req_t	*reqp;
7249430SRaymond.Chen@Sun.COM 
7259430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
7269430SRaymond.Chen@Sun.COM 	if ((wa_data->wa_intr_ph == NULL) ||
7279430SRaymond.Chen@Sun.COM 	    (wa_data->wa_intr_pipe_state != WA_PIPE_STOPPED)) {
7289430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
7299430SRaymond.Chen@Sun.COM 
7309430SRaymond.Chen@Sun.COM 		return (USB_INVALID_PIPE);
7319430SRaymond.Chen@Sun.COM 	}
7329430SRaymond.Chen@Sun.COM 
7339430SRaymond.Chen@Sun.COM 	reqp = usb_alloc_intr_req(wa_data->wa_dip, 0, flag);
7349430SRaymond.Chen@Sun.COM 	if (!reqp) {
7359430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
7369430SRaymond.Chen@Sun.COM 
7379430SRaymond.Chen@Sun.COM 		return (USB_NO_RESOURCES);
7389430SRaymond.Chen@Sun.COM 	}
7399430SRaymond.Chen@Sun.COM 
7409430SRaymond.Chen@Sun.COM 	reqp->intr_client_private = (usb_opaque_t)wa_data;
7419430SRaymond.Chen@Sun.COM 	reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
7429430SRaymond.Chen@Sun.COM 	    USB_ATTRS_AUTOCLEARING;
7439430SRaymond.Chen@Sun.COM 	reqp->intr_len = wa_data->wa_intr_ept.wMaxPacketSize;
7449430SRaymond.Chen@Sun.COM 	reqp->intr_cb = wa_data->intr_cb;
7459430SRaymond.Chen@Sun.COM 	reqp->intr_exc_cb = wa_data->intr_exc_cb;
7469430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
7479430SRaymond.Chen@Sun.COM 
7489430SRaymond.Chen@Sun.COM 	if ((rval = usb_pipe_intr_xfer(wa_data->wa_intr_ph, reqp,
7499430SRaymond.Chen@Sun.COM 	    flag)) != USB_SUCCESS) {
7509430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
7519430SRaymond.Chen@Sun.COM 		    "wusb_wa_start_nep: intr xfer fail, rval = %d",
7529430SRaymond.Chen@Sun.COM 		    rval);
7539430SRaymond.Chen@Sun.COM 
7549430SRaymond.Chen@Sun.COM 		usb_free_intr_req(reqp);
7559430SRaymond.Chen@Sun.COM 
7569430SRaymond.Chen@Sun.COM 		return (rval);
7579430SRaymond.Chen@Sun.COM 	}
7589430SRaymond.Chen@Sun.COM 
7599430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
7609430SRaymond.Chen@Sun.COM 	/* pipe state is active while the listening is on */
7619430SRaymond.Chen@Sun.COM 	wa_data->wa_intr_pipe_state = WA_PIPE_ACTIVE;
7629430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
7639430SRaymond.Chen@Sun.COM 
7649430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
7659430SRaymond.Chen@Sun.COM }
7669430SRaymond.Chen@Sun.COM 
7679430SRaymond.Chen@Sun.COM /*
7689430SRaymond.Chen@Sun.COM  * stop the notification ept from listening
7699430SRaymond.Chen@Sun.COM  */
7709430SRaymond.Chen@Sun.COM void
wusb_wa_stop_nep(wusb_wa_data_t * wa_data)7719430SRaymond.Chen@Sun.COM wusb_wa_stop_nep(wusb_wa_data_t *wa_data)
7729430SRaymond.Chen@Sun.COM {
7739430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
7749430SRaymond.Chen@Sun.COM 	if ((wa_data->wa_intr_ph == NULL) ||
7759430SRaymond.Chen@Sun.COM 	    (wa_data->wa_intr_pipe_state != WA_PIPE_ACTIVE)) {
7769430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
7779430SRaymond.Chen@Sun.COM 
7789430SRaymond.Chen@Sun.COM 		return;
7799430SRaymond.Chen@Sun.COM 	}
7809430SRaymond.Chen@Sun.COM 	wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED;
7819430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
7829430SRaymond.Chen@Sun.COM 	/* stop intr in without closing the pipe */
7839430SRaymond.Chen@Sun.COM 	usb_pipe_stop_intr_polling(wa_data->wa_intr_ph, USB_FLAGS_SLEEP);
7849430SRaymond.Chen@Sun.COM }
7859430SRaymond.Chen@Sun.COM 
7869430SRaymond.Chen@Sun.COM /*
7879430SRaymond.Chen@Sun.COM  * allocate a rpipe for transfers on a pipe
7889430SRaymond.Chen@Sun.COM  *	- Find a free RPipe
7899430SRaymond.Chen@Sun.COM  *
7909430SRaymond.Chen@Sun.COM  * For now, one rpipe is associated with only one usba pipe once
7919430SRaymond.Chen@Sun.COM  * the pipe is opened. In the future, the rpipe needs to be
7929430SRaymond.Chen@Sun.COM  * multiplexed between asynchronous endpoints
7939430SRaymond.Chen@Sun.COM  * input:
7949430SRaymond.Chen@Sun.COM  *	type: 0 - ctrl, 1 - isoc, 2 - bulk, 3 - intr
7959430SRaymond.Chen@Sun.COM  *
7969430SRaymond.Chen@Sun.COM  */
7979430SRaymond.Chen@Sun.COM /* ARGSUSED */
7989430SRaymond.Chen@Sun.COM int
wusb_wa_get_rpipe(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph,uint8_t type,wusb_wa_rpipe_hdl_t ** hdl,uint_t mask,usb_log_handle_t handle)7999430SRaymond.Chen@Sun.COM wusb_wa_get_rpipe(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
8009430SRaymond.Chen@Sun.COM 	uint8_t type, wusb_wa_rpipe_hdl_t **hdl,
8019430SRaymond.Chen@Sun.COM 	uint_t mask, usb_log_handle_t handle)
8029430SRaymond.Chen@Sun.COM {
8039430SRaymond.Chen@Sun.COM 	int			i;
8049430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t	*thdl;
8059430SRaymond.Chen@Sun.COM 	uint8_t			rp_type;
8069430SRaymond.Chen@Sun.COM 	uint8_t			ep_type = 1 << type;
8079430SRaymond.Chen@Sun.COM 
8089430SRaymond.Chen@Sun.COM 	*hdl = NULL;
8099430SRaymond.Chen@Sun.COM 
8109430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
8119430SRaymond.Chen@Sun.COM 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
8129430SRaymond.Chen@Sun.COM 		/* find the first unused rpipe */
8139430SRaymond.Chen@Sun.COM 		thdl = &wa_data->wa_rpipe_hdl[i];
8149430SRaymond.Chen@Sun.COM 		mutex_enter(&thdl->rp_mutex);
8159430SRaymond.Chen@Sun.COM 		if (thdl->rp_state != WA_RPIPE_STATE_FREE) {
8169430SRaymond.Chen@Sun.COM 			mutex_exit(&thdl->rp_mutex);
8179430SRaymond.Chen@Sun.COM 
8189430SRaymond.Chen@Sun.COM 			continue;
8199430SRaymond.Chen@Sun.COM 		}
8209430SRaymond.Chen@Sun.COM 
8219430SRaymond.Chen@Sun.COM 		/* check if the rpipe supports the ept transfer type */
8229430SRaymond.Chen@Sun.COM 		rp_type = (thdl->rp_descr.bmCharacteristics &
8239430SRaymond.Chen@Sun.COM 		    USB_RPIPE_CHA_MASK);
8249430SRaymond.Chen@Sun.COM 		if (rp_type & ep_type) {
8259430SRaymond.Chen@Sun.COM 			thdl->rp_refcnt++;
8269430SRaymond.Chen@Sun.COM 			thdl->rp_state = WA_RPIPE_STATE_IDLE;
8279430SRaymond.Chen@Sun.COM 			thdl->rp_avail_reqs = thdl->rp_descr.wRequests;
8289430SRaymond.Chen@Sun.COM 			*hdl = thdl;
8299430SRaymond.Chen@Sun.COM 			mutex_exit(&thdl->rp_mutex);
8309430SRaymond.Chen@Sun.COM 			mutex_exit(&wa_data->wa_mutex);
8319430SRaymond.Chen@Sun.COM 
8329430SRaymond.Chen@Sun.COM 			return (USB_SUCCESS);
8339430SRaymond.Chen@Sun.COM 		}
8349430SRaymond.Chen@Sun.COM 		mutex_exit(&thdl->rp_mutex);
8359430SRaymond.Chen@Sun.COM 	}
8369430SRaymond.Chen@Sun.COM 
8379430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L2(mask, handle,
8389430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_rpipe: no matching rpipe is found");
8399430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
8409430SRaymond.Chen@Sun.COM 
8419430SRaymond.Chen@Sun.COM 	return (USB_FAILURE);
8429430SRaymond.Chen@Sun.COM }
8439430SRaymond.Chen@Sun.COM 
8449430SRaymond.Chen@Sun.COM /*
8459430SRaymond.Chen@Sun.COM  * Decrease a RPipe's reference count.
8469430SRaymond.Chen@Sun.COM  *	- if count == 0, mark it as free RPipe.
8479430SRaymond.Chen@Sun.COM  */
8489430SRaymond.Chen@Sun.COM int
wusb_wa_release_rpipe(wusb_wa_data_t * wa,wusb_wa_rpipe_hdl_t * hdl)8499430SRaymond.Chen@Sun.COM wusb_wa_release_rpipe(wusb_wa_data_t *wa, wusb_wa_rpipe_hdl_t *hdl)
8509430SRaymond.Chen@Sun.COM {
8519430SRaymond.Chen@Sun.COM 	if (hdl == NULL) {
8529430SRaymond.Chen@Sun.COM 
8539430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
8549430SRaymond.Chen@Sun.COM 	}
8559430SRaymond.Chen@Sun.COM 
8569797SRaymond.Chen@Sun.COM 	mutex_enter(&wa->wa_mutex);
8579430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
8589430SRaymond.Chen@Sun.COM 	if (hdl->rp_refcnt == 0) {
8599430SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
8609797SRaymond.Chen@Sun.COM 		mutex_exit(&wa->wa_mutex);
8619430SRaymond.Chen@Sun.COM 
8629430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
8639430SRaymond.Chen@Sun.COM 	}
8649430SRaymond.Chen@Sun.COM 
8659430SRaymond.Chen@Sun.COM 	if (--hdl->rp_refcnt == 0) {
8669430SRaymond.Chen@Sun.COM 		hdl->rp_state = WA_RPIPE_STATE_FREE;
8679430SRaymond.Chen@Sun.COM 	}
8689430SRaymond.Chen@Sun.COM 
8699430SRaymond.Chen@Sun.COM 	if (hdl->rp_block_chg == 1) {
8709430SRaymond.Chen@Sun.COM 		wa->wa_avail_blocks += hdl->rp_descr.wBlocks;
8719430SRaymond.Chen@Sun.COM 		hdl->rp_descr.wBlocks = 0; /* to prevent misadd upon re-call */
8729430SRaymond.Chen@Sun.COM 		hdl->rp_block_chg = 0;
8739430SRaymond.Chen@Sun.COM 	}
8749430SRaymond.Chen@Sun.COM 
8759430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
8769797SRaymond.Chen@Sun.COM 	mutex_exit(&wa->wa_mutex);
8779430SRaymond.Chen@Sun.COM 
8789430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
8799430SRaymond.Chen@Sun.COM }
8809430SRaymond.Chen@Sun.COM 
8819430SRaymond.Chen@Sun.COM /*
8829430SRaymond.Chen@Sun.COM  * Set a RPipe's Descriptor and make the rpipe configured
8839430SRaymond.Chen@Sun.COM  *	See section 8.3.1.7
8849430SRaymond.Chen@Sun.COM  */
8859430SRaymond.Chen@Sun.COM int
wusb_wa_set_rpipe_descr(dev_info_t * dip,usb_pipe_handle_t ph,usb_wa_rpipe_descr_t * rp_descr)8869430SRaymond.Chen@Sun.COM wusb_wa_set_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph,
8879430SRaymond.Chen@Sun.COM 	usb_wa_rpipe_descr_t *rp_descr)
8889430SRaymond.Chen@Sun.COM {
8899430SRaymond.Chen@Sun.COM 	mblk_t		*data = NULL;
8909430SRaymond.Chen@Sun.COM 	usb_cr_t	completion_reason;
8919430SRaymond.Chen@Sun.COM 	usb_cb_flags_t	cb_flags;
8929430SRaymond.Chen@Sun.COM 	int		rval;
8939430SRaymond.Chen@Sun.COM 	uint8_t		*p;
8949430SRaymond.Chen@Sun.COM 
8959430SRaymond.Chen@Sun.COM 	data = allocb_wait(USB_RPIPE_DESCR_SIZE, BPRI_LO, STR_NOSIG, NULL);
8969430SRaymond.Chen@Sun.COM 	p = data->b_wptr;
8979430SRaymond.Chen@Sun.COM 	p[0] = rp_descr->bLength;
8989430SRaymond.Chen@Sun.COM 	p[1] = rp_descr->bDescriptorType;
8999430SRaymond.Chen@Sun.COM 	p[2] = rp_descr->wRPipeIndex;
9009430SRaymond.Chen@Sun.COM 	p[3] = rp_descr->wRPipeIndex >> 8;
9019430SRaymond.Chen@Sun.COM 	p[4] = rp_descr->wRequests;
9029430SRaymond.Chen@Sun.COM 	p[5] = rp_descr->wRequests >> 8;
9039430SRaymond.Chen@Sun.COM 	p[6] = rp_descr->wBlocks;
9049430SRaymond.Chen@Sun.COM 	p[7] = rp_descr->wBlocks >> 8;
9059430SRaymond.Chen@Sun.COM 	p[8] = rp_descr->wMaxPacketSize;
9069430SRaymond.Chen@Sun.COM 	p[9] = rp_descr->wMaxPacketSize >> 8;
9079430SRaymond.Chen@Sun.COM 	p[10] = rp_descr->wa_value.hwa_value.bMaxBurst;
9089430SRaymond.Chen@Sun.COM 	p[11] = rp_descr->wa_value.hwa_value.bDeviceInfoIndex;
9099430SRaymond.Chen@Sun.COM 	p[12] = rp_descr->bSpeed;
9109430SRaymond.Chen@Sun.COM 	p[13] = rp_descr->bDeviceAddress;
9119430SRaymond.Chen@Sun.COM 	p[14] = rp_descr->bEndpointAddress;
9129430SRaymond.Chen@Sun.COM 	p[15] = rp_descr->bDataSequence;
9139430SRaymond.Chen@Sun.COM 	p[16] = rp_descr->dwCurrentWindow;
9149430SRaymond.Chen@Sun.COM 	p[17] = rp_descr->dwCurrentWindow >> 8;
9159430SRaymond.Chen@Sun.COM 	p[18] = rp_descr->dwCurrentWindow >> 16;
9169430SRaymond.Chen@Sun.COM 	p[19] = rp_descr->dwCurrentWindow >> 24;
9179430SRaymond.Chen@Sun.COM 	p[20] = rp_descr->bMaxDataSequence;
9189430SRaymond.Chen@Sun.COM 	p[21] = rp_descr->bInterval;
9199430SRaymond.Chen@Sun.COM 	p[22] = rp_descr->bOverTheAirInterval;
9209430SRaymond.Chen@Sun.COM 	p[23] = rp_descr->bmAttribute;
9219430SRaymond.Chen@Sun.COM 	p[24] = rp_descr->bmCharacteristics;
9229430SRaymond.Chen@Sun.COM 	p[25] = rp_descr->bmRetryOptions;
9239430SRaymond.Chen@Sun.COM 	p[26] = rp_descr->wNumTransactionErrors;
9249430SRaymond.Chen@Sun.COM 	p[27] = rp_descr->wNumTransactionErrors >> 8;
9259430SRaymond.Chen@Sun.COM 
9269430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
9279430SRaymond.Chen@Sun.COM 	    "wusb_wa_set_rpipe_descr: RPipe Descriptors");
9289430SRaymond.Chen@Sun.COM 	wusb_wa_dump_rpipe_descr(rp_descr, DPRINT_MASK_WHCDI, whcdi_log_handle);
9299430SRaymond.Chen@Sun.COM 
9309430SRaymond.Chen@Sun.COM 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
9319430SRaymond.Chen@Sun.COM 	    WA_CLASS_RPIPE_REQ_OUT_TYPE,
9329430SRaymond.Chen@Sun.COM 	    USB_REQ_SET_DESCR,
9339430SRaymond.Chen@Sun.COM 	    USB_DESCR_TYPE_RPIPE << 8,
9349430SRaymond.Chen@Sun.COM 	    rp_descr->wRPipeIndex,
9359430SRaymond.Chen@Sun.COM 	    USB_RPIPE_DESCR_SIZE,
9369430SRaymond.Chen@Sun.COM 	    &data, 0,
9379430SRaymond.Chen@Sun.COM 	    &completion_reason, &cb_flags, 0);
9389430SRaymond.Chen@Sun.COM 
9399430SRaymond.Chen@Sun.COM 	freemsg(data);
9409430SRaymond.Chen@Sun.COM 
9419430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
9429430SRaymond.Chen@Sun.COM 	    "wusb_wa_set_rpipe_descr: rval = %d", rval);
9439430SRaymond.Chen@Sun.COM 
9449430SRaymond.Chen@Sun.COM 	return (rval);
9459430SRaymond.Chen@Sun.COM }
9469430SRaymond.Chen@Sun.COM 
9479430SRaymond.Chen@Sun.COM /* ept companion descr for the default ctrl pipe, refer to WUSB 1.0/4.8.1 */
9489430SRaymond.Chen@Sun.COM usb_ep_comp_descr_t ep_comp0 = {
9499430SRaymond.Chen@Sun.COM 	sizeof (usb_ep_comp_descr_t), USB_DESCR_TYPE_WIRELESS_EP_COMP,
9509430SRaymond.Chen@Sun.COM 	1, 2,
9519430SRaymond.Chen@Sun.COM };
9529430SRaymond.Chen@Sun.COM 
9539430SRaymond.Chen@Sun.COM /*
9549430SRaymond.Chen@Sun.COM  * Get the Endpoint Companion Descriptor for the pipe
9559430SRaymond.Chen@Sun.COM  *	ph_data - the specified pipe
9569430SRaymond.Chen@Sun.COM  *	ep_comp - the companion descriptor returned
9579430SRaymond.Chen@Sun.COM  */
9589430SRaymond.Chen@Sun.COM int
wusb_wa_get_ep_comp_descr(usba_pipe_handle_data_t * ph_data,usb_ep_comp_descr_t * ep_comp)9599430SRaymond.Chen@Sun.COM wusb_wa_get_ep_comp_descr(usba_pipe_handle_data_t *ph_data,
9609430SRaymond.Chen@Sun.COM 	usb_ep_comp_descr_t *ep_comp)
9619430SRaymond.Chen@Sun.COM {
9629430SRaymond.Chen@Sun.COM 	usb_ep_descr_t		*ep = &ph_data->p_ep;
9639430SRaymond.Chen@Sun.COM 	usb_client_dev_data_t	*dev_data;
9649430SRaymond.Chen@Sun.COM 	usb_if_data_t		*if_data;
9659430SRaymond.Chen@Sun.COM 	usb_alt_if_data_t	*altif_data;
9669430SRaymond.Chen@Sun.COM 	usb_ep_data_t		*ep_data;
9679430SRaymond.Chen@Sun.COM 	int			i, j;
9689430SRaymond.Chen@Sun.COM 
9699430SRaymond.Chen@Sun.COM 	/* default ctrl endpoint */
9709430SRaymond.Chen@Sun.COM 	if (ep->bEndpointAddress == 0) {
9719430SRaymond.Chen@Sun.COM 		*ep_comp = ep_comp0;
9729430SRaymond.Chen@Sun.COM 
9739430SRaymond.Chen@Sun.COM 		return (USB_SUCCESS);
9749430SRaymond.Chen@Sun.COM 	}
9759430SRaymond.Chen@Sun.COM 
9769430SRaymond.Chen@Sun.COM 	if (usb_get_dev_data(ph_data->p_dip, &dev_data,
9779430SRaymond.Chen@Sun.COM 	    USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
9789430SRaymond.Chen@Sun.COM 
9799430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
9809430SRaymond.Chen@Sun.COM 	}
9819430SRaymond.Chen@Sun.COM 
9829430SRaymond.Chen@Sun.COM 	/* retrieve ept companion descr from the dev data */
9839430SRaymond.Chen@Sun.COM 	if_data = &dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if];
9849430SRaymond.Chen@Sun.COM 	for (i = 0; i < if_data->if_n_alt; i++) {
9859430SRaymond.Chen@Sun.COM 		altif_data = &if_data->if_alt[i];
9869430SRaymond.Chen@Sun.COM 		for (j = 0; j < altif_data->altif_n_ep; j++) {
9879430SRaymond.Chen@Sun.COM 			ep_data = &altif_data->altif_ep[j];
9889430SRaymond.Chen@Sun.COM 			if (memcmp(&ep_data->ep_descr, ep,
9899430SRaymond.Chen@Sun.COM 			    sizeof (usb_ep_descr_t)) == 0) {
9909430SRaymond.Chen@Sun.COM 				*ep_comp = ep_data->ep_comp_descr;
9919430SRaymond.Chen@Sun.COM 				usb_free_dev_data(ph_data->p_dip, dev_data);
9929430SRaymond.Chen@Sun.COM 
9939430SRaymond.Chen@Sun.COM 				return (USB_SUCCESS);
9949430SRaymond.Chen@Sun.COM 			}
9959430SRaymond.Chen@Sun.COM 		}
9969430SRaymond.Chen@Sun.COM 	}
9979430SRaymond.Chen@Sun.COM 	usb_free_dev_data(ph_data->p_dip, dev_data);
9989430SRaymond.Chen@Sun.COM 
9999430SRaymond.Chen@Sun.COM 	return (USB_FAILURE);
10009430SRaymond.Chen@Sun.COM }
10019430SRaymond.Chen@Sun.COM 
10029430SRaymond.Chen@Sun.COM /* to check if the specified PHY speed is supported by the device */
10039430SRaymond.Chen@Sun.COM int
wusb_wa_is_speed_valid(usba_device_t * ud,uint8_t speed)10049430SRaymond.Chen@Sun.COM wusb_wa_is_speed_valid(usba_device_t *ud, uint8_t speed)
10059430SRaymond.Chen@Sun.COM {
10069430SRaymond.Chen@Sun.COM 	usb_uwb_cap_descr_t *uwb_descr = ud->usb_wireless_data->uwb_descr;
10079430SRaymond.Chen@Sun.COM 	uint8_t valid_spd[WUSB_PHY_TX_RATE_RES] = {
10089430SRaymond.Chen@Sun.COM 	    WUSB_DATA_RATE_BIT_53, WUSB_DATA_RATE_BIT_106,
10099430SRaymond.Chen@Sun.COM 	    WUSB_DATA_RATE_BIT_160, WUSB_DATA_RATE_BIT_200,
10109430SRaymond.Chen@Sun.COM 	    WUSB_DATA_RATE_BIT_320, WUSB_DATA_RATE_BIT_400,
10119430SRaymond.Chen@Sun.COM 	    WUSB_DATA_RATE_BIT_480, 0
10129430SRaymond.Chen@Sun.COM 	};
10139430SRaymond.Chen@Sun.COM 
10149430SRaymond.Chen@Sun.COM 	if (speed >= WUSB_PHY_TX_RATE_RES) {
10159430SRaymond.Chen@Sun.COM 
10169430SRaymond.Chen@Sun.COM 		return (0);
10179430SRaymond.Chen@Sun.COM 	}
10189430SRaymond.Chen@Sun.COM 
10199430SRaymond.Chen@Sun.COM 	/* this speed is not supported by the device */
10209430SRaymond.Chen@Sun.COM 	if (valid_spd[speed] != (uwb_descr->wPHYRates & valid_spd[speed])) {
10219430SRaymond.Chen@Sun.COM 
10229430SRaymond.Chen@Sun.COM 		return (0);
10239430SRaymond.Chen@Sun.COM 	}
10249430SRaymond.Chen@Sun.COM 
10259430SRaymond.Chen@Sun.COM 	return (1);
10269430SRaymond.Chen@Sun.COM }
10279430SRaymond.Chen@Sun.COM 
10289430SRaymond.Chen@Sun.COM /*
10299430SRaymond.Chen@Sun.COM  * Set up a RPipe
10309430SRaymond.Chen@Sun.COM  *	- Associate a RPipe and a pipe handle. Hence, an endpoint has
10319430SRaymond.Chen@Sun.COM  *	  RPipe to transfer data.
10329430SRaymond.Chen@Sun.COM  *	- Set this RPipe to bDeviceAddress:bEndpointAddress
10339430SRaymond.Chen@Sun.COM  *
10349430SRaymond.Chen@Sun.COM  *  wa	- wa data
10359430SRaymond.Chen@Sun.COM  *  ph	- wa's default control pipe
10369430SRaymond.Chen@Sun.COM  *  ph_data - client driver's usba pipe to be opened
10379430SRaymond.Chen@Sun.COM  *  hdl	- RPipe handle
10389430SRaymond.Chen@Sun.COM  */
10399430SRaymond.Chen@Sun.COM int
wusb_wa_set_rpipe_target(dev_info_t * dip,wusb_wa_data_t * wa,usb_pipe_handle_t ph,usba_pipe_handle_data_t * ph_data,wusb_wa_rpipe_hdl_t * hdl)10409430SRaymond.Chen@Sun.COM wusb_wa_set_rpipe_target(dev_info_t *dip, wusb_wa_data_t *wa,
10419430SRaymond.Chen@Sun.COM 	usb_pipe_handle_t ph, usba_pipe_handle_data_t *ph_data,
10429430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t *hdl)
10439430SRaymond.Chen@Sun.COM {
10449430SRaymond.Chen@Sun.COM 	int			rval;
10459430SRaymond.Chen@Sun.COM 	usb_ep_comp_descr_t	ep_comp;
10469430SRaymond.Chen@Sun.COM 	usb_ep_descr_t		*ep = &ph_data->p_ep;
10479430SRaymond.Chen@Sun.COM 	usba_device_t		*usba_device;
10489430SRaymond.Chen@Sun.COM 	uint8_t			rp_status;
10499430SRaymond.Chen@Sun.COM 	usb_wa_descr_t		*wa_desc = &wa->wa_descr;
10509430SRaymond.Chen@Sun.COM 	uint16_t		blockcnt;
10519430SRaymond.Chen@Sun.COM 	uint16_t		maxsize;
10529430SRaymond.Chen@Sun.COM 	uint16_t		seg_len;
10539430SRaymond.Chen@Sun.COM 
10549430SRaymond.Chen@Sun.COM 
10559430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
10569430SRaymond.Chen@Sun.COM 	    "wusb_wa_set_rpipe_target: ph_data = 0x%p rp_hdl = 0x%p",
10579430SRaymond.Chen@Sun.COM 	    (void*)ph_data, (void*)hdl);
10589430SRaymond.Chen@Sun.COM 
10599430SRaymond.Chen@Sun.COM 	/* Get client device's Endpoint companion descriptor */
10609430SRaymond.Chen@Sun.COM 	if ((rval = wusb_wa_get_ep_comp_descr(ph_data, &ep_comp)) !=
10619430SRaymond.Chen@Sun.COM 	    USB_SUCCESS) {
10629430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10639430SRaymond.Chen@Sun.COM 		    "wusb_wa_set_rpipe_target: get companion ep descr failed,"
10649430SRaymond.Chen@Sun.COM 		    " rval = %d", rval);
10659430SRaymond.Chen@Sun.COM 
10669430SRaymond.Chen@Sun.COM 		return (rval);
10679430SRaymond.Chen@Sun.COM 	}
10689430SRaymond.Chen@Sun.COM 
10699430SRaymond.Chen@Sun.COM 	/* set the rpipe to unconfigured state */
10709430SRaymond.Chen@Sun.COM 	if ((rval = wusb_wa_rpipe_reset(dip, ph_data, hdl, 0)) != USB_SUCCESS) {
10719430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10729430SRaymond.Chen@Sun.COM 		    "wusb_wa_set_rpipe_target: reset rpipe failed, rval = %d",
10739430SRaymond.Chen@Sun.COM 		    rval);
10749430SRaymond.Chen@Sun.COM 
10759430SRaymond.Chen@Sun.COM 		return (rval);
10769430SRaymond.Chen@Sun.COM 	}
10779430SRaymond.Chen@Sun.COM 
10789430SRaymond.Chen@Sun.COM 	if ((rval = wusb_wa_get_rpipe_status(dip, ph,
10799430SRaymond.Chen@Sun.COM 	    hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) {
10809430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10819430SRaymond.Chen@Sun.COM 		    "wusb_wa_set_rpipe_target: get rpipe status failed, "
10829430SRaymond.Chen@Sun.COM 		    "rval = %d", rval);
10839430SRaymond.Chen@Sun.COM 
10849430SRaymond.Chen@Sun.COM 		return (rval);
10859430SRaymond.Chen@Sun.COM 	}
10869430SRaymond.Chen@Sun.COM 
10879430SRaymond.Chen@Sun.COM 	if (rp_status & WA_RPIPE_CONFIGURED) {
10889430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10899430SRaymond.Chen@Sun.COM 		    "wusb_wa_set_rpipe_target: reset rpipe unsuccessful");
10909430SRaymond.Chen@Sun.COM 
10919430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
10929430SRaymond.Chen@Sun.COM 	}
10939430SRaymond.Chen@Sun.COM 
10949797SRaymond.Chen@Sun.COM 	mutex_enter(&wa->wa_mutex);
10959430SRaymond.Chen@Sun.COM 	usba_device = usba_get_usba_device(ph_data->p_dip);
10969430SRaymond.Chen@Sun.COM 
10979430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
10989430SRaymond.Chen@Sun.COM 
10999430SRaymond.Chen@Sun.COM 	/* should be 0x200 for default ctrl pipe, refer to wusb 1.0/4.8.1 */
11009430SRaymond.Chen@Sun.COM 	hdl->rp_descr.wMaxPacketSize = ep->wMaxPacketSize;
11019430SRaymond.Chen@Sun.COM 
11029430SRaymond.Chen@Sun.COM 	/*
11039430SRaymond.Chen@Sun.COM 	 * set rpipe descr values
11049430SRaymond.Chen@Sun.COM 	 *
11059430SRaymond.Chen@Sun.COM 	 * Try to use an average block value first. If it's too small,
11069430SRaymond.Chen@Sun.COM 	 * then try to allocate the minimum block size to accomodate one
11079430SRaymond.Chen@Sun.COM 	 * packet. If the required number of block is not available, return
11089430SRaymond.Chen@Sun.COM 	 * failure.
11099430SRaymond.Chen@Sun.COM 	 */
11109430SRaymond.Chen@Sun.COM 	if (hdl->rp_descr.wBlocks == 0) {
11119430SRaymond.Chen@Sun.COM 		blockcnt = wa_desc->wRPipeMaxBlock/wa_desc->wNumRPipes;
11129430SRaymond.Chen@Sun.COM 		maxsize = 1 << (wa_desc->bRPipeBlockSize - 1);
11139430SRaymond.Chen@Sun.COM 		seg_len = blockcnt * maxsize;
11149430SRaymond.Chen@Sun.COM 
11159430SRaymond.Chen@Sun.COM 		/* alloc enough blocks to accomodate one packet */
11169430SRaymond.Chen@Sun.COM 		if (ep->wMaxPacketSize > seg_len) {
11179430SRaymond.Chen@Sun.COM 			blockcnt = (ep->wMaxPacketSize + maxsize -1)/maxsize;
11189430SRaymond.Chen@Sun.COM 		}
11199430SRaymond.Chen@Sun.COM 
11209430SRaymond.Chen@Sun.COM 		/* WA don't have so many blocks to fulfill this reqirement */
11219430SRaymond.Chen@Sun.COM 		if (wa->wa_avail_blocks < blockcnt) {
11229430SRaymond.Chen@Sun.COM 			mutex_exit(&hdl->rp_mutex);
11239797SRaymond.Chen@Sun.COM 			mutex_exit(&wa->wa_mutex);
11249430SRaymond.Chen@Sun.COM 
11259430SRaymond.Chen@Sun.COM 			return (USB_FAILURE);
11269430SRaymond.Chen@Sun.COM 		}
11279430SRaymond.Chen@Sun.COM 
11289430SRaymond.Chen@Sun.COM 		/* we're satisfied */
11299430SRaymond.Chen@Sun.COM 		hdl->rp_descr.wBlocks = blockcnt;
11309430SRaymond.Chen@Sun.COM 		hdl->rp_block_chg = 1; /* the wBlocks is changed */
11319430SRaymond.Chen@Sun.COM 		wa->wa_avail_blocks -= blockcnt;
11329430SRaymond.Chen@Sun.COM 	}
11339430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
11349430SRaymond.Chen@Sun.COM 	    "wusb_wa_set_rpipe_target: wBlocks=%d, maxblock=%d, numR=%d, av=%d",
11359430SRaymond.Chen@Sun.COM 	    hdl->rp_descr.wBlocks, wa_desc->wRPipeMaxBlock, wa_desc->wNumRPipes,
11369430SRaymond.Chen@Sun.COM 	    wa->wa_avail_blocks);
11379430SRaymond.Chen@Sun.COM 
11389430SRaymond.Chen@Sun.COM 	hdl->rp_descr.wa_value.hwa_value.bMaxBurst = ep_comp.bMaxBurst;
11399430SRaymond.Chen@Sun.COM 
11409430SRaymond.Chen@Sun.COM 	/*
11419430SRaymond.Chen@Sun.COM 	 * DEVICE INDEX
11429430SRaymond.Chen@Sun.COM 	 * device info index should be zero based, refer
11439430SRaymond.Chen@Sun.COM 	 * to WUSB 1.0/8.5.3.7
11449430SRaymond.Chen@Sun.COM 	 */
11459430SRaymond.Chen@Sun.COM 	hdl->rp_descr.wa_value.hwa_value.bDeviceInfoIndex =
11469430SRaymond.Chen@Sun.COM 	    usba_device->usb_port - 1;
11479430SRaymond.Chen@Sun.COM 
11489430SRaymond.Chen@Sun.COM 	/*
11499430SRaymond.Chen@Sun.COM 	 * default ctrl pipe uses PHY base signaling rate
11509430SRaymond.Chen@Sun.COM 	 * refer to wusb 1.0/4.8.1
11519430SRaymond.Chen@Sun.COM 	 */
11529430SRaymond.Chen@Sun.COM 	if (ep->bEndpointAddress == 0) {
11539430SRaymond.Chen@Sun.COM 		hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_53;
11549430SRaymond.Chen@Sun.COM 	} else {
11559430SRaymond.Chen@Sun.COM 		if (wusb_wa_is_speed_valid(usba_device, rp_default_speed)) {
11569430SRaymond.Chen@Sun.COM 			hdl->rp_descr.bSpeed = rp_default_speed;
11579430SRaymond.Chen@Sun.COM 		} else {
11589430SRaymond.Chen@Sun.COM 			/* use a must-supported speed */
11599430SRaymond.Chen@Sun.COM 			hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_106;
11609430SRaymond.Chen@Sun.COM 		}
11619430SRaymond.Chen@Sun.COM 	}
11629430SRaymond.Chen@Sun.COM 	hdl->rp_descr.bDeviceAddress = usba_device->usb_addr;
11639430SRaymond.Chen@Sun.COM 	hdl->rp_descr.bEndpointAddress = ep->bEndpointAddress;
11649430SRaymond.Chen@Sun.COM 	hdl->rp_descr.bDataSequence = 0;
11659430SRaymond.Chen@Sun.COM 	hdl->rp_descr.dwCurrentWindow = 1;
11669430SRaymond.Chen@Sun.COM 	hdl->rp_descr.bMaxDataSequence = ep_comp.bMaxSequence - 1;
11679430SRaymond.Chen@Sun.COM 	hdl->rp_descr.bInterval = ep->bInterval;
11689430SRaymond.Chen@Sun.COM 	hdl->rp_descr.bOverTheAirInterval = ep_comp.bOverTheAirInterval;
11699430SRaymond.Chen@Sun.COM 	hdl->rp_descr.bmAttribute = ep->bmAttributes & 0x03;
11709430SRaymond.Chen@Sun.COM 	hdl->rp_descr.bmRetryOptions = 0; /* keep retrying */
11719430SRaymond.Chen@Sun.COM 	hdl->rp_descr.wNumTransactionErrors = 0;
11729430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
11739430SRaymond.Chen@Sun.COM 
11749797SRaymond.Chen@Sun.COM 	mutex_exit(&wa->wa_mutex);
11759797SRaymond.Chen@Sun.COM 
11769430SRaymond.Chen@Sun.COM 	/* set rpipe descr */
11779430SRaymond.Chen@Sun.COM 	rval = wusb_wa_set_rpipe_descr(dip, ph, &hdl->rp_descr);
11789430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
11799430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
11809430SRaymond.Chen@Sun.COM 		    "wusb_wa_set_rpipe_target: set rpipe descr failed, "
11819430SRaymond.Chen@Sun.COM 		    "rval = %d", rval);
11829430SRaymond.Chen@Sun.COM 
11839430SRaymond.Chen@Sun.COM 		return (rval);
11849430SRaymond.Chen@Sun.COM 	}
11859430SRaymond.Chen@Sun.COM 
11869430SRaymond.Chen@Sun.COM 	/* check rpipe status, must be configured and idle */
11879430SRaymond.Chen@Sun.COM 	if ((rval = wusb_wa_get_rpipe_status(dip, ph,
11889430SRaymond.Chen@Sun.COM 	    hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) {
11899430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
11909430SRaymond.Chen@Sun.COM 		    "wusb_wa_set_rpipe_target: get rpipe status failed, "
11919430SRaymond.Chen@Sun.COM 		    "rval = %d", rval);
11929430SRaymond.Chen@Sun.COM 
11939430SRaymond.Chen@Sun.COM 		return (rval);
11949430SRaymond.Chen@Sun.COM 	}
11959430SRaymond.Chen@Sun.COM 
11969430SRaymond.Chen@Sun.COM 	if (rp_status != (WA_RPIPE_CONFIGURED | WA_RPIPE_IDLE)) {
11979430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
11989430SRaymond.Chen@Sun.COM 		    "wusb_wa_set_rpipe_target: set rpipe descr unsuccessful");
11999430SRaymond.Chen@Sun.COM 
12009430SRaymond.Chen@Sun.COM 		return (USB_FAILURE);
12019430SRaymond.Chen@Sun.COM 	}
12029430SRaymond.Chen@Sun.COM 
12039430SRaymond.Chen@Sun.COM 	return (rval);
12049430SRaymond.Chen@Sun.COM }
12059430SRaymond.Chen@Sun.COM 
12069430SRaymond.Chen@Sun.COM /*
12079430SRaymond.Chen@Sun.COM  * Abort a RPipe
12089430SRaymond.Chen@Sun.COM  *	- See Section 8.3.1.1
12099430SRaymond.Chen@Sun.COM  *	- Aborts all transfers pending on the given pipe
12109430SRaymond.Chen@Sun.COM  */
12119430SRaymond.Chen@Sun.COM int
wusb_wa_rpipe_abort(dev_info_t * dip,usb_pipe_handle_t ph,wusb_wa_rpipe_hdl_t * hdl)12129430SRaymond.Chen@Sun.COM wusb_wa_rpipe_abort(dev_info_t *dip, usb_pipe_handle_t ph,
12139430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t *hdl)
12149430SRaymond.Chen@Sun.COM {
12159430SRaymond.Chen@Sun.COM 	usb_cr_t	completion_reason;
12169430SRaymond.Chen@Sun.COM 	usb_cb_flags_t	cb_flags;
12179430SRaymond.Chen@Sun.COM 	int		rval;
12189430SRaymond.Chen@Sun.COM 
12199797SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
12209430SRaymond.Chen@Sun.COM 
12219430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
12229430SRaymond.Chen@Sun.COM 	    "wusb_wa_rpipe_abort: rp_hdl = 0x%p", (void *)hdl);
12239430SRaymond.Chen@Sun.COM 
12249430SRaymond.Chen@Sun.COM 	/* only abort when there is active transfer */
12259430SRaymond.Chen@Sun.COM 	if (hdl->rp_state != WA_RPIPE_STATE_ACTIVE) {
12269797SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
12279430SRaymond.Chen@Sun.COM 
12289430SRaymond.Chen@Sun.COM 		return (USB_SUCCESS);
12299430SRaymond.Chen@Sun.COM 	}
12309430SRaymond.Chen@Sun.COM 
12319797SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
12329430SRaymond.Chen@Sun.COM 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
12339430SRaymond.Chen@Sun.COM 	    WA_CLASS_RPIPE_REQ_OUT_TYPE,
12349430SRaymond.Chen@Sun.COM 	    WA_REQ_ABORT_RPIPE,
12359430SRaymond.Chen@Sun.COM 	    0,
12369430SRaymond.Chen@Sun.COM 	    hdl->rp_descr.wRPipeIndex,
12379430SRaymond.Chen@Sun.COM 	    0,
12389430SRaymond.Chen@Sun.COM 	    NULL, 0,
12399430SRaymond.Chen@Sun.COM 	    &completion_reason, &cb_flags, 0);
12409430SRaymond.Chen@Sun.COM 
12419430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
12429430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
12439430SRaymond.Chen@Sun.COM 		    "wusb_wa_rpipe_abort: abort failed, rval = %d", rval);
12449430SRaymond.Chen@Sun.COM 
12459430SRaymond.Chen@Sun.COM 		return (rval);
12469430SRaymond.Chen@Sun.COM 	}
12479430SRaymond.Chen@Sun.COM 
12489430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
12499430SRaymond.Chen@Sun.COM }
12509430SRaymond.Chen@Sun.COM 
12519430SRaymond.Chen@Sun.COM /*
12529430SRaymond.Chen@Sun.COM  * Clear status on the remote device's endpoint, specifically clear the
12539430SRaymond.Chen@Sun.COM  * RPipe's target endpoint sequence number. See 4.5.3, 4.6.4 and Tab.8-49
12549430SRaymond.Chen@Sun.COM  * for reference of data sequence.
12559430SRaymond.Chen@Sun.COM  *
12569430SRaymond.Chen@Sun.COM  * NOTE AGAIN:
12579430SRaymond.Chen@Sun.COM  * The device endpoint will not respond to host request if the RPipe is
12589430SRaymond.Chen@Sun.COM  * reset or re-targeted, while device endpoint is not reset!
12599430SRaymond.Chen@Sun.COM  */
12609430SRaymond.Chen@Sun.COM void
wusb_wa_clear_dev_ep(usba_pipe_handle_data_t * ph)12619430SRaymond.Chen@Sun.COM wusb_wa_clear_dev_ep(usba_pipe_handle_data_t *ph)
12629430SRaymond.Chen@Sun.COM {
12639430SRaymond.Chen@Sun.COM 	uint8_t	ept_addr;
12649430SRaymond.Chen@Sun.COM 
12659430SRaymond.Chen@Sun.COM 	if (ph == NULL) {
12669430SRaymond.Chen@Sun.COM 		return;
12679430SRaymond.Chen@Sun.COM 	}
12689430SRaymond.Chen@Sun.COM 
12699430SRaymond.Chen@Sun.COM 	ept_addr = ph->p_ep.bEndpointAddress;
12709430SRaymond.Chen@Sun.COM 
12719430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(PRINT_MASK_HCDI, whcdi_log_handle,
12729430SRaymond.Chen@Sun.COM 	    "wusb_wa_clear_dev_ep:clear endpoint = 0x%02x", ept_addr);
12739430SRaymond.Chen@Sun.COM 	if (ept_addr != 0) {
12749430SRaymond.Chen@Sun.COM 	/* only clear non-default endpoints */
127510912SRaymond.Chen@Sun.COM 		(void) usb_clr_feature(ph->p_dip, USB_DEV_REQ_RCPT_EP, 0,
127610912SRaymond.Chen@Sun.COM 		    ept_addr, USB_FLAGS_SLEEP, NULL, NULL);
12779430SRaymond.Chen@Sun.COM 	}
12789430SRaymond.Chen@Sun.COM }
12799430SRaymond.Chen@Sun.COM 
12809430SRaymond.Chen@Sun.COM /*
12819430SRaymond.Chen@Sun.COM  * Reset a RPipe
12829430SRaymond.Chen@Sun.COM  *	- Reset a RPipe to a known state
12839430SRaymond.Chen@Sun.COM  *	- Pending transfers must be drained or aborted before this
12849430SRaymond.Chen@Sun.COM  *	  operation.
12859430SRaymond.Chen@Sun.COM  *	- See Section 8.3.1.10
12869430SRaymond.Chen@Sun.COM  *
12879430SRaymond.Chen@Sun.COM  *  dip - the WA's devinfo
12889430SRaymond.Chen@Sun.COM  *  ph	- RPipe's targeted remote device's endpoint pipe.
12899430SRaymond.Chen@Sun.COM  *  hdl - RPipe's handle
12909430SRaymond.Chen@Sun.COM  *
12919430SRaymond.Chen@Sun.COM  *  flag = 1, reset the RPipe descriptor to its initial state and
12929430SRaymond.Chen@Sun.COM  *	   also clear remote device endpoint
12939430SRaymond.Chen@Sun.COM  *	 = 0, not reset the RPipe descriptor. Caller should use 0 flag
12949430SRaymond.Chen@Sun.COM  *	  if it's the first time to open a pipe, because we don't have
12959430SRaymond.Chen@Sun.COM  *	  a valid ph yet before successfully opening a pipe by using
12969430SRaymond.Chen@Sun.COM  *	  usb_pipe_open().
12979430SRaymond.Chen@Sun.COM  */
12989430SRaymond.Chen@Sun.COM int
wusb_wa_rpipe_reset(dev_info_t * dip,usba_pipe_handle_data_t * ph,wusb_wa_rpipe_hdl_t * hdl,int flag)12999430SRaymond.Chen@Sun.COM wusb_wa_rpipe_reset(dev_info_t *dip, usba_pipe_handle_data_t *ph,
13009430SRaymond.Chen@Sun.COM     wusb_wa_rpipe_hdl_t *hdl, int flag)
13019430SRaymond.Chen@Sun.COM {
13029430SRaymond.Chen@Sun.COM 	int		rval = 0;
13039430SRaymond.Chen@Sun.COM 	usb_cr_t	completion_reason;
13049430SRaymond.Chen@Sun.COM 	usb_cb_flags_t	cb_flags = 0;
13059430SRaymond.Chen@Sun.COM 	usb_pipe_handle_t	default_ph;
13069430SRaymond.Chen@Sun.COM 
13079430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
13089430SRaymond.Chen@Sun.COM 	    "wusb_wa_rpipe_reset: rp_hdl = 0x%p, ep=0x%02x, flag = %d",
13099430SRaymond.Chen@Sun.COM 	    (void *)hdl, ph->p_ep.bEndpointAddress, flag);
13109430SRaymond.Chen@Sun.COM 
13119430SRaymond.Chen@Sun.COM 	/* get WA's default pipe */
13129430SRaymond.Chen@Sun.COM 	default_ph = usba_get_dflt_pipe_handle(dip);
13139430SRaymond.Chen@Sun.COM 
13149430SRaymond.Chen@Sun.COM 	rval = usb_pipe_sync_ctrl_xfer(dip, default_ph,
13159430SRaymond.Chen@Sun.COM 	    WA_CLASS_RPIPE_REQ_OUT_TYPE,
13169430SRaymond.Chen@Sun.COM 	    WA_REQ_RESET_RPIPE,
13179430SRaymond.Chen@Sun.COM 	    0,
13189430SRaymond.Chen@Sun.COM 	    hdl->rp_descr.wRPipeIndex,
13199430SRaymond.Chen@Sun.COM 	    0,
13209430SRaymond.Chen@Sun.COM 	    NULL, 0,
13219430SRaymond.Chen@Sun.COM 	    &completion_reason, &cb_flags, 0);
13229430SRaymond.Chen@Sun.COM 
13239430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
13249430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13259430SRaymond.Chen@Sun.COM 		    "wusb_wa_rpipe_reset: reset failed, rval=%d"
13269430SRaymond.Chen@Sun.COM 		    " cr=%d cb=0x%02x",
13279430SRaymond.Chen@Sun.COM 		    rval, (int)completion_reason, (int)cb_flags);
13289430SRaymond.Chen@Sun.COM 
13299430SRaymond.Chen@Sun.COM 		return (rval);
13309430SRaymond.Chen@Sun.COM 	}
13319430SRaymond.Chen@Sun.COM 
13329430SRaymond.Chen@Sun.COM 	if (flag == 0) {
13339430SRaymond.Chen@Sun.COM 		/* do nothing else, just return, the rpipe is unconfigured */
13349430SRaymond.Chen@Sun.COM 		return (USB_SUCCESS);
13359430SRaymond.Chen@Sun.COM 	}
13369430SRaymond.Chen@Sun.COM 
13379430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
13389430SRaymond.Chen@Sun.COM 	    "wusb_wa_rpipe_reset: need to clear dev pipe and reset RP descr");
13399430SRaymond.Chen@Sun.COM 
13409430SRaymond.Chen@Sun.COM 	/* set rpipe descr and make the rpipe configured */
13419430SRaymond.Chen@Sun.COM 	rval = wusb_wa_set_rpipe_descr(dip, default_ph, &hdl->rp_descr);
13429430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
13439430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13449430SRaymond.Chen@Sun.COM 		    "wusb_wa_rpipe_reset: set descr failed, rval = %d", rval);
13459430SRaymond.Chen@Sun.COM 
13469430SRaymond.Chen@Sun.COM 		return (rval);
13479430SRaymond.Chen@Sun.COM 	}
13489430SRaymond.Chen@Sun.COM 
13499430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
13509430SRaymond.Chen@Sun.COM 	hdl->rp_avail_reqs = hdl->rp_descr.wRequests;
13519430SRaymond.Chen@Sun.COM 	if (hdl->rp_state == WA_RPIPE_STATE_ERROR) {
13529430SRaymond.Chen@Sun.COM 		hdl->rp_state = WA_RPIPE_STATE_IDLE;
13539430SRaymond.Chen@Sun.COM 	}
13549430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
13559430SRaymond.Chen@Sun.COM 
13569430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
13579430SRaymond.Chen@Sun.COM 	    "wusb_wa_rpipe_reset: end");
13589430SRaymond.Chen@Sun.COM 
13599430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
13609430SRaymond.Chen@Sun.COM }
13619430SRaymond.Chen@Sun.COM 
13629430SRaymond.Chen@Sun.COM /* get rpipe status, refer to WUSB 1.0/8.3.1.5 */
13639430SRaymond.Chen@Sun.COM int
wusb_wa_get_rpipe_status(dev_info_t * dip,usb_pipe_handle_t ph,uint16_t idx,uint8_t * status)13649430SRaymond.Chen@Sun.COM wusb_wa_get_rpipe_status(dev_info_t *dip, usb_pipe_handle_t ph, uint16_t idx,
13659430SRaymond.Chen@Sun.COM 	uint8_t	*status)
13669430SRaymond.Chen@Sun.COM {
13679430SRaymond.Chen@Sun.COM 	mblk_t		*data = NULL;
13689430SRaymond.Chen@Sun.COM 	usb_cr_t	completion_reason;
13699430SRaymond.Chen@Sun.COM 	usb_cb_flags_t	cb_flags;
13709430SRaymond.Chen@Sun.COM 	int		rval;
13719430SRaymond.Chen@Sun.COM 
13729430SRaymond.Chen@Sun.COM 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
13739430SRaymond.Chen@Sun.COM 	    WA_CLASS_RPIPE_REQ_IN_TYPE,
13749430SRaymond.Chen@Sun.COM 	    USB_REQ_GET_STATUS,
13759430SRaymond.Chen@Sun.COM 	    0,
13769430SRaymond.Chen@Sun.COM 	    idx,
13779430SRaymond.Chen@Sun.COM 	    1,
13789430SRaymond.Chen@Sun.COM 	    &data, 0,
13799430SRaymond.Chen@Sun.COM 	    &completion_reason, &cb_flags, 0);
13809430SRaymond.Chen@Sun.COM 
13819430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
13829430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13839430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_rpipe_status: fail, rval=%d, cr=%d, "
13849430SRaymond.Chen@Sun.COM 		    "cb=0x%x", rval, completion_reason, cb_flags);
13859430SRaymond.Chen@Sun.COM 	} else {
13869430SRaymond.Chen@Sun.COM 		*status = *data->b_rptr;
13879430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13889430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_rpipe_status: status = %x", *status);
13899430SRaymond.Chen@Sun.COM 		freemsg(data);
13909430SRaymond.Chen@Sun.COM 	}
13919430SRaymond.Chen@Sun.COM 
13929430SRaymond.Chen@Sun.COM 	return (rval);
13939430SRaymond.Chen@Sun.COM }
13949430SRaymond.Chen@Sun.COM 
13959430SRaymond.Chen@Sun.COM /*
13969430SRaymond.Chen@Sun.COM  * WA specific operations end
13979430SRaymond.Chen@Sun.COM  */
13989430SRaymond.Chen@Sun.COM 
13999430SRaymond.Chen@Sun.COM /* Transfer related routines */
14009430SRaymond.Chen@Sun.COM wusb_wa_trans_wrapper_t *
wusb_wa_alloc_tw(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,uint32_t datalen,usb_flags_t usb_flags)14019430SRaymond.Chen@Sun.COM wusb_wa_alloc_tw(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
14029430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t	*ph, uint32_t datalen, usb_flags_t usb_flags)
14039430SRaymond.Chen@Sun.COM {
14049430SRaymond.Chen@Sun.COM 	uint_t			seg_count;
14059430SRaymond.Chen@Sun.COM 	uint32_t		seg_len, maxpktsize;
14069430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr;
14079430SRaymond.Chen@Sun.COM 
14089430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
14099430SRaymond.Chen@Sun.COM 	    "wusb_wa_alloc_tw: ph = 0x%p rp_hdl = 0x%p ",
14109430SRaymond.Chen@Sun.COM 	    (void*)ph, (void*)hdl);
14119430SRaymond.Chen@Sun.COM 
14129430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
14139430SRaymond.Chen@Sun.COM 
14149430SRaymond.Chen@Sun.COM 	/* compute the rpipe buffer size */
14159430SRaymond.Chen@Sun.COM 	seg_len = hdl->rp_descr.wBlocks *
14169430SRaymond.Chen@Sun.COM 	    (1 << (wa_data->wa_descr.bRPipeBlockSize - 1));
14179430SRaymond.Chen@Sun.COM 	maxpktsize = hdl->rp_descr.wMaxPacketSize;
14189430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
14199430SRaymond.Chen@Sun.COM 
14209430SRaymond.Chen@Sun.COM 	if (seg_len < maxpktsize) {
14219430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
14229430SRaymond.Chen@Sun.COM 		    "wusb_wa_alloc_tw: fail, segment len(%d) "
14239430SRaymond.Chen@Sun.COM 		    "< wMaxPacketSize(%d) ", seg_len, maxpktsize);
14249430SRaymond.Chen@Sun.COM 
14259430SRaymond.Chen@Sun.COM 		return (NULL);
14269430SRaymond.Chen@Sun.COM 	}
14279430SRaymond.Chen@Sun.COM 
14289430SRaymond.Chen@Sun.COM 	/*
14299430SRaymond.Chen@Sun.COM 	 * the transfer length for each segment is a multiple of the
14309430SRaymond.Chen@Sun.COM 	 * wMaxPacketSize except the last segment, and the length
14319430SRaymond.Chen@Sun.COM 	 * cannot exceed the rpipe buffer size
14329430SRaymond.Chen@Sun.COM 	 */
14339430SRaymond.Chen@Sun.COM 	seg_len = (seg_len / maxpktsize) * maxpktsize;
14349430SRaymond.Chen@Sun.COM 	if (datalen) {
14359430SRaymond.Chen@Sun.COM 		seg_count = (datalen + seg_len - 1) / seg_len;
14369430SRaymond.Chen@Sun.COM 	} else {
14379430SRaymond.Chen@Sun.COM 		seg_count = 1;
14389430SRaymond.Chen@Sun.COM 	}
14399430SRaymond.Chen@Sun.COM 
14409430SRaymond.Chen@Sun.COM 	if (seg_count > WA_MAX_SEG_COUNT) {
14419430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
14429430SRaymond.Chen@Sun.COM 		    "wusb_wa_alloc_tw: fail, seg count(%d)"
14439430SRaymond.Chen@Sun.COM 		    " > Max allowed number(%d) ", seg_count, WA_MAX_SEG_COUNT);
14449430SRaymond.Chen@Sun.COM 
14459430SRaymond.Chen@Sun.COM 		return (NULL);
14469430SRaymond.Chen@Sun.COM 	}
14479430SRaymond.Chen@Sun.COM 
14489430SRaymond.Chen@Sun.COM 	if ((wr = kmem_zalloc(sizeof (wusb_wa_trans_wrapper_t),
14499430SRaymond.Chen@Sun.COM 	    KM_NOSLEEP)) == NULL) {
14509430SRaymond.Chen@Sun.COM 
14519430SRaymond.Chen@Sun.COM 		return (NULL);
14529430SRaymond.Chen@Sun.COM 	}
14539430SRaymond.Chen@Sun.COM 
14549430SRaymond.Chen@Sun.COM 	/* allocation, not visible to other threads */
14559430SRaymond.Chen@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
14569430SRaymond.Chen@Sun.COM 
14579430SRaymond.Chen@Sun.COM 	if ((wr->wr_seg_array = kmem_zalloc(sizeof (wusb_wa_seg_t) * seg_count,
14589430SRaymond.Chen@Sun.COM 	    KM_NOSLEEP)) == NULL) {
14599430SRaymond.Chen@Sun.COM 		kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
14609430SRaymond.Chen@Sun.COM 
14619430SRaymond.Chen@Sun.COM 		return (NULL);
14629430SRaymond.Chen@Sun.COM 	}
14639430SRaymond.Chen@Sun.COM 
14649430SRaymond.Chen@Sun.COM 	/* assign a unique ID for each transfer */
14659430SRaymond.Chen@Sun.COM 	wr->wr_id = WA_GET_ID(wr);
14669430SRaymond.Chen@Sun.COM 	if (wr->wr_id == 0) {
14679430SRaymond.Chen@Sun.COM 		kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) *
14689430SRaymond.Chen@Sun.COM 		    seg_count);
14699430SRaymond.Chen@Sun.COM 		kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
14709430SRaymond.Chen@Sun.COM 
14719430SRaymond.Chen@Sun.COM 		return (NULL);
14729430SRaymond.Chen@Sun.COM 	}
14739430SRaymond.Chen@Sun.COM 
14749430SRaymond.Chen@Sun.COM 	wr->wr_ph = ph;
14759430SRaymond.Chen@Sun.COM 	wr->wr_rp = hdl;
14769430SRaymond.Chen@Sun.COM 	wr->wr_wa_data = wa_data;
14779430SRaymond.Chen@Sun.COM 	wr->wr_flags = usb_flags;
14789430SRaymond.Chen@Sun.COM 	wr->wr_nsegs = (uint8_t)seg_count;
14799430SRaymond.Chen@Sun.COM 	wr->wr_max_seglen = seg_len;
14809430SRaymond.Chen@Sun.COM 	wr->wr_has_aborted = 0;
14819430SRaymond.Chen@Sun.COM 
14829430SRaymond.Chen@Sun.COM 	cv_init(&wr->wr_cv, NULL, CV_DRIVER, NULL);
14839430SRaymond.Chen@Sun.COM 
14849430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
14859430SRaymond.Chen@Sun.COM 	    "wusb_wa_alloc_tw: wr = 0x%p id = %x nseg = %d", (void*)wr,
14869430SRaymond.Chen@Sun.COM 	    wr->wr_id, wr->wr_nsegs);
14879430SRaymond.Chen@Sun.COM 
14889430SRaymond.Chen@Sun.COM 	return (wr);
14899430SRaymond.Chen@Sun.COM }
14909430SRaymond.Chen@Sun.COM 
14919430SRaymond.Chen@Sun.COM /* create transfer wrapper for a ctrl request, return NULL on failure */
14929430SRaymond.Chen@Sun.COM wusb_wa_trans_wrapper_t *
wusb_wa_create_ctrl_wrapper(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)14939430SRaymond.Chen@Sun.COM wusb_wa_create_ctrl_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
14949430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t	*ph, usb_ctrl_req_t *ctrl_reqp,
14959430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
14969430SRaymond.Chen@Sun.COM {
14979430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr = NULL;
14989430SRaymond.Chen@Sun.COM 
14999430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
15009430SRaymond.Chen@Sun.COM 	    "wusb_wa_create_ctrl_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
15019430SRaymond.Chen@Sun.COM 	    (void *)ph, (void*)hdl, (void *)ctrl_reqp);
15029430SRaymond.Chen@Sun.COM 
15039430SRaymond.Chen@Sun.COM 	wr = wusb_wa_alloc_tw(wa_data, hdl, ph, ctrl_reqp->ctrl_wLength,
15049430SRaymond.Chen@Sun.COM 	    usb_flags);
15059430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
15069430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
15079430SRaymond.Chen@Sun.COM 		    "wusb_wa_create_ctrl_wrapper: fail to create tw for %p",
15089430SRaymond.Chen@Sun.COM 		    (void *)ctrl_reqp);
15099430SRaymond.Chen@Sun.COM 
15109430SRaymond.Chen@Sun.COM 		return (NULL);
15119430SRaymond.Chen@Sun.COM 	}
15129430SRaymond.Chen@Sun.COM 
15139430SRaymond.Chen@Sun.COM 	/* not visible to other threads yet */
15149430SRaymond.Chen@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
15159430SRaymond.Chen@Sun.COM 
15169430SRaymond.Chen@Sun.COM 	if (ctrl_reqp->ctrl_bmRequestType & USB_DEV_REQ_DEV_TO_HOST) {
15179430SRaymond.Chen@Sun.COM 		wr->wr_dir = WA_DIR_IN;
15189430SRaymond.Chen@Sun.COM 	} else {
15199430SRaymond.Chen@Sun.COM 		wr->wr_dir = WA_DIR_OUT;
15209430SRaymond.Chen@Sun.COM 	}
15219430SRaymond.Chen@Sun.COM 
15229430SRaymond.Chen@Sun.COM 	wr->wr_type = WA_XFER_REQ_TYPE_CTRL;
15239430SRaymond.Chen@Sun.COM 	wr->wr_reqp = (usb_opaque_t)ctrl_reqp;
15249430SRaymond.Chen@Sun.COM 	wr->wr_timeout = (ctrl_reqp->ctrl_timeout == 0) ?
15259430SRaymond.Chen@Sun.COM 	    WA_RPIPE_DEFAULT_TIMEOUT : ctrl_reqp->ctrl_timeout;
15269430SRaymond.Chen@Sun.COM 	wr->wr_cb = wusb_wa_handle_ctrl;
15279430SRaymond.Chen@Sun.COM 
15289430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
15299430SRaymond.Chen@Sun.COM 	    "wusb_wa_create_ctrl_wrapper: wr = 0x%p nseg = %d", (void *)wr,
15309430SRaymond.Chen@Sun.COM 	    wr->wr_nsegs);
15319430SRaymond.Chen@Sun.COM 
15329430SRaymond.Chen@Sun.COM 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
15339430SRaymond.Chen@Sun.COM 
15349430SRaymond.Chen@Sun.COM 	return (wr);
15359430SRaymond.Chen@Sun.COM }
15369430SRaymond.Chen@Sun.COM 
15379430SRaymond.Chen@Sun.COM /*
15389430SRaymond.Chen@Sun.COM  * create transfer wrapper for a bulk request, return NULL on failure
15399430SRaymond.Chen@Sun.COM  *	- split the request into multiple segments
15409430SRaymond.Chen@Sun.COM  *	- every segment is N * wMaxPacketSize
15419430SRaymond.Chen@Sun.COM  *	- segment length <= bRPipeBlockSize * wBlocks
15429430SRaymond.Chen@Sun.COM  */
15439430SRaymond.Chen@Sun.COM wusb_wa_trans_wrapper_t *
wusb_wa_create_bulk_wrapper(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)15449430SRaymond.Chen@Sun.COM wusb_wa_create_bulk_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
15459430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
15469430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
15479430SRaymond.Chen@Sun.COM {
15489430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr = NULL;
15499430SRaymond.Chen@Sun.COM 	usb_ep_descr_t		*epdt = &ph->p_ep;
15509430SRaymond.Chen@Sun.COM 
15519430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
15529430SRaymond.Chen@Sun.COM 	    "wusb_wa_create_bulk_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
15539430SRaymond.Chen@Sun.COM 	    (void *)ph, (void *)hdl, (void *)bulk_reqp);
15549430SRaymond.Chen@Sun.COM 
15559430SRaymond.Chen@Sun.COM 	wr = wusb_wa_alloc_tw(wa_data, hdl, ph, bulk_reqp->bulk_len,
15569430SRaymond.Chen@Sun.COM 	    usb_flags);
15579430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
15589430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
15599430SRaymond.Chen@Sun.COM 		    "wusb_wa_create_bulk_wrapper: fail to create tw for %p",
15609430SRaymond.Chen@Sun.COM 		    (void *)bulk_reqp);
15619430SRaymond.Chen@Sun.COM 
15629430SRaymond.Chen@Sun.COM 		return (NULL);
15639430SRaymond.Chen@Sun.COM 	}
15649430SRaymond.Chen@Sun.COM 
15659430SRaymond.Chen@Sun.COM 	/* no locking needed */
15669430SRaymond.Chen@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
15679430SRaymond.Chen@Sun.COM 
15689430SRaymond.Chen@Sun.COM 	if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
15699430SRaymond.Chen@Sun.COM 		wr->wr_dir = WA_DIR_IN;
15709430SRaymond.Chen@Sun.COM 	} else {
15719430SRaymond.Chen@Sun.COM 		wr->wr_dir = WA_DIR_OUT;
15729430SRaymond.Chen@Sun.COM 	}
15739430SRaymond.Chen@Sun.COM 
15749430SRaymond.Chen@Sun.COM 	wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR;
15759430SRaymond.Chen@Sun.COM 	wr->wr_reqp = (usb_opaque_t)bulk_reqp;
15769430SRaymond.Chen@Sun.COM 	wr->wr_timeout = (bulk_reqp->bulk_timeout == 0) ?
15779430SRaymond.Chen@Sun.COM 	    WA_RPIPE_DEFAULT_TIMEOUT : bulk_reqp->bulk_timeout;
15789430SRaymond.Chen@Sun.COM 	wr->wr_cb = wusb_wa_handle_bulk;
15799430SRaymond.Chen@Sun.COM 
15809430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
15819430SRaymond.Chen@Sun.COM 	    "wusb_wa_create_bulk_wrapper: wr = 0x%p nseg = %d", (void *)wr,
15829430SRaymond.Chen@Sun.COM 	    wr->wr_nsegs);
15839430SRaymond.Chen@Sun.COM 
15849430SRaymond.Chen@Sun.COM 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
15859430SRaymond.Chen@Sun.COM 
15869430SRaymond.Chen@Sun.COM 	return (wr);
15879430SRaymond.Chen@Sun.COM }
15889430SRaymond.Chen@Sun.COM 
15899430SRaymond.Chen@Sun.COM /*
15909430SRaymond.Chen@Sun.COM  * create transfer wrapper for a intr request, return NULL on failure
15919430SRaymond.Chen@Sun.COM  *	- split the request into multiple segments
15929430SRaymond.Chen@Sun.COM  *	- every segment is N * wMaxPacketSize
15939430SRaymond.Chen@Sun.COM  *	- segment length <= bRPipeBlockSize * wBlocks
15949430SRaymond.Chen@Sun.COM  */
15959430SRaymond.Chen@Sun.COM wusb_wa_trans_wrapper_t *
wusb_wa_create_intr_wrapper(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)15969430SRaymond.Chen@Sun.COM wusb_wa_create_intr_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
15979430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
15989430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
15999430SRaymond.Chen@Sun.COM {
16009430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr;
16019430SRaymond.Chen@Sun.COM 	usb_ep_descr_t		*epdt = &ph->p_ep;
16029430SRaymond.Chen@Sun.COM 	uint32_t		tw_len;
16039430SRaymond.Chen@Sun.COM 	usb_intr_req_t *curr_intr_reqp;
16049430SRaymond.Chen@Sun.COM 
16059430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
16069430SRaymond.Chen@Sun.COM 	    "wusb_wa_create_intr_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
16079430SRaymond.Chen@Sun.COM 	    (void *)ph, (void *)hdl, (void *)intr_reqp);
16089430SRaymond.Chen@Sun.COM 
16099430SRaymond.Chen@Sun.COM 	if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
16109430SRaymond.Chen@Sun.COM 		tw_len = (intr_reqp->intr_len) ? intr_reqp->intr_len :
16119430SRaymond.Chen@Sun.COM 		    ph->p_ep.wMaxPacketSize;
16129430SRaymond.Chen@Sun.COM 
16139430SRaymond.Chen@Sun.COM 		/* duplicate client's intr request */
16149430SRaymond.Chen@Sun.COM 		curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
16159430SRaymond.Chen@Sun.COM 		    (usb_intr_req_t *)intr_reqp, tw_len, usb_flags);
16169430SRaymond.Chen@Sun.COM 		if (curr_intr_reqp == NULL) {
16179430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
16189430SRaymond.Chen@Sun.COM 			    "wusb_wa_create_intr_wrapper: fail to create reqp");
16199430SRaymond.Chen@Sun.COM 
16209430SRaymond.Chen@Sun.COM 			return (NULL);
16219430SRaymond.Chen@Sun.COM 		}
16229430SRaymond.Chen@Sun.COM 
16239430SRaymond.Chen@Sun.COM 	} else { /* OUT */
16249430SRaymond.Chen@Sun.COM 		tw_len = intr_reqp->intr_len;
16259430SRaymond.Chen@Sun.COM 		curr_intr_reqp = intr_reqp;
16269430SRaymond.Chen@Sun.COM 	}
16279430SRaymond.Chen@Sun.COM 
16289430SRaymond.Chen@Sun.COM 	wr = wusb_wa_alloc_tw(wa_data, hdl, ph, tw_len, usb_flags);
16299430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
16309430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
16319430SRaymond.Chen@Sun.COM 		    "wusb_wa_create_bulk_wrapper: fail to create tw for %p",
16329430SRaymond.Chen@Sun.COM 		    (void *)intr_reqp);
16339430SRaymond.Chen@Sun.COM 
16349430SRaymond.Chen@Sun.COM 		return (NULL);
16359430SRaymond.Chen@Sun.COM 	}
16369430SRaymond.Chen@Sun.COM 
16379430SRaymond.Chen@Sun.COM 	/* no locking needed */
16389430SRaymond.Chen@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
16399430SRaymond.Chen@Sun.COM 
16409430SRaymond.Chen@Sun.COM 	if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
16419430SRaymond.Chen@Sun.COM 		wr->wr_dir = WA_DIR_IN;
16429430SRaymond.Chen@Sun.COM 	} else {
16439430SRaymond.Chen@Sun.COM 		wr->wr_dir = WA_DIR_OUT;
16449430SRaymond.Chen@Sun.COM 	}
16459430SRaymond.Chen@Sun.COM 
16469430SRaymond.Chen@Sun.COM 	wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR;
16479430SRaymond.Chen@Sun.COM 
16489430SRaymond.Chen@Sun.COM 	wr->wr_reqp = (usb_opaque_t)curr_intr_reqp;
16499430SRaymond.Chen@Sun.COM 
16509430SRaymond.Chen@Sun.COM 	wr->wr_timeout = (intr_reqp->intr_timeout == 0) ?
16519430SRaymond.Chen@Sun.COM 	    WA_RPIPE_DEFAULT_TIMEOUT : intr_reqp->intr_timeout;
16529430SRaymond.Chen@Sun.COM 	wr->wr_cb = wusb_wa_handle_intr;
16539430SRaymond.Chen@Sun.COM 
16549430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
16559430SRaymond.Chen@Sun.COM 	    "wusb_wa_create_intr_wrapper: wr = 0x%p nseg = %d", (void *)wr,
16569430SRaymond.Chen@Sun.COM 	    wr->wr_nsegs);
16579430SRaymond.Chen@Sun.COM 
16589430SRaymond.Chen@Sun.COM 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
16599430SRaymond.Chen@Sun.COM 
16609430SRaymond.Chen@Sun.COM 	return (wr);
16619430SRaymond.Chen@Sun.COM }
16629430SRaymond.Chen@Sun.COM 
16639430SRaymond.Chen@Sun.COM /*
16649430SRaymond.Chen@Sun.COM  * Setup the transfer request structure for a segment
16659430SRaymond.Chen@Sun.COM  * len = transfer request structure length
16669430SRaymond.Chen@Sun.COM  *	- see section 8.3.3.1 and 8.3.3.2
16679430SRaymond.Chen@Sun.COM  */
16689430SRaymond.Chen@Sun.COM void
wusb_wa_setup_trans_req(wusb_wa_trans_wrapper_t * wr,wusb_wa_seg_t * seg,uint8_t len)16699430SRaymond.Chen@Sun.COM wusb_wa_setup_trans_req(wusb_wa_trans_wrapper_t *wr, wusb_wa_seg_t *seg,
16709430SRaymond.Chen@Sun.COM 	uint8_t len)
16719430SRaymond.Chen@Sun.COM {
16729430SRaymond.Chen@Sun.COM 	mblk_t		*data = seg->seg_trans_reqp->bulk_data;
16739430SRaymond.Chen@Sun.COM 	uint8_t		*trans_req = data->b_wptr;
16749430SRaymond.Chen@Sun.COM 
16759430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
16769430SRaymond.Chen@Sun.COM 	    "wusb_wa_setup_trans_req: wr = 0x%p len = %d segnum = 0x%x",
16779430SRaymond.Chen@Sun.COM 	    (void*)wr, len, seg->seg_num);
16789430SRaymond.Chen@Sun.COM 
16799430SRaymond.Chen@Sun.COM 	bzero(trans_req, len);
16809430SRaymond.Chen@Sun.COM 	trans_req[0] = len;
16819430SRaymond.Chen@Sun.COM 	trans_req[1] = wr->wr_type;
16829430SRaymond.Chen@Sun.COM 	trans_req[2] = wr->wr_rp->rp_descr.wRPipeIndex;
16839430SRaymond.Chen@Sun.COM 	trans_req[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8;
16849430SRaymond.Chen@Sun.COM 	trans_req[4] = seg->seg_id;	/* dwTransferID */
16859430SRaymond.Chen@Sun.COM 	trans_req[5] = seg->seg_id >> 8;
16869430SRaymond.Chen@Sun.COM 	trans_req[6] = seg->seg_id >> 16;
16879430SRaymond.Chen@Sun.COM 	trans_req[7] = seg->seg_id >> 24;
16889430SRaymond.Chen@Sun.COM 	trans_req[8] = seg->seg_len;
16899430SRaymond.Chen@Sun.COM 	trans_req[9] = seg->seg_len >> 8;
16909430SRaymond.Chen@Sun.COM 	trans_req[10] = seg->seg_len >> 16;
16919430SRaymond.Chen@Sun.COM 	trans_req[11] = seg->seg_len >> 24;
16929430SRaymond.Chen@Sun.COM 	trans_req[12] = seg->seg_num;
16939430SRaymond.Chen@Sun.COM 
16949430SRaymond.Chen@Sun.COM 	/*
16959430SRaymond.Chen@Sun.COM 	 * 8-byte setupdata only for the first segment of a ctrl
16969430SRaymond.Chen@Sun.COM 	 * transfer request
16979430SRaymond.Chen@Sun.COM 	 */
16989430SRaymond.Chen@Sun.COM 	if (wr->wr_type == WA_XFER_REQ_TYPE_CTRL) {
16999430SRaymond.Chen@Sun.COM 		usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)wr->wr_reqp;
17009430SRaymond.Chen@Sun.COM 
17019430SRaymond.Chen@Sun.COM 		/* what is the unsecured flag for ? */
17029430SRaymond.Chen@Sun.COM 		trans_req[13] = wr->wr_dir | WA_CTRL_SECRT_REGULAR;
17039430SRaymond.Chen@Sun.COM 		if ((seg->seg_num & 0x7f) == 0) {
17049430SRaymond.Chen@Sun.COM 			/* only send baSetupDate on the first segment */
17059430SRaymond.Chen@Sun.COM 			trans_req[16] = ctrl_req->ctrl_bmRequestType;
17069430SRaymond.Chen@Sun.COM 			trans_req[17] = ctrl_req->ctrl_bRequest;
17079430SRaymond.Chen@Sun.COM 			trans_req[18] = ctrl_req->ctrl_wValue;
17089430SRaymond.Chen@Sun.COM 			trans_req[19] = ctrl_req->ctrl_wValue >> 8;
17099430SRaymond.Chen@Sun.COM 			trans_req[20] = ctrl_req->ctrl_wIndex;
17109430SRaymond.Chen@Sun.COM 			trans_req[21] = ctrl_req->ctrl_wIndex >> 8;
17119430SRaymond.Chen@Sun.COM 			trans_req[22] = ctrl_req->ctrl_wLength;
17129430SRaymond.Chen@Sun.COM 			trans_req[23] = ctrl_req->ctrl_wLength >> 8;
17139430SRaymond.Chen@Sun.COM 
17149430SRaymond.Chen@Sun.COM 		}
17159430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
17169430SRaymond.Chen@Sun.COM 		    "wusb_wa_setup_trans_req: Ctrl segment = %02x",
17179430SRaymond.Chen@Sun.COM 		    seg->seg_num);
17189430SRaymond.Chen@Sun.COM 
17199430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
17209430SRaymond.Chen@Sun.COM 		    "wusb_wa_setup_trans_req: Ctrl Setup Data: "
17219430SRaymond.Chen@Sun.COM 		    "%02x %02x %02x %02x %02x %02x %02x %02x",
17229430SRaymond.Chen@Sun.COM 		    trans_req[16], trans_req[17], trans_req[18],
17239430SRaymond.Chen@Sun.COM 		    trans_req[19], trans_req[20], trans_req[21],
17249430SRaymond.Chen@Sun.COM 		    trans_req[22], trans_req[23]);
17259430SRaymond.Chen@Sun.COM 	}
17269430SRaymond.Chen@Sun.COM 	data->b_wptr += len;
17279430SRaymond.Chen@Sun.COM }
17289430SRaymond.Chen@Sun.COM 
17299430SRaymond.Chen@Sun.COM /*
17309430SRaymond.Chen@Sun.COM  * WA bulk pipe callbacks
17319430SRaymond.Chen@Sun.COM  *   wusb_wa_trans_bulk_cb: transfer request stage normal callback
17329430SRaymond.Chen@Sun.COM  *   wusb_wa_trans_bulk_exc_cb: transfer request stage exceptional callback
17339430SRaymond.Chen@Sun.COM  *
17349430SRaymond.Chen@Sun.COM  *   wusb_wa_data_bulk_cb: transfer data stage normal callback
17359430SRaymond.Chen@Sun.COM  *   wusb_wa_data_bulk_exc_cb: transfer data stage exceptional callback
17369430SRaymond.Chen@Sun.COM  *
17379430SRaymond.Chen@Sun.COM  * see WUSB1.0 8.3.3 for details
17389430SRaymond.Chen@Sun.COM  */
17399430SRaymond.Chen@Sun.COM void
wusb_wa_trans_bulk_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)17409430SRaymond.Chen@Sun.COM wusb_wa_trans_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
17419430SRaymond.Chen@Sun.COM {
17429430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
17439430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
17449430SRaymond.Chen@Sun.COM 
17459430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
17469430SRaymond.Chen@Sun.COM 	    "wusb_wa_trans_bulk_cb: ph=%p req=0x%p cr=%d", (void*)ph,
17479430SRaymond.Chen@Sun.COM 	    (void*)req, req->bulk_completion_reason);
17489430SRaymond.Chen@Sun.COM 
17499430SRaymond.Chen@Sun.COM 	mutex_enter(&wr->wr_rp->rp_mutex);
17509430SRaymond.Chen@Sun.COM 
17519430SRaymond.Chen@Sun.COM 	/* callback returned, this seg can be freed */
17529430SRaymond.Chen@Sun.COM 	seg->seg_trans_req_state = 0;
17539430SRaymond.Chen@Sun.COM 
17549430SRaymond.Chen@Sun.COM 	cv_signal(&seg->seg_trans_cv);
17559430SRaymond.Chen@Sun.COM 	mutex_exit(&wr->wr_rp->rp_mutex);
17569430SRaymond.Chen@Sun.COM }
17579430SRaymond.Chen@Sun.COM 
17589430SRaymond.Chen@Sun.COM void
wusb_wa_trans_bulk_exc_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)17599430SRaymond.Chen@Sun.COM wusb_wa_trans_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
17609430SRaymond.Chen@Sun.COM {
17619430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
17629430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
17639430SRaymond.Chen@Sun.COM 
17649430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
17659430SRaymond.Chen@Sun.COM 	    "wusb_wa_trans_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph,
17669430SRaymond.Chen@Sun.COM 	    (void *)req, req->bulk_completion_reason);
17679430SRaymond.Chen@Sun.COM 
17689430SRaymond.Chen@Sun.COM 	mutex_enter(&wr->wr_rp->rp_mutex);
17699430SRaymond.Chen@Sun.COM 
17709430SRaymond.Chen@Sun.COM 	/* callback returned, this seg can be freed */
17719430SRaymond.Chen@Sun.COM 	seg->seg_trans_req_state = 0;
17729430SRaymond.Chen@Sun.COM 
17739430SRaymond.Chen@Sun.COM 	cv_signal(&seg->seg_trans_cv);
17749430SRaymond.Chen@Sun.COM 	mutex_exit(&wr->wr_rp->rp_mutex);
17759430SRaymond.Chen@Sun.COM }
17769430SRaymond.Chen@Sun.COM 
17779430SRaymond.Chen@Sun.COM void
wusb_wa_data_bulk_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)17789430SRaymond.Chen@Sun.COM wusb_wa_data_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
17799430SRaymond.Chen@Sun.COM {
17809430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
17819430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
17829430SRaymond.Chen@Sun.COM 
17839430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
17849430SRaymond.Chen@Sun.COM 	    "wusb_wa_data_bulk_cb: ph=%p req=0x%p cr=%d", (void *)ph,
17859430SRaymond.Chen@Sun.COM 	    (void *)req, req->bulk_completion_reason);
17869430SRaymond.Chen@Sun.COM 
17879430SRaymond.Chen@Sun.COM 	mutex_enter(&wr->wr_rp->rp_mutex);
17889430SRaymond.Chen@Sun.COM 
17899430SRaymond.Chen@Sun.COM 	/* callback returned, this seg can be freed */
17909430SRaymond.Chen@Sun.COM 	seg->seg_data_req_state = 0;
17919430SRaymond.Chen@Sun.COM 
17929430SRaymond.Chen@Sun.COM 	cv_signal(&seg->seg_data_cv);
17939430SRaymond.Chen@Sun.COM 	mutex_exit(&wr->wr_rp->rp_mutex);
17949430SRaymond.Chen@Sun.COM }
17959430SRaymond.Chen@Sun.COM 
17969430SRaymond.Chen@Sun.COM void
wusb_wa_data_bulk_exc_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)17979430SRaymond.Chen@Sun.COM wusb_wa_data_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
17989430SRaymond.Chen@Sun.COM {
17999430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
18009430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
18019430SRaymond.Chen@Sun.COM 
18029430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
18039430SRaymond.Chen@Sun.COM 	    "wusb_wa_data_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph,
18049430SRaymond.Chen@Sun.COM 	    (void *)req, req->bulk_completion_reason);
18059430SRaymond.Chen@Sun.COM 
18069430SRaymond.Chen@Sun.COM 	mutex_enter(&wr->wr_rp->rp_mutex);
18079430SRaymond.Chen@Sun.COM 
18089430SRaymond.Chen@Sun.COM 	/* callback returned, this seg can be freed */
18099430SRaymond.Chen@Sun.COM 	seg->seg_data_req_state = 0;
18109430SRaymond.Chen@Sun.COM 
18119430SRaymond.Chen@Sun.COM 	cv_signal(&seg->seg_data_cv);
18129430SRaymond.Chen@Sun.COM 	mutex_exit(&wr->wr_rp->rp_mutex);
18139430SRaymond.Chen@Sun.COM }
18149430SRaymond.Chen@Sun.COM 
18159430SRaymond.Chen@Sun.COM /*
18169430SRaymond.Chen@Sun.COM  * Setup all the transfer request segments, including the transfer request
18179430SRaymond.Chen@Sun.COM  * stage and data stage for out transfer.
18189430SRaymond.Chen@Sun.COM  * len = total size of payload data to transfer
18199430SRaymond.Chen@Sun.COM  *	- for every segment, allocate a new bulk request for Transfer
18209430SRaymond.Chen@Sun.COM  *	  Request. Fill the request with the segment and wrapper data.
18219430SRaymond.Chen@Sun.COM  *	- for every segment, allocate a new bulk request for data stage.
18229430SRaymond.Chen@Sun.COM  *
18239430SRaymond.Chen@Sun.COM  */
18249430SRaymond.Chen@Sun.COM int
wusb_wa_setup_segs(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,uint32_t len,mblk_t * data)18259430SRaymond.Chen@Sun.COM wusb_wa_setup_segs(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
18269430SRaymond.Chen@Sun.COM 	uint32_t len, mblk_t *data)
18279430SRaymond.Chen@Sun.COM {
18289430SRaymond.Chen@Sun.COM 	int		i, rval;
18299430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t	*seg;
18309430SRaymond.Chen@Sun.COM 	usb_bulk_req_t	*trans_req, *data_req;
18319430SRaymond.Chen@Sun.COM 	uint8_t		trans_req_len;
18329430SRaymond.Chen@Sun.COM 	uint8_t		*p;
18339430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t *hdl = NULL;
18349430SRaymond.Chen@Sun.COM 
18359430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
18369430SRaymond.Chen@Sun.COM 	    "wusb_wa_setup_segs: wr = 0x%p len = %d data = 0x%p", (void *)wr,
18379430SRaymond.Chen@Sun.COM 	    len, (void *)data);
18389430SRaymond.Chen@Sun.COM 
18399430SRaymond.Chen@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
18409430SRaymond.Chen@Sun.COM 
18419430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
18429430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
18439430SRaymond.Chen@Sun.COM 		    "wusb_wa_setup_segs: invalid wr");
18449430SRaymond.Chen@Sun.COM 
18459430SRaymond.Chen@Sun.COM 		return (USB_INVALID_ARGS);
18469430SRaymond.Chen@Sun.COM 	}
18479430SRaymond.Chen@Sun.COM 
18489430SRaymond.Chen@Sun.COM 	if ((len != 0) && (data != NULL)) {
18499430SRaymond.Chen@Sun.COM 		p = data->b_rptr;
18509430SRaymond.Chen@Sun.COM 	}
18519430SRaymond.Chen@Sun.COM 
18529430SRaymond.Chen@Sun.COM 	for (i = 0; i < wr->wr_nsegs; i++) {
18539430SRaymond.Chen@Sun.COM 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*seg));
18549430SRaymond.Chen@Sun.COM 
18559430SRaymond.Chen@Sun.COM 		seg = &wr->wr_seg_array[i];
18569430SRaymond.Chen@Sun.COM 		cv_init(&seg->seg_trans_cv, NULL, CV_DRIVER, NULL);
18579430SRaymond.Chen@Sun.COM 		cv_init(&seg->seg_data_cv, NULL, CV_DRIVER, NULL);
18589430SRaymond.Chen@Sun.COM 		seg->seg_wr = wr;
18599430SRaymond.Chen@Sun.COM 		seg->seg_num = (uint8_t)i;	/* 0-based */
18609430SRaymond.Chen@Sun.COM 		seg->seg_len = wr->wr_max_seglen;
18619430SRaymond.Chen@Sun.COM 		if (i == (wr->wr_nsegs - 1)) {
18629430SRaymond.Chen@Sun.COM 			seg->seg_num |= 0x80;	/* last segment */
18639430SRaymond.Chen@Sun.COM 			seg->seg_len = len;
18649430SRaymond.Chen@Sun.COM 		} else {
18659430SRaymond.Chen@Sun.COM 			len -= seg->seg_len;
18669430SRaymond.Chen@Sun.COM 		}
18679430SRaymond.Chen@Sun.COM 
18689430SRaymond.Chen@Sun.COM 		/*
18699430SRaymond.Chen@Sun.COM 		 * set seg_id, all segs are the same or unique ??
18709430SRaymond.Chen@Sun.COM 		 * now make all segs share the same id
18719430SRaymond.Chen@Sun.COM 		 */
18729430SRaymond.Chen@Sun.COM 		seg->seg_id = wr->wr_id;
18739430SRaymond.Chen@Sun.COM 
18749430SRaymond.Chen@Sun.COM 		/* alloc transfer request and set values */
18759430SRaymond.Chen@Sun.COM 		switch (wr->wr_type) {
18769430SRaymond.Chen@Sun.COM 		case WA_XFER_REQ_TYPE_CTRL:
18779430SRaymond.Chen@Sun.COM 			trans_req_len = WA_CTRL_REQ_LEN;
18789430SRaymond.Chen@Sun.COM 			break;
18799430SRaymond.Chen@Sun.COM 		case WA_XFER_REQ_TYPE_BULK_INTR:
18809430SRaymond.Chen@Sun.COM 			trans_req_len = WA_BULK_INTR_REQ_LEN;
18819430SRaymond.Chen@Sun.COM 
18829430SRaymond.Chen@Sun.COM 			break;
18839430SRaymond.Chen@Sun.COM 		default:
18849430SRaymond.Chen@Sun.COM 			trans_req_len = 0;
18859430SRaymond.Chen@Sun.COM 			break;
18869430SRaymond.Chen@Sun.COM 		}
18879430SRaymond.Chen@Sun.COM 
18889430SRaymond.Chen@Sun.COM 		if (trans_req_len == 0) {
18899430SRaymond.Chen@Sun.COM 			rval = USB_NOT_SUPPORTED;
18909430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
18919430SRaymond.Chen@Sun.COM 			    "wusb_wa_setup_segs: trans len error");
18929430SRaymond.Chen@Sun.COM 
18939430SRaymond.Chen@Sun.COM 			goto error;
18949430SRaymond.Chen@Sun.COM 		}
18959430SRaymond.Chen@Sun.COM 
18969430SRaymond.Chen@Sun.COM 		/* alloc transfer request for the ith seg */
18979430SRaymond.Chen@Sun.COM 		trans_req = usb_alloc_bulk_req(wa_data->wa_dip,
18989430SRaymond.Chen@Sun.COM 		    trans_req_len, USB_FLAGS_NOSLEEP);
18999430SRaymond.Chen@Sun.COM 		if (trans_req == NULL) {
19009430SRaymond.Chen@Sun.COM 			rval = USB_NO_RESOURCES;
19019430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
19029430SRaymond.Chen@Sun.COM 			    "wusb_wa_setup_segs: can't alloc_bulk_req");
19039430SRaymond.Chen@Sun.COM 
19049430SRaymond.Chen@Sun.COM 			goto error;
19059430SRaymond.Chen@Sun.COM 		}
19069430SRaymond.Chen@Sun.COM 
19079430SRaymond.Chen@Sun.COM 		/* setup the ith transfer request */
19089430SRaymond.Chen@Sun.COM 		trans_req->bulk_len = trans_req_len;
19099430SRaymond.Chen@Sun.COM 		trans_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
19109430SRaymond.Chen@Sun.COM 		trans_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
19119430SRaymond.Chen@Sun.COM 		trans_req->bulk_cb = wusb_wa_trans_bulk_cb;
19129430SRaymond.Chen@Sun.COM 		trans_req->bulk_exc_cb = wusb_wa_trans_bulk_exc_cb;
19139430SRaymond.Chen@Sun.COM 		trans_req->bulk_client_private = (usb_opaque_t)seg;
19149430SRaymond.Chen@Sun.COM 
19159430SRaymond.Chen@Sun.COM 		seg->seg_trans_reqp = trans_req;
19169430SRaymond.Chen@Sun.COM 		wusb_wa_setup_trans_req(wr, seg, trans_req_len);
19179430SRaymond.Chen@Sun.COM 
19189430SRaymond.Chen@Sun.COM 		if (seg->seg_len != 0) {
19199430SRaymond.Chen@Sun.COM 			/* alloc request for data stage */
19209430SRaymond.Chen@Sun.COM 			data_req = usb_alloc_bulk_req(wa_data->wa_dip,
19219430SRaymond.Chen@Sun.COM 			    seg->seg_len, USB_FLAGS_NOSLEEP);
19229430SRaymond.Chen@Sun.COM 			if (data_req == NULL) {
19239430SRaymond.Chen@Sun.COM 				rval = USB_NO_RESOURCES;
19249430SRaymond.Chen@Sun.COM 				USB_DPRINTF_L2(DPRINT_MASK_WHCDI,
19259430SRaymond.Chen@Sun.COM 				    whcdi_log_handle,
19269430SRaymond.Chen@Sun.COM 				    "wusb_wa_setup_segs: can't alloc_bulk_req"
19279430SRaymond.Chen@Sun.COM 				    " for data");
19289430SRaymond.Chen@Sun.COM 
19299430SRaymond.Chen@Sun.COM 				goto error;
19309430SRaymond.Chen@Sun.COM 			}
19319430SRaymond.Chen@Sun.COM 
19329430SRaymond.Chen@Sun.COM 			/* setup the ith data transfer */
19339430SRaymond.Chen@Sun.COM 			data_req->bulk_len = seg->seg_len;
19349430SRaymond.Chen@Sun.COM 			data_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
19359430SRaymond.Chen@Sun.COM 			data_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
19369430SRaymond.Chen@Sun.COM 
19379430SRaymond.Chen@Sun.COM 			data_req->bulk_cb = wusb_wa_data_bulk_cb;
19389430SRaymond.Chen@Sun.COM 			data_req->bulk_exc_cb = wusb_wa_data_bulk_exc_cb;
19399430SRaymond.Chen@Sun.COM 			data_req->bulk_client_private = (usb_opaque_t)seg;
19409430SRaymond.Chen@Sun.COM 
19419430SRaymond.Chen@Sun.COM 			seg->seg_data_reqp = data_req;
19429430SRaymond.Chen@Sun.COM 
19439430SRaymond.Chen@Sun.COM 			/*
19449430SRaymond.Chen@Sun.COM 			 * Copy data from client driver to bulk request for
19459430SRaymond.Chen@Sun.COM 			 * an OUT endpoint.
19469430SRaymond.Chen@Sun.COM 			 */
19479430SRaymond.Chen@Sun.COM 			if (wr->wr_dir == WA_DIR_OUT) {
19489430SRaymond.Chen@Sun.COM 				ASSERT(data != NULL);
19499430SRaymond.Chen@Sun.COM 				/*
19509430SRaymond.Chen@Sun.COM 				 * cannot increase data->b_rptr,
19519430SRaymond.Chen@Sun.COM 				 * or scsa2usb panic at bulk out
19529430SRaymond.Chen@Sun.COM 				 */
19539430SRaymond.Chen@Sun.COM 				ASSERT((intptr_t)((uintptr_t)data->b_wptr -
19549430SRaymond.Chen@Sun.COM 				    (uintptr_t)p) >= seg->seg_len);
19559430SRaymond.Chen@Sun.COM 				bcopy(p,
19569430SRaymond.Chen@Sun.COM 				    data_req->bulk_data->b_wptr,
19579430SRaymond.Chen@Sun.COM 				    seg->seg_len);
19589430SRaymond.Chen@Sun.COM 				p += seg->seg_len;
19599430SRaymond.Chen@Sun.COM 
19609430SRaymond.Chen@Sun.COM 				data_req->bulk_data->b_wptr += seg->seg_len;
19619430SRaymond.Chen@Sun.COM 			}
19629430SRaymond.Chen@Sun.COM 		}
19639430SRaymond.Chen@Sun.COM 
19649430SRaymond.Chen@Sun.COM 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*seg));
19659430SRaymond.Chen@Sun.COM 	}
19669430SRaymond.Chen@Sun.COM 
19679430SRaymond.Chen@Sun.COM 	/* zero timeout means to wait infinitely */
19689430SRaymond.Chen@Sun.COM 	/*
19699430SRaymond.Chen@Sun.COM 	 * if this is the first time this WR to be transfered,
19709430SRaymond.Chen@Sun.COM 	 * we'll add it to its rpipe handle's timeout queue
19719430SRaymond.Chen@Sun.COM 	 */
19729430SRaymond.Chen@Sun.COM 	if (wr->wr_timeout > 0) {
19739430SRaymond.Chen@Sun.COM 		hdl = wr->wr_rp;
19749430SRaymond.Chen@Sun.COM 
19759430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
19769430SRaymond.Chen@Sun.COM 		    "wusb_wa_setup_segs: timeout=%d", wr->wr_timeout);
19779430SRaymond.Chen@Sun.COM 
19789430SRaymond.Chen@Sun.COM 		mutex_enter(&hdl->rp_mutex);
19799430SRaymond.Chen@Sun.COM 
19809430SRaymond.Chen@Sun.COM 		/* Add this new wrapper to the head of RPipe's timeout list */
19819430SRaymond.Chen@Sun.COM 		if (hdl->rp_timeout_list) {
19829430SRaymond.Chen@Sun.COM 			wr->wr_timeout_next = hdl->rp_timeout_list;
19839430SRaymond.Chen@Sun.COM 		}
19849430SRaymond.Chen@Sun.COM 
19859430SRaymond.Chen@Sun.COM 		hdl->rp_timeout_list = wr;
19869430SRaymond.Chen@Sun.COM 
19879430SRaymond.Chen@Sun.COM 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
19889430SRaymond.Chen@Sun.COM 
19899430SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
19909430SRaymond.Chen@Sun.COM 	}
19919430SRaymond.Chen@Sun.COM 
19929430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
19939430SRaymond.Chen@Sun.COM 
19949430SRaymond.Chen@Sun.COM error:
19959430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
19969430SRaymond.Chen@Sun.COM 	    "wusb_wa_setup_segs: fail, rval = %d", rval);
19979430SRaymond.Chen@Sun.COM 
19989430SRaymond.Chen@Sun.COM 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
19999430SRaymond.Chen@Sun.COM 
20009430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
20019430SRaymond.Chen@Sun.COM 	wusb_wa_free_segs(wr);
20029430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
20039430SRaymond.Chen@Sun.COM 
20049430SRaymond.Chen@Sun.COM 	return (rval);
20059430SRaymond.Chen@Sun.COM }
20069430SRaymond.Chen@Sun.COM 
20079430SRaymond.Chen@Sun.COM /* allocate transfer wrapper and setup all transfer segments */
20089430SRaymond.Chen@Sun.COM wusb_wa_trans_wrapper_t *
wusb_wa_alloc_ctrl_resources(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)20099430SRaymond.Chen@Sun.COM wusb_wa_alloc_ctrl_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
20109430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
20119430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
20129430SRaymond.Chen@Sun.COM {
20139430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr;
20149430SRaymond.Chen@Sun.COM 
20159430SRaymond.Chen@Sun.COM 	wr = wusb_wa_create_ctrl_wrapper(wa_data, hdl, ph, ctrl_reqp,
20169430SRaymond.Chen@Sun.COM 	    usb_flags);
20179430SRaymond.Chen@Sun.COM 
20189430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
20199430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
20209430SRaymond.Chen@Sun.COM 		    "wusb_wa_alloc_ctrl_resources failed");
20219430SRaymond.Chen@Sun.COM 
20229430SRaymond.Chen@Sun.COM 		return (NULL);
20239430SRaymond.Chen@Sun.COM 	}
20249430SRaymond.Chen@Sun.COM 
20259430SRaymond.Chen@Sun.COM 	if (wusb_wa_setup_segs(wa_data, wr, ctrl_reqp->ctrl_wLength,
20269430SRaymond.Chen@Sun.COM 	    ctrl_reqp->ctrl_data) != USB_SUCCESS) {
20279430SRaymond.Chen@Sun.COM 		wusb_wa_free_trans_wrapper(wr);
20289430SRaymond.Chen@Sun.COM 
20299430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
20309430SRaymond.Chen@Sun.COM 		    "wusb_wa_alloc_ctrl_resources failed to setup segs");
20319430SRaymond.Chen@Sun.COM 
20329430SRaymond.Chen@Sun.COM 		return (NULL);
20339430SRaymond.Chen@Sun.COM 	}
20349430SRaymond.Chen@Sun.COM 
20359430SRaymond.Chen@Sun.COM 	return (wr);
20369430SRaymond.Chen@Sun.COM }
20379430SRaymond.Chen@Sun.COM 
20389430SRaymond.Chen@Sun.COM /* allocate transfer wrapper and setup all transfer segments */
20399430SRaymond.Chen@Sun.COM wusb_wa_trans_wrapper_t *
wusb_wa_alloc_bulk_resources(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)20409430SRaymond.Chen@Sun.COM wusb_wa_alloc_bulk_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
20419430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
20429430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
20439430SRaymond.Chen@Sun.COM {
20449430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr;
20459430SRaymond.Chen@Sun.COM 
20469430SRaymond.Chen@Sun.COM 	wr = wusb_wa_create_bulk_wrapper(wa_data, hdl, ph, bulk_reqp,
20479430SRaymond.Chen@Sun.COM 	    usb_flags);
20489430SRaymond.Chen@Sun.COM 
20499430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
20509430SRaymond.Chen@Sun.COM 
20519430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
20529430SRaymond.Chen@Sun.COM 		    "wusb_wa_alloc_bulk_resources: failed to create wr");
20539430SRaymond.Chen@Sun.COM 
20549430SRaymond.Chen@Sun.COM 		return (NULL);
20559430SRaymond.Chen@Sun.COM 	}
20569430SRaymond.Chen@Sun.COM 
20579430SRaymond.Chen@Sun.COM 	if (wusb_wa_setup_segs(wa_data, wr, bulk_reqp->bulk_len,
20589430SRaymond.Chen@Sun.COM 	    bulk_reqp->bulk_data) != USB_SUCCESS) {
20599430SRaymond.Chen@Sun.COM 		wusb_wa_free_trans_wrapper(wr);
20609430SRaymond.Chen@Sun.COM 
20619430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
20629430SRaymond.Chen@Sun.COM 		    "wusb_wa_alloc_bulk_resources:failed to setup segs");
20639430SRaymond.Chen@Sun.COM 		return (NULL);
20649430SRaymond.Chen@Sun.COM 	}
20659430SRaymond.Chen@Sun.COM 
20669430SRaymond.Chen@Sun.COM 	return (wr);
20679430SRaymond.Chen@Sun.COM }
20689430SRaymond.Chen@Sun.COM 
20699430SRaymond.Chen@Sun.COM /*
20709430SRaymond.Chen@Sun.COM  * allocate transfer wrapper and setup all transfer segments
20719430SRaymond.Chen@Sun.COM  * if it's an IN request, duplicate it.
20729430SRaymond.Chen@Sun.COM  */
20739430SRaymond.Chen@Sun.COM wusb_wa_trans_wrapper_t *
wusb_wa_alloc_intr_resources(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)20749430SRaymond.Chen@Sun.COM wusb_wa_alloc_intr_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
20759430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
20769430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
20779430SRaymond.Chen@Sun.COM {
20789430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr;
20799430SRaymond.Chen@Sun.COM 
20809430SRaymond.Chen@Sun.COM 	wr = wusb_wa_create_intr_wrapper(wa_data, hdl, ph, intr_reqp,
20819430SRaymond.Chen@Sun.COM 	    usb_flags);
20829430SRaymond.Chen@Sun.COM 
20839430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
20849430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
20859430SRaymond.Chen@Sun.COM 		    "wusb_wa_alloc_intr_resources: failed to create wr");
20869430SRaymond.Chen@Sun.COM 
20879430SRaymond.Chen@Sun.COM 		return (NULL);
20889430SRaymond.Chen@Sun.COM 	}
20899430SRaymond.Chen@Sun.COM 
20909430SRaymond.Chen@Sun.COM 	if (wusb_wa_setup_segs(wa_data, wr, intr_reqp->intr_len,
20919430SRaymond.Chen@Sun.COM 	    intr_reqp->intr_data) != USB_SUCCESS) {
20929430SRaymond.Chen@Sun.COM 		wusb_wa_free_trans_wrapper(wr);
20939430SRaymond.Chen@Sun.COM 
20949430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
20959430SRaymond.Chen@Sun.COM 		    "wusb_wa_alloc_intr_resources: failed to setup segs");
20969430SRaymond.Chen@Sun.COM 
20979430SRaymond.Chen@Sun.COM 		return (NULL);
20989430SRaymond.Chen@Sun.COM 	}
20999430SRaymond.Chen@Sun.COM 
21009430SRaymond.Chen@Sun.COM 	return (wr);
21019430SRaymond.Chen@Sun.COM }
21029430SRaymond.Chen@Sun.COM 
21039430SRaymond.Chen@Sun.COM /* free the bulk request structures for all segments */
21049430SRaymond.Chen@Sun.COM void
wusb_wa_free_segs(wusb_wa_trans_wrapper_t * wr)21059430SRaymond.Chen@Sun.COM wusb_wa_free_segs(wusb_wa_trans_wrapper_t *wr)
21069430SRaymond.Chen@Sun.COM {
21079430SRaymond.Chen@Sun.COM 	int		i;
21089430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t	*seg;
21099430SRaymond.Chen@Sun.COM 
21109430SRaymond.Chen@Sun.COM 	ASSERT(mutex_owned(&wr->wr_rp->rp_mutex));
21119430SRaymond.Chen@Sun.COM 
21129430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
21139430SRaymond.Chen@Sun.COM 	    "wusb_wa_free_segs: wr = 0x%p, segs=%p", (void *)wr,
21149430SRaymond.Chen@Sun.COM 	    (void *)wr->wr_seg_array);
21159430SRaymond.Chen@Sun.COM 
21169430SRaymond.Chen@Sun.COM 	if (wr->wr_seg_array == NULL) {
21179430SRaymond.Chen@Sun.COM 		return;
21189430SRaymond.Chen@Sun.COM 	}
21199430SRaymond.Chen@Sun.COM 
21209797SRaymond.Chen@Sun.COM 
21219430SRaymond.Chen@Sun.COM 	for (i = 0; i < wr->wr_nsegs; i++) {
21229430SRaymond.Chen@Sun.COM 		seg = &wr->wr_seg_array[i];
21239430SRaymond.Chen@Sun.COM 
21249430SRaymond.Chen@Sun.COM 		if (seg->seg_trans_reqp != NULL) {
21259430SRaymond.Chen@Sun.COM 			while (seg->seg_trans_req_state == 1) {
21269430SRaymond.Chen@Sun.COM 				cv_wait(&seg->seg_trans_cv,
21279430SRaymond.Chen@Sun.COM 				    &wr->wr_rp->rp_mutex);
21289430SRaymond.Chen@Sun.COM 			}
21299430SRaymond.Chen@Sun.COM 			/* free the bulk req for transfer request */
21309430SRaymond.Chen@Sun.COM 			usb_free_bulk_req(seg->seg_trans_reqp);
21319430SRaymond.Chen@Sun.COM 			seg->seg_trans_reqp = NULL;
21329430SRaymond.Chen@Sun.COM 		}
21339430SRaymond.Chen@Sun.COM 
21349430SRaymond.Chen@Sun.COM 		if (seg->seg_data_reqp != NULL) {
21359430SRaymond.Chen@Sun.COM 			while (seg->seg_data_req_state == 1) {
21369430SRaymond.Chen@Sun.COM 				cv_wait(&seg->seg_data_cv,
21379430SRaymond.Chen@Sun.COM 				    &wr->wr_rp->rp_mutex);
21389430SRaymond.Chen@Sun.COM 			}
21399430SRaymond.Chen@Sun.COM 			/* free the bulk req for data transfer */
21409430SRaymond.Chen@Sun.COM 			usb_free_bulk_req(seg->seg_data_reqp);
21419430SRaymond.Chen@Sun.COM 			seg->seg_data_reqp = NULL;
21429430SRaymond.Chen@Sun.COM 		}
21439430SRaymond.Chen@Sun.COM 
21449430SRaymond.Chen@Sun.COM 		cv_destroy(&seg->seg_trans_cv);
21459430SRaymond.Chen@Sun.COM 		cv_destroy(&seg->seg_data_cv);
21469430SRaymond.Chen@Sun.COM 	}
21479430SRaymond.Chen@Sun.COM 
21489430SRaymond.Chen@Sun.COM 	kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) * wr->wr_nsegs);
21499430SRaymond.Chen@Sun.COM 
21509430SRaymond.Chen@Sun.COM 	wr->wr_seg_array = NULL;
21519430SRaymond.Chen@Sun.COM 	wr->wr_nsegs = 0;
21529430SRaymond.Chen@Sun.COM }
21539430SRaymond.Chen@Sun.COM 
21549430SRaymond.Chen@Sun.COM /* free transfer wrapper */
21559430SRaymond.Chen@Sun.COM void
wusb_wa_free_trans_wrapper(wusb_wa_trans_wrapper_t * wr)21569430SRaymond.Chen@Sun.COM wusb_wa_free_trans_wrapper(wusb_wa_trans_wrapper_t *wr)
21579430SRaymond.Chen@Sun.COM {
21589430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t *hdl = NULL;
21599430SRaymond.Chen@Sun.COM 
21609430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
21619430SRaymond.Chen@Sun.COM 	    "wusb_wa_free_trans_wrapper: wr = 0x%p", (void *)wr);
21629430SRaymond.Chen@Sun.COM 
21639430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
21649430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
21659430SRaymond.Chen@Sun.COM 		    "wusb_wa_free_trans_wrapper: NULL wrapper");
21669430SRaymond.Chen@Sun.COM 		return;
21679430SRaymond.Chen@Sun.COM 	}
21689430SRaymond.Chen@Sun.COM 
21699430SRaymond.Chen@Sun.COM 	hdl = wr->wr_rp;
21709430SRaymond.Chen@Sun.COM 
21719430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
21729430SRaymond.Chen@Sun.COM 
21739430SRaymond.Chen@Sun.COM 	wusb_wa_remove_wr_from_timeout_list(hdl, wr);
21749430SRaymond.Chen@Sun.COM 
21759430SRaymond.Chen@Sun.COM 	if (wr->wr_seg_array != NULL) {
21769430SRaymond.Chen@Sun.COM 		wusb_wa_free_segs(wr);
21779430SRaymond.Chen@Sun.COM 		kmem_free(wr->wr_seg_array,
21789430SRaymond.Chen@Sun.COM 		    sizeof (wusb_wa_seg_t) * wr->wr_nsegs);
21799430SRaymond.Chen@Sun.COM 	}
21809430SRaymond.Chen@Sun.COM 
21819430SRaymond.Chen@Sun.COM 	if (wr->wr_id != 0) {
21829430SRaymond.Chen@Sun.COM 		WA_FREE_ID(wr->wr_id);
21839430SRaymond.Chen@Sun.COM 	}
21849430SRaymond.Chen@Sun.COM 
21859430SRaymond.Chen@Sun.COM 	cv_destroy(&wr->wr_cv);
21869430SRaymond.Chen@Sun.COM 
21879430SRaymond.Chen@Sun.COM 	kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
21889430SRaymond.Chen@Sun.COM 
21899430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
21909430SRaymond.Chen@Sun.COM }
21919430SRaymond.Chen@Sun.COM 
21929430SRaymond.Chen@Sun.COM /* abort a transfer, refer to WUSB 1.0/8.3.3.5 */
21939430SRaymond.Chen@Sun.COM void
wusb_wa_abort_req(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,uint32_t id)21949430SRaymond.Chen@Sun.COM wusb_wa_abort_req(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
21959430SRaymond.Chen@Sun.COM 	uint32_t id)
21969430SRaymond.Chen@Sun.COM {
21979430SRaymond.Chen@Sun.COM 	usb_bulk_req_t	*req;
21989430SRaymond.Chen@Sun.COM 	uint8_t		*p;
21999430SRaymond.Chen@Sun.COM 	int		rval;
22009430SRaymond.Chen@Sun.COM 
22019430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
22029430SRaymond.Chen@Sun.COM 	    "wusb_wa_abort_req: wr = 0x%p", (void *)wr);
22039430SRaymond.Chen@Sun.COM 
22049430SRaymond.Chen@Sun.COM 	req = usb_alloc_bulk_req(wa_data->wa_dip, WA_ABORT_REQ_LEN,
22059430SRaymond.Chen@Sun.COM 	    USB_FLAGS_NOSLEEP);
22069430SRaymond.Chen@Sun.COM 	if (req == NULL) {
22079430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
22089430SRaymond.Chen@Sun.COM 		    "wusb_wa_abort_req: alloc bulk req failed");
22099430SRaymond.Chen@Sun.COM 
22109430SRaymond.Chen@Sun.COM 		return;
22119430SRaymond.Chen@Sun.COM 	}
22129430SRaymond.Chen@Sun.COM 
22139430SRaymond.Chen@Sun.COM 	req->bulk_len = WA_ABORT_REQ_LEN;
22149430SRaymond.Chen@Sun.COM 	req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
22159430SRaymond.Chen@Sun.COM 	req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
22169430SRaymond.Chen@Sun.COM 	p = req->bulk_data->b_wptr;
22179430SRaymond.Chen@Sun.COM 	p[0] = WA_ABORT_REQ_LEN;
22189430SRaymond.Chen@Sun.COM 	p[1] = WA_XFER_REQ_TYPE_ABORT;
22199430SRaymond.Chen@Sun.COM 	p[2] = wr->wr_rp->rp_descr.wRPipeIndex;
22209430SRaymond.Chen@Sun.COM 	p[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8;
22219430SRaymond.Chen@Sun.COM 	p[4] = (uint8_t)id;
22229430SRaymond.Chen@Sun.COM 	p[5] = (uint8_t)(id >> 8);
22239430SRaymond.Chen@Sun.COM 	p[6] = (uint8_t)(id >> 16);
22249430SRaymond.Chen@Sun.COM 	p[7] = (uint8_t)(id >> 24);
22259430SRaymond.Chen@Sun.COM 	req->bulk_data->b_wptr += WA_ABORT_REQ_LEN;
22269430SRaymond.Chen@Sun.COM 
22279797SRaymond.Chen@Sun.COM 	mutex_exit(&wr->wr_rp->rp_mutex);
22289430SRaymond.Chen@Sun.COM 	rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req,
22299430SRaymond.Chen@Sun.COM 	    USB_FLAGS_SLEEP);
22309797SRaymond.Chen@Sun.COM 	mutex_enter(&wr->wr_rp->rp_mutex);
22319430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
22329430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
22339430SRaymond.Chen@Sun.COM 		    "wusb_wa_abort_req: send abort req failed, rval = %d",
22349430SRaymond.Chen@Sun.COM 		    rval);
22359430SRaymond.Chen@Sun.COM 	}
22369430SRaymond.Chen@Sun.COM 	usb_free_bulk_req(req);
22379430SRaymond.Chen@Sun.COM }
22389430SRaymond.Chen@Sun.COM 
22399430SRaymond.Chen@Sun.COM static void
wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * tw)22409430SRaymond.Chen@Sun.COM wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl,
22419430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *tw)
22429430SRaymond.Chen@Sun.COM {
22439430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *prev, *next;
22449430SRaymond.Chen@Sun.COM 	int ret = 0; /* debug only */
22459430SRaymond.Chen@Sun.COM 
22469430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
22479430SRaymond.Chen@Sun.COM 	    "remove_wr_from_timeout_list: %p", (void *)tw);
22489430SRaymond.Chen@Sun.COM 
22499430SRaymond.Chen@Sun.COM 	if (hdl->rp_timeout_list) {
22509430SRaymond.Chen@Sun.COM 		if (hdl->rp_timeout_list == tw) {
22519430SRaymond.Chen@Sun.COM 			hdl->rp_timeout_list = tw->wr_timeout_next;
22529430SRaymond.Chen@Sun.COM 			tw->wr_timeout_next = NULL;
22539430SRaymond.Chen@Sun.COM 			ret = 1;
22549430SRaymond.Chen@Sun.COM 		} else {
22559430SRaymond.Chen@Sun.COM 			prev = hdl->rp_timeout_list;
22569430SRaymond.Chen@Sun.COM 			next = prev->wr_timeout_next;
22579430SRaymond.Chen@Sun.COM 
22589430SRaymond.Chen@Sun.COM 			while (next && (next != tw)) {
22599430SRaymond.Chen@Sun.COM 				prev = next;
22609430SRaymond.Chen@Sun.COM 				next = next->wr_timeout_next;
22619430SRaymond.Chen@Sun.COM 			}
22629430SRaymond.Chen@Sun.COM 
22639430SRaymond.Chen@Sun.COM 			if (next == tw) {
22649430SRaymond.Chen@Sun.COM 				prev->wr_timeout_next = next->wr_timeout_next;
22659430SRaymond.Chen@Sun.COM 				tw->wr_timeout_next = NULL;
22669430SRaymond.Chen@Sun.COM 				ret = 1;
22679430SRaymond.Chen@Sun.COM 			}
22689430SRaymond.Chen@Sun.COM 		}
22699430SRaymond.Chen@Sun.COM 	}
22709430SRaymond.Chen@Sun.COM 
22719430SRaymond.Chen@Sun.COM 	/* debug only */
22729430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
22739430SRaymond.Chen@Sun.COM 	    "remove_wr_from_timeout_list: %p, on the list:%d",
22749430SRaymond.Chen@Sun.COM 	    (void *)tw, ret);
22759430SRaymond.Chen@Sun.COM }
22769430SRaymond.Chen@Sun.COM 
22779430SRaymond.Chen@Sun.COM /* start timer on a rpipe */
22789430SRaymond.Chen@Sun.COM void
wusb_wa_start_xfer_timer(wusb_wa_rpipe_hdl_t * hdl)22799430SRaymond.Chen@Sun.COM wusb_wa_start_xfer_timer(wusb_wa_rpipe_hdl_t *hdl)
22809430SRaymond.Chen@Sun.COM {
22819430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
22829430SRaymond.Chen@Sun.COM 	    "wusb_wa_start_xfer_timer: rpipe hdl = 0x%p", (void *)hdl);
22839430SRaymond.Chen@Sun.COM 
22849430SRaymond.Chen@Sun.COM 	ASSERT(mutex_owned(&hdl->rp_mutex));
22859430SRaymond.Chen@Sun.COM 
22869430SRaymond.Chen@Sun.COM 	/*
22879430SRaymond.Chen@Sun.COM 	 * wr_timeout is in Seconds
22889430SRaymond.Chen@Sun.COM 	 */
22899430SRaymond.Chen@Sun.COM 	/*
22909430SRaymond.Chen@Sun.COM 	 * Start the rpipe's timer only if currently timer is not
22919430SRaymond.Chen@Sun.COM 	 * running and if there are transfers on the rpipe.
22929430SRaymond.Chen@Sun.COM 	 * The timer will be per rpipe.
22939430SRaymond.Chen@Sun.COM 	 *
22949430SRaymond.Chen@Sun.COM 	 * The RPipe's timer expires every 1s. When this timer expires, the
22959430SRaymond.Chen@Sun.COM 	 * handler gets called and will decrease every pending transfer
22969430SRaymond.Chen@Sun.COM 	 * wrapper's timeout value.
22979430SRaymond.Chen@Sun.COM 	 */
22989430SRaymond.Chen@Sun.COM 	if ((!hdl->rp_timer_id) && (hdl->rp_timeout_list)) {
22999430SRaymond.Chen@Sun.COM 		hdl->rp_timer_id = timeout(wusb_wa_xfer_timeout_handler,
23009430SRaymond.Chen@Sun.COM 		    (void *)hdl, drv_usectohz(1000000));
23019430SRaymond.Chen@Sun.COM 	}
23029430SRaymond.Chen@Sun.COM }
23039430SRaymond.Chen@Sun.COM 
23049430SRaymond.Chen@Sun.COM /* transfer timeout handler */
23059430SRaymond.Chen@Sun.COM void
wusb_wa_xfer_timeout_handler(void * arg)23069430SRaymond.Chen@Sun.COM wusb_wa_xfer_timeout_handler(void *arg)
23079430SRaymond.Chen@Sun.COM {
23089430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t	*hdl = (wusb_wa_rpipe_hdl_t *)arg;
23099430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr = NULL;
23109430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*next = NULL;
23119430SRaymond.Chen@Sun.COM 	wusb_wa_data_t		*wa_data = NULL;
23129430SRaymond.Chen@Sun.COM 	int			rval;
23139430SRaymond.Chen@Sun.COM 	uint8_t			rp_status;
23149430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*expire_list = NULL;
23159430SRaymond.Chen@Sun.COM 
23169430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
23179430SRaymond.Chen@Sun.COM 	    "wusb_wa_xfer_timeout_handler: rphdl = 0x%p ", (void *)hdl);
23189430SRaymond.Chen@Sun.COM 
23199430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
23209430SRaymond.Chen@Sun.COM 
23219430SRaymond.Chen@Sun.COM 	/*
23229430SRaymond.Chen@Sun.COM 	 * Check whether still timeout handler is valid.
23239430SRaymond.Chen@Sun.COM 	 */
23249430SRaymond.Chen@Sun.COM 	if (hdl->rp_timer_id != 0) {
23259430SRaymond.Chen@Sun.COM 
23269430SRaymond.Chen@Sun.COM 		/* Reset the timer id to zero */
23279430SRaymond.Chen@Sun.COM 		hdl->rp_timer_id = 0;
23289430SRaymond.Chen@Sun.COM 	} else {
23299430SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
23309430SRaymond.Chen@Sun.COM 
23319430SRaymond.Chen@Sun.COM 		return;
23329430SRaymond.Chen@Sun.COM 	}
23339430SRaymond.Chen@Sun.COM 
23349430SRaymond.Chen@Sun.COM 	/*
23359430SRaymond.Chen@Sun.COM 	 * Check each transfer wrapper on this RPipe's timeout queue
23369430SRaymond.Chen@Sun.COM 	 * Actually, due to USBA's limitation and queueing, there's only one
23379430SRaymond.Chen@Sun.COM 	 * usba_request submitted to HCD at a specific pipe. Hence, only one
23389430SRaymond.Chen@Sun.COM 	 * WR can be on this RPipe's list at any moment.
23399430SRaymond.Chen@Sun.COM 	 */
23409430SRaymond.Chen@Sun.COM 	wr = hdl->rp_timeout_list;
23419430SRaymond.Chen@Sun.COM 	while (wr) {
23429430SRaymond.Chen@Sun.COM 		next = wr->wr_timeout_next;
23439430SRaymond.Chen@Sun.COM 
23449430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
23459430SRaymond.Chen@Sun.COM 		    "wusb_wa_xfer_timeout_handler: rhdl=0x%p"
23469430SRaymond.Chen@Sun.COM 		    " wr=0x%p(to=%d) nxt=0x%p", (void *)hdl, (void *)wr,
23479430SRaymond.Chen@Sun.COM 		    wr->wr_timeout, (void *)next);
23489430SRaymond.Chen@Sun.COM 
23499430SRaymond.Chen@Sun.COM 		/*
23509430SRaymond.Chen@Sun.COM 		 * 1 second passed. Decrease every transfer wrapper's
23519430SRaymond.Chen@Sun.COM 		 * timeout value. If the timeout < 0 (expired), remove this
23529430SRaymond.Chen@Sun.COM 		 * wrapper from the timeout list and put it on the
23539430SRaymond.Chen@Sun.COM 		 * expire_list.
23549430SRaymond.Chen@Sun.COM 		 */
23559430SRaymond.Chen@Sun.COM 		wr->wr_timeout--;
23569430SRaymond.Chen@Sun.COM 		if (wr->wr_timeout <= 0) {
23579430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
23589430SRaymond.Chen@Sun.COM 			    "wusb_wa_xfer_timeout_handler: 0x%p time out",
23599430SRaymond.Chen@Sun.COM 			    (void *)wr);
23609430SRaymond.Chen@Sun.COM 
23619430SRaymond.Chen@Sun.COM 			/* remove it from the rpipe's timeout list */
23629430SRaymond.Chen@Sun.COM 			wusb_wa_remove_wr_from_timeout_list(hdl, wr);
23639430SRaymond.Chen@Sun.COM 
23649430SRaymond.Chen@Sun.COM 			/* put it on the expired list */
23659430SRaymond.Chen@Sun.COM 			wr->wr_timeout_next = expire_list;
23669430SRaymond.Chen@Sun.COM 			expire_list = wr;
23679430SRaymond.Chen@Sun.COM 
23689430SRaymond.Chen@Sun.COM 		}
23699430SRaymond.Chen@Sun.COM 
23709430SRaymond.Chen@Sun.COM 		wr = next;
23719430SRaymond.Chen@Sun.COM 	}
23729430SRaymond.Chen@Sun.COM 
23739430SRaymond.Chen@Sun.COM 	/* Restart this RPipe's timer */
23749430SRaymond.Chen@Sun.COM 	wusb_wa_start_xfer_timer(hdl);
23759430SRaymond.Chen@Sun.COM 
23769430SRaymond.Chen@Sun.COM 	/* timeout handling */
23779430SRaymond.Chen@Sun.COM 	wr = expire_list;
23789430SRaymond.Chen@Sun.COM 	while (wr) {
23799430SRaymond.Chen@Sun.COM 		next = wr->wr_timeout_next;
23809430SRaymond.Chen@Sun.COM 
23819430SRaymond.Chen@Sun.COM 		/* other thread shouldn't continue processing it */
23829430SRaymond.Chen@Sun.COM 		wr->wr_state = WR_TIMEOUT;
23839430SRaymond.Chen@Sun.COM 
23849430SRaymond.Chen@Sun.COM 		wa_data = wr->wr_wa_data;
23859797SRaymond.Chen@Sun.COM 
23869797SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
23879430SRaymond.Chen@Sun.COM 		rval = wusb_wa_get_rpipe_status(wa_data->wa_dip,
23889430SRaymond.Chen@Sun.COM 		    wa_data->wa_default_pipe, hdl->rp_descr.wRPipeIndex,
23899430SRaymond.Chen@Sun.COM 		    &rp_status);
23909797SRaymond.Chen@Sun.COM 		mutex_enter(&hdl->rp_mutex);
23919797SRaymond.Chen@Sun.COM 
23929430SRaymond.Chen@Sun.COM 		if (rval != USB_SUCCESS) {
23939430SRaymond.Chen@Sun.COM 			/* reset WA perhaps? */
23949430SRaymond.Chen@Sun.COM 			hdl->rp_state = WA_RPIPE_STATE_ERROR;
23959430SRaymond.Chen@Sun.COM 			hdl->rp_curr_wr = NULL;
23969430SRaymond.Chen@Sun.COM 			mutex_exit(&hdl->rp_mutex);
23979430SRaymond.Chen@Sun.COM 			wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 1);
23989430SRaymond.Chen@Sun.COM 			mutex_enter(&hdl->rp_mutex);
23999430SRaymond.Chen@Sun.COM 
24009430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
24019430SRaymond.Chen@Sun.COM 			    "wusb_wa_xfer_timeout_handler: fail to get"
24029430SRaymond.Chen@Sun.COM 			    " rpipe status, rval = %d", rval);
24039430SRaymond.Chen@Sun.COM 
24049430SRaymond.Chen@Sun.COM 			goto continuing;
24059430SRaymond.Chen@Sun.COM 		}
24069430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
24079430SRaymond.Chen@Sun.COM 		    "wusb_wa_xfer_timeout_handler: rpstat=0x%02x, wr=0x%p,"
24089430SRaymond.Chen@Sun.COM 		    " wr_state=%d", rp_status, (void *)wr, wr->wr_state);
24099430SRaymond.Chen@Sun.COM 
24109430SRaymond.Chen@Sun.COM 		if (!(rp_status & WA_RPIPE_IDLE)) {
24119430SRaymond.Chen@Sun.COM 		/*
24129430SRaymond.Chen@Sun.COM 		 * If RP is not idle, then it must be processing this WR.
24139430SRaymond.Chen@Sun.COM 		 * Abort this request to make the RPipe idle.
24149430SRaymond.Chen@Sun.COM 		 */
24159430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
24169430SRaymond.Chen@Sun.COM 			    "wusb_wa_xfer_timeout_handler: rp not idle");
24179430SRaymond.Chen@Sun.COM 
24189797SRaymond.Chen@Sun.COM 			mutex_exit(&hdl->rp_mutex);
24199430SRaymond.Chen@Sun.COM 			rval = wusb_wa_rpipe_abort(wa_data->wa_dip,
24209430SRaymond.Chen@Sun.COM 			    wa_data->wa_default_pipe, hdl);
24219797SRaymond.Chen@Sun.COM 			mutex_enter(&hdl->rp_mutex);
24229430SRaymond.Chen@Sun.COM 
24239430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI,
24249430SRaymond.Chen@Sun.COM 			    whcdi_log_handle,
24259430SRaymond.Chen@Sun.COM 			    "wusb_wa_xfer_timeout_handler: abort rpipe"
24269430SRaymond.Chen@Sun.COM 			    " fail rval = %d", rval);
24279430SRaymond.Chen@Sun.COM 
24289430SRaymond.Chen@Sun.COM 			if (rval == 0) {
24299430SRaymond.Chen@Sun.COM 				/*
24309430SRaymond.Chen@Sun.COM 				 * wait for the result thread to get
24319430SRaymond.Chen@Sun.COM 				 * Aborted result. If this wr hasn't been
24329430SRaymond.Chen@Sun.COM 				 * aborted, wait it.
24339430SRaymond.Chen@Sun.COM 				 */
24349430SRaymond.Chen@Sun.COM 				if ((wr->wr_has_aborted == 0) &&
2435*11066Srafael.vanoni@sun.com 				    (cv_reltimedwait(&wr->wr_cv, &hdl->rp_mutex,
2436*11066Srafael.vanoni@sun.com 				    drv_usectohz(100 * 1000), TR_CLOCK_TICK)
24379430SRaymond.Chen@Sun.COM 				    >= 0)) {
24389430SRaymond.Chen@Sun.COM 				    /* 100ms, random number, long enough? */
24399430SRaymond.Chen@Sun.COM 
24409430SRaymond.Chen@Sun.COM 					/* the result thread has processed it */
24419430SRaymond.Chen@Sun.COM 					goto continuing;
24429430SRaymond.Chen@Sun.COM 				}
24439430SRaymond.Chen@Sun.COM 
24449430SRaymond.Chen@Sun.COM 				USB_DPRINTF_L3(DPRINT_MASK_WHCDI,
24459430SRaymond.Chen@Sun.COM 				    whcdi_log_handle,
24469430SRaymond.Chen@Sun.COM 				    "wusb_wa_xfer_timeout_handler: result"
24479430SRaymond.Chen@Sun.COM 				    " thread can't get the aborted request");
24489430SRaymond.Chen@Sun.COM 			}
24499430SRaymond.Chen@Sun.COM 		}
24509430SRaymond.Chen@Sun.COM 
24519430SRaymond.Chen@Sun.COM 		/*
24529430SRaymond.Chen@Sun.COM 		 * 1)The Rpipe is idle, OR,
24539430SRaymond.Chen@Sun.COM 		 * 2)rpipe_abort fails, OR,
24549430SRaymond.Chen@Sun.COM 		 * 3)The result thread hasn't got an aborted result in 100ms,
24559430SRaymond.Chen@Sun.COM 		 * most likely the result is lost. We can not depend on WA to
24569430SRaymond.Chen@Sun.COM 		 * return result for this aborted request. The WA seems not
24579430SRaymond.Chen@Sun.COM 		 * always returning such result. This will cause some hcdi
24589430SRaymond.Chen@Sun.COM 		 * ops hang.
24599430SRaymond.Chen@Sun.COM 		 */
24609430SRaymond.Chen@Sun.COM 		hdl->rp_state = WA_RPIPE_STATE_IDLE;
24619430SRaymond.Chen@Sun.COM 		hdl->rp_curr_wr = NULL;
24629430SRaymond.Chen@Sun.COM 
24639430SRaymond.Chen@Sun.COM 		/* release this WR's occupied req */
24649430SRaymond.Chen@Sun.COM 		hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
24659430SRaymond.Chen@Sun.COM 		cv_signal(&hdl->rp_cv);
24669430SRaymond.Chen@Sun.COM 
24679430SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
24689430SRaymond.Chen@Sun.COM 
24699430SRaymond.Chen@Sun.COM 		wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 0);
24709430SRaymond.Chen@Sun.COM 		mutex_enter(&hdl->rp_mutex);
24719430SRaymond.Chen@Sun.COM 
24729430SRaymond.Chen@Sun.COM continuing:
24739430SRaymond.Chen@Sun.COM 		wr = next;
24749430SRaymond.Chen@Sun.COM 	}
24759430SRaymond.Chen@Sun.COM 
24769430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
24779430SRaymond.Chen@Sun.COM }
24789430SRaymond.Chen@Sun.COM 
24799430SRaymond.Chen@Sun.COM /* stop timer */
24809430SRaymond.Chen@Sun.COM void
wusb_wa_stop_xfer_timer(wusb_wa_trans_wrapper_t * wr)24819430SRaymond.Chen@Sun.COM wusb_wa_stop_xfer_timer(wusb_wa_trans_wrapper_t *wr)
24829430SRaymond.Chen@Sun.COM {
24839430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t	*hdl = wr->wr_rp;
24849430SRaymond.Chen@Sun.COM 	timeout_id_t		timer_id;
24859430SRaymond.Chen@Sun.COM 
24869430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
24879430SRaymond.Chen@Sun.COM 	    "wusb_wa_stop_xfer_timer: wr = 0x%p", (void *)wr);
24889430SRaymond.Chen@Sun.COM 
24899430SRaymond.Chen@Sun.COM 	ASSERT(mutex_owned(&hdl->rp_mutex));
24909430SRaymond.Chen@Sun.COM 
24919430SRaymond.Chen@Sun.COM 	if (hdl->rp_timer_id == 0) {
24929430SRaymond.Chen@Sun.COM 
24939430SRaymond.Chen@Sun.COM 		return;
24949430SRaymond.Chen@Sun.COM 	}
24959430SRaymond.Chen@Sun.COM 
24969430SRaymond.Chen@Sun.COM 	timer_id = hdl->rp_timer_id;
24979430SRaymond.Chen@Sun.COM 	hdl->rp_timer_id = 0;
24989430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
24999430SRaymond.Chen@Sun.COM 
25009430SRaymond.Chen@Sun.COM 	(void) untimeout(timer_id);
25019430SRaymond.Chen@Sun.COM 
25029430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
25039430SRaymond.Chen@Sun.COM }
25049430SRaymond.Chen@Sun.COM 
25059430SRaymond.Chen@Sun.COM 
25069430SRaymond.Chen@Sun.COM /*
25079430SRaymond.Chen@Sun.COM  * send transfer request and data to the bulk out pipe
25089430SRaymond.Chen@Sun.COM  *
25099430SRaymond.Chen@Sun.COM  * General transfer function for WA transfer, see Section 8.3.3.
25109430SRaymond.Chen@Sun.COM  */
25119430SRaymond.Chen@Sun.COM /* ARGSUSED */
25129430SRaymond.Chen@Sun.COM int
wusb_wa_wr_xfer(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * wr,usb_flags_t usb_flags)25139430SRaymond.Chen@Sun.COM wusb_wa_wr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
25149430SRaymond.Chen@Sun.COM     wusb_wa_trans_wrapper_t *wr, usb_flags_t usb_flags)
25159430SRaymond.Chen@Sun.COM {
25169430SRaymond.Chen@Sun.COM 	int		i, rval;
25179430SRaymond.Chen@Sun.COM 	uint8_t		curr_seg;
25189430SRaymond.Chen@Sun.COM 	usb_bulk_req_t	*req;
25199430SRaymond.Chen@Sun.COM 
25209430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
25219430SRaymond.Chen@Sun.COM 	    "wusb_wa_wr_xfer: wr = 0x%p", (void *)wr);
25229430SRaymond.Chen@Sun.COM 
25239430SRaymond.Chen@Sun.COM 	ASSERT(wr->wr_seg_array != NULL);
25249430SRaymond.Chen@Sun.COM 
25259430SRaymond.Chen@Sun.COM 	ASSERT(mutex_owned(&hdl->rp_mutex));
25269430SRaymond.Chen@Sun.COM 
25279430SRaymond.Chen@Sun.COM 	if (hdl->rp_state == WA_RPIPE_STATE_IDLE) {
25289430SRaymond.Chen@Sun.COM 		hdl->rp_state = WA_RPIPE_STATE_ACTIVE;
25299430SRaymond.Chen@Sun.COM 		hdl->rp_curr_wr = wr;
25309430SRaymond.Chen@Sun.COM 	}
25319430SRaymond.Chen@Sun.COM 	curr_seg = wr->wr_curr_seg;
25329430SRaymond.Chen@Sun.COM 
25339430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
25349430SRaymond.Chen@Sun.COM 	    "wusb_wa_wr_xfer: curr_seg = %d, avail_req = %d", curr_seg,
25359430SRaymond.Chen@Sun.COM 	    hdl->rp_avail_reqs);
25369430SRaymond.Chen@Sun.COM 
25379430SRaymond.Chen@Sun.COM 	/*
25389430SRaymond.Chen@Sun.COM 	 * For every segment,
25399430SRaymond.Chen@Sun.COM 	 *	Step 1: contruct a bulk req containing Transfer
25409430SRaymond.Chen@Sun.COM 	 *		Request(T8-12 and T8-10)
25419430SRaymond.Chen@Sun.COM 	 *	Step 2: alloc another bulk req if there's any data
25429430SRaymond.Chen@Sun.COM 	 *		for OUT endpoints.
25439430SRaymond.Chen@Sun.COM 	 *
25449430SRaymond.Chen@Sun.COM 	 *	For IN endpoints, the data is returned in the
25459430SRaymond.Chen@Sun.COM 	 *	GetResult thread.
25469430SRaymond.Chen@Sun.COM 	 * Just throw as many as maximum available requests to the RPipe.
25479430SRaymond.Chen@Sun.COM 	 * If the avail_req is zero, wait!
25489430SRaymond.Chen@Sun.COM 	 *
25499430SRaymond.Chen@Sun.COM 	 * When a request is finished, the avail_req will be increased
25509430SRaymond.Chen@Sun.COM 	 * in the result thread.
25519430SRaymond.Chen@Sun.COM 	 */
25529430SRaymond.Chen@Sun.COM 	for (i = curr_seg; i < wr->wr_nsegs; i++) {
25539430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
25549430SRaymond.Chen@Sun.COM 		    "wusb_wa_wr_xfer: wr=%p curr_seg = %d, avail_req = %d,"
25559430SRaymond.Chen@Sun.COM 		    " dir=%s", (void *)wr, curr_seg, hdl->rp_avail_reqs,
25569430SRaymond.Chen@Sun.COM 		    (wr->wr_dir == WA_DIR_IN)?"IN":"OUT");
25579430SRaymond.Chen@Sun.COM 
25589430SRaymond.Chen@Sun.COM 		/* waiting for available requests if wr is still good */
25599430SRaymond.Chen@Sun.COM 		while ((hdl->rp_avail_reqs == 0) && (wr->wr_state == 0)) {
25609430SRaymond.Chen@Sun.COM 			rval = cv_wait_sig(&hdl->rp_cv, &hdl->rp_mutex);
25619430SRaymond.Chen@Sun.COM 		}
25629430SRaymond.Chen@Sun.COM 
25639430SRaymond.Chen@Sun.COM 		if ((wr->wr_curr_seg - wr->wr_seg_done) >= 1) {
25649430SRaymond.Chen@Sun.COM 			/* send only one segment */
25659430SRaymond.Chen@Sun.COM 
25669430SRaymond.Chen@Sun.COM 			break;
25679430SRaymond.Chen@Sun.COM 		}
25689430SRaymond.Chen@Sun.COM 
25699430SRaymond.Chen@Sun.COM 		if (wr->wr_state != 0) {
25709430SRaymond.Chen@Sun.COM 		/* wr transfer error, don't continue */
25719430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
25729430SRaymond.Chen@Sun.COM 			    "wusb_wa_wr_xfer: wr_state!=0(%d)", wr->wr_state);
25739430SRaymond.Chen@Sun.COM 
25749430SRaymond.Chen@Sun.COM 			break;
25759430SRaymond.Chen@Sun.COM 		}
25769430SRaymond.Chen@Sun.COM 
25779430SRaymond.Chen@Sun.COM 		req = wr->wr_seg_array[i].seg_trans_reqp;
25789430SRaymond.Chen@Sun.COM 		ASSERT(req != NULL);
25799430SRaymond.Chen@Sun.COM 
25809797SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
25819430SRaymond.Chen@Sun.COM 		/* send ith transfer request */
25829430SRaymond.Chen@Sun.COM 		rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0);
25839797SRaymond.Chen@Sun.COM 		mutex_enter(&hdl->rp_mutex);
25849430SRaymond.Chen@Sun.COM 		if (rval != USB_SUCCESS) {
25859430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
25869430SRaymond.Chen@Sun.COM 			    "wusb_wa_wr_xfer: send transfer request %d failed,"
25879430SRaymond.Chen@Sun.COM 			    "rv=%d", i, rval);
25889430SRaymond.Chen@Sun.COM 
25899430SRaymond.Chen@Sun.COM 			wr->wr_seg_array[i].seg_trans_req_state = 0; /* clear */
25909430SRaymond.Chen@Sun.COM 
25919430SRaymond.Chen@Sun.COM 			if (i == 0) {
25929430SRaymond.Chen@Sun.COM 				/* no xfer in processing */
25939430SRaymond.Chen@Sun.COM 				hdl->rp_state = WA_RPIPE_STATE_IDLE;
25949430SRaymond.Chen@Sun.COM 				hdl->rp_curr_wr = NULL;
25959430SRaymond.Chen@Sun.COM 
25969430SRaymond.Chen@Sun.COM 				return (rval);
25979430SRaymond.Chen@Sun.COM 			}
25989430SRaymond.Chen@Sun.COM 			wusb_wa_abort_req(wa_data, wr, wr->wr_id);
25999430SRaymond.Chen@Sun.COM 			wr->wr_state = WR_SEG_REQ_ERR;	/* sending tr error */
26009430SRaymond.Chen@Sun.COM 
26019430SRaymond.Chen@Sun.COM 			break;
26029430SRaymond.Chen@Sun.COM 		}
26039430SRaymond.Chen@Sun.COM 		wr->wr_seg_array[i].seg_trans_req_state = 1; /* submitted */
26049430SRaymond.Chen@Sun.COM 
26059430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
26069430SRaymond.Chen@Sun.COM 		    "wusb_wa_wr_xfer: seg(%d) request(0x%p) sent,"
26079430SRaymond.Chen@Sun.COM 		    " avail_req = %d", i, (void*)req, hdl->rp_avail_reqs);
26089430SRaymond.Chen@Sun.COM 
26099430SRaymond.Chen@Sun.COM 		hdl->rp_avail_reqs--;
26109430SRaymond.Chen@Sun.COM 
26119430SRaymond.Chen@Sun.COM 		/* Get data in the GetResult thread for IN eps */
26129430SRaymond.Chen@Sun.COM 		if (wr->wr_dir == WA_DIR_IN) {
26139430SRaymond.Chen@Sun.COM 			wr->wr_curr_seg++;
26149430SRaymond.Chen@Sun.COM 
26159430SRaymond.Chen@Sun.COM 			/* only send data for out request */
26169430SRaymond.Chen@Sun.COM 			continue;
26179430SRaymond.Chen@Sun.COM 		}
26189430SRaymond.Chen@Sun.COM 
26199430SRaymond.Chen@Sun.COM 		req = wr->wr_seg_array[i].seg_data_reqp;
26209430SRaymond.Chen@Sun.COM 		if (req == NULL) {
26219430SRaymond.Chen@Sun.COM 			/* no data stage */
26229430SRaymond.Chen@Sun.COM 			wr->wr_curr_seg++;
26239430SRaymond.Chen@Sun.COM 
26249430SRaymond.Chen@Sun.COM 			continue;
26259430SRaymond.Chen@Sun.COM 		}
26269430SRaymond.Chen@Sun.COM 
26279430SRaymond.Chen@Sun.COM 		wr->wr_seg_array[i].seg_data_req_state = 1; /* submitted */
26289797SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
26299430SRaymond.Chen@Sun.COM 		/* send ith data asynchronously */
26309430SRaymond.Chen@Sun.COM 		rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0);
26319797SRaymond.Chen@Sun.COM 		mutex_enter(&hdl->rp_mutex);
26329430SRaymond.Chen@Sun.COM 		if (rval != USB_SUCCESS) {
26339430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
26349430SRaymond.Chen@Sun.COM 			    "wusb_wa_wr_xfer: send transfer data %d failed",
26359430SRaymond.Chen@Sun.COM 			    i);
26369430SRaymond.Chen@Sun.COM 
26379430SRaymond.Chen@Sun.COM 			wr->wr_seg_array[i].seg_data_req_state = 0; /* clear */
26389430SRaymond.Chen@Sun.COM 
26399430SRaymond.Chen@Sun.COM 			wusb_wa_abort_req(wa_data, wr, wr->wr_id);
26409430SRaymond.Chen@Sun.COM 			wr->wr_state = WR_SEG_DAT_ERR; /* sending data error */
26419430SRaymond.Chen@Sun.COM 
26429430SRaymond.Chen@Sun.COM 			/* not inc rp_avail_reqs until callback */
26439430SRaymond.Chen@Sun.COM 
26449430SRaymond.Chen@Sun.COM 			break;
26459430SRaymond.Chen@Sun.COM 		}
26469430SRaymond.Chen@Sun.COM 
26479430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
26489430SRaymond.Chen@Sun.COM 		    "wusb_wa_wr_xfer: seg(%d) data(0x%p) sent, avail_req = %d",
26499430SRaymond.Chen@Sun.COM 		    i, (void*)req, hdl->rp_avail_reqs);
26509430SRaymond.Chen@Sun.COM 
26519430SRaymond.Chen@Sun.COM 		wr->wr_curr_seg++;
26529430SRaymond.Chen@Sun.COM 	}
26539430SRaymond.Chen@Sun.COM 
26549430SRaymond.Chen@Sun.COM 	/* start timer */
26559430SRaymond.Chen@Sun.COM 	wusb_wa_start_xfer_timer(hdl);
26569430SRaymond.Chen@Sun.COM 	/*
26579430SRaymond.Chen@Sun.COM 	 * return success even if the xfer is not complete, the callback
26589430SRaymond.Chen@Sun.COM 	 * will only continue sending segs when (wr_error_state = 0 &&
26599430SRaymond.Chen@Sun.COM 	 * wr_curr_seg < wr_nsegs)
26609430SRaymond.Chen@Sun.COM 	 */
26619430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
26629430SRaymond.Chen@Sun.COM }
26639430SRaymond.Chen@Sun.COM 
26649430SRaymond.Chen@Sun.COM /*
26659430SRaymond.Chen@Sun.COM  * submit wr according to rpipe status
26669430SRaymond.Chen@Sun.COM  *	- check RPipe state
26679430SRaymond.Chen@Sun.COM  *	- call general WA transfer function to do transfer
26689430SRaymond.Chen@Sun.COM  *
26699430SRaymond.Chen@Sun.COM  * usba only submits one transfer to the host controller per pipe at a time
26709430SRaymond.Chen@Sun.COM  * and starts next when the previous one completed. So the hwahc now
26719430SRaymond.Chen@Sun.COM  * assumes one transfer per rpipe at a time. This won't be necessary to
26729430SRaymond.Chen@Sun.COM  * change unless the usba scheme is changed.
26739430SRaymond.Chen@Sun.COM  */
26749430SRaymond.Chen@Sun.COM int
wusb_wa_submit_ctrl_wr(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * wr,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)26759430SRaymond.Chen@Sun.COM wusb_wa_submit_ctrl_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
26769430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *wr, usb_ctrl_req_t *ctrl_reqp,
26779430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
26789430SRaymond.Chen@Sun.COM {
26799430SRaymond.Chen@Sun.COM 	int		rval;
26809430SRaymond.Chen@Sun.COM 
26819430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
26829430SRaymond.Chen@Sun.COM 	switch (hdl->rp_state) {
26839430SRaymond.Chen@Sun.COM 	case WA_RPIPE_STATE_IDLE:
26849430SRaymond.Chen@Sun.COM 		rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
26859430SRaymond.Chen@Sun.COM 		break;
26869430SRaymond.Chen@Sun.COM 	case WA_RPIPE_STATE_ACTIVE:
26879430SRaymond.Chen@Sun.COM 		/* only allow one req at a time, this should not happen */
26889430SRaymond.Chen@Sun.COM 	default:
26899430SRaymond.Chen@Sun.COM 		rval = USB_PIPE_ERROR;
26909430SRaymond.Chen@Sun.COM 		break;
26919430SRaymond.Chen@Sun.COM 	}
26929430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
26939430SRaymond.Chen@Sun.COM 
26949430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
26959430SRaymond.Chen@Sun.COM 		if (ctrl_reqp->ctrl_completion_reason == USB_CR_OK) {
26969430SRaymond.Chen@Sun.COM 			ctrl_reqp->ctrl_completion_reason = usba_rval2cr(rval);
26979430SRaymond.Chen@Sun.COM 		}
26989430SRaymond.Chen@Sun.COM 		mutex_enter(&hdl->rp_mutex);
26999430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
27009430SRaymond.Chen@Sun.COM 		    "wusb_wa_submit_ctrl_wr:fail, reqp=0x%p, rpstat=%d, rv=%d",
27019430SRaymond.Chen@Sun.COM 		    (void*)ctrl_reqp, hdl->rp_state, rval);
27029430SRaymond.Chen@Sun.COM 
27039430SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
27049430SRaymond.Chen@Sun.COM 
27059430SRaymond.Chen@Sun.COM 		wusb_wa_free_trans_wrapper(wr);
27069430SRaymond.Chen@Sun.COM 	}
27079430SRaymond.Chen@Sun.COM 
27089430SRaymond.Chen@Sun.COM 	/* In other cases, wr will be freed in callback */
27099430SRaymond.Chen@Sun.COM 	return (rval);
27109430SRaymond.Chen@Sun.COM }
27119430SRaymond.Chen@Sun.COM 
27129430SRaymond.Chen@Sun.COM /*
27139430SRaymond.Chen@Sun.COM  * Transfer a control request:
27149430SRaymond.Chen@Sun.COM  *	- allocate a transfer wrapper(TW) for this request
27159430SRaymond.Chen@Sun.COM  *	- submit this TW
27169430SRaymond.Chen@Sun.COM  */
27179430SRaymond.Chen@Sun.COM int
wusb_wa_ctrl_xfer(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp,usb_flags_t usb_flags)27189430SRaymond.Chen@Sun.COM wusb_wa_ctrl_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
27199430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
27209430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
27219430SRaymond.Chen@Sun.COM {
27229430SRaymond.Chen@Sun.COM 	int			rval;
27239430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr;
27249430SRaymond.Chen@Sun.COM 
27259430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
27269430SRaymond.Chen@Sun.COM 	    "wusb_wa_ctrl_xfer: ph = 0x%p reqp = 0x%p",
27279430SRaymond.Chen@Sun.COM 	    (void*)ph, (void*)ctrl_reqp);
27289430SRaymond.Chen@Sun.COM 
27299430SRaymond.Chen@Sun.COM 	wr = wusb_wa_alloc_ctrl_resources(wa_data, hdl, ph, ctrl_reqp,
27309430SRaymond.Chen@Sun.COM 	    usb_flags);
27319430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
27329430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
27339430SRaymond.Chen@Sun.COM 		    "wusb_wa_ctrl_req: alloc ctrl resource failed");
27349430SRaymond.Chen@Sun.COM 
27359430SRaymond.Chen@Sun.COM 		return (USB_NO_RESOURCES);
27369430SRaymond.Chen@Sun.COM 	}
27379430SRaymond.Chen@Sun.COM 
27389430SRaymond.Chen@Sun.COM 	rval = wusb_wa_submit_ctrl_wr(wa_data, hdl, wr, ctrl_reqp, usb_flags);
27399430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
27409430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
27419430SRaymond.Chen@Sun.COM 		    "wusb_wa_submit_ctrl_wr: submit ctrl req failed, rval = %d",
27429430SRaymond.Chen@Sun.COM 		    rval);
27439430SRaymond.Chen@Sun.COM 	}
27449430SRaymond.Chen@Sun.COM 
27459430SRaymond.Chen@Sun.COM 	return (rval);
27469430SRaymond.Chen@Sun.COM }
27479430SRaymond.Chen@Sun.COM 
27489430SRaymond.Chen@Sun.COM /*
27499430SRaymond.Chen@Sun.COM  * submit wr according to rpipe status
27509430SRaymond.Chen@Sun.COM  *
27519430SRaymond.Chen@Sun.COM  * usba only submits one transfer to the host controller per pipe at a time
27529430SRaymond.Chen@Sun.COM  * and starts next when the previous one completed. So the hwahc now
27539430SRaymond.Chen@Sun.COM  * assumes one transfer per rpipe at a time. This won't be necessary to
27549430SRaymond.Chen@Sun.COM  * change unless the usba scheme is changed.
27559430SRaymond.Chen@Sun.COM  */
27569430SRaymond.Chen@Sun.COM int
wusb_wa_submit_bulk_wr(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * wr,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)27579430SRaymond.Chen@Sun.COM wusb_wa_submit_bulk_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
27589430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *wr, usb_bulk_req_t *bulk_reqp,
27599430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
27609430SRaymond.Chen@Sun.COM {
27619430SRaymond.Chen@Sun.COM 	int		rval;
27629430SRaymond.Chen@Sun.COM 
27639430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
27649430SRaymond.Chen@Sun.COM 	switch (hdl->rp_state) {
27659430SRaymond.Chen@Sun.COM 	case WA_RPIPE_STATE_IDLE:
27669430SRaymond.Chen@Sun.COM 		rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
27679430SRaymond.Chen@Sun.COM 		break;
27689430SRaymond.Chen@Sun.COM 	case WA_RPIPE_STATE_ACTIVE:
27699430SRaymond.Chen@Sun.COM 		/* only allow one req at a time, this should not happen */
27709430SRaymond.Chen@Sun.COM 	default:
27719430SRaymond.Chen@Sun.COM 		rval = USB_PIPE_ERROR;
27729430SRaymond.Chen@Sun.COM 		break;
27739430SRaymond.Chen@Sun.COM 	}
27749430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
27759430SRaymond.Chen@Sun.COM 
27769430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
27779430SRaymond.Chen@Sun.COM 		if (bulk_reqp->bulk_completion_reason == USB_CR_OK) {
27789430SRaymond.Chen@Sun.COM 			bulk_reqp->bulk_completion_reason = usba_rval2cr(rval);
27799430SRaymond.Chen@Sun.COM 		}
27809430SRaymond.Chen@Sun.COM 		wusb_wa_free_trans_wrapper(wr);
27819430SRaymond.Chen@Sun.COM 	}
27829430SRaymond.Chen@Sun.COM 
27839430SRaymond.Chen@Sun.COM 	/* In other cases, wr will be freed in callback */
27849430SRaymond.Chen@Sun.COM 	return (rval);
27859430SRaymond.Chen@Sun.COM }
27869430SRaymond.Chen@Sun.COM 
27879430SRaymond.Chen@Sun.COM /*
27889430SRaymond.Chen@Sun.COM  * WA general bulk transfer
27899430SRaymond.Chen@Sun.COM  *	- allocate bulk resources
27909430SRaymond.Chen@Sun.COM  *	- submit the bulk request
27919430SRaymond.Chen@Sun.COM  */
27929430SRaymond.Chen@Sun.COM int
wusb_wa_bulk_xfer(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_bulk_req_t * bulk_reqp,usb_flags_t usb_flags)27939430SRaymond.Chen@Sun.COM wusb_wa_bulk_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
27949430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
27959430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
27969430SRaymond.Chen@Sun.COM {
27979430SRaymond.Chen@Sun.COM 	int			rval;
27989430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr;
27999430SRaymond.Chen@Sun.COM 
28009430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
28019430SRaymond.Chen@Sun.COM 	    "wusb_wa_bulk_xfer: ph = 0x%p reqp = 0x%p",
28029430SRaymond.Chen@Sun.COM 	    (void *)ph, (void *)bulk_reqp);
28039430SRaymond.Chen@Sun.COM 
28049430SRaymond.Chen@Sun.COM 	wr = wusb_wa_alloc_bulk_resources(wa_data, hdl, ph, bulk_reqp,
28059430SRaymond.Chen@Sun.COM 	    usb_flags);
28069430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
28079430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
28089430SRaymond.Chen@Sun.COM 		    "wusb_wa_bulk_xfer: alloc bulk resource failed");
28099430SRaymond.Chen@Sun.COM 
28109430SRaymond.Chen@Sun.COM 		return (USB_NO_RESOURCES);
28119430SRaymond.Chen@Sun.COM 	}
28129430SRaymond.Chen@Sun.COM 
28139430SRaymond.Chen@Sun.COM 	rval = wusb_wa_submit_bulk_wr(wa_data, hdl, wr, bulk_reqp,
28149430SRaymond.Chen@Sun.COM 	    usb_flags);
28159430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
28169430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
28179430SRaymond.Chen@Sun.COM 		    "wusb_wa_bulk_req: submit bulk req failed, rval = %d",
28189430SRaymond.Chen@Sun.COM 		    rval);
28199430SRaymond.Chen@Sun.COM 	}
28209430SRaymond.Chen@Sun.COM 
28219430SRaymond.Chen@Sun.COM 	return (rval);
28229430SRaymond.Chen@Sun.COM }
28239430SRaymond.Chen@Sun.COM 
28249430SRaymond.Chen@Sun.COM /*
28259430SRaymond.Chen@Sun.COM  * submit wr according to rpipe status
28269430SRaymond.Chen@Sun.COM  *
28279430SRaymond.Chen@Sun.COM  * usba only submits one transfer to the host controller per pipe at a time
28289430SRaymond.Chen@Sun.COM  * and starts next when the previous one completed. So the hwahc now
28299430SRaymond.Chen@Sun.COM  * assumes one transfer per rpipe at a time. This won't be necessary to
28309430SRaymond.Chen@Sun.COM  * change unless the usba scheme is changed.
28319430SRaymond.Chen@Sun.COM  */
28329430SRaymond.Chen@Sun.COM int
wusb_wa_submit_intr_wr(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * wr,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)28339430SRaymond.Chen@Sun.COM wusb_wa_submit_intr_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
28349430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *wr, usb_intr_req_t *intr_reqp,
28359430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
28369430SRaymond.Chen@Sun.COM {
28379430SRaymond.Chen@Sun.COM 	int		rval;
28389430SRaymond.Chen@Sun.COM 
28399430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
28409430SRaymond.Chen@Sun.COM 	switch (hdl->rp_state) {
28419430SRaymond.Chen@Sun.COM 	case WA_RPIPE_STATE_IDLE:
28429430SRaymond.Chen@Sun.COM 		rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
28439430SRaymond.Chen@Sun.COM 		break;
28449430SRaymond.Chen@Sun.COM 	case WA_RPIPE_STATE_ACTIVE:
28459430SRaymond.Chen@Sun.COM 		/* only allow one req at a time, this should not happen */
28469430SRaymond.Chen@Sun.COM 	default:
28479430SRaymond.Chen@Sun.COM 		rval = USB_PIPE_ERROR;
28489430SRaymond.Chen@Sun.COM 		break;
28499430SRaymond.Chen@Sun.COM 	}
28509430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
28519430SRaymond.Chen@Sun.COM 
28529430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
28539430SRaymond.Chen@Sun.COM 		if (intr_reqp->intr_completion_reason == USB_CR_OK) {
28549430SRaymond.Chen@Sun.COM 			intr_reqp->intr_completion_reason = usba_rval2cr(rval);
28559430SRaymond.Chen@Sun.COM 		}
28569430SRaymond.Chen@Sun.COM 		wusb_wa_free_trans_wrapper(wr);
28579430SRaymond.Chen@Sun.COM 	}
28589430SRaymond.Chen@Sun.COM 
28599430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
28609430SRaymond.Chen@Sun.COM 	    "wusb_wa_submit_intr_wr: submit intr req, rval = %d", rval);
28619430SRaymond.Chen@Sun.COM 
28629430SRaymond.Chen@Sun.COM 	/* In other cases, wr will be freed in callback */
28639430SRaymond.Chen@Sun.COM 	return (rval);
28649430SRaymond.Chen@Sun.COM }
28659430SRaymond.Chen@Sun.COM 
28669430SRaymond.Chen@Sun.COM /*
28679430SRaymond.Chen@Sun.COM  * do intr xfer
28689430SRaymond.Chen@Sun.COM  *
28699430SRaymond.Chen@Sun.COM  * Now only one time intr transfer is supported. intr polling is not
28709430SRaymond.Chen@Sun.COM  * supported.
28719430SRaymond.Chen@Sun.COM  */
28729430SRaymond.Chen@Sun.COM int
wusb_wa_intr_xfer(wusb_wa_data_t * wa_data,wusb_wa_rpipe_hdl_t * hdl,usba_pipe_handle_data_t * ph,usb_intr_req_t * intr_reqp,usb_flags_t usb_flags)28739430SRaymond.Chen@Sun.COM wusb_wa_intr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
28749430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
28759430SRaymond.Chen@Sun.COM 	usb_flags_t usb_flags)
28769430SRaymond.Chen@Sun.COM {
28779430SRaymond.Chen@Sun.COM 	int			rval;
28789430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr;
28799430SRaymond.Chen@Sun.COM 
28809430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
28819430SRaymond.Chen@Sun.COM 	    "wusb_wa_intr_xfer: ph = 0x%p reqp = 0x%p",
28829430SRaymond.Chen@Sun.COM 	    (void *)ph, (void *)intr_reqp);
28839430SRaymond.Chen@Sun.COM 
28849430SRaymond.Chen@Sun.COM 	wr = wusb_wa_alloc_intr_resources(wa_data, hdl, ph, intr_reqp,
28859430SRaymond.Chen@Sun.COM 	    usb_flags);
28869430SRaymond.Chen@Sun.COM 	if (wr == NULL) {
28879430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
28889430SRaymond.Chen@Sun.COM 		    "wusb_wa_intr_req: alloc intr resource failed");
28899430SRaymond.Chen@Sun.COM 
28909430SRaymond.Chen@Sun.COM 		return (USB_NO_RESOURCES);
28919430SRaymond.Chen@Sun.COM 	}
28929430SRaymond.Chen@Sun.COM 
28939430SRaymond.Chen@Sun.COM 	rval = wusb_wa_submit_intr_wr(wa_data, hdl, wr, intr_reqp,
28949430SRaymond.Chen@Sun.COM 	    usb_flags);
28959430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
28969430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
28979430SRaymond.Chen@Sun.COM 		    "wusb_wa_intr_req: submit intr req failed, rval = %d",
28989430SRaymond.Chen@Sun.COM 		    rval);
28999430SRaymond.Chen@Sun.COM 
29009430SRaymond.Chen@Sun.COM 		return (rval);
29019430SRaymond.Chen@Sun.COM 	}
29029430SRaymond.Chen@Sun.COM 
29039430SRaymond.Chen@Sun.COM 	/*
29049430SRaymond.Chen@Sun.COM 	 * have successfully duplicate and queue one more request on
29059430SRaymond.Chen@Sun.COM 	 * the pipe. Increase the pipe request count.
29069430SRaymond.Chen@Sun.COM 	 */
29079430SRaymond.Chen@Sun.COM 	if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
29089430SRaymond.Chen@Sun.COM 		mutex_enter(&ph->p_mutex);
29099430SRaymond.Chen@Sun.COM 
29109430SRaymond.Chen@Sun.COM 		/*
29119430SRaymond.Chen@Sun.COM 		 * this count will be decremented by usba_req_normal_cb
29129430SRaymond.Chen@Sun.COM 		 * or usba_req_exc_cb (called by hcdi_do_cb <-- usba_hcdi_cb)
29139430SRaymond.Chen@Sun.COM 		 */
29149430SRaymond.Chen@Sun.COM 		ph->p_req_count++;
29159430SRaymond.Chen@Sun.COM 
29169430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
29179430SRaymond.Chen@Sun.COM 		    "wusb_wa_intr_req: p_req_cnt = %d", ph->p_req_count);
29189430SRaymond.Chen@Sun.COM 
29199430SRaymond.Chen@Sun.COM 		mutex_exit(&ph->p_mutex);
29209430SRaymond.Chen@Sun.COM 	}
29219430SRaymond.Chen@Sun.COM 
29229430SRaymond.Chen@Sun.COM 	return (rval);
29239430SRaymond.Chen@Sun.COM }
29249430SRaymond.Chen@Sun.COM 
29259430SRaymond.Chen@Sun.COM /*
29269430SRaymond.Chen@Sun.COM  * For an IN transfer request, receive transfer data on bulk-in ept
29279430SRaymond.Chen@Sun.COM  * The bulk_req has been allocated when allocating transfer resources
29289430SRaymond.Chen@Sun.COM  */
29299430SRaymond.Chen@Sun.COM int
wusb_wa_get_data(wusb_wa_data_t * wa_data,wusb_wa_seg_t * seg,uint32_t len)29309430SRaymond.Chen@Sun.COM wusb_wa_get_data(wusb_wa_data_t *wa_data, wusb_wa_seg_t *seg, uint32_t len)
29319430SRaymond.Chen@Sun.COM {
29329430SRaymond.Chen@Sun.COM 	usb_bulk_req_t		*req;
29339430SRaymond.Chen@Sun.COM 	int			rval;
29349430SRaymond.Chen@Sun.COM 
29359430SRaymond.Chen@Sun.COM 	if (len == 0) {
29369430SRaymond.Chen@Sun.COM 
29379430SRaymond.Chen@Sun.COM 		return (USB_SUCCESS);
29389430SRaymond.Chen@Sun.COM 	}
29399430SRaymond.Chen@Sun.COM 
29409430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
29419430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_data: get data for wr: 0x%p", (void *)seg->seg_wr);
29429430SRaymond.Chen@Sun.COM 
29439430SRaymond.Chen@Sun.COM 	req = seg->seg_data_reqp;
29449430SRaymond.Chen@Sun.COM 	ASSERT(req != NULL);
29459430SRaymond.Chen@Sun.COM 
29469430SRaymond.Chen@Sun.COM 	/* adjust bulk in length to actual length */
29479430SRaymond.Chen@Sun.COM 	req->bulk_len = len;
29489430SRaymond.Chen@Sun.COM 	rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req,
29499430SRaymond.Chen@Sun.COM 	    USB_FLAGS_SLEEP);
29509430SRaymond.Chen@Sun.COM 
29519430SRaymond.Chen@Sun.COM 	return (rval);
29529430SRaymond.Chen@Sun.COM }
29539430SRaymond.Chen@Sun.COM 
29549430SRaymond.Chen@Sun.COM /*
29559430SRaymond.Chen@Sun.COM  * to retrieve a transfer_wrapper by dwTransferID
29569430SRaymond.Chen@Sun.COM  *
29579430SRaymond.Chen@Sun.COM  * Though to search a list looks not so efficient, we have to give up
29589430SRaymond.Chen@Sun.COM  * id32_lookup(). When a transfer segment is throwed to HWA device, we
29599430SRaymond.Chen@Sun.COM  * can't anticipate when the result will be returned, even if we try to
29609430SRaymond.Chen@Sun.COM  * abort it. If we have freed the transfer wrapper due to timeout, then
29619430SRaymond.Chen@Sun.COM  * after a moment, that TW's segment is accomplished by hardware. If
29629430SRaymond.Chen@Sun.COM  * id32_lookup() is used to look up corresponding TW, we'll get an invalid
29639430SRaymond.Chen@Sun.COM  * address. Unfortunately, id32_lookup() can't judge validity of its
29649430SRaymond.Chen@Sun.COM  * returned address.
29659430SRaymond.Chen@Sun.COM  */
29669430SRaymond.Chen@Sun.COM wusb_wa_trans_wrapper_t *
wusb_wa_retrieve_wr(wusb_wa_data_t * wa_data,uint32_t id)29679430SRaymond.Chen@Sun.COM wusb_wa_retrieve_wr(wusb_wa_data_t *wa_data, uint32_t id)
29689430SRaymond.Chen@Sun.COM {
29699430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t *rph;
29709430SRaymond.Chen@Sun.COM 	uint16_t	i;
29719430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t *tw;
29729430SRaymond.Chen@Sun.COM 
29739430SRaymond.Chen@Sun.COM 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
29749430SRaymond.Chen@Sun.COM 		rph = &wa_data->wa_rpipe_hdl[i];
29759430SRaymond.Chen@Sun.COM 
29769430SRaymond.Chen@Sun.COM 		mutex_enter(&rph->rp_mutex);
29779430SRaymond.Chen@Sun.COM 		/* all outstanding TWs are put on the timeout list */
29789430SRaymond.Chen@Sun.COM 		tw = rph->rp_timeout_list;
29799430SRaymond.Chen@Sun.COM 
29809430SRaymond.Chen@Sun.COM 		while (tw) {
29819430SRaymond.Chen@Sun.COM 			if (tw->wr_id == id) {
29829430SRaymond.Chen@Sun.COM 				mutex_exit(&rph->rp_mutex);
29839430SRaymond.Chen@Sun.COM 				return (tw);
29849430SRaymond.Chen@Sun.COM 			}
29859430SRaymond.Chen@Sun.COM 			tw = tw->wr_timeout_next;
29869430SRaymond.Chen@Sun.COM 		}
29879430SRaymond.Chen@Sun.COM 		mutex_exit(&rph->rp_mutex);
29889430SRaymond.Chen@Sun.COM 	}
29899430SRaymond.Chen@Sun.COM 
29909430SRaymond.Chen@Sun.COM 	return (NULL);
29919430SRaymond.Chen@Sun.COM }
29929430SRaymond.Chen@Sun.COM 
29939430SRaymond.Chen@Sun.COM /* endlessly wait for transfer result on bulk-in ept and handle the result */
29949430SRaymond.Chen@Sun.COM int
wusb_wa_get_xfer_result(wusb_wa_data_t * wa_data)29959430SRaymond.Chen@Sun.COM wusb_wa_get_xfer_result(wusb_wa_data_t *wa_data)
29969430SRaymond.Chen@Sun.COM {
29979430SRaymond.Chen@Sun.COM 	usb_bulk_req_t		*req;
29989430SRaymond.Chen@Sun.COM 	int			rval;
29999430SRaymond.Chen@Sun.COM 	mblk_t			*data;
30009430SRaymond.Chen@Sun.COM 	uint8_t			*p;
30019430SRaymond.Chen@Sun.COM 	wa_xfer_result_t	result;
30029430SRaymond.Chen@Sun.COM 	wusb_wa_trans_wrapper_t	*wr;
30039430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t		*seg;
30049430SRaymond.Chen@Sun.COM 	uint8_t			status;
30059430SRaymond.Chen@Sun.COM 	uint_t			len;
30069430SRaymond.Chen@Sun.COM 	uint8_t			lastseg = 0;
30079430SRaymond.Chen@Sun.COM 	usb_cr_t		cr;
30089430SRaymond.Chen@Sun.COM 	uint32_t		act_len;
30099430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t	*hdl;
30109430SRaymond.Chen@Sun.COM 
30119430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
30129430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_xfer_result: started, wa=0x%p", (void*)wa_data);
30139430SRaymond.Chen@Sun.COM 
30149430SRaymond.Chen@Sun.COM 	/* grab lock before accessing wa_data */
30159430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
30169430SRaymond.Chen@Sun.COM 
30179430SRaymond.Chen@Sun.COM 	len = wa_data->wa_bulkin_ept.wMaxPacketSize;
30189430SRaymond.Chen@Sun.COM 
30199430SRaymond.Chen@Sun.COM 	req = usb_alloc_bulk_req(wa_data->wa_dip, len,
30209430SRaymond.Chen@Sun.COM 	    USB_FLAGS_NOSLEEP);
30219430SRaymond.Chen@Sun.COM 	if (req == NULL) {
30229430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
30239430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_xfer_result: alloc bulk req failed");
30249430SRaymond.Chen@Sun.COM 
30259430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
30269430SRaymond.Chen@Sun.COM 
30279430SRaymond.Chen@Sun.COM 		return (USB_NO_RESOURCES);
30289430SRaymond.Chen@Sun.COM 	}
30299430SRaymond.Chen@Sun.COM 
30309430SRaymond.Chen@Sun.COM 	req->bulk_len = len;
30319430SRaymond.Chen@Sun.COM 	req->bulk_timeout = 0;
30329430SRaymond.Chen@Sun.COM 	req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK |
30339430SRaymond.Chen@Sun.COM 	    USB_ATTRS_AUTOCLEARING;
30349430SRaymond.Chen@Sun.COM 
30359430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
30369430SRaymond.Chen@Sun.COM 
30379430SRaymond.Chen@Sun.COM 	/* Get the Transfer Result head, see Table 8-14 */
30389430SRaymond.Chen@Sun.COM 	rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req,
30399430SRaymond.Chen@Sun.COM 	    USB_FLAGS_SLEEP);
30409430SRaymond.Chen@Sun.COM 	if ((rval != USB_SUCCESS) || (req->bulk_data == NULL)) {
30419430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
30429430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_xfer_result: bulk xfer failed or "
30439430SRaymond.Chen@Sun.COM 		    "null data returned, rval=%d, req->bulk_data = %p",
30449430SRaymond.Chen@Sun.COM 		    rval, (void*)req->bulk_data);
30459430SRaymond.Chen@Sun.COM 		usb_free_bulk_req(req);
30469430SRaymond.Chen@Sun.COM 
30479430SRaymond.Chen@Sun.COM 		return (rval);
30489430SRaymond.Chen@Sun.COM 	}
30499430SRaymond.Chen@Sun.COM 
30509430SRaymond.Chen@Sun.COM 	data = req->bulk_data;
30519430SRaymond.Chen@Sun.COM 	p = data->b_rptr;
30529430SRaymond.Chen@Sun.COM 
30539430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
30549430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_xfer_result: received data len = %d",
30559430SRaymond.Chen@Sun.COM 	    (int)MBLKL(data));
30569430SRaymond.Chen@Sun.COM 
30579430SRaymond.Chen@Sun.COM 	if ((MBLKL(data) != WA_XFER_RESULT_LEN) ||
30589430SRaymond.Chen@Sun.COM 	    (p[1] != WA_RESULT_TYPE_TRANSFER)) {
30599430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
30609430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_xfer_result: invalid xfer result, "
30619430SRaymond.Chen@Sun.COM 		    "len = %d, p0 = 0x%x, p1 = 0x%x, p6 = 0x%x",
30629430SRaymond.Chen@Sun.COM 		    (int)MBLKL(data), p[0], p[1], p[6]);
30639430SRaymond.Chen@Sun.COM 
30649430SRaymond.Chen@Sun.COM 		usb_free_bulk_req(req);
30659430SRaymond.Chen@Sun.COM 
30669430SRaymond.Chen@Sun.COM 		return (USB_SUCCESS); /* don't stop this thread */
30679430SRaymond.Chen@Sun.COM 	}
30689430SRaymond.Chen@Sun.COM 
30699430SRaymond.Chen@Sun.COM 	/* Transfer result. Section 8.3.3.4 */
30709430SRaymond.Chen@Sun.COM 	(void) usb_parse_data("ccllccl", p, WA_XFER_RESULT_LEN, &result,
30719430SRaymond.Chen@Sun.COM 	    sizeof (wa_xfer_result_t));
30729430SRaymond.Chen@Sun.COM 
30739430SRaymond.Chen@Sun.COM 
30749430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
30759430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_xfer_result: id = 0x%x len = 0x%x nseg = 0x%02x"
30769430SRaymond.Chen@Sun.COM 	    " status = 0x%02x(0x%02x)", result.dwTransferID,
30779430SRaymond.Chen@Sun.COM 	    result.dwTransferLength, result.bTransferSegment,
30789430SRaymond.Chen@Sun.COM 	    result.bTransferStatus, p[11]&0x0f);
30799430SRaymond.Chen@Sun.COM 
30809430SRaymond.Chen@Sun.COM 	req->bulk_data = NULL; /* don't free it. we still need it */
30819430SRaymond.Chen@Sun.COM 	usb_free_bulk_req(req);
30829430SRaymond.Chen@Sun.COM 
30839430SRaymond.Chen@Sun.COM 	status = result.bTransferStatus;
30849430SRaymond.Chen@Sun.COM 	if ((status & 0x3f) == WA_STS_NOT_FOUND) {
30859430SRaymond.Chen@Sun.COM 		freemsg(data);
30869430SRaymond.Chen@Sun.COM 		/*
30879430SRaymond.Chen@Sun.COM 		 * The result is just ignored since the transfer request
30889430SRaymond.Chen@Sun.COM 		 * has completed
30899430SRaymond.Chen@Sun.COM 		 */
30909430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
30919430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_xfer_result: TransferID not found");
30929430SRaymond.Chen@Sun.COM 
30939430SRaymond.Chen@Sun.COM 		return (USB_SUCCESS);
30949430SRaymond.Chen@Sun.COM 	}
30959430SRaymond.Chen@Sun.COM 
30969430SRaymond.Chen@Sun.COM 	mutex_enter(&wa_data->wa_mutex);
30979430SRaymond.Chen@Sun.COM 	wr = wusb_wa_retrieve_wr(wa_data, result.dwTransferID);
30989430SRaymond.Chen@Sun.COM 	if ((wr == NULL)) {
30999430SRaymond.Chen@Sun.COM 	/* this id's corresponding WR may have been freed by timeout handler */
31009430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
31019430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_xfer_result: wr == deadbeef or NULL");
31029430SRaymond.Chen@Sun.COM 
31039430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
31049430SRaymond.Chen@Sun.COM 		freemsg(data);
31059430SRaymond.Chen@Sun.COM 
31069430SRaymond.Chen@Sun.COM 		return (USB_SUCCESS);
31079430SRaymond.Chen@Sun.COM 	}
31089430SRaymond.Chen@Sun.COM 
31099430SRaymond.Chen@Sun.COM 	/* bit 7 is last segment flag */
31109430SRaymond.Chen@Sun.COM 	if ((result.bTransferSegment & 0x7f) >= wr->wr_nsegs) {
31119430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
31129430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_xfer_result: error - "
31139430SRaymond.Chen@Sun.COM 		    " bTransferSegment(%d) > segment coutnts(%d)",
31149430SRaymond.Chen@Sun.COM 		    (result.bTransferSegment & 0x7f), wr->wr_nsegs);
31159430SRaymond.Chen@Sun.COM 
31169430SRaymond.Chen@Sun.COM 		goto err;
31179430SRaymond.Chen@Sun.COM 	}
31189430SRaymond.Chen@Sun.COM 
31199430SRaymond.Chen@Sun.COM 	lastseg = result.bTransferSegment & 0x80;
31209430SRaymond.Chen@Sun.COM 	hdl = wr->wr_rp;
31219430SRaymond.Chen@Sun.COM 
31229430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
31239430SRaymond.Chen@Sun.COM 	seg = &wr->wr_seg_array[result.bTransferSegment & 0x7f];
31249430SRaymond.Chen@Sun.COM 	seg->seg_status = result.bTransferStatus;
31259430SRaymond.Chen@Sun.COM 	act_len = seg->seg_actual_len = result.dwTransferLength;
31269430SRaymond.Chen@Sun.COM 
31279430SRaymond.Chen@Sun.COM 	/*
31289430SRaymond.Chen@Sun.COM 	 * if this is the last segment, we should not continue.
31299430SRaymond.Chen@Sun.COM 	 * IMPT: we expect the WA deliver result sequentially.
31309430SRaymond.Chen@Sun.COM 	 */
31319430SRaymond.Chen@Sun.COM 	seg->seg_done = (result.bTransferSegment) & 0x80;
31329430SRaymond.Chen@Sun.COM 
31339430SRaymond.Chen@Sun.COM 	wr->wr_seg_done++;
31349430SRaymond.Chen@Sun.COM 	hdl->rp_avail_reqs++;
31359430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
31369430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_xfer_result: wr = %p, rp=%p, avail_req=%d", (void*)wr,
31379430SRaymond.Chen@Sun.COM 	    (void*)wr->wr_rp, hdl->rp_avail_reqs);
31389430SRaymond.Chen@Sun.COM 
31399430SRaymond.Chen@Sun.COM 	cv_broadcast(&hdl->rp_cv);
31409430SRaymond.Chen@Sun.COM 
31419430SRaymond.Chen@Sun.COM 	if (status & 0x40) {
31429430SRaymond.Chen@Sun.COM 		status = 0; /* ignore warning, see Tab8-15 */
31439430SRaymond.Chen@Sun.COM 	}
31449430SRaymond.Chen@Sun.COM 	seg->seg_status = status;
31459430SRaymond.Chen@Sun.COM 
31469430SRaymond.Chen@Sun.COM 	/* Error bit set */
31479430SRaymond.Chen@Sun.COM 	if (status & 0x80) {
31489430SRaymond.Chen@Sun.COM 		/* don't change timeout error */
31499430SRaymond.Chen@Sun.COM 		if (wr->wr_state != WR_TIMEOUT) {
31509430SRaymond.Chen@Sun.COM 			wr->wr_state = WR_XFER_ERR;
31519430SRaymond.Chen@Sun.COM 		}
31529430SRaymond.Chen@Sun.COM 
31539430SRaymond.Chen@Sun.COM 		/*
31549430SRaymond.Chen@Sun.COM 		 * The timeout handler is waiting, but the result thread will
31559430SRaymond.Chen@Sun.COM 		 * process this wr.
31569430SRaymond.Chen@Sun.COM 		 */
31579430SRaymond.Chen@Sun.COM 		if ((wr->wr_state == WR_TIMEOUT) &&
31589430SRaymond.Chen@Sun.COM 		    (status & 0x3F) == WA_STS_ABORTED) {
31599430SRaymond.Chen@Sun.COM 			wr->wr_has_aborted = 1;
31609430SRaymond.Chen@Sun.COM 			cv_signal(&wr->wr_cv); /* to inform timeout hdler */
31619430SRaymond.Chen@Sun.COM 		}
31629430SRaymond.Chen@Sun.COM 
31639430SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
31649430SRaymond.Chen@Sun.COM 		/* seg error, don't proceed with this WR */
31659430SRaymond.Chen@Sun.COM 		goto err;
31669430SRaymond.Chen@Sun.COM 	}
31679430SRaymond.Chen@Sun.COM 
31689430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
31699430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_xfer_result: status = 0x%02x dir=%s",
31709430SRaymond.Chen@Sun.COM 	    status, (wr->wr_dir == WA_DIR_IN)?"IN":"OUT");
31719430SRaymond.Chen@Sun.COM 
31729430SRaymond.Chen@Sun.COM 	/*
31739430SRaymond.Chen@Sun.COM 	 * for an IN endpoint and data length > 0 and no error, read in
31749430SRaymond.Chen@Sun.COM 	 * the real data. Otherwise, for OUT EP, or data length = 0, or
31759430SRaymond.Chen@Sun.COM 	 * segment error, don't read.
31769430SRaymond.Chen@Sun.COM 	 */
31779430SRaymond.Chen@Sun.COM 	if ((wr->wr_dir == WA_DIR_IN) &&
31789430SRaymond.Chen@Sun.COM 	    (act_len > 0) &&
31799430SRaymond.Chen@Sun.COM 	    ((status & 0x3F) == 0)) { /* if segment error, don't read */
31809430SRaymond.Chen@Sun.COM 		/* receive data */
31819430SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
31829430SRaymond.Chen@Sun.COM 		mutex_exit(&wa_data->wa_mutex);
31839430SRaymond.Chen@Sun.COM 		rval = wusb_wa_get_data(wa_data, seg, act_len);
31849430SRaymond.Chen@Sun.COM 		mutex_enter(&wa_data->wa_mutex);
31859430SRaymond.Chen@Sun.COM 		mutex_enter(&hdl->rp_mutex);
31869430SRaymond.Chen@Sun.COM 		if (rval != USB_SUCCESS) {
31879430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
31889430SRaymond.Chen@Sun.COM 			    "wusb_wa_get_xfer_result: can't get seg data:%d",
31899430SRaymond.Chen@Sun.COM 			    rval);
31909430SRaymond.Chen@Sun.COM 
31919430SRaymond.Chen@Sun.COM 			mutex_exit(&hdl->rp_mutex);
31929430SRaymond.Chen@Sun.COM 
31939430SRaymond.Chen@Sun.COM 			goto err;
31949430SRaymond.Chen@Sun.COM 		}
31959430SRaymond.Chen@Sun.COM 
31969430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
31979430SRaymond.Chen@Sun.COM 		    "wusb_wa_get_xfer_result: get (%dB) data for IN ep",
31989430SRaymond.Chen@Sun.COM 		    act_len);
31999430SRaymond.Chen@Sun.COM 	}
32009430SRaymond.Chen@Sun.COM 
32019430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
32029430SRaymond.Chen@Sun.COM 
32039430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
32049430SRaymond.Chen@Sun.COM 
32059430SRaymond.Chen@Sun.COM 	/* check if the whole transfer has completed */
32069430SRaymond.Chen@Sun.COM 	wusb_wa_check_req_done(wa_data, wr, lastseg);
32079430SRaymond.Chen@Sun.COM 
32089430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
32099430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_xfer_result: ended");
32109430SRaymond.Chen@Sun.COM 
32119430SRaymond.Chen@Sun.COM 	freemsg(data);
32129430SRaymond.Chen@Sun.COM 
32139430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
32149430SRaymond.Chen@Sun.COM 
32159430SRaymond.Chen@Sun.COM err:
32169430SRaymond.Chen@Sun.COM 	mutex_exit(&wa_data->wa_mutex);
32179430SRaymond.Chen@Sun.COM 
32189430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
32199430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
32209430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_xfer_result: segment(%02x) error, abort wr 0x%p,"
32219430SRaymond.Chen@Sun.COM 	    "wr_state=%d", result.bTransferSegment, (void*)wr, wr->wr_state);
32229430SRaymond.Chen@Sun.COM 
32239430SRaymond.Chen@Sun.COM 	/* if it's timeout, just return the TIMEOUT error */
32249430SRaymond.Chen@Sun.COM 	if (wr->wr_state == WR_TIMEOUT) {
32259430SRaymond.Chen@Sun.COM 		cr = USB_CR_TIMEOUT;
32269430SRaymond.Chen@Sun.COM 	} else {
32279430SRaymond.Chen@Sun.COM 		cr = wusb_wa_sts2cr(status);
32289430SRaymond.Chen@Sun.COM 	}
32299430SRaymond.Chen@Sun.COM 
32309430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
32319430SRaymond.Chen@Sun.COM 
32329430SRaymond.Chen@Sun.COM 	wusb_wa_handle_error(wa_data, wr, cr);
32339430SRaymond.Chen@Sun.COM 
32349430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
32359430SRaymond.Chen@Sun.COM 	    "wusb_wa_get_xfer_result: error end, cr=%d",
32369430SRaymond.Chen@Sun.COM 	    cr);
32379430SRaymond.Chen@Sun.COM 
32389430SRaymond.Chen@Sun.COM 	freemsg(data);
32399430SRaymond.Chen@Sun.COM 
32409430SRaymond.Chen@Sun.COM 	return (USB_SUCCESS);
32419430SRaymond.Chen@Sun.COM }
32429430SRaymond.Chen@Sun.COM 
32439430SRaymond.Chen@Sun.COM 
32449430SRaymond.Chen@Sun.COM static void
wusb_wa_handle_error(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr)32459430SRaymond.Chen@Sun.COM wusb_wa_handle_error(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
32469430SRaymond.Chen@Sun.COM     usb_cr_t cr)
32479430SRaymond.Chen@Sun.COM {
32489430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
32499430SRaymond.Chen@Sun.COM 	    "wusb_wa_handle_error: start");
32509430SRaymond.Chen@Sun.COM 
32519430SRaymond.Chen@Sun.COM 	mutex_enter(&wr->wr_rp->rp_mutex);
32529430SRaymond.Chen@Sun.COM 	if (wr->wr_seg_done != wr->wr_curr_seg) {
32539430SRaymond.Chen@Sun.COM 	/* still segments pending, abort them */
32549430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
32559430SRaymond.Chen@Sun.COM 		    "wusb_wa_handle_error: segment err, abort other segs");
32569430SRaymond.Chen@Sun.COM 
32579430SRaymond.Chen@Sun.COM 		wusb_wa_abort_req(wa_data, wr, wr->wr_id);
32589430SRaymond.Chen@Sun.COM 	}
32599430SRaymond.Chen@Sun.COM 
32609430SRaymond.Chen@Sun.COM 	wusb_wa_stop_xfer_timer(wr);
32619430SRaymond.Chen@Sun.COM 	wr->wr_rp->rp_state = WA_RPIPE_STATE_IDLE;
32629430SRaymond.Chen@Sun.COM 	wr->wr_rp->rp_curr_wr = NULL;
32639430SRaymond.Chen@Sun.COM 	mutex_exit(&wr->wr_rp->rp_mutex);
32649430SRaymond.Chen@Sun.COM 
32659430SRaymond.Chen@Sun.COM 	wr->wr_cb(wa_data, wr, cr, 1);
32669430SRaymond.Chen@Sun.COM 
32679430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
32689430SRaymond.Chen@Sun.COM 	    "wusb_wa_handle_error: error end, cr=%d",
32699430SRaymond.Chen@Sun.COM 	    cr);
32709430SRaymond.Chen@Sun.COM }
32719430SRaymond.Chen@Sun.COM 
32729430SRaymond.Chen@Sun.COM /*
32739430SRaymond.Chen@Sun.COM  * Check if current request is done, if yes, do callback and move on to
32749430SRaymond.Chen@Sun.COM  * next request; if there is any uncleared error, do callback to cleanup
32759430SRaymond.Chen@Sun.COM  * the pipe
32769430SRaymond.Chen@Sun.COM  */
32779430SRaymond.Chen@Sun.COM void
wusb_wa_check_req_done(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,uint8_t lastseg)32789430SRaymond.Chen@Sun.COM wusb_wa_check_req_done(wusb_wa_data_t *wa_data,
32799430SRaymond.Chen@Sun.COM     wusb_wa_trans_wrapper_t *wr, uint8_t lastseg)
32809430SRaymond.Chen@Sun.COM {
32819430SRaymond.Chen@Sun.COM 	wusb_wa_rpipe_hdl_t	*hdl = wr->wr_rp;
32829430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t		*seg;
32839430SRaymond.Chen@Sun.COM 	int			i, rval;
32849430SRaymond.Chen@Sun.COM 	usb_cr_t		cr;
32859430SRaymond.Chen@Sun.COM 
32869430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
32879430SRaymond.Chen@Sun.COM 	    "wusb_wa_check_req_done: wr = 0x%p, lastseg=%02x",
32889430SRaymond.Chen@Sun.COM 	    (void*)wr, lastseg);
32899430SRaymond.Chen@Sun.COM 
32909430SRaymond.Chen@Sun.COM 	mutex_enter(&hdl->rp_mutex);
32919430SRaymond.Chen@Sun.COM 	/* not done: submitted segs not finished and lastseg not set */
32929430SRaymond.Chen@Sun.COM 	if ((wr->wr_seg_done != wr->wr_curr_seg) && (!lastseg)) {
32939430SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
32949430SRaymond.Chen@Sun.COM 
32959430SRaymond.Chen@Sun.COM 		return;
32969430SRaymond.Chen@Sun.COM 	}
32979430SRaymond.Chen@Sun.COM 
32989430SRaymond.Chen@Sun.COM 	if (wr->wr_state != 0) { /* abort somewhere */
32999430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
33009430SRaymond.Chen@Sun.COM 		    "wusb_wa_check_req_done: tw(%p) aborted somewhere",
33019430SRaymond.Chen@Sun.COM 		    (void*)wr);
33029430SRaymond.Chen@Sun.COM 		cr = USB_CR_UNSPECIFIED_ERR;
33039430SRaymond.Chen@Sun.COM 
33049430SRaymond.Chen@Sun.COM 		goto reset;
33059430SRaymond.Chen@Sun.COM 	}
33069430SRaymond.Chen@Sun.COM 
33079430SRaymond.Chen@Sun.COM 	/* check if there is any error */
33089430SRaymond.Chen@Sun.COM 	for (i = 0; i < wr->wr_curr_seg; i++) {
33099430SRaymond.Chen@Sun.COM 		seg = &wr->wr_seg_array[i];
33109430SRaymond.Chen@Sun.COM 		if (seg->seg_status != WA_STS_SUCCESS) {
33119430SRaymond.Chen@Sun.COM 			/* what about short xfer? need to fix */
33129430SRaymond.Chen@Sun.COM 			cr = wusb_wa_sts2cr(seg->seg_status);
33139430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
33149430SRaymond.Chen@Sun.COM 			    "wusb_wa_check_req_done: seg fail, status=%02x",
33159430SRaymond.Chen@Sun.COM 			    seg->seg_status);
33169430SRaymond.Chen@Sun.COM 
33179430SRaymond.Chen@Sun.COM 			goto reset;
33189430SRaymond.Chen@Sun.COM 		}
33199430SRaymond.Chen@Sun.COM 
33209430SRaymond.Chen@Sun.COM 		if (seg->seg_done == 0x80) {
33219430SRaymond.Chen@Sun.COM 		/* device has told this is the last segment, we're done */
33229430SRaymond.Chen@Sun.COM 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
33239430SRaymond.Chen@Sun.COM 			    "wusb_wa_check_req_done: last seg");
33249430SRaymond.Chen@Sun.COM 
33259430SRaymond.Chen@Sun.COM 			goto done;
33269430SRaymond.Chen@Sun.COM 		}
33279430SRaymond.Chen@Sun.COM 	}
33289430SRaymond.Chen@Sun.COM 
33299430SRaymond.Chen@Sun.COM 	/* check if current request has completed */
33309430SRaymond.Chen@Sun.COM 	/*
33319430SRaymond.Chen@Sun.COM 	 * Transfer another segment.
33329430SRaymond.Chen@Sun.COM 	 *
33339430SRaymond.Chen@Sun.COM 	 */
33349430SRaymond.Chen@Sun.COM 	if (wr->wr_curr_seg < wr->wr_nsegs) {
33359430SRaymond.Chen@Sun.COM 		/* send the remained segments */
33369430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
33379430SRaymond.Chen@Sun.COM 		    "wusb_wa_check_req_done: req not completed, restart");
33389430SRaymond.Chen@Sun.COM 
33399430SRaymond.Chen@Sun.COM 		rval = wusb_wa_wr_xfer(wa_data, hdl, wr, wr->wr_flags);
33409430SRaymond.Chen@Sun.COM 		if (rval != USB_SUCCESS) {
33419430SRaymond.Chen@Sun.COM 			cr = usba_rval2cr(rval);
33429430SRaymond.Chen@Sun.COM 
33439430SRaymond.Chen@Sun.COM 			goto reset;
33449430SRaymond.Chen@Sun.COM 		}
33459430SRaymond.Chen@Sun.COM 
33469430SRaymond.Chen@Sun.COM 		mutex_exit(&hdl->rp_mutex);
33479430SRaymond.Chen@Sun.COM 
33489430SRaymond.Chen@Sun.COM 		return;
33499430SRaymond.Chen@Sun.COM 	}
33509430SRaymond.Chen@Sun.COM 
33519430SRaymond.Chen@Sun.COM done:
33529430SRaymond.Chen@Sun.COM 	wusb_wa_stop_xfer_timer(wr);
33539430SRaymond.Chen@Sun.COM 
33549430SRaymond.Chen@Sun.COM 	/* release the occupied requests */
33559430SRaymond.Chen@Sun.COM 	hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
33569430SRaymond.Chen@Sun.COM 	cv_signal(&hdl->rp_cv);
33579430SRaymond.Chen@Sun.COM 
33589430SRaymond.Chen@Sun.COM 	hdl->rp_state = WA_RPIPE_STATE_IDLE;
33599430SRaymond.Chen@Sun.COM 	hdl->rp_curr_wr = NULL;
33609430SRaymond.Chen@Sun.COM 	wr->wr_state = WR_FINISHED;
33619430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
33629430SRaymond.Chen@Sun.COM 
33639430SRaymond.Chen@Sun.COM 	wr->wr_cb(wa_data, wr, USB_CR_OK, 0);
33649430SRaymond.Chen@Sun.COM 
33659430SRaymond.Chen@Sun.COM 	/* Need to move on to next request? usba will do this */
33669430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
33679430SRaymond.Chen@Sun.COM 	    "wusb_wa_check_req_done: ended");
33689430SRaymond.Chen@Sun.COM 
33699430SRaymond.Chen@Sun.COM 	return;
33709430SRaymond.Chen@Sun.COM 
33719430SRaymond.Chen@Sun.COM reset:
33729430SRaymond.Chen@Sun.COM 	wusb_wa_stop_xfer_timer(wr);
33739430SRaymond.Chen@Sun.COM 
33749430SRaymond.Chen@Sun.COM 	/* not necessary to reset the RPipe */
33759430SRaymond.Chen@Sun.COM 	hdl->rp_state = WA_RPIPE_STATE_IDLE;
33769430SRaymond.Chen@Sun.COM 	hdl->rp_curr_wr = NULL;
33779430SRaymond.Chen@Sun.COM 
33789430SRaymond.Chen@Sun.COM 	hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
33799430SRaymond.Chen@Sun.COM 	cv_signal(&hdl->rp_cv);
33809430SRaymond.Chen@Sun.COM 
33819430SRaymond.Chen@Sun.COM 	/* if it's timeout, just return the TIMEOUT error */
33829430SRaymond.Chen@Sun.COM 	if (wr->wr_state == WR_TIMEOUT)
33839430SRaymond.Chen@Sun.COM 		cr = USB_CR_TIMEOUT;
33849430SRaymond.Chen@Sun.COM 
33859430SRaymond.Chen@Sun.COM 	mutex_exit(&hdl->rp_mutex);
33869430SRaymond.Chen@Sun.COM 
33879430SRaymond.Chen@Sun.COM 	wr->wr_cb(wa_data, wr, cr, 1);
33889430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
33899430SRaymond.Chen@Sun.COM 	    "wusb_wa_check_req_done: reset end");
33909430SRaymond.Chen@Sun.COM }
33919430SRaymond.Chen@Sun.COM 
33929430SRaymond.Chen@Sun.COM /*
33939430SRaymond.Chen@Sun.COM  * callback for ctrl transfer
33949430SRaymond.Chen@Sun.COM  *
33959430SRaymond.Chen@Sun.COM  * reset_flag: not support yet
33969430SRaymond.Chen@Sun.COM  */
33979430SRaymond.Chen@Sun.COM void
wusb_wa_handle_ctrl(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr,uint_t reset_flag)33989430SRaymond.Chen@Sun.COM wusb_wa_handle_ctrl(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
33999430SRaymond.Chen@Sun.COM 	usb_cr_t cr, uint_t reset_flag)
34009430SRaymond.Chen@Sun.COM {
34019430SRaymond.Chen@Sun.COM 	usb_ctrl_req_t	*req;
34029430SRaymond.Chen@Sun.COM 	usb_bulk_req_t	*bulk_req;
34039430SRaymond.Chen@Sun.COM 	mblk_t		*data, *bulk_data;
34049430SRaymond.Chen@Sun.COM 	int		i;
34059430SRaymond.Chen@Sun.COM 	size_t		len;
34069430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t	*seg;
34079430SRaymond.Chen@Sun.COM 
34089430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
34099430SRaymond.Chen@Sun.COM 	    "wusb_wa_handle_ctrl: wr = 0x%p, cr = 0x%x, flag=%d",
34109430SRaymond.Chen@Sun.COM 	    (void*)wr, cr, reset_flag);
34119430SRaymond.Chen@Sun.COM 
34129430SRaymond.Chen@Sun.COM 	req = (usb_ctrl_req_t *)wr->wr_reqp;
34139430SRaymond.Chen@Sun.COM 
34149430SRaymond.Chen@Sun.COM 	if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
34159430SRaymond.Chen@Sun.COM 
34169430SRaymond.Chen@Sun.COM 		/* do callback */
34179430SRaymond.Chen@Sun.COM 		wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
34189430SRaymond.Chen@Sun.COM 
34199430SRaymond.Chen@Sun.COM 		return;
34209430SRaymond.Chen@Sun.COM 	}
34219430SRaymond.Chen@Sun.COM 
34229430SRaymond.Chen@Sun.COM 	mutex_enter(&wr->wr_rp->rp_mutex);
34239430SRaymond.Chen@Sun.COM 	data = req->ctrl_data;
34249430SRaymond.Chen@Sun.COM 	for (i = 0; i < wr->wr_nsegs; i++) {
34259430SRaymond.Chen@Sun.COM 		seg = &wr->wr_seg_array[i];
34269430SRaymond.Chen@Sun.COM 		/* copy received data to original req buffer */
34279430SRaymond.Chen@Sun.COM 		bulk_req = (usb_bulk_req_t *)
34289430SRaymond.Chen@Sun.COM 		    wr->wr_seg_array[i].seg_data_reqp;
34299430SRaymond.Chen@Sun.COM 		bulk_data = bulk_req->bulk_data;
34309430SRaymond.Chen@Sun.COM 		len = MBLKL(bulk_data);
34319430SRaymond.Chen@Sun.COM 		bcopy(bulk_data->b_rptr, data->b_wptr, len);
34329430SRaymond.Chen@Sun.COM 		data->b_wptr += len;
34339430SRaymond.Chen@Sun.COM 		if (len < wr->wr_seg_array[i].seg_len) {
34349430SRaymond.Chen@Sun.COM 			/* short xfer */
34359430SRaymond.Chen@Sun.COM 			break;
34369430SRaymond.Chen@Sun.COM 		}
34379430SRaymond.Chen@Sun.COM 
34389430SRaymond.Chen@Sun.COM 		if (seg->seg_done == 0x80) {
34399430SRaymond.Chen@Sun.COM 		/* last segment, finish */
34409430SRaymond.Chen@Sun.COM 			break;
34419430SRaymond.Chen@Sun.COM 		}
34429430SRaymond.Chen@Sun.COM 	}
34439430SRaymond.Chen@Sun.COM 
34449430SRaymond.Chen@Sun.COM 	mutex_exit(&wr->wr_rp->rp_mutex);
34459430SRaymond.Chen@Sun.COM 	/* do callback */
34469430SRaymond.Chen@Sun.COM 	wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
34479430SRaymond.Chen@Sun.COM }
34489430SRaymond.Chen@Sun.COM 
34499430SRaymond.Chen@Sun.COM /*
34509430SRaymond.Chen@Sun.COM  * callback for bulk transfer
34519430SRaymond.Chen@Sun.COM  *
34529430SRaymond.Chen@Sun.COM  * reset_flag: not support yet
34539430SRaymond.Chen@Sun.COM  */
34549430SRaymond.Chen@Sun.COM void
wusb_wa_handle_bulk(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr,uint_t reset_flag)34559430SRaymond.Chen@Sun.COM wusb_wa_handle_bulk(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
34569430SRaymond.Chen@Sun.COM 	usb_cr_t cr, uint_t reset_flag)
34579430SRaymond.Chen@Sun.COM {
34589430SRaymond.Chen@Sun.COM 	usb_bulk_req_t	*req;
34599430SRaymond.Chen@Sun.COM 	usb_bulk_req_t	*bulk_req;
34609430SRaymond.Chen@Sun.COM 	mblk_t		*data, *bulk_data;
34619430SRaymond.Chen@Sun.COM 	int		i;
34629430SRaymond.Chen@Sun.COM 	size_t		len;
34639430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t	*seg;
34649430SRaymond.Chen@Sun.COM 
34659430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
34669430SRaymond.Chen@Sun.COM 	    "wusb_wa_handle_bulk: wr = 0x%p, cr = 0x%x, flag=%d",
34679430SRaymond.Chen@Sun.COM 	    (void*)wr, cr, reset_flag);
34689430SRaymond.Chen@Sun.COM 
34699430SRaymond.Chen@Sun.COM 	req = (usb_bulk_req_t *)wr->wr_reqp;
34709430SRaymond.Chen@Sun.COM 
34719430SRaymond.Chen@Sun.COM 	if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
34729430SRaymond.Chen@Sun.COM 		/* do callback */
34739430SRaymond.Chen@Sun.COM 		wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
34749430SRaymond.Chen@Sun.COM 
34759430SRaymond.Chen@Sun.COM 		return;
34769430SRaymond.Chen@Sun.COM 	}
34779430SRaymond.Chen@Sun.COM 
34789430SRaymond.Chen@Sun.COM 	mutex_enter(&wr->wr_rp->rp_mutex);
34799430SRaymond.Chen@Sun.COM 	data = req->bulk_data;
34809430SRaymond.Chen@Sun.COM 	for (i = 0; i < wr->wr_nsegs; i++) {
34819430SRaymond.Chen@Sun.COM 		seg = &wr->wr_seg_array[i];
34829430SRaymond.Chen@Sun.COM 		/* copy received data to original req buffer */
34839430SRaymond.Chen@Sun.COM 		bulk_req = (usb_bulk_req_t *)
34849430SRaymond.Chen@Sun.COM 		    wr->wr_seg_array[i].seg_data_reqp;
34859430SRaymond.Chen@Sun.COM 		bulk_data = bulk_req->bulk_data;
34869430SRaymond.Chen@Sun.COM 		len = MBLKL(bulk_data);
34879430SRaymond.Chen@Sun.COM 		bcopy(bulk_data->b_rptr, data->b_wptr, len);
34889430SRaymond.Chen@Sun.COM 		data->b_wptr += len;
34899430SRaymond.Chen@Sun.COM 		if (len < wr->wr_seg_array[i].seg_len) {
34909430SRaymond.Chen@Sun.COM 			/* short xfer */
34919430SRaymond.Chen@Sun.COM 			break;
34929430SRaymond.Chen@Sun.COM 		}
34939430SRaymond.Chen@Sun.COM 
34949430SRaymond.Chen@Sun.COM 		if (seg->seg_done == 0x80) {
34959430SRaymond.Chen@Sun.COM 		/* last segment, finish */
34969430SRaymond.Chen@Sun.COM 			break;
34979430SRaymond.Chen@Sun.COM 		}
34989430SRaymond.Chen@Sun.COM 	}
34999430SRaymond.Chen@Sun.COM 
35009430SRaymond.Chen@Sun.COM 	mutex_exit(&wr->wr_rp->rp_mutex);
35019430SRaymond.Chen@Sun.COM 	/* do callback */
35029430SRaymond.Chen@Sun.COM 	wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
35039430SRaymond.Chen@Sun.COM }
35049430SRaymond.Chen@Sun.COM 
35059430SRaymond.Chen@Sun.COM int
wa_submit_periodic_req(wusb_wa_data_t * wa_data,usba_pipe_handle_data_t * ph)35069430SRaymond.Chen@Sun.COM wa_submit_periodic_req(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph)
35079430SRaymond.Chen@Sun.COM {
35089430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
35099430SRaymond.Chen@Sun.COM 	    "wa_submit_periodic_req: wa_data=0x%p, ph=0x%p",
35109430SRaymond.Chen@Sun.COM 	    (void*)wa_data, (void*)ph);
35119430SRaymond.Chen@Sun.COM 
35129430SRaymond.Chen@Sun.COM 	return (wa_data->pipe_periodic_req(wa_data, ph));
35139430SRaymond.Chen@Sun.COM }
35149430SRaymond.Chen@Sun.COM 
35159430SRaymond.Chen@Sun.COM /*
35169430SRaymond.Chen@Sun.COM  * callback for intr transfer
35179430SRaymond.Chen@Sun.COM  *
35189430SRaymond.Chen@Sun.COM  * reset_flag: not support yet
35199430SRaymond.Chen@Sun.COM  */
35209430SRaymond.Chen@Sun.COM void
wusb_wa_handle_intr(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr,uint_t reset_flag)35219430SRaymond.Chen@Sun.COM wusb_wa_handle_intr(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
35229430SRaymond.Chen@Sun.COM 	usb_cr_t cr, uint_t reset_flag)
35239430SRaymond.Chen@Sun.COM {
35249430SRaymond.Chen@Sun.COM 	usb_intr_req_t	*req;
35259430SRaymond.Chen@Sun.COM 	usb_req_attrs_t	attrs;
35269430SRaymond.Chen@Sun.COM 	usba_pipe_handle_data_t *ph = wr->wr_ph;
35279430SRaymond.Chen@Sun.COM 	usb_bulk_req_t	*bulk_req;
35289430SRaymond.Chen@Sun.COM 	mblk_t		*data, *bulk_data;
35299430SRaymond.Chen@Sun.COM 	int		i;
35309430SRaymond.Chen@Sun.COM 	size_t		len;
35319430SRaymond.Chen@Sun.COM 	int		rval;
35329430SRaymond.Chen@Sun.COM 	wusb_wa_seg_t	*seg;
35339430SRaymond.Chen@Sun.COM 
35349430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
35359430SRaymond.Chen@Sun.COM 	    "wusb_wa_handle_intr: wr = 0x%p, cr = 0x%x, flag=%d",
35369430SRaymond.Chen@Sun.COM 	    (void*)wr, cr, reset_flag);
35379430SRaymond.Chen@Sun.COM 
35389430SRaymond.Chen@Sun.COM 	req = (usb_intr_req_t *)wr->wr_reqp;
35399430SRaymond.Chen@Sun.COM 	attrs = req->intr_attributes;
35409430SRaymond.Chen@Sun.COM 
35419430SRaymond.Chen@Sun.COM 	if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
35429430SRaymond.Chen@Sun.COM 		/* do callback */
35439430SRaymond.Chen@Sun.COM 		wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
35449430SRaymond.Chen@Sun.COM 
35459430SRaymond.Chen@Sun.COM 		return;
35469430SRaymond.Chen@Sun.COM 	}
35479430SRaymond.Chen@Sun.COM 
35489430SRaymond.Chen@Sun.COM 	mutex_enter(&wr->wr_rp->rp_mutex);
35499430SRaymond.Chen@Sun.COM 	/* copy data to client's buffer */
35509430SRaymond.Chen@Sun.COM 	data = req->intr_data;
35519430SRaymond.Chen@Sun.COM 	for (i = 0; i < wr->wr_nsegs; i++) {
35529430SRaymond.Chen@Sun.COM 		seg = &wr->wr_seg_array[i];
35539430SRaymond.Chen@Sun.COM 		/* copy received data to original req buffer */
35549430SRaymond.Chen@Sun.COM 		bulk_req = (usb_bulk_req_t *)
35559430SRaymond.Chen@Sun.COM 		    wr->wr_seg_array[i].seg_data_reqp;
35569430SRaymond.Chen@Sun.COM 		bulk_data = bulk_req->bulk_data;
35579430SRaymond.Chen@Sun.COM 		len = MBLKL(bulk_data);
35589430SRaymond.Chen@Sun.COM 		bcopy(bulk_data->b_rptr, data->b_wptr, len);
35599430SRaymond.Chen@Sun.COM 		data->b_wptr += len;
35609430SRaymond.Chen@Sun.COM 		if (len < wr->wr_seg_array[i].seg_len) {
35619430SRaymond.Chen@Sun.COM 			/* short xfer */
35629430SRaymond.Chen@Sun.COM 			break;
35639430SRaymond.Chen@Sun.COM 		}
35649430SRaymond.Chen@Sun.COM 
35659430SRaymond.Chen@Sun.COM 		if (seg->seg_done & 0x80) {
35669430SRaymond.Chen@Sun.COM 
35679430SRaymond.Chen@Sun.COM 			break;
35689430SRaymond.Chen@Sun.COM 		}
35699430SRaymond.Chen@Sun.COM 	}
35709430SRaymond.Chen@Sun.COM 
35719430SRaymond.Chen@Sun.COM 	if (attrs & USB_ATTRS_ONE_XFER) {
35729430SRaymond.Chen@Sun.COM 	/* client requires ONE_XFER request, return */
35739430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
35749430SRaymond.Chen@Sun.COM 		    "wusb_wa_handle_intr: ONE_XFER set");
35759430SRaymond.Chen@Sun.COM 
35769430SRaymond.Chen@Sun.COM 		mutex_exit(&wr->wr_rp->rp_mutex);
35779430SRaymond.Chen@Sun.COM 		goto finish;
35789430SRaymond.Chen@Sun.COM 	}
35799430SRaymond.Chen@Sun.COM 
35809430SRaymond.Chen@Sun.COM 	/* polling mode */
35819430SRaymond.Chen@Sun.COM 	mutex_exit(&wr->wr_rp->rp_mutex);
35829430SRaymond.Chen@Sun.COM 	rval = wa_submit_periodic_req(wa_data, ph);
35839430SRaymond.Chen@Sun.COM 	if (rval != USB_SUCCESS) {
35849430SRaymond.Chen@Sun.COM 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
35859430SRaymond.Chen@Sun.COM 		    "wusb_wa_handle_intr: polling, fail to resubmit req");
35869430SRaymond.Chen@Sun.COM 
35879430SRaymond.Chen@Sun.COM 		goto finish;
35889430SRaymond.Chen@Sun.COM 	}
35899430SRaymond.Chen@Sun.COM 
35909430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
35919430SRaymond.Chen@Sun.COM 	    "wusb_wa_handle_intr: polling, resubmit request, rv=%d", rval);
35929430SRaymond.Chen@Sun.COM 
35939430SRaymond.Chen@Sun.COM finish:
35949430SRaymond.Chen@Sun.COM 	/* do callback */
35959430SRaymond.Chen@Sun.COM 	wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
35969430SRaymond.Chen@Sun.COM 
35979430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
35989430SRaymond.Chen@Sun.COM 	    "wusb_wa_handle_intr: end");
35999430SRaymond.Chen@Sun.COM }
36009430SRaymond.Chen@Sun.COM 
36019430SRaymond.Chen@Sun.COM /*
36029430SRaymond.Chen@Sun.COM  * free transfer wrapper
36039430SRaymond.Chen@Sun.COM  * call host controller driver callback for completion handling
36049430SRaymond.Chen@Sun.COM  *
36059430SRaymond.Chen@Sun.COM  * This callback will call WA's specific callback function.
36069430SRaymond.Chen@Sun.COM  * The callback functions should call usba_hcdi_cb() to pass request
36079430SRaymond.Chen@Sun.COM  * back to client driver.
36089430SRaymond.Chen@Sun.COM  */
36099430SRaymond.Chen@Sun.COM void
wusb_wa_callback(wusb_wa_data_t * wa_data,usba_pipe_handle_data_t * ph,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr)36109430SRaymond.Chen@Sun.COM wusb_wa_callback(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph,
36119430SRaymond.Chen@Sun.COM     wusb_wa_trans_wrapper_t *wr, usb_cr_t cr)
36129430SRaymond.Chen@Sun.COM {
36139430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
36149430SRaymond.Chen@Sun.COM 	    "wusb_wa_callback: wr=0x%p, cr=0x%x, ph=0x%p, req = 0x%p",
36159430SRaymond.Chen@Sun.COM 	    (void*)wr, cr, (void*)ph, (void*)((wr == NULL)?0:wr->wr_reqp));
36169430SRaymond.Chen@Sun.COM 
36179430SRaymond.Chen@Sun.COM 	if (cr == USB_CR_FLUSHED) {
36189430SRaymond.Chen@Sun.COM 		/*
36199430SRaymond.Chen@Sun.COM 		 * the wr is aborted. mark the rpipe as error,
36209430SRaymond.Chen@Sun.COM 		 * so that the periodic xfer callbacks will not submit
36219430SRaymond.Chen@Sun.COM 		 * further requests.
36229430SRaymond.Chen@Sun.COM 		 */
36239430SRaymond.Chen@Sun.COM 		mutex_enter(&wr->wr_rp->rp_mutex);
36249430SRaymond.Chen@Sun.COM 		wr->wr_rp->rp_state = WA_RPIPE_STATE_ERROR;
36259430SRaymond.Chen@Sun.COM 		mutex_exit(&wr->wr_rp->rp_mutex);
36269430SRaymond.Chen@Sun.COM 	}
36279430SRaymond.Chen@Sun.COM 
36289430SRaymond.Chen@Sun.COM 	wa_data->rpipe_xfer_cb(wa_data->wa_dip, ph, wr, cr);
36299430SRaymond.Chen@Sun.COM 
36309430SRaymond.Chen@Sun.COM 	/*
36319430SRaymond.Chen@Sun.COM 	 * need to consider carefully when to free wrapper
36329430SRaymond.Chen@Sun.COM 	 * if the rpipe is reset, what to do with current wr in processing?
36339430SRaymond.Chen@Sun.COM 	 */
36349430SRaymond.Chen@Sun.COM 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
36359430SRaymond.Chen@Sun.COM 	    "wusb_wa_callback: hwahc callback finish for wr= 0x%p, free it",
36369430SRaymond.Chen@Sun.COM 	    (void*)wr);
36379430SRaymond.Chen@Sun.COM 
36389430SRaymond.Chen@Sun.COM 	wusb_wa_free_trans_wrapper(wr);
36399430SRaymond.Chen@Sun.COM }
36409430SRaymond.Chen@Sun.COM 
36419430SRaymond.Chen@Sun.COM static struct {
36429430SRaymond.Chen@Sun.COM 	uint8_t	status;
36439430SRaymond.Chen@Sun.COM 	usb_cr_t	cr;
36449430SRaymond.Chen@Sun.COM } sts2cr[] = {
36459430SRaymond.Chen@Sun.COM 	{WA_STS_SUCCESS,	USB_CR_OK},
36469430SRaymond.Chen@Sun.COM 	{WA_STS_HALTED,		USB_CR_STALL},
36479430SRaymond.Chen@Sun.COM 	{WA_STS_DATA_BUFFER_ERROR,	USB_CR_DATA_OVERRUN},
36489430SRaymond.Chen@Sun.COM 	{WA_STS_BABBLE,		USB_CR_DATA_UNDERRUN},
36499430SRaymond.Chen@Sun.COM 	{WA_STS_NOT_FOUND,	USB_CR_NOT_ACCESSED},
36509430SRaymond.Chen@Sun.COM 	{WA_STS_INSUFFICIENT_RESOURCE,	USB_CR_NO_RESOURCES},
36519430SRaymond.Chen@Sun.COM 	{0x80 | WA_STS_TRANSACTION_ERROR,	USB_CR_STALL},
36529430SRaymond.Chen@Sun.COM 	{0x40 | WA_STS_TRANSACTION_ERROR,	USB_CR_OK},
36539430SRaymond.Chen@Sun.COM 	{WA_STS_ABORTED,	USB_CR_FLUSHED},
36549430SRaymond.Chen@Sun.COM 	{WA_STS_RPIPE_NOT_READY,	USB_CR_DEV_NOT_RESP},
36559430SRaymond.Chen@Sun.COM 	{WA_STS_INVALID_REQ_FORMAT,	USB_CR_CRC},
36569430SRaymond.Chen@Sun.COM 	{WA_STS_UNEXPECTED_SEGMENT_NUM,	USB_CR_UNEXP_PID},
36579430SRaymond.Chen@Sun.COM 	{WA_STS_RPIPE_TYPE_MISMATCH,	USB_CR_NOT_SUPPORTED},
36589430SRaymond.Chen@Sun.COM 	{WA_STS_PACKET_DISCARDED,	USB_CR_PID_CHECKFAILURE},
36599430SRaymond.Chen@Sun.COM 	{0xff,		0}	/* end */
36609430SRaymond.Chen@Sun.COM };
36619430SRaymond.Chen@Sun.COM 
36629430SRaymond.Chen@Sun.COM /* translate transfer status to USB completion reason */
36639430SRaymond.Chen@Sun.COM usb_cr_t
wusb_wa_sts2cr(uint8_t rawstatus)36649430SRaymond.Chen@Sun.COM wusb_wa_sts2cr(uint8_t rawstatus)
36659430SRaymond.Chen@Sun.COM {
36669430SRaymond.Chen@Sun.COM 	int	i;
36679430SRaymond.Chen@Sun.COM 	uint8_t	status;
36689430SRaymond.Chen@Sun.COM 
36699430SRaymond.Chen@Sun.COM 	/* cares about bits5:0 in WUSB 1.0 */
36709430SRaymond.Chen@Sun.COM 	if ((rawstatus & 0x1f) == WA_STS_TRANSACTION_ERROR) {
36719430SRaymond.Chen@Sun.COM 		status = rawstatus;
36729430SRaymond.Chen@Sun.COM 	} else {
36739430SRaymond.Chen@Sun.COM 		status = rawstatus & 0x1f;
36749430SRaymond.Chen@Sun.COM 	}
36759430SRaymond.Chen@Sun.COM 
36769430SRaymond.Chen@Sun.COM 	for (i = 0; sts2cr[i].status != 0xff; i++) {
36779430SRaymond.Chen@Sun.COM 		if (sts2cr[i].status == status) {
36789430SRaymond.Chen@Sun.COM 
36799430SRaymond.Chen@Sun.COM 			return (sts2cr[i].cr);
36809430SRaymond.Chen@Sun.COM 		}
36819430SRaymond.Chen@Sun.COM 	}
36829430SRaymond.Chen@Sun.COM 
36839430SRaymond.Chen@Sun.COM 	return (USB_CR_UNSPECIFIED_ERR);
36849430SRaymond.Chen@Sun.COM }
3685