xref: /onnv-gate/usr/src/uts/common/io/usb/usba/wa.c (revision 11066:cebb50cbe4f9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Wire Adapter Operations
28  * Both DWA and HWA have the same kind of functional components, the
29  * Wire Adapter. Functions defined in this file are to handle WA's
30  * class specific Descriptors, Requests, Notifications and Transfers.
31  * DWA or HWA specific descriptors, requests are not handled here.
32  */
33 
34 #include <sys/usb/hwa/hwahc/hwahc.h>
35 #include <sys/usb/hwa/hwahc/hwahc_util.h>
36 #include <sys/usb/usba/wa.h>
37 #include <sys/usb/usba/wusba.h>
38 #include <sys/usb/usba/whcdi.h>
39 #include <sys/usb/usba.h>
40 #include <sys/usb/usba/usba_impl.h>
41 #include <sys/usb/usba/usba_devdb.h>	/* usba_devdb_refresh */
42 #include <sys/usb/hubd/hubdvar.h>
43 #include <sys/usb/hubd/hubd_impl.h>	/* hubd_ioctl_data_t */
44 #include <sys/strsubr.h>	/* allocb_wait */
45 #include <sys/strsun.h>		/* MBLKL macro */
46 
47 extern usb_log_handle_t whcdi_log_handle;
48 
49 /* default rpipe PHY transfer speed */
50 static uint8_t rp_default_speed = WUSB_PHY_TX_RATE_106;
51 
52 /* function prototypes */
53 static void wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl,
54 	wusb_wa_trans_wrapper_t *tw);
55 static void wusb_wa_handle_error(wusb_wa_data_t *wa_data,
56 	wusb_wa_trans_wrapper_t *wr, usb_cr_t cr);
57 
58 /*
59  * Parse Wire Adapter class desriptor.
60  *	- see 8.4.3.7 & 8.5.2.7
61  *
62  *	wa_descr - the parsed descriptors.
63  *	altif_data - the passed in raw descriptor data.
64  */
65 int
wusb_parse_wa_descr(usb_wa_descr_t * wa_descr,usb_alt_if_data_t * altif_data)66 wusb_parse_wa_descr(usb_wa_descr_t *wa_descr, usb_alt_if_data_t *altif_data)
67 {
68 	usb_cvs_data_t	*cvs_data;
69 	int		i;
70 	size_t		count;
71 
72 	if ((wa_descr == NULL) || (altif_data == NULL)) {
73 		return (USB_INVALID_ARGS);
74 	}
75 
76 	for (i = 0; i < altif_data->altif_n_cvs; i++) {
77 		cvs_data = &altif_data->altif_cvs[i];
78 		if (cvs_data->cvs_buf == NULL) {
79 			continue;
80 		}
81 		if (cvs_data->cvs_buf[1] == USB_DESCR_TYPE_WA) {
82 			count = usb_parse_data("ccsccsscccc",
83 			    cvs_data->cvs_buf, cvs_data->cvs_buf_len,
84 			    (void *)wa_descr,
85 			    (size_t)USB_WA_DESCR_SIZE);
86 			if (count != USB_WA_DESCR_SIZE) {
87 				return (USB_FAILURE);
88 			} else {
89 				return (USB_SUCCESS);
90 			}
91 		}
92 	}
93 
94 	return (USB_FAILURE);
95 }
96 
97 /* initialize rpipe structures */
98 void
wusb_wa_rpipes_init(wusb_wa_data_t * wa_data)99 wusb_wa_rpipes_init(wusb_wa_data_t *wa_data)
100 {
101 	int			i;
102 	wusb_wa_rpipe_hdl_t	*hdl;
103 
104 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
105 		hdl = &wa_data->wa_rpipe_hdl[i];
106 		mutex_init(&hdl->rp_mutex, NULL, MUTEX_DRIVER, NULL);
107 		cv_init(&hdl->rp_cv, NULL, CV_DRIVER, NULL);
108 
109 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdl));
110 		hdl->rp_state = WA_RPIPE_STATE_FREE;
111 		hdl->rp_refcnt = 0;
112 		hdl->rp_timeout_list = NULL;
113 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*hdl));
114 	}
115 }
116 
117 /* deinitialize rpipe structures */
118 void
wusb_wa_rpipes_fini(wusb_wa_data_t * wa_data)119 wusb_wa_rpipes_fini(wusb_wa_data_t *wa_data)
120 {
121 	int			i;
122 	wusb_wa_rpipe_hdl_t	*hdl;
123 
124 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
125 		hdl = &wa_data->wa_rpipe_hdl[i];
126 		mutex_destroy(&hdl->rp_mutex);
127 		cv_destroy(&hdl->rp_cv);
128 	}
129 }
130 
131 
132 /*
133  * wusb_wa_data_init:
134  *	WA interface validation
135  *	Parse WA class descriptors
136  *	Set up RPipes
137  *	Set up callbacks
138  */
139 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)140 wusb_wa_data_init(dev_info_t *dip, wusb_wa_data_t *wa_data, wusb_wa_cb_t *cbs,
141 	usb_client_dev_data_t *dev_data,
142 	uint_t mask, usb_log_handle_t handle)
143 {
144 	usb_alt_if_data_t	*altif_data;
145 	usb_ep_data_t		*ep_data;
146 	int			ifno;
147 	int			rval;
148 
149 	if ((wa_data == NULL) || (dev_data == NULL)) {
150 
151 		return (USB_INVALID_ARGS);
152 	}
153 
154 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data));
155 
156 	/* get inf descr and ept descrs from altif data */
157 	altif_data = &dev_data->dev_curr_cfg->
158 	    cfg_if[dev_data->dev_curr_if].if_alt[0];
159 
160 	/* T.8-44. Wire Adapter */
161 	if (altif_data->altif_descr.bInterfaceSubClass !=
162 	    USB_SUBCLS_WUSB_2) {
163 		USB_DPRINTF_L2(mask, handle,
164 		    "wusb_init_wa_data: invalid interface subclass (0x%x)",
165 		    altif_data->altif_descr.bInterfaceSubClass);
166 
167 		return (USB_FAILURE);
168 	}
169 
170 	/* at least 3 EPs, INTR IN + BULK IN + BULK OUT */
171 	if (altif_data->altif_n_ep < 3) {
172 		USB_DPRINTF_L2(mask, handle,
173 		    "wusb_init_wa_data: invalid alt 0 for interface %d",
174 		    dev_data->dev_curr_if);
175 
176 		return (USB_FAILURE);
177 	}
178 
179 	wa_data->wa_ifno = ifno = dev_data->dev_curr_if;
180 	wa_data->wa_if_descr = altif_data->altif_descr;
181 
182 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
183 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT)) != NULL) {
184 		wa_data->wa_bulkout_ept = ep_data->ep_descr;
185 	}
186 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
187 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN)) != NULL) {
188 		wa_data->wa_bulkin_ept = ep_data->ep_descr;
189 	}
190 	if ((ep_data = usb_lookup_ep_data(dip, dev_data, ifno, 0, 0,
191 	    USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
192 		wa_data->wa_intr_ept = ep_data->ep_descr;
193 	}
194 
195 	if ((wa_data->wa_bulkout_ept.bLength == 0) ||
196 	    (wa_data->wa_bulkin_ept.bLength == 0) ||
197 	    (wa_data->wa_intr_ept.bLength == 0)) {
198 		USB_DPRINTF_L2(mask, handle,
199 		    "wusb_init_wa_data: the minimum endpoint set is not "
200 		    "supported");
201 
202 		return (USB_FAILURE);
203 	}
204 
205 	/* parse the WA descriptor */
206 	if ((rval = wusb_parse_wa_descr(&wa_data->wa_descr, altif_data)) !=
207 	    USB_SUCCESS) {
208 		USB_DPRINTF_L2(mask, handle,
209 		    "wusb_init_wa_data: parse wire adapter class descr failed");
210 
211 		return (rval);
212 	}
213 	wa_data->wa_avail_blocks = wa_data->wa_descr.wRPipeMaxBlock;
214 
215 	wa_data->wa_dip = dip;
216 
217 	/* initialize rpipe handlers */
218 	wa_data->wa_num_rpipes = wa_data->wa_descr.wNumRPipes;
219 
220 	wa_data->wa_rpipe_hdl = kmem_zalloc((wa_data->wa_num_rpipes *
221 	    sizeof (wusb_wa_rpipe_hdl_t)), KM_SLEEP);
222 
223 	/* init rpipes */
224 	wusb_wa_rpipes_init(wa_data);
225 
226 	/* register callbacks */
227 	wa_data->pipe_periodic_req = cbs->pipe_periodic_req;
228 	wa_data->intr_cb = cbs->intr_cb;
229 	wa_data->intr_exc_cb = cbs->intr_exc_cb;
230 	wa_data->rpipe_xfer_cb = cbs->rpipe_xfer_cb;
231 
232 	mutex_init(&wa_data->wa_mutex, NULL, MUTEX_DRIVER, NULL);
233 
234 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data));
235 
236 	return (USB_SUCCESS);
237 }
238 
239 /* deinitialize data transfer related resources */
240 void
wusb_wa_data_fini(wusb_wa_data_t * wa_data)241 wusb_wa_data_fini(wusb_wa_data_t *wa_data)
242 {
243 	mutex_enter(&wa_data->wa_mutex);
244 	if (wa_data->wa_rpipe_hdl) {
245 		wusb_wa_rpipes_fini(wa_data);
246 		kmem_free(wa_data->wa_rpipe_hdl, wa_data->wa_num_rpipes *
247 		    sizeof (wusb_wa_rpipe_hdl_t));
248 	}
249 	mutex_exit(&wa_data->wa_mutex);
250 	mutex_destroy(&wa_data->wa_mutex);
251 }
252 
wusb_wa_dump_rpipe_descr(usb_wa_rpipe_descr_t * pd,uint_t mask,usb_log_handle_t handle)253 void wusb_wa_dump_rpipe_descr(usb_wa_rpipe_descr_t *pd, uint_t mask,
254     usb_log_handle_t handle)
255 {
256 	USB_DPRINTF_L4(mask, handle, "RPipe Descriptor:\n"
257 	    "\tWRPipeIndex=%d wRequests=%d wBlocks=%d\n"
258 	    "\twMaxPacketSize=%d bHSHubAddress=%d\n"
259 	    "\tbHSHubPort=%d bSpeed=%d bDeviceAddress=%d\n"
260 	    "\tbEndpointAddress=0x%02x bDataSequence=%d\n"
261 	    "\tdwCurrentWindow=0x%08x bMaxDataSequence=%d",
262 	    pd->wRPipeIndex, pd->wRequests, pd->wBlocks, pd->wMaxPacketSize,
263 	    pd->wa_value.hwa_value.bMaxBurst,
264 	    pd->wa_value.hwa_value.bDeviceInfoIndex,
265 	    pd->bSpeed, pd->bDeviceAddress,
266 	    pd->bEndpointAddress, pd->bDataSequence, pd->dwCurrentWindow,
267 	    pd->bMaxDataSequence);
268 
269 	USB_DPRINTF_L4(mask, handle,
270 	    "(cont'ed)bInterval=%d bOverTheAirInterval=%d\n"
271 	    "\tbmAttribute=0x%02x bmCharacter=0x%02x\n"
272 	    "\tbmRetryOptions=0x%02x wNumTransactionErrors=%d\n",
273 	    pd->bInterval, pd->bOverTheAirInterval,
274 	    pd->bmAttribute, pd->bmCharacteristics, pd->bmRetryOptions,
275 	    pd->wNumTransactionErrors);
276 
277 }
278 
279 /* get rpipe descr of a certain index, refer to WUSB 1.0/8.3.1.4 */
280 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)281 wusb_wa_get_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph,
282 	uint16_t idx, usb_wa_rpipe_descr_t *descr,
283 	uint_t mask, usb_log_handle_t handle)
284 {
285 	mblk_t		*data = NULL;
286 	usb_cr_t	completion_reason;
287 	usb_cb_flags_t	cb_flags;
288 	size_t		count;
289 	int		rval;
290 
291 	/*
292 	 * This descriptor is critical for later operations to succeed.
293 	 * So, we must wait here.
294 	 */
295 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
296 	    WA_CLASS_RPIPE_REQ_IN_TYPE,
297 	    USB_REQ_GET_DESCR,
298 	    USB_DESCR_TYPE_RPIPE << 8,
299 	    idx,
300 	    USB_RPIPE_DESCR_SIZE,
301 	    &data, 0,
302 	    &completion_reason, &cb_flags, 0);
303 
304 	if (rval != USB_SUCCESS) {
305 		USB_DPRINTF_L2(mask, handle,
306 		    "wusb_wa_get_rpipe_descr: rval=%d, cr=%d, "
307 		    "cb=0x%x", rval, completion_reason, cb_flags);
308 
309 		goto done;
310 	}
311 
312 	if (MBLKL(data) != USB_RPIPE_DESCR_SIZE) {
313 		USB_DPRINTF_L2(mask, handle,
314 		    "wusb_wa_get_rpipe_descr: return size %d",
315 		    (int)MBLKL(data));
316 		rval = USB_FAILURE;
317 
318 		goto done;
319 	}
320 
321 	count = usb_parse_data("2c4s6cl6cs", data->b_rptr,
322 	    USB_RPIPE_DESCR_SIZE, descr, sizeof (usb_wa_rpipe_descr_t));
323 
324 	if (count == USB_PARSE_ERROR) {
325 		USB_DPRINTF_L2(mask, handle,
326 		    "wusb_wa_get_rpipe_descr: parse error");
327 		rval = USB_FAILURE;
328 
329 		goto done;
330 	}
331 
332 	wusb_wa_dump_rpipe_descr(descr, mask, handle);
333 
334 	freemsg(data);
335 	data = NULL;
336 
337 	return (USB_SUCCESS);
338 
339 done:
340 	if (data) {
341 		freemsg(data);
342 	}
343 
344 	return (rval);
345 }
346 
347 /*
348  * Get All the RPipes' descriptors of an HWA
349  *	- WA RPipe descriptor are not returned as part of the
350  *	cofiguration descriptor. We have to get it separately.
351  *	- See section 8.4.3.19 and 8.5.2.11
352  */
353 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)354 wusb_wa_get_rpipe_descrs(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
355 	uint_t mask, usb_log_handle_t handle)
356 {
357 	dev_info_t	*dip = wa_data->wa_dip;
358 	int		i, rval;
359 
360 	if ((dip == NULL) || (ph == NULL)) {
361 
362 		return (USB_INVALID_ARGS);
363 	}
364 
365 	/* called at initialization, no other threads yet */
366 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wa_data));
367 
368 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
369 		rval = wusb_wa_get_rpipe_descr(dip, ph, i,
370 		    &wa_data->wa_rpipe_hdl[i].rp_descr, mask, handle);
371 
372 		if (rval != USB_SUCCESS) {
373 			USB_DPRINTF_L2(mask, handle,
374 			    "wusb_wa_get_rpipe_descrs: fail to get rpipe "
375 			    "descr for idx %d", i);
376 
377 			return (rval);
378 		}
379 	}
380 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wa_data));
381 
382 	return (USB_SUCCESS);
383 }
384 
385 /*
386  * Get Wire Adapter's Status
387  *	See section 8.3.1.6
388  */
389 int
wusb_get_wa_status(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph,uint32_t * status)390 wusb_get_wa_status(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
391 	uint32_t *status)
392 {
393 	dev_info_t	*dip = wa_data->wa_dip;
394 	int		rval = USB_SUCCESS;
395 	mblk_t		*data = NULL;
396 	usb_cr_t	completion_reason;
397 	usb_cb_flags_t	cb_flags;
398 
399 	if ((dip == NULL) || (ph == NULL)) {
400 
401 		return (USB_INVALID_ARGS);
402 	}
403 
404 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
405 	    WUSB_CLASS_IF_REQ_IN_TYPE,
406 	    USB_REQ_GET_STATUS,
407 	    0,
408 	    wa_data->wa_ifno,
409 	    WA_GET_WA_STATUS_LEN,
410 	    &data, 0,
411 	    &completion_reason, &cb_flags, 0);
412 
413 	if (rval != USB_SUCCESS) {
414 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
415 		    "wusb_get_wa_status: can't retrieve status");
416 
417 		goto done;
418 	}
419 
420 	*status = (*(data->b_rptr + 3) << 24) | (*(data->b_rptr + 2) << 16) |
421 	    (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
422 
423 done:
424 	if (data) {
425 		freemsg(data);
426 	}
427 
428 	return (rval);
429 }
430 
431 /*
432  * Reset WA
433  *	See 8.3.1.9
434  */
435 int
wusb_wa_reset(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph)436 wusb_wa_reset(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
437 {
438 	dev_info_t	*dip = wa_data->wa_dip;
439 	usb_cr_t	completion_reason;
440 	usb_cb_flags_t	cb_flags;
441 	int		rval, i;
442 	uint32_t	status;
443 
444 	if ((dip == NULL) || (ph == NULL)) {
445 
446 		return (USB_INVALID_ARGS);
447 	}
448 
449 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
450 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
451 	    USB_REQ_SET_FEATURE,
452 	    WA_DEV_RESET,
453 	    wa_data->wa_ifno,
454 	    0,
455 	    NULL, 0,
456 	    &completion_reason, &cb_flags, 0);
457 
458 	if (rval != USB_SUCCESS) {
459 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
460 		    "wusb_wa_reset: can't reset wa, rval = %d, cr=%d", rval,
461 		    completion_reason);
462 
463 		return (rval);
464 	}
465 
466 	for (i = 0; i < 10; i++) {
467 		delay(drv_usectohz(50000));
468 
469 		rval = wusb_get_wa_status(wa_data, ph, &status);
470 		if (rval != USB_SUCCESS) {
471 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
472 			    "wusb_wa_reset: can't get status, rval = %d",
473 			    rval);
474 
475 			return (rval);
476 		}
477 
478 		if (!(status & WA_HC_RESET_IN_PROGRESS)) {
479 
480 			return (USB_SUCCESS);
481 		}
482 	}
483 
484 	return (USB_FAILURE);
485 }
486 
487 /*
488  * Enable wire adapter.
489  *	See 8.3.1.9
490  */
491 int
wusb_wa_enable(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph)492 wusb_wa_enable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
493 {
494 	dev_info_t	*dip = wa_data->wa_dip;
495 	usb_cr_t	completion_reason;
496 	usb_cb_flags_t	cb_flags;
497 	int		rval, i;
498 	uint32_t	status;
499 
500 	if ((dip == NULL) || (ph == NULL)) {
501 
502 		return (USB_INVALID_ARGS);
503 	}
504 
505 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
506 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
507 	    USB_REQ_SET_FEATURE,
508 	    WA_DEV_ENABLE,
509 	    wa_data->wa_ifno,
510 	    0,
511 	    NULL, 0,
512 	    &completion_reason, &cb_flags, 0);
513 
514 	if (rval != USB_SUCCESS) {
515 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
516 		    "wusb_wa_enable: can't enable WA, rval = %d, cr=%d",
517 		    rval, completion_reason);
518 
519 		return (rval);
520 	}
521 
522 	for (i = 0; i < 10; i++) {
523 		delay(drv_usectohz(50000));
524 
525 		rval = wusb_get_wa_status(wa_data, ph, &status);
526 		if (rval != USB_SUCCESS) {
527 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
528 			    "wusb_wa_enable: can't get status, rval = %d",
529 			    rval);
530 
531 			return (rval);
532 		}
533 
534 		if (status & WA_HC_ENABLED) {
535 
536 			return (USB_SUCCESS);
537 		}
538 	}
539 
540 	return (USB_FAILURE);
541 }
542 
543 /*
544  * Disable WA. Clear a fearture.
545  *	See Section 8.3.1.3
546  */
547 int
wusb_wa_disable(wusb_wa_data_t * wa_data,usb_pipe_handle_t ph)548 wusb_wa_disable(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph)
549 {
550 	dev_info_t	*dip = wa_data->wa_dip;
551 	usb_cr_t	completion_reason;
552 	usb_cb_flags_t	cb_flags;
553 	int		rval, i;
554 	uint32_t	status;
555 
556 	if ((dip == NULL) || (ph == NULL)) {
557 
558 		return (USB_INVALID_ARGS);
559 	}
560 
561 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
562 	    WUSB_CLASS_IF_REQ_OUT_TYPE,
563 	    USB_REQ_CLEAR_FEATURE,
564 	    WA_DEV_ENABLE,
565 	    wa_data->wa_ifno,
566 	    0,
567 	    NULL, 0,
568 	    &completion_reason, &cb_flags, 0);
569 
570 	if (rval != USB_SUCCESS) {
571 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
572 		    "wusb_wa_disable: can't disable wa, rval = %d, cr = %d",
573 		    rval, completion_reason);
574 
575 		return (rval);
576 	}
577 
578 	for (i = 0; i < 10; i++) {
579 		delay(drv_usectohz(50000));
580 
581 		rval = wusb_get_wa_status(wa_data, ph, &status);
582 		if (rval != USB_SUCCESS) {
583 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
584 			    "wusb_wa_disable: can't get status, rval = %d",
585 			    rval);
586 
587 			return (rval);
588 		}
589 
590 		if (!(status & WA_HC_ENABLED)) {
591 
592 			return (USB_SUCCESS);
593 		}
594 	}
595 
596 	return (USB_FAILURE);
597 }
598 
599 /*
600  * Open the two bulk endpoints and one interrupt IN endpoint, defined in
601  * a WA's data transfer interface. See 8.1.2
602  */
603 int
wusb_wa_open_pipes(wusb_wa_data_t * wa_data)604 wusb_wa_open_pipes(wusb_wa_data_t *wa_data)
605 {
606 	int	rval;
607 
608 	mutex_enter(&wa_data->wa_mutex);
609 	if (wa_data->wa_state & WA_PIPES_OPENED) {
610 		mutex_exit(&wa_data->wa_mutex);
611 
612 		return (USB_SUCCESS);
613 	}
614 	wa_data->wa_pipe_policy.pp_max_async_reqs = 1;
615 	mutex_exit(&wa_data->wa_mutex);
616 
617 	rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_intr_ept,
618 	    &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
619 	    &wa_data->wa_intr_ph);
620 	if (rval != USB_SUCCESS) {
621 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
622 		    "wusb_wa_open_pipes: can't open intr pipe, rval = %d",
623 		    rval);
624 
625 		return (rval);
626 	}
627 
628 	rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkin_ept,
629 	    &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
630 	    &wa_data->wa_bulkin_ph);
631 	if (rval != USB_SUCCESS) {
632 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
633 		    "wusb_wa_open_pipes: can't open bulkin pipe, rval = %d",
634 		    rval);
635 
636 		usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
637 		    USB_FLAGS_SLEEP, NULL, NULL);
638 		mutex_enter(&wa_data->wa_mutex);
639 		wa_data->wa_intr_ph = NULL;
640 		mutex_exit(&wa_data->wa_mutex);
641 
642 		return (rval);
643 	}
644 
645 	rval = usb_pipe_open(wa_data->wa_dip, &wa_data->wa_bulkout_ept,
646 	    &wa_data->wa_pipe_policy, USB_FLAGS_SLEEP,
647 	    &wa_data->wa_bulkout_ph);
648 
649 	if (rval != USB_SUCCESS) {
650 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
651 		    "wusb_wa_open_pipes: can't open bulkout pipe, rval = %d",
652 		    rval);
653 
654 		usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
655 		    USB_FLAGS_SLEEP, NULL, NULL);
656 		usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph,
657 		    USB_FLAGS_SLEEP, NULL, NULL);
658 		mutex_enter(&wa_data->wa_mutex);
659 		wa_data->wa_intr_ph = NULL;
660 		wa_data->wa_bulkin_ph = NULL;
661 		mutex_exit(&wa_data->wa_mutex);
662 
663 		return (rval);
664 	}
665 
666 	mutex_enter(&wa_data->wa_mutex);
667 	/* mark the state stopped until listening is started on the pipes */
668 	wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED;
669 	wa_data->wa_bulkin_pipe_state = WA_PIPE_STOPPED;
670 	/* no listening on this pipe, just mark it active */
671 	wa_data->wa_bulkout_pipe_state = WA_PIPE_ACTIVE;
672 	wa_data->wa_state |= WA_PIPES_OPENED;
673 	mutex_exit(&wa_data->wa_mutex);
674 
675 	return (USB_SUCCESS);
676 }
677 
678 /*
679  * Close WA's pipes.
680  */
681 void
wusb_wa_close_pipes(wusb_wa_data_t * wa_data)682 wusb_wa_close_pipes(wusb_wa_data_t *wa_data)
683 {
684 	mutex_enter(&wa_data->wa_mutex);
685 	if ((wa_data->wa_state & WA_PIPES_OPENED) == 0) {
686 		mutex_exit(&wa_data->wa_mutex);
687 
688 		return;
689 	}
690 
691 	mutex_exit(&wa_data->wa_mutex);
692 
693 	usb_pipe_close(wa_data->wa_dip, wa_data->wa_intr_ph,
694 	    USB_FLAGS_SLEEP, NULL, NULL);
695 
696 	if (wa_data->wa_bulkin_ph != NULL) {
697 		usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkin_ph,
698 		    USB_FLAGS_SLEEP, NULL, NULL);
699 	}
700 
701 	usb_pipe_close(wa_data->wa_dip, wa_data->wa_bulkout_ph,
702 	    USB_FLAGS_SLEEP, NULL, NULL);
703 
704 	mutex_enter(&wa_data->wa_mutex);
705 	wa_data->wa_intr_ph = NULL;
706 	wa_data->wa_bulkin_ph = NULL;
707 	wa_data->wa_bulkout_ph = NULL;
708 	wa_data->wa_intr_pipe_state = WA_PIPE_CLOSED;
709 	wa_data->wa_bulkin_pipe_state = WA_PIPE_CLOSED;
710 	wa_data->wa_bulkout_pipe_state = WA_PIPE_CLOSED;
711 	wa_data->wa_state &= ~WA_PIPES_OPENED;
712 	mutex_exit(&wa_data->wa_mutex);
713 }
714 
715 /*
716  * start listening for transfer completion notifications or device
717  * notifications on the notification ept
718  */
719 int
wusb_wa_start_nep(wusb_wa_data_t * wa_data,usb_flags_t flag)720 wusb_wa_start_nep(wusb_wa_data_t *wa_data, usb_flags_t flag)
721 {
722 	int		rval;
723 	usb_intr_req_t	*reqp;
724 
725 	mutex_enter(&wa_data->wa_mutex);
726 	if ((wa_data->wa_intr_ph == NULL) ||
727 	    (wa_data->wa_intr_pipe_state != WA_PIPE_STOPPED)) {
728 		mutex_exit(&wa_data->wa_mutex);
729 
730 		return (USB_INVALID_PIPE);
731 	}
732 
733 	reqp = usb_alloc_intr_req(wa_data->wa_dip, 0, flag);
734 	if (!reqp) {
735 		mutex_exit(&wa_data->wa_mutex);
736 
737 		return (USB_NO_RESOURCES);
738 	}
739 
740 	reqp->intr_client_private = (usb_opaque_t)wa_data;
741 	reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
742 	    USB_ATTRS_AUTOCLEARING;
743 	reqp->intr_len = wa_data->wa_intr_ept.wMaxPacketSize;
744 	reqp->intr_cb = wa_data->intr_cb;
745 	reqp->intr_exc_cb = wa_data->intr_exc_cb;
746 	mutex_exit(&wa_data->wa_mutex);
747 
748 	if ((rval = usb_pipe_intr_xfer(wa_data->wa_intr_ph, reqp,
749 	    flag)) != USB_SUCCESS) {
750 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
751 		    "wusb_wa_start_nep: intr xfer fail, rval = %d",
752 		    rval);
753 
754 		usb_free_intr_req(reqp);
755 
756 		return (rval);
757 	}
758 
759 	mutex_enter(&wa_data->wa_mutex);
760 	/* pipe state is active while the listening is on */
761 	wa_data->wa_intr_pipe_state = WA_PIPE_ACTIVE;
762 	mutex_exit(&wa_data->wa_mutex);
763 
764 	return (USB_SUCCESS);
765 }
766 
767 /*
768  * stop the notification ept from listening
769  */
770 void
wusb_wa_stop_nep(wusb_wa_data_t * wa_data)771 wusb_wa_stop_nep(wusb_wa_data_t *wa_data)
772 {
773 	mutex_enter(&wa_data->wa_mutex);
774 	if ((wa_data->wa_intr_ph == NULL) ||
775 	    (wa_data->wa_intr_pipe_state != WA_PIPE_ACTIVE)) {
776 		mutex_exit(&wa_data->wa_mutex);
777 
778 		return;
779 	}
780 	wa_data->wa_intr_pipe_state = WA_PIPE_STOPPED;
781 	mutex_exit(&wa_data->wa_mutex);
782 	/* stop intr in without closing the pipe */
783 	usb_pipe_stop_intr_polling(wa_data->wa_intr_ph, USB_FLAGS_SLEEP);
784 }
785 
786 /*
787  * allocate a rpipe for transfers on a pipe
788  *	- Find a free RPipe
789  *
790  * For now, one rpipe is associated with only one usba pipe once
791  * the pipe is opened. In the future, the rpipe needs to be
792  * multiplexed between asynchronous endpoints
793  * input:
794  *	type: 0 - ctrl, 1 - isoc, 2 - bulk, 3 - intr
795  *
796  */
797 /* ARGSUSED */
798 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)799 wusb_wa_get_rpipe(wusb_wa_data_t *wa_data, usb_pipe_handle_t ph,
800 	uint8_t type, wusb_wa_rpipe_hdl_t **hdl,
801 	uint_t mask, usb_log_handle_t handle)
802 {
803 	int			i;
804 	wusb_wa_rpipe_hdl_t	*thdl;
805 	uint8_t			rp_type;
806 	uint8_t			ep_type = 1 << type;
807 
808 	*hdl = NULL;
809 
810 	mutex_enter(&wa_data->wa_mutex);
811 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
812 		/* find the first unused rpipe */
813 		thdl = &wa_data->wa_rpipe_hdl[i];
814 		mutex_enter(&thdl->rp_mutex);
815 		if (thdl->rp_state != WA_RPIPE_STATE_FREE) {
816 			mutex_exit(&thdl->rp_mutex);
817 
818 			continue;
819 		}
820 
821 		/* check if the rpipe supports the ept transfer type */
822 		rp_type = (thdl->rp_descr.bmCharacteristics &
823 		    USB_RPIPE_CHA_MASK);
824 		if (rp_type & ep_type) {
825 			thdl->rp_refcnt++;
826 			thdl->rp_state = WA_RPIPE_STATE_IDLE;
827 			thdl->rp_avail_reqs = thdl->rp_descr.wRequests;
828 			*hdl = thdl;
829 			mutex_exit(&thdl->rp_mutex);
830 			mutex_exit(&wa_data->wa_mutex);
831 
832 			return (USB_SUCCESS);
833 		}
834 		mutex_exit(&thdl->rp_mutex);
835 	}
836 
837 	USB_DPRINTF_L2(mask, handle,
838 	    "wusb_wa_get_rpipe: no matching rpipe is found");
839 	mutex_exit(&wa_data->wa_mutex);
840 
841 	return (USB_FAILURE);
842 }
843 
844 /*
845  * Decrease a RPipe's reference count.
846  *	- if count == 0, mark it as free RPipe.
847  */
848 int
wusb_wa_release_rpipe(wusb_wa_data_t * wa,wusb_wa_rpipe_hdl_t * hdl)849 wusb_wa_release_rpipe(wusb_wa_data_t *wa, wusb_wa_rpipe_hdl_t *hdl)
850 {
851 	if (hdl == NULL) {
852 
853 		return (USB_FAILURE);
854 	}
855 
856 	mutex_enter(&wa->wa_mutex);
857 	mutex_enter(&hdl->rp_mutex);
858 	if (hdl->rp_refcnt == 0) {
859 		mutex_exit(&hdl->rp_mutex);
860 		mutex_exit(&wa->wa_mutex);
861 
862 		return (USB_FAILURE);
863 	}
864 
865 	if (--hdl->rp_refcnt == 0) {
866 		hdl->rp_state = WA_RPIPE_STATE_FREE;
867 	}
868 
869 	if (hdl->rp_block_chg == 1) {
870 		wa->wa_avail_blocks += hdl->rp_descr.wBlocks;
871 		hdl->rp_descr.wBlocks = 0; /* to prevent misadd upon re-call */
872 		hdl->rp_block_chg = 0;
873 	}
874 
875 	mutex_exit(&hdl->rp_mutex);
876 	mutex_exit(&wa->wa_mutex);
877 
878 	return (USB_SUCCESS);
879 }
880 
881 /*
882  * Set a RPipe's Descriptor and make the rpipe configured
883  *	See section 8.3.1.7
884  */
885 int
wusb_wa_set_rpipe_descr(dev_info_t * dip,usb_pipe_handle_t ph,usb_wa_rpipe_descr_t * rp_descr)886 wusb_wa_set_rpipe_descr(dev_info_t *dip, usb_pipe_handle_t ph,
887 	usb_wa_rpipe_descr_t *rp_descr)
888 {
889 	mblk_t		*data = NULL;
890 	usb_cr_t	completion_reason;
891 	usb_cb_flags_t	cb_flags;
892 	int		rval;
893 	uint8_t		*p;
894 
895 	data = allocb_wait(USB_RPIPE_DESCR_SIZE, BPRI_LO, STR_NOSIG, NULL);
896 	p = data->b_wptr;
897 	p[0] = rp_descr->bLength;
898 	p[1] = rp_descr->bDescriptorType;
899 	p[2] = rp_descr->wRPipeIndex;
900 	p[3] = rp_descr->wRPipeIndex >> 8;
901 	p[4] = rp_descr->wRequests;
902 	p[5] = rp_descr->wRequests >> 8;
903 	p[6] = rp_descr->wBlocks;
904 	p[7] = rp_descr->wBlocks >> 8;
905 	p[8] = rp_descr->wMaxPacketSize;
906 	p[9] = rp_descr->wMaxPacketSize >> 8;
907 	p[10] = rp_descr->wa_value.hwa_value.bMaxBurst;
908 	p[11] = rp_descr->wa_value.hwa_value.bDeviceInfoIndex;
909 	p[12] = rp_descr->bSpeed;
910 	p[13] = rp_descr->bDeviceAddress;
911 	p[14] = rp_descr->bEndpointAddress;
912 	p[15] = rp_descr->bDataSequence;
913 	p[16] = rp_descr->dwCurrentWindow;
914 	p[17] = rp_descr->dwCurrentWindow >> 8;
915 	p[18] = rp_descr->dwCurrentWindow >> 16;
916 	p[19] = rp_descr->dwCurrentWindow >> 24;
917 	p[20] = rp_descr->bMaxDataSequence;
918 	p[21] = rp_descr->bInterval;
919 	p[22] = rp_descr->bOverTheAirInterval;
920 	p[23] = rp_descr->bmAttribute;
921 	p[24] = rp_descr->bmCharacteristics;
922 	p[25] = rp_descr->bmRetryOptions;
923 	p[26] = rp_descr->wNumTransactionErrors;
924 	p[27] = rp_descr->wNumTransactionErrors >> 8;
925 
926 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
927 	    "wusb_wa_set_rpipe_descr: RPipe Descriptors");
928 	wusb_wa_dump_rpipe_descr(rp_descr, DPRINT_MASK_WHCDI, whcdi_log_handle);
929 
930 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
931 	    WA_CLASS_RPIPE_REQ_OUT_TYPE,
932 	    USB_REQ_SET_DESCR,
933 	    USB_DESCR_TYPE_RPIPE << 8,
934 	    rp_descr->wRPipeIndex,
935 	    USB_RPIPE_DESCR_SIZE,
936 	    &data, 0,
937 	    &completion_reason, &cb_flags, 0);
938 
939 	freemsg(data);
940 
941 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
942 	    "wusb_wa_set_rpipe_descr: rval = %d", rval);
943 
944 	return (rval);
945 }
946 
947 /* ept companion descr for the default ctrl pipe, refer to WUSB 1.0/4.8.1 */
948 usb_ep_comp_descr_t ep_comp0 = {
949 	sizeof (usb_ep_comp_descr_t), USB_DESCR_TYPE_WIRELESS_EP_COMP,
950 	1, 2,
951 };
952 
953 /*
954  * Get the Endpoint Companion Descriptor for the pipe
955  *	ph_data - the specified pipe
956  *	ep_comp - the companion descriptor returned
957  */
958 int
wusb_wa_get_ep_comp_descr(usba_pipe_handle_data_t * ph_data,usb_ep_comp_descr_t * ep_comp)959 wusb_wa_get_ep_comp_descr(usba_pipe_handle_data_t *ph_data,
960 	usb_ep_comp_descr_t *ep_comp)
961 {
962 	usb_ep_descr_t		*ep = &ph_data->p_ep;
963 	usb_client_dev_data_t	*dev_data;
964 	usb_if_data_t		*if_data;
965 	usb_alt_if_data_t	*altif_data;
966 	usb_ep_data_t		*ep_data;
967 	int			i, j;
968 
969 	/* default ctrl endpoint */
970 	if (ep->bEndpointAddress == 0) {
971 		*ep_comp = ep_comp0;
972 
973 		return (USB_SUCCESS);
974 	}
975 
976 	if (usb_get_dev_data(ph_data->p_dip, &dev_data,
977 	    USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
978 
979 		return (USB_FAILURE);
980 	}
981 
982 	/* retrieve ept companion descr from the dev data */
983 	if_data = &dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if];
984 	for (i = 0; i < if_data->if_n_alt; i++) {
985 		altif_data = &if_data->if_alt[i];
986 		for (j = 0; j < altif_data->altif_n_ep; j++) {
987 			ep_data = &altif_data->altif_ep[j];
988 			if (memcmp(&ep_data->ep_descr, ep,
989 			    sizeof (usb_ep_descr_t)) == 0) {
990 				*ep_comp = ep_data->ep_comp_descr;
991 				usb_free_dev_data(ph_data->p_dip, dev_data);
992 
993 				return (USB_SUCCESS);
994 			}
995 		}
996 	}
997 	usb_free_dev_data(ph_data->p_dip, dev_data);
998 
999 	return (USB_FAILURE);
1000 }
1001 
1002 /* to check if the specified PHY speed is supported by the device */
1003 int
wusb_wa_is_speed_valid(usba_device_t * ud,uint8_t speed)1004 wusb_wa_is_speed_valid(usba_device_t *ud, uint8_t speed)
1005 {
1006 	usb_uwb_cap_descr_t *uwb_descr = ud->usb_wireless_data->uwb_descr;
1007 	uint8_t valid_spd[WUSB_PHY_TX_RATE_RES] = {
1008 	    WUSB_DATA_RATE_BIT_53, WUSB_DATA_RATE_BIT_106,
1009 	    WUSB_DATA_RATE_BIT_160, WUSB_DATA_RATE_BIT_200,
1010 	    WUSB_DATA_RATE_BIT_320, WUSB_DATA_RATE_BIT_400,
1011 	    WUSB_DATA_RATE_BIT_480, 0
1012 	};
1013 
1014 	if (speed >= WUSB_PHY_TX_RATE_RES) {
1015 
1016 		return (0);
1017 	}
1018 
1019 	/* this speed is not supported by the device */
1020 	if (valid_spd[speed] != (uwb_descr->wPHYRates & valid_spd[speed])) {
1021 
1022 		return (0);
1023 	}
1024 
1025 	return (1);
1026 }
1027 
1028 /*
1029  * Set up a RPipe
1030  *	- Associate a RPipe and a pipe handle. Hence, an endpoint has
1031  *	  RPipe to transfer data.
1032  *	- Set this RPipe to bDeviceAddress:bEndpointAddress
1033  *
1034  *  wa	- wa data
1035  *  ph	- wa's default control pipe
1036  *  ph_data - client driver's usba pipe to be opened
1037  *  hdl	- RPipe handle
1038  */
1039 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)1040 wusb_wa_set_rpipe_target(dev_info_t *dip, wusb_wa_data_t *wa,
1041 	usb_pipe_handle_t ph, usba_pipe_handle_data_t *ph_data,
1042 	wusb_wa_rpipe_hdl_t *hdl)
1043 {
1044 	int			rval;
1045 	usb_ep_comp_descr_t	ep_comp;
1046 	usb_ep_descr_t		*ep = &ph_data->p_ep;
1047 	usba_device_t		*usba_device;
1048 	uint8_t			rp_status;
1049 	usb_wa_descr_t		*wa_desc = &wa->wa_descr;
1050 	uint16_t		blockcnt;
1051 	uint16_t		maxsize;
1052 	uint16_t		seg_len;
1053 
1054 
1055 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1056 	    "wusb_wa_set_rpipe_target: ph_data = 0x%p rp_hdl = 0x%p",
1057 	    (void*)ph_data, (void*)hdl);
1058 
1059 	/* Get client device's Endpoint companion descriptor */
1060 	if ((rval = wusb_wa_get_ep_comp_descr(ph_data, &ep_comp)) !=
1061 	    USB_SUCCESS) {
1062 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1063 		    "wusb_wa_set_rpipe_target: get companion ep descr failed,"
1064 		    " rval = %d", rval);
1065 
1066 		return (rval);
1067 	}
1068 
1069 	/* set the rpipe to unconfigured state */
1070 	if ((rval = wusb_wa_rpipe_reset(dip, ph_data, hdl, 0)) != USB_SUCCESS) {
1071 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1072 		    "wusb_wa_set_rpipe_target: reset rpipe failed, rval = %d",
1073 		    rval);
1074 
1075 		return (rval);
1076 	}
1077 
1078 	if ((rval = wusb_wa_get_rpipe_status(dip, ph,
1079 	    hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) {
1080 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1081 		    "wusb_wa_set_rpipe_target: get rpipe status failed, "
1082 		    "rval = %d", rval);
1083 
1084 		return (rval);
1085 	}
1086 
1087 	if (rp_status & WA_RPIPE_CONFIGURED) {
1088 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1089 		    "wusb_wa_set_rpipe_target: reset rpipe unsuccessful");
1090 
1091 		return (USB_FAILURE);
1092 	}
1093 
1094 	mutex_enter(&wa->wa_mutex);
1095 	usba_device = usba_get_usba_device(ph_data->p_dip);
1096 
1097 	mutex_enter(&hdl->rp_mutex);
1098 
1099 	/* should be 0x200 for default ctrl pipe, refer to wusb 1.0/4.8.1 */
1100 	hdl->rp_descr.wMaxPacketSize = ep->wMaxPacketSize;
1101 
1102 	/*
1103 	 * set rpipe descr values
1104 	 *
1105 	 * Try to use an average block value first. If it's too small,
1106 	 * then try to allocate the minimum block size to accomodate one
1107 	 * packet. If the required number of block is not available, return
1108 	 * failure.
1109 	 */
1110 	if (hdl->rp_descr.wBlocks == 0) {
1111 		blockcnt = wa_desc->wRPipeMaxBlock/wa_desc->wNumRPipes;
1112 		maxsize = 1 << (wa_desc->bRPipeBlockSize - 1);
1113 		seg_len = blockcnt * maxsize;
1114 
1115 		/* alloc enough blocks to accomodate one packet */
1116 		if (ep->wMaxPacketSize > seg_len) {
1117 			blockcnt = (ep->wMaxPacketSize + maxsize -1)/maxsize;
1118 		}
1119 
1120 		/* WA don't have so many blocks to fulfill this reqirement */
1121 		if (wa->wa_avail_blocks < blockcnt) {
1122 			mutex_exit(&hdl->rp_mutex);
1123 			mutex_exit(&wa->wa_mutex);
1124 
1125 			return (USB_FAILURE);
1126 		}
1127 
1128 		/* we're satisfied */
1129 		hdl->rp_descr.wBlocks = blockcnt;
1130 		hdl->rp_block_chg = 1; /* the wBlocks is changed */
1131 		wa->wa_avail_blocks -= blockcnt;
1132 	}
1133 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1134 	    "wusb_wa_set_rpipe_target: wBlocks=%d, maxblock=%d, numR=%d, av=%d",
1135 	    hdl->rp_descr.wBlocks, wa_desc->wRPipeMaxBlock, wa_desc->wNumRPipes,
1136 	    wa->wa_avail_blocks);
1137 
1138 	hdl->rp_descr.wa_value.hwa_value.bMaxBurst = ep_comp.bMaxBurst;
1139 
1140 	/*
1141 	 * DEVICE INDEX
1142 	 * device info index should be zero based, refer
1143 	 * to WUSB 1.0/8.5.3.7
1144 	 */
1145 	hdl->rp_descr.wa_value.hwa_value.bDeviceInfoIndex =
1146 	    usba_device->usb_port - 1;
1147 
1148 	/*
1149 	 * default ctrl pipe uses PHY base signaling rate
1150 	 * refer to wusb 1.0/4.8.1
1151 	 */
1152 	if (ep->bEndpointAddress == 0) {
1153 		hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_53;
1154 	} else {
1155 		if (wusb_wa_is_speed_valid(usba_device, rp_default_speed)) {
1156 			hdl->rp_descr.bSpeed = rp_default_speed;
1157 		} else {
1158 			/* use a must-supported speed */
1159 			hdl->rp_descr.bSpeed = WUSB_PHY_TX_RATE_106;
1160 		}
1161 	}
1162 	hdl->rp_descr.bDeviceAddress = usba_device->usb_addr;
1163 	hdl->rp_descr.bEndpointAddress = ep->bEndpointAddress;
1164 	hdl->rp_descr.bDataSequence = 0;
1165 	hdl->rp_descr.dwCurrentWindow = 1;
1166 	hdl->rp_descr.bMaxDataSequence = ep_comp.bMaxSequence - 1;
1167 	hdl->rp_descr.bInterval = ep->bInterval;
1168 	hdl->rp_descr.bOverTheAirInterval = ep_comp.bOverTheAirInterval;
1169 	hdl->rp_descr.bmAttribute = ep->bmAttributes & 0x03;
1170 	hdl->rp_descr.bmRetryOptions = 0; /* keep retrying */
1171 	hdl->rp_descr.wNumTransactionErrors = 0;
1172 	mutex_exit(&hdl->rp_mutex);
1173 
1174 	mutex_exit(&wa->wa_mutex);
1175 
1176 	/* set rpipe descr */
1177 	rval = wusb_wa_set_rpipe_descr(dip, ph, &hdl->rp_descr);
1178 	if (rval != USB_SUCCESS) {
1179 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1180 		    "wusb_wa_set_rpipe_target: set rpipe descr failed, "
1181 		    "rval = %d", rval);
1182 
1183 		return (rval);
1184 	}
1185 
1186 	/* check rpipe status, must be configured and idle */
1187 	if ((rval = wusb_wa_get_rpipe_status(dip, ph,
1188 	    hdl->rp_descr.wRPipeIndex, &rp_status)) != USB_SUCCESS) {
1189 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1190 		    "wusb_wa_set_rpipe_target: get rpipe status failed, "
1191 		    "rval = %d", rval);
1192 
1193 		return (rval);
1194 	}
1195 
1196 	if (rp_status != (WA_RPIPE_CONFIGURED | WA_RPIPE_IDLE)) {
1197 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1198 		    "wusb_wa_set_rpipe_target: set rpipe descr unsuccessful");
1199 
1200 		return (USB_FAILURE);
1201 	}
1202 
1203 	return (rval);
1204 }
1205 
1206 /*
1207  * Abort a RPipe
1208  *	- See Section 8.3.1.1
1209  *	- Aborts all transfers pending on the given pipe
1210  */
1211 int
wusb_wa_rpipe_abort(dev_info_t * dip,usb_pipe_handle_t ph,wusb_wa_rpipe_hdl_t * hdl)1212 wusb_wa_rpipe_abort(dev_info_t *dip, usb_pipe_handle_t ph,
1213 	wusb_wa_rpipe_hdl_t *hdl)
1214 {
1215 	usb_cr_t	completion_reason;
1216 	usb_cb_flags_t	cb_flags;
1217 	int		rval;
1218 
1219 	mutex_enter(&hdl->rp_mutex);
1220 
1221 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1222 	    "wusb_wa_rpipe_abort: rp_hdl = 0x%p", (void *)hdl);
1223 
1224 	/* only abort when there is active transfer */
1225 	if (hdl->rp_state != WA_RPIPE_STATE_ACTIVE) {
1226 		mutex_exit(&hdl->rp_mutex);
1227 
1228 		return (USB_SUCCESS);
1229 	}
1230 
1231 	mutex_exit(&hdl->rp_mutex);
1232 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1233 	    WA_CLASS_RPIPE_REQ_OUT_TYPE,
1234 	    WA_REQ_ABORT_RPIPE,
1235 	    0,
1236 	    hdl->rp_descr.wRPipeIndex,
1237 	    0,
1238 	    NULL, 0,
1239 	    &completion_reason, &cb_flags, 0);
1240 
1241 	if (rval != USB_SUCCESS) {
1242 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1243 		    "wusb_wa_rpipe_abort: abort failed, rval = %d", rval);
1244 
1245 		return (rval);
1246 	}
1247 
1248 	return (USB_SUCCESS);
1249 }
1250 
1251 /*
1252  * Clear status on the remote device's endpoint, specifically clear the
1253  * RPipe's target endpoint sequence number. See 4.5.3, 4.6.4 and Tab.8-49
1254  * for reference of data sequence.
1255  *
1256  * NOTE AGAIN:
1257  * The device endpoint will not respond to host request if the RPipe is
1258  * reset or re-targeted, while device endpoint is not reset!
1259  */
1260 void
wusb_wa_clear_dev_ep(usba_pipe_handle_data_t * ph)1261 wusb_wa_clear_dev_ep(usba_pipe_handle_data_t *ph)
1262 {
1263 	uint8_t	ept_addr;
1264 
1265 	if (ph == NULL) {
1266 		return;
1267 	}
1268 
1269 	ept_addr = ph->p_ep.bEndpointAddress;
1270 
1271 	USB_DPRINTF_L4(PRINT_MASK_HCDI, whcdi_log_handle,
1272 	    "wusb_wa_clear_dev_ep:clear endpoint = 0x%02x", ept_addr);
1273 	if (ept_addr != 0) {
1274 	/* only clear non-default endpoints */
1275 		(void) usb_clr_feature(ph->p_dip, USB_DEV_REQ_RCPT_EP, 0,
1276 		    ept_addr, USB_FLAGS_SLEEP, NULL, NULL);
1277 	}
1278 }
1279 
1280 /*
1281  * Reset a RPipe
1282  *	- Reset a RPipe to a known state
1283  *	- Pending transfers must be drained or aborted before this
1284  *	  operation.
1285  *	- See Section 8.3.1.10
1286  *
1287  *  dip - the WA's devinfo
1288  *  ph	- RPipe's targeted remote device's endpoint pipe.
1289  *  hdl - RPipe's handle
1290  *
1291  *  flag = 1, reset the RPipe descriptor to its initial state and
1292  *	   also clear remote device endpoint
1293  *	 = 0, not reset the RPipe descriptor. Caller should use 0 flag
1294  *	  if it's the first time to open a pipe, because we don't have
1295  *	  a valid ph yet before successfully opening a pipe by using
1296  *	  usb_pipe_open().
1297  */
1298 int
wusb_wa_rpipe_reset(dev_info_t * dip,usba_pipe_handle_data_t * ph,wusb_wa_rpipe_hdl_t * hdl,int flag)1299 wusb_wa_rpipe_reset(dev_info_t *dip, usba_pipe_handle_data_t *ph,
1300     wusb_wa_rpipe_hdl_t *hdl, int flag)
1301 {
1302 	int		rval = 0;
1303 	usb_cr_t	completion_reason;
1304 	usb_cb_flags_t	cb_flags = 0;
1305 	usb_pipe_handle_t	default_ph;
1306 
1307 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1308 	    "wusb_wa_rpipe_reset: rp_hdl = 0x%p, ep=0x%02x, flag = %d",
1309 	    (void *)hdl, ph->p_ep.bEndpointAddress, flag);
1310 
1311 	/* get WA's default pipe */
1312 	default_ph = usba_get_dflt_pipe_handle(dip);
1313 
1314 	rval = usb_pipe_sync_ctrl_xfer(dip, default_ph,
1315 	    WA_CLASS_RPIPE_REQ_OUT_TYPE,
1316 	    WA_REQ_RESET_RPIPE,
1317 	    0,
1318 	    hdl->rp_descr.wRPipeIndex,
1319 	    0,
1320 	    NULL, 0,
1321 	    &completion_reason, &cb_flags, 0);
1322 
1323 	if (rval != USB_SUCCESS) {
1324 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1325 		    "wusb_wa_rpipe_reset: reset failed, rval=%d"
1326 		    " cr=%d cb=0x%02x",
1327 		    rval, (int)completion_reason, (int)cb_flags);
1328 
1329 		return (rval);
1330 	}
1331 
1332 	if (flag == 0) {
1333 		/* do nothing else, just return, the rpipe is unconfigured */
1334 		return (USB_SUCCESS);
1335 	}
1336 
1337 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1338 	    "wusb_wa_rpipe_reset: need to clear dev pipe and reset RP descr");
1339 
1340 	/* set rpipe descr and make the rpipe configured */
1341 	rval = wusb_wa_set_rpipe_descr(dip, default_ph, &hdl->rp_descr);
1342 	if (rval != USB_SUCCESS) {
1343 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1344 		    "wusb_wa_rpipe_reset: set descr failed, rval = %d", rval);
1345 
1346 		return (rval);
1347 	}
1348 
1349 	mutex_enter(&hdl->rp_mutex);
1350 	hdl->rp_avail_reqs = hdl->rp_descr.wRequests;
1351 	if (hdl->rp_state == WA_RPIPE_STATE_ERROR) {
1352 		hdl->rp_state = WA_RPIPE_STATE_IDLE;
1353 	}
1354 	mutex_exit(&hdl->rp_mutex);
1355 
1356 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1357 	    "wusb_wa_rpipe_reset: end");
1358 
1359 	return (USB_SUCCESS);
1360 }
1361 
1362 /* get rpipe status, refer to WUSB 1.0/8.3.1.5 */
1363 int
wusb_wa_get_rpipe_status(dev_info_t * dip,usb_pipe_handle_t ph,uint16_t idx,uint8_t * status)1364 wusb_wa_get_rpipe_status(dev_info_t *dip, usb_pipe_handle_t ph, uint16_t idx,
1365 	uint8_t	*status)
1366 {
1367 	mblk_t		*data = NULL;
1368 	usb_cr_t	completion_reason;
1369 	usb_cb_flags_t	cb_flags;
1370 	int		rval;
1371 
1372 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1373 	    WA_CLASS_RPIPE_REQ_IN_TYPE,
1374 	    USB_REQ_GET_STATUS,
1375 	    0,
1376 	    idx,
1377 	    1,
1378 	    &data, 0,
1379 	    &completion_reason, &cb_flags, 0);
1380 
1381 	if (rval != USB_SUCCESS) {
1382 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1383 		    "wusb_wa_get_rpipe_status: fail, rval=%d, cr=%d, "
1384 		    "cb=0x%x", rval, completion_reason, cb_flags);
1385 	} else {
1386 		*status = *data->b_rptr;
1387 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1388 		    "wusb_wa_get_rpipe_status: status = %x", *status);
1389 		freemsg(data);
1390 	}
1391 
1392 	return (rval);
1393 }
1394 
1395 /*
1396  * WA specific operations end
1397  */
1398 
1399 /* Transfer related routines */
1400 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)1401 wusb_wa_alloc_tw(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1402 	usba_pipe_handle_data_t	*ph, uint32_t datalen, usb_flags_t usb_flags)
1403 {
1404 	uint_t			seg_count;
1405 	uint32_t		seg_len, maxpktsize;
1406 	wusb_wa_trans_wrapper_t	*wr;
1407 
1408 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1409 	    "wusb_wa_alloc_tw: ph = 0x%p rp_hdl = 0x%p ",
1410 	    (void*)ph, (void*)hdl);
1411 
1412 	mutex_enter(&hdl->rp_mutex);
1413 
1414 	/* compute the rpipe buffer size */
1415 	seg_len = hdl->rp_descr.wBlocks *
1416 	    (1 << (wa_data->wa_descr.bRPipeBlockSize - 1));
1417 	maxpktsize = hdl->rp_descr.wMaxPacketSize;
1418 	mutex_exit(&hdl->rp_mutex);
1419 
1420 	if (seg_len < maxpktsize) {
1421 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1422 		    "wusb_wa_alloc_tw: fail, segment len(%d) "
1423 		    "< wMaxPacketSize(%d) ", seg_len, maxpktsize);
1424 
1425 		return (NULL);
1426 	}
1427 
1428 	/*
1429 	 * the transfer length for each segment is a multiple of the
1430 	 * wMaxPacketSize except the last segment, and the length
1431 	 * cannot exceed the rpipe buffer size
1432 	 */
1433 	seg_len = (seg_len / maxpktsize) * maxpktsize;
1434 	if (datalen) {
1435 		seg_count = (datalen + seg_len - 1) / seg_len;
1436 	} else {
1437 		seg_count = 1;
1438 	}
1439 
1440 	if (seg_count > WA_MAX_SEG_COUNT) {
1441 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1442 		    "wusb_wa_alloc_tw: fail, seg count(%d)"
1443 		    " > Max allowed number(%d) ", seg_count, WA_MAX_SEG_COUNT);
1444 
1445 		return (NULL);
1446 	}
1447 
1448 	if ((wr = kmem_zalloc(sizeof (wusb_wa_trans_wrapper_t),
1449 	    KM_NOSLEEP)) == NULL) {
1450 
1451 		return (NULL);
1452 	}
1453 
1454 	/* allocation, not visible to other threads */
1455 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1456 
1457 	if ((wr->wr_seg_array = kmem_zalloc(sizeof (wusb_wa_seg_t) * seg_count,
1458 	    KM_NOSLEEP)) == NULL) {
1459 		kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
1460 
1461 		return (NULL);
1462 	}
1463 
1464 	/* assign a unique ID for each transfer */
1465 	wr->wr_id = WA_GET_ID(wr);
1466 	if (wr->wr_id == 0) {
1467 		kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) *
1468 		    seg_count);
1469 		kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
1470 
1471 		return (NULL);
1472 	}
1473 
1474 	wr->wr_ph = ph;
1475 	wr->wr_rp = hdl;
1476 	wr->wr_wa_data = wa_data;
1477 	wr->wr_flags = usb_flags;
1478 	wr->wr_nsegs = (uint8_t)seg_count;
1479 	wr->wr_max_seglen = seg_len;
1480 	wr->wr_has_aborted = 0;
1481 
1482 	cv_init(&wr->wr_cv, NULL, CV_DRIVER, NULL);
1483 
1484 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1485 	    "wusb_wa_alloc_tw: wr = 0x%p id = %x nseg = %d", (void*)wr,
1486 	    wr->wr_id, wr->wr_nsegs);
1487 
1488 	return (wr);
1489 }
1490 
1491 /* create transfer wrapper for a ctrl request, return NULL on failure */
1492 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)1493 wusb_wa_create_ctrl_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1494 	usba_pipe_handle_data_t	*ph, usb_ctrl_req_t *ctrl_reqp,
1495 	usb_flags_t usb_flags)
1496 {
1497 	wusb_wa_trans_wrapper_t	*wr = NULL;
1498 
1499 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1500 	    "wusb_wa_create_ctrl_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
1501 	    (void *)ph, (void*)hdl, (void *)ctrl_reqp);
1502 
1503 	wr = wusb_wa_alloc_tw(wa_data, hdl, ph, ctrl_reqp->ctrl_wLength,
1504 	    usb_flags);
1505 	if (wr == NULL) {
1506 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1507 		    "wusb_wa_create_ctrl_wrapper: fail to create tw for %p",
1508 		    (void *)ctrl_reqp);
1509 
1510 		return (NULL);
1511 	}
1512 
1513 	/* not visible to other threads yet */
1514 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1515 
1516 	if (ctrl_reqp->ctrl_bmRequestType & USB_DEV_REQ_DEV_TO_HOST) {
1517 		wr->wr_dir = WA_DIR_IN;
1518 	} else {
1519 		wr->wr_dir = WA_DIR_OUT;
1520 	}
1521 
1522 	wr->wr_type = WA_XFER_REQ_TYPE_CTRL;
1523 	wr->wr_reqp = (usb_opaque_t)ctrl_reqp;
1524 	wr->wr_timeout = (ctrl_reqp->ctrl_timeout == 0) ?
1525 	    WA_RPIPE_DEFAULT_TIMEOUT : ctrl_reqp->ctrl_timeout;
1526 	wr->wr_cb = wusb_wa_handle_ctrl;
1527 
1528 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1529 	    "wusb_wa_create_ctrl_wrapper: wr = 0x%p nseg = %d", (void *)wr,
1530 	    wr->wr_nsegs);
1531 
1532 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1533 
1534 	return (wr);
1535 }
1536 
1537 /*
1538  * create transfer wrapper for a bulk request, return NULL on failure
1539  *	- split the request into multiple segments
1540  *	- every segment is N * wMaxPacketSize
1541  *	- segment length <= bRPipeBlockSize * wBlocks
1542  */
1543 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)1544 wusb_wa_create_bulk_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1545 	usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
1546 	usb_flags_t usb_flags)
1547 {
1548 	wusb_wa_trans_wrapper_t	*wr = NULL;
1549 	usb_ep_descr_t		*epdt = &ph->p_ep;
1550 
1551 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1552 	    "wusb_wa_create_bulk_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
1553 	    (void *)ph, (void *)hdl, (void *)bulk_reqp);
1554 
1555 	wr = wusb_wa_alloc_tw(wa_data, hdl, ph, bulk_reqp->bulk_len,
1556 	    usb_flags);
1557 	if (wr == NULL) {
1558 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1559 		    "wusb_wa_create_bulk_wrapper: fail to create tw for %p",
1560 		    (void *)bulk_reqp);
1561 
1562 		return (NULL);
1563 	}
1564 
1565 	/* no locking needed */
1566 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1567 
1568 	if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1569 		wr->wr_dir = WA_DIR_IN;
1570 	} else {
1571 		wr->wr_dir = WA_DIR_OUT;
1572 	}
1573 
1574 	wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR;
1575 	wr->wr_reqp = (usb_opaque_t)bulk_reqp;
1576 	wr->wr_timeout = (bulk_reqp->bulk_timeout == 0) ?
1577 	    WA_RPIPE_DEFAULT_TIMEOUT : bulk_reqp->bulk_timeout;
1578 	wr->wr_cb = wusb_wa_handle_bulk;
1579 
1580 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1581 	    "wusb_wa_create_bulk_wrapper: wr = 0x%p nseg = %d", (void *)wr,
1582 	    wr->wr_nsegs);
1583 
1584 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1585 
1586 	return (wr);
1587 }
1588 
1589 /*
1590  * create transfer wrapper for a intr request, return NULL on failure
1591  *	- split the request into multiple segments
1592  *	- every segment is N * wMaxPacketSize
1593  *	- segment length <= bRPipeBlockSize * wBlocks
1594  */
1595 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)1596 wusb_wa_create_intr_wrapper(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
1597 	usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
1598 	usb_flags_t usb_flags)
1599 {
1600 	wusb_wa_trans_wrapper_t	*wr;
1601 	usb_ep_descr_t		*epdt = &ph->p_ep;
1602 	uint32_t		tw_len;
1603 	usb_intr_req_t *curr_intr_reqp;
1604 
1605 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1606 	    "wusb_wa_create_intr_wrapper: ph = 0x%p rp_hdl = 0x%p reqp = 0x%p",
1607 	    (void *)ph, (void *)hdl, (void *)intr_reqp);
1608 
1609 	if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1610 		tw_len = (intr_reqp->intr_len) ? intr_reqp->intr_len :
1611 		    ph->p_ep.wMaxPacketSize;
1612 
1613 		/* duplicate client's intr request */
1614 		curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
1615 		    (usb_intr_req_t *)intr_reqp, tw_len, usb_flags);
1616 		if (curr_intr_reqp == NULL) {
1617 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1618 			    "wusb_wa_create_intr_wrapper: fail to create reqp");
1619 
1620 			return (NULL);
1621 		}
1622 
1623 	} else { /* OUT */
1624 		tw_len = intr_reqp->intr_len;
1625 		curr_intr_reqp = intr_reqp;
1626 	}
1627 
1628 	wr = wusb_wa_alloc_tw(wa_data, hdl, ph, tw_len, usb_flags);
1629 	if (wr == NULL) {
1630 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1631 		    "wusb_wa_create_bulk_wrapper: fail to create tw for %p",
1632 		    (void *)intr_reqp);
1633 
1634 		return (NULL);
1635 	}
1636 
1637 	/* no locking needed */
1638 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1639 
1640 	if ((epdt->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
1641 		wr->wr_dir = WA_DIR_IN;
1642 	} else {
1643 		wr->wr_dir = WA_DIR_OUT;
1644 	}
1645 
1646 	wr->wr_type = WA_XFER_REQ_TYPE_BULK_INTR;
1647 
1648 	wr->wr_reqp = (usb_opaque_t)curr_intr_reqp;
1649 
1650 	wr->wr_timeout = (intr_reqp->intr_timeout == 0) ?
1651 	    WA_RPIPE_DEFAULT_TIMEOUT : intr_reqp->intr_timeout;
1652 	wr->wr_cb = wusb_wa_handle_intr;
1653 
1654 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1655 	    "wusb_wa_create_intr_wrapper: wr = 0x%p nseg = %d", (void *)wr,
1656 	    wr->wr_nsegs);
1657 
1658 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1659 
1660 	return (wr);
1661 }
1662 
1663 /*
1664  * Setup the transfer request structure for a segment
1665  * len = transfer request structure length
1666  *	- see section 8.3.3.1 and 8.3.3.2
1667  */
1668 void
wusb_wa_setup_trans_req(wusb_wa_trans_wrapper_t * wr,wusb_wa_seg_t * seg,uint8_t len)1669 wusb_wa_setup_trans_req(wusb_wa_trans_wrapper_t *wr, wusb_wa_seg_t *seg,
1670 	uint8_t len)
1671 {
1672 	mblk_t		*data = seg->seg_trans_reqp->bulk_data;
1673 	uint8_t		*trans_req = data->b_wptr;
1674 
1675 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1676 	    "wusb_wa_setup_trans_req: wr = 0x%p len = %d segnum = 0x%x",
1677 	    (void*)wr, len, seg->seg_num);
1678 
1679 	bzero(trans_req, len);
1680 	trans_req[0] = len;
1681 	trans_req[1] = wr->wr_type;
1682 	trans_req[2] = wr->wr_rp->rp_descr.wRPipeIndex;
1683 	trans_req[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8;
1684 	trans_req[4] = seg->seg_id;	/* dwTransferID */
1685 	trans_req[5] = seg->seg_id >> 8;
1686 	trans_req[6] = seg->seg_id >> 16;
1687 	trans_req[7] = seg->seg_id >> 24;
1688 	trans_req[8] = seg->seg_len;
1689 	trans_req[9] = seg->seg_len >> 8;
1690 	trans_req[10] = seg->seg_len >> 16;
1691 	trans_req[11] = seg->seg_len >> 24;
1692 	trans_req[12] = seg->seg_num;
1693 
1694 	/*
1695 	 * 8-byte setupdata only for the first segment of a ctrl
1696 	 * transfer request
1697 	 */
1698 	if (wr->wr_type == WA_XFER_REQ_TYPE_CTRL) {
1699 		usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)wr->wr_reqp;
1700 
1701 		/* what is the unsecured flag for ? */
1702 		trans_req[13] = wr->wr_dir | WA_CTRL_SECRT_REGULAR;
1703 		if ((seg->seg_num & 0x7f) == 0) {
1704 			/* only send baSetupDate on the first segment */
1705 			trans_req[16] = ctrl_req->ctrl_bmRequestType;
1706 			trans_req[17] = ctrl_req->ctrl_bRequest;
1707 			trans_req[18] = ctrl_req->ctrl_wValue;
1708 			trans_req[19] = ctrl_req->ctrl_wValue >> 8;
1709 			trans_req[20] = ctrl_req->ctrl_wIndex;
1710 			trans_req[21] = ctrl_req->ctrl_wIndex >> 8;
1711 			trans_req[22] = ctrl_req->ctrl_wLength;
1712 			trans_req[23] = ctrl_req->ctrl_wLength >> 8;
1713 
1714 		}
1715 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1716 		    "wusb_wa_setup_trans_req: Ctrl segment = %02x",
1717 		    seg->seg_num);
1718 
1719 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1720 		    "wusb_wa_setup_trans_req: Ctrl Setup Data: "
1721 		    "%02x %02x %02x %02x %02x %02x %02x %02x",
1722 		    trans_req[16], trans_req[17], trans_req[18],
1723 		    trans_req[19], trans_req[20], trans_req[21],
1724 		    trans_req[22], trans_req[23]);
1725 	}
1726 	data->b_wptr += len;
1727 }
1728 
1729 /*
1730  * WA bulk pipe callbacks
1731  *   wusb_wa_trans_bulk_cb: transfer request stage normal callback
1732  *   wusb_wa_trans_bulk_exc_cb: transfer request stage exceptional callback
1733  *
1734  *   wusb_wa_data_bulk_cb: transfer data stage normal callback
1735  *   wusb_wa_data_bulk_exc_cb: transfer data stage exceptional callback
1736  *
1737  * see WUSB1.0 8.3.3 for details
1738  */
1739 void
wusb_wa_trans_bulk_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)1740 wusb_wa_trans_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1741 {
1742 	wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1743 	wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1744 
1745 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1746 	    "wusb_wa_trans_bulk_cb: ph=%p req=0x%p cr=%d", (void*)ph,
1747 	    (void*)req, req->bulk_completion_reason);
1748 
1749 	mutex_enter(&wr->wr_rp->rp_mutex);
1750 
1751 	/* callback returned, this seg can be freed */
1752 	seg->seg_trans_req_state = 0;
1753 
1754 	cv_signal(&seg->seg_trans_cv);
1755 	mutex_exit(&wr->wr_rp->rp_mutex);
1756 }
1757 
1758 void
wusb_wa_trans_bulk_exc_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)1759 wusb_wa_trans_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1760 {
1761 	wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1762 	wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1763 
1764 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1765 	    "wusb_wa_trans_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph,
1766 	    (void *)req, req->bulk_completion_reason);
1767 
1768 	mutex_enter(&wr->wr_rp->rp_mutex);
1769 
1770 	/* callback returned, this seg can be freed */
1771 	seg->seg_trans_req_state = 0;
1772 
1773 	cv_signal(&seg->seg_trans_cv);
1774 	mutex_exit(&wr->wr_rp->rp_mutex);
1775 }
1776 
1777 void
wusb_wa_data_bulk_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)1778 wusb_wa_data_bulk_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1779 {
1780 	wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1781 	wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1782 
1783 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1784 	    "wusb_wa_data_bulk_cb: ph=%p req=0x%p cr=%d", (void *)ph,
1785 	    (void *)req, req->bulk_completion_reason);
1786 
1787 	mutex_enter(&wr->wr_rp->rp_mutex);
1788 
1789 	/* callback returned, this seg can be freed */
1790 	seg->seg_data_req_state = 0;
1791 
1792 	cv_signal(&seg->seg_data_cv);
1793 	mutex_exit(&wr->wr_rp->rp_mutex);
1794 }
1795 
1796 void
wusb_wa_data_bulk_exc_cb(usb_pipe_handle_t ph,struct usb_bulk_req * req)1797 wusb_wa_data_bulk_exc_cb(usb_pipe_handle_t ph, struct usb_bulk_req *req)
1798 {
1799 	wusb_wa_seg_t *seg = (wusb_wa_seg_t *)req->bulk_client_private;
1800 	wusb_wa_trans_wrapper_t *wr = (wusb_wa_trans_wrapper_t *)seg->seg_wr;
1801 
1802 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1803 	    "wusb_wa_data_bulk_exc_cb: ph=%p req=0x%p cr=%d", (void *)ph,
1804 	    (void *)req, req->bulk_completion_reason);
1805 
1806 	mutex_enter(&wr->wr_rp->rp_mutex);
1807 
1808 	/* callback returned, this seg can be freed */
1809 	seg->seg_data_req_state = 0;
1810 
1811 	cv_signal(&seg->seg_data_cv);
1812 	mutex_exit(&wr->wr_rp->rp_mutex);
1813 }
1814 
1815 /*
1816  * Setup all the transfer request segments, including the transfer request
1817  * stage and data stage for out transfer.
1818  * len = total size of payload data to transfer
1819  *	- for every segment, allocate a new bulk request for Transfer
1820  *	  Request. Fill the request with the segment and wrapper data.
1821  *	- for every segment, allocate a new bulk request for data stage.
1822  *
1823  */
1824 int
wusb_wa_setup_segs(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,uint32_t len,mblk_t * data)1825 wusb_wa_setup_segs(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
1826 	uint32_t len, mblk_t *data)
1827 {
1828 	int		i, rval;
1829 	wusb_wa_seg_t	*seg;
1830 	usb_bulk_req_t	*trans_req, *data_req;
1831 	uint8_t		trans_req_len;
1832 	uint8_t		*p;
1833 	wusb_wa_rpipe_hdl_t *hdl = NULL;
1834 
1835 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1836 	    "wusb_wa_setup_segs: wr = 0x%p len = %d data = 0x%p", (void *)wr,
1837 	    len, (void *)data);
1838 
1839 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*wr));
1840 
1841 	if (wr == NULL) {
1842 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1843 		    "wusb_wa_setup_segs: invalid wr");
1844 
1845 		return (USB_INVALID_ARGS);
1846 	}
1847 
1848 	if ((len != 0) && (data != NULL)) {
1849 		p = data->b_rptr;
1850 	}
1851 
1852 	for (i = 0; i < wr->wr_nsegs; i++) {
1853 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*seg));
1854 
1855 		seg = &wr->wr_seg_array[i];
1856 		cv_init(&seg->seg_trans_cv, NULL, CV_DRIVER, NULL);
1857 		cv_init(&seg->seg_data_cv, NULL, CV_DRIVER, NULL);
1858 		seg->seg_wr = wr;
1859 		seg->seg_num = (uint8_t)i;	/* 0-based */
1860 		seg->seg_len = wr->wr_max_seglen;
1861 		if (i == (wr->wr_nsegs - 1)) {
1862 			seg->seg_num |= 0x80;	/* last segment */
1863 			seg->seg_len = len;
1864 		} else {
1865 			len -= seg->seg_len;
1866 		}
1867 
1868 		/*
1869 		 * set seg_id, all segs are the same or unique ??
1870 		 * now make all segs share the same id
1871 		 */
1872 		seg->seg_id = wr->wr_id;
1873 
1874 		/* alloc transfer request and set values */
1875 		switch (wr->wr_type) {
1876 		case WA_XFER_REQ_TYPE_CTRL:
1877 			trans_req_len = WA_CTRL_REQ_LEN;
1878 			break;
1879 		case WA_XFER_REQ_TYPE_BULK_INTR:
1880 			trans_req_len = WA_BULK_INTR_REQ_LEN;
1881 
1882 			break;
1883 		default:
1884 			trans_req_len = 0;
1885 			break;
1886 		}
1887 
1888 		if (trans_req_len == 0) {
1889 			rval = USB_NOT_SUPPORTED;
1890 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1891 			    "wusb_wa_setup_segs: trans len error");
1892 
1893 			goto error;
1894 		}
1895 
1896 		/* alloc transfer request for the ith seg */
1897 		trans_req = usb_alloc_bulk_req(wa_data->wa_dip,
1898 		    trans_req_len, USB_FLAGS_NOSLEEP);
1899 		if (trans_req == NULL) {
1900 			rval = USB_NO_RESOURCES;
1901 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1902 			    "wusb_wa_setup_segs: can't alloc_bulk_req");
1903 
1904 			goto error;
1905 		}
1906 
1907 		/* setup the ith transfer request */
1908 		trans_req->bulk_len = trans_req_len;
1909 		trans_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
1910 		trans_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1911 		trans_req->bulk_cb = wusb_wa_trans_bulk_cb;
1912 		trans_req->bulk_exc_cb = wusb_wa_trans_bulk_exc_cb;
1913 		trans_req->bulk_client_private = (usb_opaque_t)seg;
1914 
1915 		seg->seg_trans_reqp = trans_req;
1916 		wusb_wa_setup_trans_req(wr, seg, trans_req_len);
1917 
1918 		if (seg->seg_len != 0) {
1919 			/* alloc request for data stage */
1920 			data_req = usb_alloc_bulk_req(wa_data->wa_dip,
1921 			    seg->seg_len, USB_FLAGS_NOSLEEP);
1922 			if (data_req == NULL) {
1923 				rval = USB_NO_RESOURCES;
1924 				USB_DPRINTF_L2(DPRINT_MASK_WHCDI,
1925 				    whcdi_log_handle,
1926 				    "wusb_wa_setup_segs: can't alloc_bulk_req"
1927 				    " for data");
1928 
1929 				goto error;
1930 			}
1931 
1932 			/* setup the ith data transfer */
1933 			data_req->bulk_len = seg->seg_len;
1934 			data_req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
1935 			data_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1936 
1937 			data_req->bulk_cb = wusb_wa_data_bulk_cb;
1938 			data_req->bulk_exc_cb = wusb_wa_data_bulk_exc_cb;
1939 			data_req->bulk_client_private = (usb_opaque_t)seg;
1940 
1941 			seg->seg_data_reqp = data_req;
1942 
1943 			/*
1944 			 * Copy data from client driver to bulk request for
1945 			 * an OUT endpoint.
1946 			 */
1947 			if (wr->wr_dir == WA_DIR_OUT) {
1948 				ASSERT(data != NULL);
1949 				/*
1950 				 * cannot increase data->b_rptr,
1951 				 * or scsa2usb panic at bulk out
1952 				 */
1953 				ASSERT((intptr_t)((uintptr_t)data->b_wptr -
1954 				    (uintptr_t)p) >= seg->seg_len);
1955 				bcopy(p,
1956 				    data_req->bulk_data->b_wptr,
1957 				    seg->seg_len);
1958 				p += seg->seg_len;
1959 
1960 				data_req->bulk_data->b_wptr += seg->seg_len;
1961 			}
1962 		}
1963 
1964 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*seg));
1965 	}
1966 
1967 	/* zero timeout means to wait infinitely */
1968 	/*
1969 	 * if this is the first time this WR to be transfered,
1970 	 * we'll add it to its rpipe handle's timeout queue
1971 	 */
1972 	if (wr->wr_timeout > 0) {
1973 		hdl = wr->wr_rp;
1974 
1975 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1976 		    "wusb_wa_setup_segs: timeout=%d", wr->wr_timeout);
1977 
1978 		mutex_enter(&hdl->rp_mutex);
1979 
1980 		/* Add this new wrapper to the head of RPipe's timeout list */
1981 		if (hdl->rp_timeout_list) {
1982 			wr->wr_timeout_next = hdl->rp_timeout_list;
1983 		}
1984 
1985 		hdl->rp_timeout_list = wr;
1986 
1987 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1988 
1989 		mutex_exit(&hdl->rp_mutex);
1990 	}
1991 
1992 	return (USB_SUCCESS);
1993 
1994 error:
1995 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1996 	    "wusb_wa_setup_segs: fail, rval = %d", rval);
1997 
1998 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*wr));
1999 
2000 	mutex_enter(&hdl->rp_mutex);
2001 	wusb_wa_free_segs(wr);
2002 	mutex_exit(&hdl->rp_mutex);
2003 
2004 	return (rval);
2005 }
2006 
2007 /* allocate transfer wrapper and setup all transfer segments */
2008 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)2009 wusb_wa_alloc_ctrl_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2010 	usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
2011 	usb_flags_t usb_flags)
2012 {
2013 	wusb_wa_trans_wrapper_t	*wr;
2014 
2015 	wr = wusb_wa_create_ctrl_wrapper(wa_data, hdl, ph, ctrl_reqp,
2016 	    usb_flags);
2017 
2018 	if (wr == NULL) {
2019 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2020 		    "wusb_wa_alloc_ctrl_resources failed");
2021 
2022 		return (NULL);
2023 	}
2024 
2025 	if (wusb_wa_setup_segs(wa_data, wr, ctrl_reqp->ctrl_wLength,
2026 	    ctrl_reqp->ctrl_data) != USB_SUCCESS) {
2027 		wusb_wa_free_trans_wrapper(wr);
2028 
2029 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2030 		    "wusb_wa_alloc_ctrl_resources failed to setup segs");
2031 
2032 		return (NULL);
2033 	}
2034 
2035 	return (wr);
2036 }
2037 
2038 /* allocate transfer wrapper and setup all transfer segments */
2039 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)2040 wusb_wa_alloc_bulk_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2041 	usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
2042 	usb_flags_t usb_flags)
2043 {
2044 	wusb_wa_trans_wrapper_t	*wr;
2045 
2046 	wr = wusb_wa_create_bulk_wrapper(wa_data, hdl, ph, bulk_reqp,
2047 	    usb_flags);
2048 
2049 	if (wr == NULL) {
2050 
2051 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2052 		    "wusb_wa_alloc_bulk_resources: failed to create wr");
2053 
2054 		return (NULL);
2055 	}
2056 
2057 	if (wusb_wa_setup_segs(wa_data, wr, bulk_reqp->bulk_len,
2058 	    bulk_reqp->bulk_data) != USB_SUCCESS) {
2059 		wusb_wa_free_trans_wrapper(wr);
2060 
2061 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2062 		    "wusb_wa_alloc_bulk_resources:failed to setup segs");
2063 		return (NULL);
2064 	}
2065 
2066 	return (wr);
2067 }
2068 
2069 /*
2070  * allocate transfer wrapper and setup all transfer segments
2071  * if it's an IN request, duplicate it.
2072  */
2073 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)2074 wusb_wa_alloc_intr_resources(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2075 	usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
2076 	usb_flags_t usb_flags)
2077 {
2078 	wusb_wa_trans_wrapper_t	*wr;
2079 
2080 	wr = wusb_wa_create_intr_wrapper(wa_data, hdl, ph, intr_reqp,
2081 	    usb_flags);
2082 
2083 	if (wr == NULL) {
2084 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2085 		    "wusb_wa_alloc_intr_resources: failed to create wr");
2086 
2087 		return (NULL);
2088 	}
2089 
2090 	if (wusb_wa_setup_segs(wa_data, wr, intr_reqp->intr_len,
2091 	    intr_reqp->intr_data) != USB_SUCCESS) {
2092 		wusb_wa_free_trans_wrapper(wr);
2093 
2094 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2095 		    "wusb_wa_alloc_intr_resources: failed to setup segs");
2096 
2097 		return (NULL);
2098 	}
2099 
2100 	return (wr);
2101 }
2102 
2103 /* free the bulk request structures for all segments */
2104 void
wusb_wa_free_segs(wusb_wa_trans_wrapper_t * wr)2105 wusb_wa_free_segs(wusb_wa_trans_wrapper_t *wr)
2106 {
2107 	int		i;
2108 	wusb_wa_seg_t	*seg;
2109 
2110 	ASSERT(mutex_owned(&wr->wr_rp->rp_mutex));
2111 
2112 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2113 	    "wusb_wa_free_segs: wr = 0x%p, segs=%p", (void *)wr,
2114 	    (void *)wr->wr_seg_array);
2115 
2116 	if (wr->wr_seg_array == NULL) {
2117 		return;
2118 	}
2119 
2120 
2121 	for (i = 0; i < wr->wr_nsegs; i++) {
2122 		seg = &wr->wr_seg_array[i];
2123 
2124 		if (seg->seg_trans_reqp != NULL) {
2125 			while (seg->seg_trans_req_state == 1) {
2126 				cv_wait(&seg->seg_trans_cv,
2127 				    &wr->wr_rp->rp_mutex);
2128 			}
2129 			/* free the bulk req for transfer request */
2130 			usb_free_bulk_req(seg->seg_trans_reqp);
2131 			seg->seg_trans_reqp = NULL;
2132 		}
2133 
2134 		if (seg->seg_data_reqp != NULL) {
2135 			while (seg->seg_data_req_state == 1) {
2136 				cv_wait(&seg->seg_data_cv,
2137 				    &wr->wr_rp->rp_mutex);
2138 			}
2139 			/* free the bulk req for data transfer */
2140 			usb_free_bulk_req(seg->seg_data_reqp);
2141 			seg->seg_data_reqp = NULL;
2142 		}
2143 
2144 		cv_destroy(&seg->seg_trans_cv);
2145 		cv_destroy(&seg->seg_data_cv);
2146 	}
2147 
2148 	kmem_free(wr->wr_seg_array, sizeof (wusb_wa_seg_t) * wr->wr_nsegs);
2149 
2150 	wr->wr_seg_array = NULL;
2151 	wr->wr_nsegs = 0;
2152 }
2153 
2154 /* free transfer wrapper */
2155 void
wusb_wa_free_trans_wrapper(wusb_wa_trans_wrapper_t * wr)2156 wusb_wa_free_trans_wrapper(wusb_wa_trans_wrapper_t *wr)
2157 {
2158 	wusb_wa_rpipe_hdl_t *hdl = NULL;
2159 
2160 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2161 	    "wusb_wa_free_trans_wrapper: wr = 0x%p", (void *)wr);
2162 
2163 	if (wr == NULL) {
2164 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2165 		    "wusb_wa_free_trans_wrapper: NULL wrapper");
2166 		return;
2167 	}
2168 
2169 	hdl = wr->wr_rp;
2170 
2171 	mutex_enter(&hdl->rp_mutex);
2172 
2173 	wusb_wa_remove_wr_from_timeout_list(hdl, wr);
2174 
2175 	if (wr->wr_seg_array != NULL) {
2176 		wusb_wa_free_segs(wr);
2177 		kmem_free(wr->wr_seg_array,
2178 		    sizeof (wusb_wa_seg_t) * wr->wr_nsegs);
2179 	}
2180 
2181 	if (wr->wr_id != 0) {
2182 		WA_FREE_ID(wr->wr_id);
2183 	}
2184 
2185 	cv_destroy(&wr->wr_cv);
2186 
2187 	kmem_free(wr, sizeof (wusb_wa_trans_wrapper_t));
2188 
2189 	mutex_exit(&hdl->rp_mutex);
2190 }
2191 
2192 /* abort a transfer, refer to WUSB 1.0/8.3.3.5 */
2193 void
wusb_wa_abort_req(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,uint32_t id)2194 wusb_wa_abort_req(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
2195 	uint32_t id)
2196 {
2197 	usb_bulk_req_t	*req;
2198 	uint8_t		*p;
2199 	int		rval;
2200 
2201 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2202 	    "wusb_wa_abort_req: wr = 0x%p", (void *)wr);
2203 
2204 	req = usb_alloc_bulk_req(wa_data->wa_dip, WA_ABORT_REQ_LEN,
2205 	    USB_FLAGS_NOSLEEP);
2206 	if (req == NULL) {
2207 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2208 		    "wusb_wa_abort_req: alloc bulk req failed");
2209 
2210 		return;
2211 	}
2212 
2213 	req->bulk_len = WA_ABORT_REQ_LEN;
2214 	req->bulk_timeout = WA_RPIPE_DEFAULT_TIMEOUT;
2215 	req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
2216 	p = req->bulk_data->b_wptr;
2217 	p[0] = WA_ABORT_REQ_LEN;
2218 	p[1] = WA_XFER_REQ_TYPE_ABORT;
2219 	p[2] = wr->wr_rp->rp_descr.wRPipeIndex;
2220 	p[3] = wr->wr_rp->rp_descr.wRPipeIndex >> 8;
2221 	p[4] = (uint8_t)id;
2222 	p[5] = (uint8_t)(id >> 8);
2223 	p[6] = (uint8_t)(id >> 16);
2224 	p[7] = (uint8_t)(id >> 24);
2225 	req->bulk_data->b_wptr += WA_ABORT_REQ_LEN;
2226 
2227 	mutex_exit(&wr->wr_rp->rp_mutex);
2228 	rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req,
2229 	    USB_FLAGS_SLEEP);
2230 	mutex_enter(&wr->wr_rp->rp_mutex);
2231 	if (rval != USB_SUCCESS) {
2232 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2233 		    "wusb_wa_abort_req: send abort req failed, rval = %d",
2234 		    rval);
2235 	}
2236 	usb_free_bulk_req(req);
2237 }
2238 
2239 static void
wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t * hdl,wusb_wa_trans_wrapper_t * tw)2240 wusb_wa_remove_wr_from_timeout_list(wusb_wa_rpipe_hdl_t *hdl,
2241 	wusb_wa_trans_wrapper_t *tw)
2242 {
2243 	wusb_wa_trans_wrapper_t *prev, *next;
2244 	int ret = 0; /* debug only */
2245 
2246 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2247 	    "remove_wr_from_timeout_list: %p", (void *)tw);
2248 
2249 	if (hdl->rp_timeout_list) {
2250 		if (hdl->rp_timeout_list == tw) {
2251 			hdl->rp_timeout_list = tw->wr_timeout_next;
2252 			tw->wr_timeout_next = NULL;
2253 			ret = 1;
2254 		} else {
2255 			prev = hdl->rp_timeout_list;
2256 			next = prev->wr_timeout_next;
2257 
2258 			while (next && (next != tw)) {
2259 				prev = next;
2260 				next = next->wr_timeout_next;
2261 			}
2262 
2263 			if (next == tw) {
2264 				prev->wr_timeout_next = next->wr_timeout_next;
2265 				tw->wr_timeout_next = NULL;
2266 				ret = 1;
2267 			}
2268 		}
2269 	}
2270 
2271 	/* debug only */
2272 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2273 	    "remove_wr_from_timeout_list: %p, on the list:%d",
2274 	    (void *)tw, ret);
2275 }
2276 
2277 /* start timer on a rpipe */
2278 void
wusb_wa_start_xfer_timer(wusb_wa_rpipe_hdl_t * hdl)2279 wusb_wa_start_xfer_timer(wusb_wa_rpipe_hdl_t *hdl)
2280 {
2281 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2282 	    "wusb_wa_start_xfer_timer: rpipe hdl = 0x%p", (void *)hdl);
2283 
2284 	ASSERT(mutex_owned(&hdl->rp_mutex));
2285 
2286 	/*
2287 	 * wr_timeout is in Seconds
2288 	 */
2289 	/*
2290 	 * Start the rpipe's timer only if currently timer is not
2291 	 * running and if there are transfers on the rpipe.
2292 	 * The timer will be per rpipe.
2293 	 *
2294 	 * The RPipe's timer expires every 1s. When this timer expires, the
2295 	 * handler gets called and will decrease every pending transfer
2296 	 * wrapper's timeout value.
2297 	 */
2298 	if ((!hdl->rp_timer_id) && (hdl->rp_timeout_list)) {
2299 		hdl->rp_timer_id = timeout(wusb_wa_xfer_timeout_handler,
2300 		    (void *)hdl, drv_usectohz(1000000));
2301 	}
2302 }
2303 
2304 /* transfer timeout handler */
2305 void
wusb_wa_xfer_timeout_handler(void * arg)2306 wusb_wa_xfer_timeout_handler(void *arg)
2307 {
2308 	wusb_wa_rpipe_hdl_t	*hdl = (wusb_wa_rpipe_hdl_t *)arg;
2309 	wusb_wa_trans_wrapper_t	*wr = NULL;
2310 	wusb_wa_trans_wrapper_t	*next = NULL;
2311 	wusb_wa_data_t		*wa_data = NULL;
2312 	int			rval;
2313 	uint8_t			rp_status;
2314 	wusb_wa_trans_wrapper_t	*expire_list = NULL;
2315 
2316 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2317 	    "wusb_wa_xfer_timeout_handler: rphdl = 0x%p ", (void *)hdl);
2318 
2319 	mutex_enter(&hdl->rp_mutex);
2320 
2321 	/*
2322 	 * Check whether still timeout handler is valid.
2323 	 */
2324 	if (hdl->rp_timer_id != 0) {
2325 
2326 		/* Reset the timer id to zero */
2327 		hdl->rp_timer_id = 0;
2328 	} else {
2329 		mutex_exit(&hdl->rp_mutex);
2330 
2331 		return;
2332 	}
2333 
2334 	/*
2335 	 * Check each transfer wrapper on this RPipe's timeout queue
2336 	 * Actually, due to USBA's limitation and queueing, there's only one
2337 	 * usba_request submitted to HCD at a specific pipe. Hence, only one
2338 	 * WR can be on this RPipe's list at any moment.
2339 	 */
2340 	wr = hdl->rp_timeout_list;
2341 	while (wr) {
2342 		next = wr->wr_timeout_next;
2343 
2344 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2345 		    "wusb_wa_xfer_timeout_handler: rhdl=0x%p"
2346 		    " wr=0x%p(to=%d) nxt=0x%p", (void *)hdl, (void *)wr,
2347 		    wr->wr_timeout, (void *)next);
2348 
2349 		/*
2350 		 * 1 second passed. Decrease every transfer wrapper's
2351 		 * timeout value. If the timeout < 0 (expired), remove this
2352 		 * wrapper from the timeout list and put it on the
2353 		 * expire_list.
2354 		 */
2355 		wr->wr_timeout--;
2356 		if (wr->wr_timeout <= 0) {
2357 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2358 			    "wusb_wa_xfer_timeout_handler: 0x%p time out",
2359 			    (void *)wr);
2360 
2361 			/* remove it from the rpipe's timeout list */
2362 			wusb_wa_remove_wr_from_timeout_list(hdl, wr);
2363 
2364 			/* put it on the expired list */
2365 			wr->wr_timeout_next = expire_list;
2366 			expire_list = wr;
2367 
2368 		}
2369 
2370 		wr = next;
2371 	}
2372 
2373 	/* Restart this RPipe's timer */
2374 	wusb_wa_start_xfer_timer(hdl);
2375 
2376 	/* timeout handling */
2377 	wr = expire_list;
2378 	while (wr) {
2379 		next = wr->wr_timeout_next;
2380 
2381 		/* other thread shouldn't continue processing it */
2382 		wr->wr_state = WR_TIMEOUT;
2383 
2384 		wa_data = wr->wr_wa_data;
2385 
2386 		mutex_exit(&hdl->rp_mutex);
2387 		rval = wusb_wa_get_rpipe_status(wa_data->wa_dip,
2388 		    wa_data->wa_default_pipe, hdl->rp_descr.wRPipeIndex,
2389 		    &rp_status);
2390 		mutex_enter(&hdl->rp_mutex);
2391 
2392 		if (rval != USB_SUCCESS) {
2393 			/* reset WA perhaps? */
2394 			hdl->rp_state = WA_RPIPE_STATE_ERROR;
2395 			hdl->rp_curr_wr = NULL;
2396 			mutex_exit(&hdl->rp_mutex);
2397 			wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 1);
2398 			mutex_enter(&hdl->rp_mutex);
2399 
2400 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2401 			    "wusb_wa_xfer_timeout_handler: fail to get"
2402 			    " rpipe status, rval = %d", rval);
2403 
2404 			goto continuing;
2405 		}
2406 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2407 		    "wusb_wa_xfer_timeout_handler: rpstat=0x%02x, wr=0x%p,"
2408 		    " wr_state=%d", rp_status, (void *)wr, wr->wr_state);
2409 
2410 		if (!(rp_status & WA_RPIPE_IDLE)) {
2411 		/*
2412 		 * If RP is not idle, then it must be processing this WR.
2413 		 * Abort this request to make the RPipe idle.
2414 		 */
2415 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2416 			    "wusb_wa_xfer_timeout_handler: rp not idle");
2417 
2418 			mutex_exit(&hdl->rp_mutex);
2419 			rval = wusb_wa_rpipe_abort(wa_data->wa_dip,
2420 			    wa_data->wa_default_pipe, hdl);
2421 			mutex_enter(&hdl->rp_mutex);
2422 
2423 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI,
2424 			    whcdi_log_handle,
2425 			    "wusb_wa_xfer_timeout_handler: abort rpipe"
2426 			    " fail rval = %d", rval);
2427 
2428 			if (rval == 0) {
2429 				/*
2430 				 * wait for the result thread to get
2431 				 * Aborted result. If this wr hasn't been
2432 				 * aborted, wait it.
2433 				 */
2434 				if ((wr->wr_has_aborted == 0) &&
2435 				    (cv_reltimedwait(&wr->wr_cv, &hdl->rp_mutex,
2436 				    drv_usectohz(100 * 1000), TR_CLOCK_TICK)
2437 				    >= 0)) {
2438 				    /* 100ms, random number, long enough? */
2439 
2440 					/* the result thread has processed it */
2441 					goto continuing;
2442 				}
2443 
2444 				USB_DPRINTF_L3(DPRINT_MASK_WHCDI,
2445 				    whcdi_log_handle,
2446 				    "wusb_wa_xfer_timeout_handler: result"
2447 				    " thread can't get the aborted request");
2448 			}
2449 		}
2450 
2451 		/*
2452 		 * 1)The Rpipe is idle, OR,
2453 		 * 2)rpipe_abort fails, OR,
2454 		 * 3)The result thread hasn't got an aborted result in 100ms,
2455 		 * most likely the result is lost. We can not depend on WA to
2456 		 * return result for this aborted request. The WA seems not
2457 		 * always returning such result. This will cause some hcdi
2458 		 * ops hang.
2459 		 */
2460 		hdl->rp_state = WA_RPIPE_STATE_IDLE;
2461 		hdl->rp_curr_wr = NULL;
2462 
2463 		/* release this WR's occupied req */
2464 		hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
2465 		cv_signal(&hdl->rp_cv);
2466 
2467 		mutex_exit(&hdl->rp_mutex);
2468 
2469 		wr->wr_cb(wa_data, wr, USB_CR_TIMEOUT, 0);
2470 		mutex_enter(&hdl->rp_mutex);
2471 
2472 continuing:
2473 		wr = next;
2474 	}
2475 
2476 	mutex_exit(&hdl->rp_mutex);
2477 }
2478 
2479 /* stop timer */
2480 void
wusb_wa_stop_xfer_timer(wusb_wa_trans_wrapper_t * wr)2481 wusb_wa_stop_xfer_timer(wusb_wa_trans_wrapper_t *wr)
2482 {
2483 	wusb_wa_rpipe_hdl_t	*hdl = wr->wr_rp;
2484 	timeout_id_t		timer_id;
2485 
2486 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2487 	    "wusb_wa_stop_xfer_timer: wr = 0x%p", (void *)wr);
2488 
2489 	ASSERT(mutex_owned(&hdl->rp_mutex));
2490 
2491 	if (hdl->rp_timer_id == 0) {
2492 
2493 		return;
2494 	}
2495 
2496 	timer_id = hdl->rp_timer_id;
2497 	hdl->rp_timer_id = 0;
2498 	mutex_exit(&hdl->rp_mutex);
2499 
2500 	(void) untimeout(timer_id);
2501 
2502 	mutex_enter(&hdl->rp_mutex);
2503 }
2504 
2505 
2506 /*
2507  * send transfer request and data to the bulk out pipe
2508  *
2509  * General transfer function for WA transfer, see Section 8.3.3.
2510  */
2511 /* ARGSUSED */
2512 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)2513 wusb_wa_wr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2514     wusb_wa_trans_wrapper_t *wr, usb_flags_t usb_flags)
2515 {
2516 	int		i, rval;
2517 	uint8_t		curr_seg;
2518 	usb_bulk_req_t	*req;
2519 
2520 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2521 	    "wusb_wa_wr_xfer: wr = 0x%p", (void *)wr);
2522 
2523 	ASSERT(wr->wr_seg_array != NULL);
2524 
2525 	ASSERT(mutex_owned(&hdl->rp_mutex));
2526 
2527 	if (hdl->rp_state == WA_RPIPE_STATE_IDLE) {
2528 		hdl->rp_state = WA_RPIPE_STATE_ACTIVE;
2529 		hdl->rp_curr_wr = wr;
2530 	}
2531 	curr_seg = wr->wr_curr_seg;
2532 
2533 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2534 	    "wusb_wa_wr_xfer: curr_seg = %d, avail_req = %d", curr_seg,
2535 	    hdl->rp_avail_reqs);
2536 
2537 	/*
2538 	 * For every segment,
2539 	 *	Step 1: contruct a bulk req containing Transfer
2540 	 *		Request(T8-12 and T8-10)
2541 	 *	Step 2: alloc another bulk req if there's any data
2542 	 *		for OUT endpoints.
2543 	 *
2544 	 *	For IN endpoints, the data is returned in the
2545 	 *	GetResult thread.
2546 	 * Just throw as many as maximum available requests to the RPipe.
2547 	 * If the avail_req is zero, wait!
2548 	 *
2549 	 * When a request is finished, the avail_req will be increased
2550 	 * in the result thread.
2551 	 */
2552 	for (i = curr_seg; i < wr->wr_nsegs; i++) {
2553 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2554 		    "wusb_wa_wr_xfer: wr=%p curr_seg = %d, avail_req = %d,"
2555 		    " dir=%s", (void *)wr, curr_seg, hdl->rp_avail_reqs,
2556 		    (wr->wr_dir == WA_DIR_IN)?"IN":"OUT");
2557 
2558 		/* waiting for available requests if wr is still good */
2559 		while ((hdl->rp_avail_reqs == 0) && (wr->wr_state == 0)) {
2560 			rval = cv_wait_sig(&hdl->rp_cv, &hdl->rp_mutex);
2561 		}
2562 
2563 		if ((wr->wr_curr_seg - wr->wr_seg_done) >= 1) {
2564 			/* send only one segment */
2565 
2566 			break;
2567 		}
2568 
2569 		if (wr->wr_state != 0) {
2570 		/* wr transfer error, don't continue */
2571 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2572 			    "wusb_wa_wr_xfer: wr_state!=0(%d)", wr->wr_state);
2573 
2574 			break;
2575 		}
2576 
2577 		req = wr->wr_seg_array[i].seg_trans_reqp;
2578 		ASSERT(req != NULL);
2579 
2580 		mutex_exit(&hdl->rp_mutex);
2581 		/* send ith transfer request */
2582 		rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0);
2583 		mutex_enter(&hdl->rp_mutex);
2584 		if (rval != USB_SUCCESS) {
2585 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2586 			    "wusb_wa_wr_xfer: send transfer request %d failed,"
2587 			    "rv=%d", i, rval);
2588 
2589 			wr->wr_seg_array[i].seg_trans_req_state = 0; /* clear */
2590 
2591 			if (i == 0) {
2592 				/* no xfer in processing */
2593 				hdl->rp_state = WA_RPIPE_STATE_IDLE;
2594 				hdl->rp_curr_wr = NULL;
2595 
2596 				return (rval);
2597 			}
2598 			wusb_wa_abort_req(wa_data, wr, wr->wr_id);
2599 			wr->wr_state = WR_SEG_REQ_ERR;	/* sending tr error */
2600 
2601 			break;
2602 		}
2603 		wr->wr_seg_array[i].seg_trans_req_state = 1; /* submitted */
2604 
2605 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2606 		    "wusb_wa_wr_xfer: seg(%d) request(0x%p) sent,"
2607 		    " avail_req = %d", i, (void*)req, hdl->rp_avail_reqs);
2608 
2609 		hdl->rp_avail_reqs--;
2610 
2611 		/* Get data in the GetResult thread for IN eps */
2612 		if (wr->wr_dir == WA_DIR_IN) {
2613 			wr->wr_curr_seg++;
2614 
2615 			/* only send data for out request */
2616 			continue;
2617 		}
2618 
2619 		req = wr->wr_seg_array[i].seg_data_reqp;
2620 		if (req == NULL) {
2621 			/* no data stage */
2622 			wr->wr_curr_seg++;
2623 
2624 			continue;
2625 		}
2626 
2627 		wr->wr_seg_array[i].seg_data_req_state = 1; /* submitted */
2628 		mutex_exit(&hdl->rp_mutex);
2629 		/* send ith data asynchronously */
2630 		rval = usb_pipe_bulk_xfer(wa_data->wa_bulkout_ph, req, 0);
2631 		mutex_enter(&hdl->rp_mutex);
2632 		if (rval != USB_SUCCESS) {
2633 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2634 			    "wusb_wa_wr_xfer: send transfer data %d failed",
2635 			    i);
2636 
2637 			wr->wr_seg_array[i].seg_data_req_state = 0; /* clear */
2638 
2639 			wusb_wa_abort_req(wa_data, wr, wr->wr_id);
2640 			wr->wr_state = WR_SEG_DAT_ERR; /* sending data error */
2641 
2642 			/* not inc rp_avail_reqs until callback */
2643 
2644 			break;
2645 		}
2646 
2647 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2648 		    "wusb_wa_wr_xfer: seg(%d) data(0x%p) sent, avail_req = %d",
2649 		    i, (void*)req, hdl->rp_avail_reqs);
2650 
2651 		wr->wr_curr_seg++;
2652 	}
2653 
2654 	/* start timer */
2655 	wusb_wa_start_xfer_timer(hdl);
2656 	/*
2657 	 * return success even if the xfer is not complete, the callback
2658 	 * will only continue sending segs when (wr_error_state = 0 &&
2659 	 * wr_curr_seg < wr_nsegs)
2660 	 */
2661 	return (USB_SUCCESS);
2662 }
2663 
2664 /*
2665  * submit wr according to rpipe status
2666  *	- check RPipe state
2667  *	- call general WA transfer function to do transfer
2668  *
2669  * usba only submits one transfer to the host controller per pipe at a time
2670  * and starts next when the previous one completed. So the hwahc now
2671  * assumes one transfer per rpipe at a time. This won't be necessary to
2672  * change unless the usba scheme is changed.
2673  */
2674 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)2675 wusb_wa_submit_ctrl_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2676 	wusb_wa_trans_wrapper_t *wr, usb_ctrl_req_t *ctrl_reqp,
2677 	usb_flags_t usb_flags)
2678 {
2679 	int		rval;
2680 
2681 	mutex_enter(&hdl->rp_mutex);
2682 	switch (hdl->rp_state) {
2683 	case WA_RPIPE_STATE_IDLE:
2684 		rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
2685 		break;
2686 	case WA_RPIPE_STATE_ACTIVE:
2687 		/* only allow one req at a time, this should not happen */
2688 	default:
2689 		rval = USB_PIPE_ERROR;
2690 		break;
2691 	}
2692 	mutex_exit(&hdl->rp_mutex);
2693 
2694 	if (rval != USB_SUCCESS) {
2695 		if (ctrl_reqp->ctrl_completion_reason == USB_CR_OK) {
2696 			ctrl_reqp->ctrl_completion_reason = usba_rval2cr(rval);
2697 		}
2698 		mutex_enter(&hdl->rp_mutex);
2699 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2700 		    "wusb_wa_submit_ctrl_wr:fail, reqp=0x%p, rpstat=%d, rv=%d",
2701 		    (void*)ctrl_reqp, hdl->rp_state, rval);
2702 
2703 		mutex_exit(&hdl->rp_mutex);
2704 
2705 		wusb_wa_free_trans_wrapper(wr);
2706 	}
2707 
2708 	/* In other cases, wr will be freed in callback */
2709 	return (rval);
2710 }
2711 
2712 /*
2713  * Transfer a control request:
2714  *	- allocate a transfer wrapper(TW) for this request
2715  *	- submit this TW
2716  */
2717 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)2718 wusb_wa_ctrl_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2719 	usba_pipe_handle_data_t *ph, usb_ctrl_req_t *ctrl_reqp,
2720 	usb_flags_t usb_flags)
2721 {
2722 	int			rval;
2723 	wusb_wa_trans_wrapper_t	*wr;
2724 
2725 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2726 	    "wusb_wa_ctrl_xfer: ph = 0x%p reqp = 0x%p",
2727 	    (void*)ph, (void*)ctrl_reqp);
2728 
2729 	wr = wusb_wa_alloc_ctrl_resources(wa_data, hdl, ph, ctrl_reqp,
2730 	    usb_flags);
2731 	if (wr == NULL) {
2732 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2733 		    "wusb_wa_ctrl_req: alloc ctrl resource failed");
2734 
2735 		return (USB_NO_RESOURCES);
2736 	}
2737 
2738 	rval = wusb_wa_submit_ctrl_wr(wa_data, hdl, wr, ctrl_reqp, usb_flags);
2739 	if (rval != USB_SUCCESS) {
2740 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2741 		    "wusb_wa_submit_ctrl_wr: submit ctrl req failed, rval = %d",
2742 		    rval);
2743 	}
2744 
2745 	return (rval);
2746 }
2747 
2748 /*
2749  * submit wr according to rpipe status
2750  *
2751  * usba only submits one transfer to the host controller per pipe at a time
2752  * and starts next when the previous one completed. So the hwahc now
2753  * assumes one transfer per rpipe at a time. This won't be necessary to
2754  * change unless the usba scheme is changed.
2755  */
2756 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)2757 wusb_wa_submit_bulk_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2758 	wusb_wa_trans_wrapper_t *wr, usb_bulk_req_t *bulk_reqp,
2759 	usb_flags_t usb_flags)
2760 {
2761 	int		rval;
2762 
2763 	mutex_enter(&hdl->rp_mutex);
2764 	switch (hdl->rp_state) {
2765 	case WA_RPIPE_STATE_IDLE:
2766 		rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
2767 		break;
2768 	case WA_RPIPE_STATE_ACTIVE:
2769 		/* only allow one req at a time, this should not happen */
2770 	default:
2771 		rval = USB_PIPE_ERROR;
2772 		break;
2773 	}
2774 	mutex_exit(&hdl->rp_mutex);
2775 
2776 	if (rval != USB_SUCCESS) {
2777 		if (bulk_reqp->bulk_completion_reason == USB_CR_OK) {
2778 			bulk_reqp->bulk_completion_reason = usba_rval2cr(rval);
2779 		}
2780 		wusb_wa_free_trans_wrapper(wr);
2781 	}
2782 
2783 	/* In other cases, wr will be freed in callback */
2784 	return (rval);
2785 }
2786 
2787 /*
2788  * WA general bulk transfer
2789  *	- allocate bulk resources
2790  *	- submit the bulk request
2791  */
2792 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)2793 wusb_wa_bulk_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2794 	usba_pipe_handle_data_t *ph, usb_bulk_req_t *bulk_reqp,
2795 	usb_flags_t usb_flags)
2796 {
2797 	int			rval;
2798 	wusb_wa_trans_wrapper_t	*wr;
2799 
2800 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2801 	    "wusb_wa_bulk_xfer: ph = 0x%p reqp = 0x%p",
2802 	    (void *)ph, (void *)bulk_reqp);
2803 
2804 	wr = wusb_wa_alloc_bulk_resources(wa_data, hdl, ph, bulk_reqp,
2805 	    usb_flags);
2806 	if (wr == NULL) {
2807 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2808 		    "wusb_wa_bulk_xfer: alloc bulk resource failed");
2809 
2810 		return (USB_NO_RESOURCES);
2811 	}
2812 
2813 	rval = wusb_wa_submit_bulk_wr(wa_data, hdl, wr, bulk_reqp,
2814 	    usb_flags);
2815 	if (rval != USB_SUCCESS) {
2816 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2817 		    "wusb_wa_bulk_req: submit bulk req failed, rval = %d",
2818 		    rval);
2819 	}
2820 
2821 	return (rval);
2822 }
2823 
2824 /*
2825  * submit wr according to rpipe status
2826  *
2827  * usba only submits one transfer to the host controller per pipe at a time
2828  * and starts next when the previous one completed. So the hwahc now
2829  * assumes one transfer per rpipe at a time. This won't be necessary to
2830  * change unless the usba scheme is changed.
2831  */
2832 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)2833 wusb_wa_submit_intr_wr(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2834 	wusb_wa_trans_wrapper_t *wr, usb_intr_req_t *intr_reqp,
2835 	usb_flags_t usb_flags)
2836 {
2837 	int		rval;
2838 
2839 	mutex_enter(&hdl->rp_mutex);
2840 	switch (hdl->rp_state) {
2841 	case WA_RPIPE_STATE_IDLE:
2842 		rval = wusb_wa_wr_xfer(wa_data, hdl, wr, usb_flags);
2843 		break;
2844 	case WA_RPIPE_STATE_ACTIVE:
2845 		/* only allow one req at a time, this should not happen */
2846 	default:
2847 		rval = USB_PIPE_ERROR;
2848 		break;
2849 	}
2850 	mutex_exit(&hdl->rp_mutex);
2851 
2852 	if (rval != USB_SUCCESS) {
2853 		if (intr_reqp->intr_completion_reason == USB_CR_OK) {
2854 			intr_reqp->intr_completion_reason = usba_rval2cr(rval);
2855 		}
2856 		wusb_wa_free_trans_wrapper(wr);
2857 	}
2858 
2859 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2860 	    "wusb_wa_submit_intr_wr: submit intr req, rval = %d", rval);
2861 
2862 	/* In other cases, wr will be freed in callback */
2863 	return (rval);
2864 }
2865 
2866 /*
2867  * do intr xfer
2868  *
2869  * Now only one time intr transfer is supported. intr polling is not
2870  * supported.
2871  */
2872 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)2873 wusb_wa_intr_xfer(wusb_wa_data_t *wa_data, wusb_wa_rpipe_hdl_t *hdl,
2874 	usba_pipe_handle_data_t *ph, usb_intr_req_t *intr_reqp,
2875 	usb_flags_t usb_flags)
2876 {
2877 	int			rval;
2878 	wusb_wa_trans_wrapper_t	*wr;
2879 
2880 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2881 	    "wusb_wa_intr_xfer: ph = 0x%p reqp = 0x%p",
2882 	    (void *)ph, (void *)intr_reqp);
2883 
2884 	wr = wusb_wa_alloc_intr_resources(wa_data, hdl, ph, intr_reqp,
2885 	    usb_flags);
2886 	if (wr == NULL) {
2887 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2888 		    "wusb_wa_intr_req: alloc intr resource failed");
2889 
2890 		return (USB_NO_RESOURCES);
2891 	}
2892 
2893 	rval = wusb_wa_submit_intr_wr(wa_data, hdl, wr, intr_reqp,
2894 	    usb_flags);
2895 	if (rval != USB_SUCCESS) {
2896 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2897 		    "wusb_wa_intr_req: submit intr req failed, rval = %d",
2898 		    rval);
2899 
2900 		return (rval);
2901 	}
2902 
2903 	/*
2904 	 * have successfully duplicate and queue one more request on
2905 	 * the pipe. Increase the pipe request count.
2906 	 */
2907 	if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
2908 		mutex_enter(&ph->p_mutex);
2909 
2910 		/*
2911 		 * this count will be decremented by usba_req_normal_cb
2912 		 * or usba_req_exc_cb (called by hcdi_do_cb <-- usba_hcdi_cb)
2913 		 */
2914 		ph->p_req_count++;
2915 
2916 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2917 		    "wusb_wa_intr_req: p_req_cnt = %d", ph->p_req_count);
2918 
2919 		mutex_exit(&ph->p_mutex);
2920 	}
2921 
2922 	return (rval);
2923 }
2924 
2925 /*
2926  * For an IN transfer request, receive transfer data on bulk-in ept
2927  * The bulk_req has been allocated when allocating transfer resources
2928  */
2929 int
wusb_wa_get_data(wusb_wa_data_t * wa_data,wusb_wa_seg_t * seg,uint32_t len)2930 wusb_wa_get_data(wusb_wa_data_t *wa_data, wusb_wa_seg_t *seg, uint32_t len)
2931 {
2932 	usb_bulk_req_t		*req;
2933 	int			rval;
2934 
2935 	if (len == 0) {
2936 
2937 		return (USB_SUCCESS);
2938 	}
2939 
2940 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2941 	    "wusb_wa_get_data: get data for wr: 0x%p", (void *)seg->seg_wr);
2942 
2943 	req = seg->seg_data_reqp;
2944 	ASSERT(req != NULL);
2945 
2946 	/* adjust bulk in length to actual length */
2947 	req->bulk_len = len;
2948 	rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req,
2949 	    USB_FLAGS_SLEEP);
2950 
2951 	return (rval);
2952 }
2953 
2954 /*
2955  * to retrieve a transfer_wrapper by dwTransferID
2956  *
2957  * Though to search a list looks not so efficient, we have to give up
2958  * id32_lookup(). When a transfer segment is throwed to HWA device, we
2959  * can't anticipate when the result will be returned, even if we try to
2960  * abort it. If we have freed the transfer wrapper due to timeout, then
2961  * after a moment, that TW's segment is accomplished by hardware. If
2962  * id32_lookup() is used to look up corresponding TW, we'll get an invalid
2963  * address. Unfortunately, id32_lookup() can't judge validity of its
2964  * returned address.
2965  */
2966 wusb_wa_trans_wrapper_t *
wusb_wa_retrieve_wr(wusb_wa_data_t * wa_data,uint32_t id)2967 wusb_wa_retrieve_wr(wusb_wa_data_t *wa_data, uint32_t id)
2968 {
2969 	wusb_wa_rpipe_hdl_t *rph;
2970 	uint16_t	i;
2971 	wusb_wa_trans_wrapper_t *tw;
2972 
2973 	for (i = 0; i < wa_data->wa_num_rpipes; i++) {
2974 		rph = &wa_data->wa_rpipe_hdl[i];
2975 
2976 		mutex_enter(&rph->rp_mutex);
2977 		/* all outstanding TWs are put on the timeout list */
2978 		tw = rph->rp_timeout_list;
2979 
2980 		while (tw) {
2981 			if (tw->wr_id == id) {
2982 				mutex_exit(&rph->rp_mutex);
2983 				return (tw);
2984 			}
2985 			tw = tw->wr_timeout_next;
2986 		}
2987 		mutex_exit(&rph->rp_mutex);
2988 	}
2989 
2990 	return (NULL);
2991 }
2992 
2993 /* endlessly wait for transfer result on bulk-in ept and handle the result */
2994 int
wusb_wa_get_xfer_result(wusb_wa_data_t * wa_data)2995 wusb_wa_get_xfer_result(wusb_wa_data_t *wa_data)
2996 {
2997 	usb_bulk_req_t		*req;
2998 	int			rval;
2999 	mblk_t			*data;
3000 	uint8_t			*p;
3001 	wa_xfer_result_t	result;
3002 	wusb_wa_trans_wrapper_t	*wr;
3003 	wusb_wa_seg_t		*seg;
3004 	uint8_t			status;
3005 	uint_t			len;
3006 	uint8_t			lastseg = 0;
3007 	usb_cr_t		cr;
3008 	uint32_t		act_len;
3009 	wusb_wa_rpipe_hdl_t	*hdl;
3010 
3011 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3012 	    "wusb_wa_get_xfer_result: started, wa=0x%p", (void*)wa_data);
3013 
3014 	/* grab lock before accessing wa_data */
3015 	mutex_enter(&wa_data->wa_mutex);
3016 
3017 	len = wa_data->wa_bulkin_ept.wMaxPacketSize;
3018 
3019 	req = usb_alloc_bulk_req(wa_data->wa_dip, len,
3020 	    USB_FLAGS_NOSLEEP);
3021 	if (req == NULL) {
3022 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3023 		    "wusb_wa_get_xfer_result: alloc bulk req failed");
3024 
3025 		mutex_exit(&wa_data->wa_mutex);
3026 
3027 		return (USB_NO_RESOURCES);
3028 	}
3029 
3030 	req->bulk_len = len;
3031 	req->bulk_timeout = 0;
3032 	req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK |
3033 	    USB_ATTRS_AUTOCLEARING;
3034 
3035 	mutex_exit(&wa_data->wa_mutex);
3036 
3037 	/* Get the Transfer Result head, see Table 8-14 */
3038 	rval = usb_pipe_bulk_xfer(wa_data->wa_bulkin_ph, req,
3039 	    USB_FLAGS_SLEEP);
3040 	if ((rval != USB_SUCCESS) || (req->bulk_data == NULL)) {
3041 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3042 		    "wusb_wa_get_xfer_result: bulk xfer failed or "
3043 		    "null data returned, rval=%d, req->bulk_data = %p",
3044 		    rval, (void*)req->bulk_data);
3045 		usb_free_bulk_req(req);
3046 
3047 		return (rval);
3048 	}
3049 
3050 	data = req->bulk_data;
3051 	p = data->b_rptr;
3052 
3053 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3054 	    "wusb_wa_get_xfer_result: received data len = %d",
3055 	    (int)MBLKL(data));
3056 
3057 	if ((MBLKL(data) != WA_XFER_RESULT_LEN) ||
3058 	    (p[1] != WA_RESULT_TYPE_TRANSFER)) {
3059 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3060 		    "wusb_wa_get_xfer_result: invalid xfer result, "
3061 		    "len = %d, p0 = 0x%x, p1 = 0x%x, p6 = 0x%x",
3062 		    (int)MBLKL(data), p[0], p[1], p[6]);
3063 
3064 		usb_free_bulk_req(req);
3065 
3066 		return (USB_SUCCESS); /* don't stop this thread */
3067 	}
3068 
3069 	/* Transfer result. Section 8.3.3.4 */
3070 	(void) usb_parse_data("ccllccl", p, WA_XFER_RESULT_LEN, &result,
3071 	    sizeof (wa_xfer_result_t));
3072 
3073 
3074 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3075 	    "wusb_wa_get_xfer_result: id = 0x%x len = 0x%x nseg = 0x%02x"
3076 	    " status = 0x%02x(0x%02x)", result.dwTransferID,
3077 	    result.dwTransferLength, result.bTransferSegment,
3078 	    result.bTransferStatus, p[11]&0x0f);
3079 
3080 	req->bulk_data = NULL; /* don't free it. we still need it */
3081 	usb_free_bulk_req(req);
3082 
3083 	status = result.bTransferStatus;
3084 	if ((status & 0x3f) == WA_STS_NOT_FOUND) {
3085 		freemsg(data);
3086 		/*
3087 		 * The result is just ignored since the transfer request
3088 		 * has completed
3089 		 */
3090 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3091 		    "wusb_wa_get_xfer_result: TransferID not found");
3092 
3093 		return (USB_SUCCESS);
3094 	}
3095 
3096 	mutex_enter(&wa_data->wa_mutex);
3097 	wr = wusb_wa_retrieve_wr(wa_data, result.dwTransferID);
3098 	if ((wr == NULL)) {
3099 	/* this id's corresponding WR may have been freed by timeout handler */
3100 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3101 		    "wusb_wa_get_xfer_result: wr == deadbeef or NULL");
3102 
3103 		mutex_exit(&wa_data->wa_mutex);
3104 		freemsg(data);
3105 
3106 		return (USB_SUCCESS);
3107 	}
3108 
3109 	/* bit 7 is last segment flag */
3110 	if ((result.bTransferSegment & 0x7f) >= wr->wr_nsegs) {
3111 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3112 		    "wusb_wa_get_xfer_result: error - "
3113 		    " bTransferSegment(%d) > segment coutnts(%d)",
3114 		    (result.bTransferSegment & 0x7f), wr->wr_nsegs);
3115 
3116 		goto err;
3117 	}
3118 
3119 	lastseg = result.bTransferSegment & 0x80;
3120 	hdl = wr->wr_rp;
3121 
3122 	mutex_enter(&hdl->rp_mutex);
3123 	seg = &wr->wr_seg_array[result.bTransferSegment & 0x7f];
3124 	seg->seg_status = result.bTransferStatus;
3125 	act_len = seg->seg_actual_len = result.dwTransferLength;
3126 
3127 	/*
3128 	 * if this is the last segment, we should not continue.
3129 	 * IMPT: we expect the WA deliver result sequentially.
3130 	 */
3131 	seg->seg_done = (result.bTransferSegment) & 0x80;
3132 
3133 	wr->wr_seg_done++;
3134 	hdl->rp_avail_reqs++;
3135 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3136 	    "wusb_wa_get_xfer_result: wr = %p, rp=%p, avail_req=%d", (void*)wr,
3137 	    (void*)wr->wr_rp, hdl->rp_avail_reqs);
3138 
3139 	cv_broadcast(&hdl->rp_cv);
3140 
3141 	if (status & 0x40) {
3142 		status = 0; /* ignore warning, see Tab8-15 */
3143 	}
3144 	seg->seg_status = status;
3145 
3146 	/* Error bit set */
3147 	if (status & 0x80) {
3148 		/* don't change timeout error */
3149 		if (wr->wr_state != WR_TIMEOUT) {
3150 			wr->wr_state = WR_XFER_ERR;
3151 		}
3152 
3153 		/*
3154 		 * The timeout handler is waiting, but the result thread will
3155 		 * process this wr.
3156 		 */
3157 		if ((wr->wr_state == WR_TIMEOUT) &&
3158 		    (status & 0x3F) == WA_STS_ABORTED) {
3159 			wr->wr_has_aborted = 1;
3160 			cv_signal(&wr->wr_cv); /* to inform timeout hdler */
3161 		}
3162 
3163 		mutex_exit(&hdl->rp_mutex);
3164 		/* seg error, don't proceed with this WR */
3165 		goto err;
3166 	}
3167 
3168 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3169 	    "wusb_wa_get_xfer_result: status = 0x%02x dir=%s",
3170 	    status, (wr->wr_dir == WA_DIR_IN)?"IN":"OUT");
3171 
3172 	/*
3173 	 * for an IN endpoint and data length > 0 and no error, read in
3174 	 * the real data. Otherwise, for OUT EP, or data length = 0, or
3175 	 * segment error, don't read.
3176 	 */
3177 	if ((wr->wr_dir == WA_DIR_IN) &&
3178 	    (act_len > 0) &&
3179 	    ((status & 0x3F) == 0)) { /* if segment error, don't read */
3180 		/* receive data */
3181 		mutex_exit(&hdl->rp_mutex);
3182 		mutex_exit(&wa_data->wa_mutex);
3183 		rval = wusb_wa_get_data(wa_data, seg, act_len);
3184 		mutex_enter(&wa_data->wa_mutex);
3185 		mutex_enter(&hdl->rp_mutex);
3186 		if (rval != USB_SUCCESS) {
3187 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3188 			    "wusb_wa_get_xfer_result: can't get seg data:%d",
3189 			    rval);
3190 
3191 			mutex_exit(&hdl->rp_mutex);
3192 
3193 			goto err;
3194 		}
3195 
3196 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3197 		    "wusb_wa_get_xfer_result: get (%dB) data for IN ep",
3198 		    act_len);
3199 	}
3200 
3201 	mutex_exit(&hdl->rp_mutex);
3202 
3203 	mutex_exit(&wa_data->wa_mutex);
3204 
3205 	/* check if the whole transfer has completed */
3206 	wusb_wa_check_req_done(wa_data, wr, lastseg);
3207 
3208 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3209 	    "wusb_wa_get_xfer_result: ended");
3210 
3211 	freemsg(data);
3212 
3213 	return (USB_SUCCESS);
3214 
3215 err:
3216 	mutex_exit(&wa_data->wa_mutex);
3217 
3218 	mutex_enter(&hdl->rp_mutex);
3219 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3220 	    "wusb_wa_get_xfer_result: segment(%02x) error, abort wr 0x%p,"
3221 	    "wr_state=%d", result.bTransferSegment, (void*)wr, wr->wr_state);
3222 
3223 	/* if it's timeout, just return the TIMEOUT error */
3224 	if (wr->wr_state == WR_TIMEOUT) {
3225 		cr = USB_CR_TIMEOUT;
3226 	} else {
3227 		cr = wusb_wa_sts2cr(status);
3228 	}
3229 
3230 	mutex_exit(&hdl->rp_mutex);
3231 
3232 	wusb_wa_handle_error(wa_data, wr, cr);
3233 
3234 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3235 	    "wusb_wa_get_xfer_result: error end, cr=%d",
3236 	    cr);
3237 
3238 	freemsg(data);
3239 
3240 	return (USB_SUCCESS);
3241 }
3242 
3243 
3244 static void
wusb_wa_handle_error(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,usb_cr_t cr)3245 wusb_wa_handle_error(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3246     usb_cr_t cr)
3247 {
3248 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3249 	    "wusb_wa_handle_error: start");
3250 
3251 	mutex_enter(&wr->wr_rp->rp_mutex);
3252 	if (wr->wr_seg_done != wr->wr_curr_seg) {
3253 	/* still segments pending, abort them */
3254 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
3255 		    "wusb_wa_handle_error: segment err, abort other segs");
3256 
3257 		wusb_wa_abort_req(wa_data, wr, wr->wr_id);
3258 	}
3259 
3260 	wusb_wa_stop_xfer_timer(wr);
3261 	wr->wr_rp->rp_state = WA_RPIPE_STATE_IDLE;
3262 	wr->wr_rp->rp_curr_wr = NULL;
3263 	mutex_exit(&wr->wr_rp->rp_mutex);
3264 
3265 	wr->wr_cb(wa_data, wr, cr, 1);
3266 
3267 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3268 	    "wusb_wa_handle_error: error end, cr=%d",
3269 	    cr);
3270 }
3271 
3272 /*
3273  * Check if current request is done, if yes, do callback and move on to
3274  * next request; if there is any uncleared error, do callback to cleanup
3275  * the pipe
3276  */
3277 void
wusb_wa_check_req_done(wusb_wa_data_t * wa_data,wusb_wa_trans_wrapper_t * wr,uint8_t lastseg)3278 wusb_wa_check_req_done(wusb_wa_data_t *wa_data,
3279     wusb_wa_trans_wrapper_t *wr, uint8_t lastseg)
3280 {
3281 	wusb_wa_rpipe_hdl_t	*hdl = wr->wr_rp;
3282 	wusb_wa_seg_t		*seg;
3283 	int			i, rval;
3284 	usb_cr_t		cr;
3285 
3286 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3287 	    "wusb_wa_check_req_done: wr = 0x%p, lastseg=%02x",
3288 	    (void*)wr, lastseg);
3289 
3290 	mutex_enter(&hdl->rp_mutex);
3291 	/* not done: submitted segs not finished and lastseg not set */
3292 	if ((wr->wr_seg_done != wr->wr_curr_seg) && (!lastseg)) {
3293 		mutex_exit(&hdl->rp_mutex);
3294 
3295 		return;
3296 	}
3297 
3298 	if (wr->wr_state != 0) { /* abort somewhere */
3299 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3300 		    "wusb_wa_check_req_done: tw(%p) aborted somewhere",
3301 		    (void*)wr);
3302 		cr = USB_CR_UNSPECIFIED_ERR;
3303 
3304 		goto reset;
3305 	}
3306 
3307 	/* check if there is any error */
3308 	for (i = 0; i < wr->wr_curr_seg; i++) {
3309 		seg = &wr->wr_seg_array[i];
3310 		if (seg->seg_status != WA_STS_SUCCESS) {
3311 			/* what about short xfer? need to fix */
3312 			cr = wusb_wa_sts2cr(seg->seg_status);
3313 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3314 			    "wusb_wa_check_req_done: seg fail, status=%02x",
3315 			    seg->seg_status);
3316 
3317 			goto reset;
3318 		}
3319 
3320 		if (seg->seg_done == 0x80) {
3321 		/* device has told this is the last segment, we're done */
3322 			USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3323 			    "wusb_wa_check_req_done: last seg");
3324 
3325 			goto done;
3326 		}
3327 	}
3328 
3329 	/* check if current request has completed */
3330 	/*
3331 	 * Transfer another segment.
3332 	 *
3333 	 */
3334 	if (wr->wr_curr_seg < wr->wr_nsegs) {
3335 		/* send the remained segments */
3336 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3337 		    "wusb_wa_check_req_done: req not completed, restart");
3338 
3339 		rval = wusb_wa_wr_xfer(wa_data, hdl, wr, wr->wr_flags);
3340 		if (rval != USB_SUCCESS) {
3341 			cr = usba_rval2cr(rval);
3342 
3343 			goto reset;
3344 		}
3345 
3346 		mutex_exit(&hdl->rp_mutex);
3347 
3348 		return;
3349 	}
3350 
3351 done:
3352 	wusb_wa_stop_xfer_timer(wr);
3353 
3354 	/* release the occupied requests */
3355 	hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
3356 	cv_signal(&hdl->rp_cv);
3357 
3358 	hdl->rp_state = WA_RPIPE_STATE_IDLE;
3359 	hdl->rp_curr_wr = NULL;
3360 	wr->wr_state = WR_FINISHED;
3361 	mutex_exit(&hdl->rp_mutex);
3362 
3363 	wr->wr_cb(wa_data, wr, USB_CR_OK, 0);
3364 
3365 	/* Need to move on to next request? usba will do this */
3366 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3367 	    "wusb_wa_check_req_done: ended");
3368 
3369 	return;
3370 
3371 reset:
3372 	wusb_wa_stop_xfer_timer(wr);
3373 
3374 	/* not necessary to reset the RPipe */
3375 	hdl->rp_state = WA_RPIPE_STATE_IDLE;
3376 	hdl->rp_curr_wr = NULL;
3377 
3378 	hdl->rp_avail_reqs += (wr->wr_curr_seg - wr->wr_seg_done);
3379 	cv_signal(&hdl->rp_cv);
3380 
3381 	/* if it's timeout, just return the TIMEOUT error */
3382 	if (wr->wr_state == WR_TIMEOUT)
3383 		cr = USB_CR_TIMEOUT;
3384 
3385 	mutex_exit(&hdl->rp_mutex);
3386 
3387 	wr->wr_cb(wa_data, wr, cr, 1);
3388 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3389 	    "wusb_wa_check_req_done: reset end");
3390 }
3391 
3392 /*
3393  * callback for ctrl transfer
3394  *
3395  * reset_flag: not support yet
3396  */
3397 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)3398 wusb_wa_handle_ctrl(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3399 	usb_cr_t cr, uint_t reset_flag)
3400 {
3401 	usb_ctrl_req_t	*req;
3402 	usb_bulk_req_t	*bulk_req;
3403 	mblk_t		*data, *bulk_data;
3404 	int		i;
3405 	size_t		len;
3406 	wusb_wa_seg_t	*seg;
3407 
3408 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3409 	    "wusb_wa_handle_ctrl: wr = 0x%p, cr = 0x%x, flag=%d",
3410 	    (void*)wr, cr, reset_flag);
3411 
3412 	req = (usb_ctrl_req_t *)wr->wr_reqp;
3413 
3414 	if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
3415 
3416 		/* do callback */
3417 		wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3418 
3419 		return;
3420 	}
3421 
3422 	mutex_enter(&wr->wr_rp->rp_mutex);
3423 	data = req->ctrl_data;
3424 	for (i = 0; i < wr->wr_nsegs; i++) {
3425 		seg = &wr->wr_seg_array[i];
3426 		/* copy received data to original req buffer */
3427 		bulk_req = (usb_bulk_req_t *)
3428 		    wr->wr_seg_array[i].seg_data_reqp;
3429 		bulk_data = bulk_req->bulk_data;
3430 		len = MBLKL(bulk_data);
3431 		bcopy(bulk_data->b_rptr, data->b_wptr, len);
3432 		data->b_wptr += len;
3433 		if (len < wr->wr_seg_array[i].seg_len) {
3434 			/* short xfer */
3435 			break;
3436 		}
3437 
3438 		if (seg->seg_done == 0x80) {
3439 		/* last segment, finish */
3440 			break;
3441 		}
3442 	}
3443 
3444 	mutex_exit(&wr->wr_rp->rp_mutex);
3445 	/* do callback */
3446 	wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3447 }
3448 
3449 /*
3450  * callback for bulk transfer
3451  *
3452  * reset_flag: not support yet
3453  */
3454 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)3455 wusb_wa_handle_bulk(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3456 	usb_cr_t cr, uint_t reset_flag)
3457 {
3458 	usb_bulk_req_t	*req;
3459 	usb_bulk_req_t	*bulk_req;
3460 	mblk_t		*data, *bulk_data;
3461 	int		i;
3462 	size_t		len;
3463 	wusb_wa_seg_t	*seg;
3464 
3465 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3466 	    "wusb_wa_handle_bulk: wr = 0x%p, cr = 0x%x, flag=%d",
3467 	    (void*)wr, cr, reset_flag);
3468 
3469 	req = (usb_bulk_req_t *)wr->wr_reqp;
3470 
3471 	if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
3472 		/* do callback */
3473 		wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3474 
3475 		return;
3476 	}
3477 
3478 	mutex_enter(&wr->wr_rp->rp_mutex);
3479 	data = req->bulk_data;
3480 	for (i = 0; i < wr->wr_nsegs; i++) {
3481 		seg = &wr->wr_seg_array[i];
3482 		/* copy received data to original req buffer */
3483 		bulk_req = (usb_bulk_req_t *)
3484 		    wr->wr_seg_array[i].seg_data_reqp;
3485 		bulk_data = bulk_req->bulk_data;
3486 		len = MBLKL(bulk_data);
3487 		bcopy(bulk_data->b_rptr, data->b_wptr, len);
3488 		data->b_wptr += len;
3489 		if (len < wr->wr_seg_array[i].seg_len) {
3490 			/* short xfer */
3491 			break;
3492 		}
3493 
3494 		if (seg->seg_done == 0x80) {
3495 		/* last segment, finish */
3496 			break;
3497 		}
3498 	}
3499 
3500 	mutex_exit(&wr->wr_rp->rp_mutex);
3501 	/* do callback */
3502 	wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3503 }
3504 
3505 int
wa_submit_periodic_req(wusb_wa_data_t * wa_data,usba_pipe_handle_data_t * ph)3506 wa_submit_periodic_req(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph)
3507 {
3508 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3509 	    "wa_submit_periodic_req: wa_data=0x%p, ph=0x%p",
3510 	    (void*)wa_data, (void*)ph);
3511 
3512 	return (wa_data->pipe_periodic_req(wa_data, ph));
3513 }
3514 
3515 /*
3516  * callback for intr transfer
3517  *
3518  * reset_flag: not support yet
3519  */
3520 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)3521 wusb_wa_handle_intr(wusb_wa_data_t *wa_data, wusb_wa_trans_wrapper_t *wr,
3522 	usb_cr_t cr, uint_t reset_flag)
3523 {
3524 	usb_intr_req_t	*req;
3525 	usb_req_attrs_t	attrs;
3526 	usba_pipe_handle_data_t *ph = wr->wr_ph;
3527 	usb_bulk_req_t	*bulk_req;
3528 	mblk_t		*data, *bulk_data;
3529 	int		i;
3530 	size_t		len;
3531 	int		rval;
3532 	wusb_wa_seg_t	*seg;
3533 
3534 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3535 	    "wusb_wa_handle_intr: wr = 0x%p, cr = 0x%x, flag=%d",
3536 	    (void*)wr, cr, reset_flag);
3537 
3538 	req = (usb_intr_req_t *)wr->wr_reqp;
3539 	attrs = req->intr_attributes;
3540 
3541 	if ((wr->wr_dir == WA_DIR_OUT) || (cr != USB_CR_OK)) {
3542 		/* do callback */
3543 		wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3544 
3545 		return;
3546 	}
3547 
3548 	mutex_enter(&wr->wr_rp->rp_mutex);
3549 	/* copy data to client's buffer */
3550 	data = req->intr_data;
3551 	for (i = 0; i < wr->wr_nsegs; i++) {
3552 		seg = &wr->wr_seg_array[i];
3553 		/* copy received data to original req buffer */
3554 		bulk_req = (usb_bulk_req_t *)
3555 		    wr->wr_seg_array[i].seg_data_reqp;
3556 		bulk_data = bulk_req->bulk_data;
3557 		len = MBLKL(bulk_data);
3558 		bcopy(bulk_data->b_rptr, data->b_wptr, len);
3559 		data->b_wptr += len;
3560 		if (len < wr->wr_seg_array[i].seg_len) {
3561 			/* short xfer */
3562 			break;
3563 		}
3564 
3565 		if (seg->seg_done & 0x80) {
3566 
3567 			break;
3568 		}
3569 	}
3570 
3571 	if (attrs & USB_ATTRS_ONE_XFER) {
3572 	/* client requires ONE_XFER request, return */
3573 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3574 		    "wusb_wa_handle_intr: ONE_XFER set");
3575 
3576 		mutex_exit(&wr->wr_rp->rp_mutex);
3577 		goto finish;
3578 	}
3579 
3580 	/* polling mode */
3581 	mutex_exit(&wr->wr_rp->rp_mutex);
3582 	rval = wa_submit_periodic_req(wa_data, ph);
3583 	if (rval != USB_SUCCESS) {
3584 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3585 		    "wusb_wa_handle_intr: polling, fail to resubmit req");
3586 
3587 		goto finish;
3588 	}
3589 
3590 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3591 	    "wusb_wa_handle_intr: polling, resubmit request, rv=%d", rval);
3592 
3593 finish:
3594 	/* do callback */
3595 	wusb_wa_callback(wa_data, wr->wr_ph, wr, cr);
3596 
3597 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3598 	    "wusb_wa_handle_intr: end");
3599 }
3600 
3601 /*
3602  * free transfer wrapper
3603  * call host controller driver callback for completion handling
3604  *
3605  * This callback will call WA's specific callback function.
3606  * The callback functions should call usba_hcdi_cb() to pass request
3607  * back to client driver.
3608  */
3609 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)3610 wusb_wa_callback(wusb_wa_data_t *wa_data, usba_pipe_handle_data_t *ph,
3611     wusb_wa_trans_wrapper_t *wr, usb_cr_t cr)
3612 {
3613 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3614 	    "wusb_wa_callback: wr=0x%p, cr=0x%x, ph=0x%p, req = 0x%p",
3615 	    (void*)wr, cr, (void*)ph, (void*)((wr == NULL)?0:wr->wr_reqp));
3616 
3617 	if (cr == USB_CR_FLUSHED) {
3618 		/*
3619 		 * the wr is aborted. mark the rpipe as error,
3620 		 * so that the periodic xfer callbacks will not submit
3621 		 * further requests.
3622 		 */
3623 		mutex_enter(&wr->wr_rp->rp_mutex);
3624 		wr->wr_rp->rp_state = WA_RPIPE_STATE_ERROR;
3625 		mutex_exit(&wr->wr_rp->rp_mutex);
3626 	}
3627 
3628 	wa_data->rpipe_xfer_cb(wa_data->wa_dip, ph, wr, cr);
3629 
3630 	/*
3631 	 * need to consider carefully when to free wrapper
3632 	 * if the rpipe is reset, what to do with current wr in processing?
3633 	 */
3634 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
3635 	    "wusb_wa_callback: hwahc callback finish for wr= 0x%p, free it",
3636 	    (void*)wr);
3637 
3638 	wusb_wa_free_trans_wrapper(wr);
3639 }
3640 
3641 static struct {
3642 	uint8_t	status;
3643 	usb_cr_t	cr;
3644 } sts2cr[] = {
3645 	{WA_STS_SUCCESS,	USB_CR_OK},
3646 	{WA_STS_HALTED,		USB_CR_STALL},
3647 	{WA_STS_DATA_BUFFER_ERROR,	USB_CR_DATA_OVERRUN},
3648 	{WA_STS_BABBLE,		USB_CR_DATA_UNDERRUN},
3649 	{WA_STS_NOT_FOUND,	USB_CR_NOT_ACCESSED},
3650 	{WA_STS_INSUFFICIENT_RESOURCE,	USB_CR_NO_RESOURCES},
3651 	{0x80 | WA_STS_TRANSACTION_ERROR,	USB_CR_STALL},
3652 	{0x40 | WA_STS_TRANSACTION_ERROR,	USB_CR_OK},
3653 	{WA_STS_ABORTED,	USB_CR_FLUSHED},
3654 	{WA_STS_RPIPE_NOT_READY,	USB_CR_DEV_NOT_RESP},
3655 	{WA_STS_INVALID_REQ_FORMAT,	USB_CR_CRC},
3656 	{WA_STS_UNEXPECTED_SEGMENT_NUM,	USB_CR_UNEXP_PID},
3657 	{WA_STS_RPIPE_TYPE_MISMATCH,	USB_CR_NOT_SUPPORTED},
3658 	{WA_STS_PACKET_DISCARDED,	USB_CR_PID_CHECKFAILURE},
3659 	{0xff,		0}	/* end */
3660 };
3661 
3662 /* translate transfer status to USB completion reason */
3663 usb_cr_t
wusb_wa_sts2cr(uint8_t rawstatus)3664 wusb_wa_sts2cr(uint8_t rawstatus)
3665 {
3666 	int	i;
3667 	uint8_t	status;
3668 
3669 	/* cares about bits5:0 in WUSB 1.0 */
3670 	if ((rawstatus & 0x1f) == WA_STS_TRANSACTION_ERROR) {
3671 		status = rawstatus;
3672 	} else {
3673 		status = rawstatus & 0x1f;
3674 	}
3675 
3676 	for (i = 0; sts2cr[i].status != 0xff; i++) {
3677 		if (sts2cr[i].status == status) {
3678 
3679 			return (sts2cr[i].cr);
3680 		}
3681 	}
3682 
3683 	return (USB_CR_UNSPECIFIED_ERR);
3684 }
3685