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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * EHCI Host Controller Driver (EHCI)
31  *
32  * The EHCI driver is a software driver which interfaces to the Universal
33  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
34  * the Host Controller is defined by the EHCI Host Controller Interface.
35  *
36  * This module contains the EHCI driver isochronous code, which handles all
37  * Checking of status of USB transfers, error recovery and callbacks.
38  */
39 #include <sys/usb/hcd/ehci/ehcid.h>
40 #include <sys/usb/hcd/ehci/ehci_xfer.h>
41 #include <sys/usb/hcd/ehci/ehci_util.h>
42 #include <sys/usb/hcd/ehci/ehci_isoch.h>
43 #include <sys/usb/hcd/ehci/ehci_isoch_util.h>
44 
45 /*
46  * Isochronous initialization functions
47  */
48 int ehci_isoc_init(
49 	ehci_state_t		*ehcip);
50 void ehci_isoc_cleanup(
51 	ehci_state_t		*ehcip);
52 void ehci_isoc_pipe_cleanup(
53 	ehci_state_t		*ehcip,
54 	usba_pipe_handle_data_t *ph);
55 static void ehci_wait_for_isoc_completion(
56 	ehci_state_t		*ehcip,
57 	ehci_pipe_private_t	*pp);
58 
59 /*
60  * Isochronous request functions
61  */
62 ehci_isoc_xwrapper_t *ehci_allocate_isoc_resources(
63 	ehci_state_t		*ehcip,
64 	usba_pipe_handle_data_t *ph,
65 	usb_isoc_req_t		*isoc_reqp,
66 	usb_flags_t		usb_flags);
67 int ehci_insert_isoc_req(
68 	ehci_state_t		*ehcip,
69 	ehci_pipe_private_t	*pp,
70 	ehci_isoc_xwrapper_t	*itw,
71 	usb_flags_t		usb_flags);
72 static int ehci_insert_sitd_req(
73 	ehci_state_t		*ehcip,
74 	ehci_pipe_private_t	*pp,
75 	ehci_isoc_xwrapper_t	*itw,
76 	usb_flags_t		usb_flags);
77 static int ehci_insert_isoc_with_frame_number(
78 	ehci_state_t		*ehcip,
79 	ehci_pipe_private_t	*pp,
80 	ehci_isoc_xwrapper_t	*itw,
81 	ehci_itd_t		*current_sitd);
82 static void ehci_remove_isoc_itds(
83 	ehci_state_t		*ehcip,
84 	ehci_pipe_private_t	*pp);
85 static void ehci_mark_reclaim_isoc(
86 	ehci_state_t		*ehcip,
87 	ehci_pipe_private_t	*pp);
88 static void ehci_reclaim_isoc(
89 	ehci_state_t		*ehcip,
90 	ehci_isoc_xwrapper_t	*itw,
91 	ehci_itd_t		*itd,
92 	ehci_pipe_private_t	*pp);
93 int	ehci_start_isoc_polling(
94 	ehci_state_t		*ehcip,
95 	usba_pipe_handle_data_t	*ph,
96 	usb_flags_t		flags);
97 
98 /*
99  * Isochronronous handling functions.
100  */
101 void ehci_traverse_active_isoc_list(
102 	ehci_state_t		*ehcip);
103 static void ehci_handle_isoc(
104 	ehci_state_t		*ehcip,
105 	ehci_isoc_xwrapper_t	*itw,
106 	ehci_itd_t		*itd);
107 static void ehci_handle_itd(
108 	ehci_state_t		*ehcip,
109 	ehci_pipe_private_t	*pp,
110 	ehci_isoc_xwrapper_t	*itw,
111 	ehci_itd_t		*itd,
112 	void			*tw_handle_callback_value);
113 static void ehci_handle_sitd(
114 	ehci_state_t		*ehcip,
115 	ehci_pipe_private_t	*pp,
116 	ehci_isoc_xwrapper_t	*itw,
117 	ehci_itd_t		*itd,
118 	void			*tw_handle_callback_value);
119 static void ehci_sendup_itd_message(
120 	ehci_state_t		*ehcip,
121 	ehci_pipe_private_t	*pp,
122 	ehci_isoc_xwrapper_t	*itw,
123 	ehci_itd_t		*td,
124 	usb_cr_t		error);
125 void ehci_hcdi_isoc_callback(
126 	usba_pipe_handle_data_t	*ph,
127 	ehci_isoc_xwrapper_t	*itw,
128 	usb_cr_t		completion_reason);
129 
130 
131 /*
132  * Isochronous initialization functions
133  */
134 /*
135  * Initialize all the needed resources needed by isochronous pipes.
136  */
137 int
138 ehci_isoc_init(
139 	ehci_state_t		*ehcip)
140 {
141 	return (ehci_allocate_isoc_pools(ehcip));
142 }
143 
144 
145 /*
146  * Cleanup isochronous resources.
147  */
148 void
149 ehci_isoc_cleanup(
150 	ehci_state_t		*ehcip)
151 {
152 	ehci_isoc_xwrapper_t	*itw;
153 	ehci_pipe_private_t	*pp;
154 	ehci_itd_t		*itd;
155 	int			i, ctrl, rval;
156 
157 	/* Free all the buffers */
158 	if (ehcip->ehci_itd_pool_addr && ehcip->ehci_itd_pool_mem_handle) {
159 		for (i = 0; i < ehci_get_itd_pool_size(); i ++) {
160 			itd = &ehcip->ehci_itd_pool_addr[i];
161 			ctrl = Get_ITD(ehcip->
162 			    ehci_itd_pool_addr[i].itd_state);
163 
164 			if ((ctrl != EHCI_ITD_FREE) &&
165 			    (ctrl != EHCI_ITD_DUMMY) &&
166 			    (itd->itd_trans_wrapper)) {
167 
168 				mutex_enter(&ehcip->ehci_int_mutex);
169 
170 				itw = (ehci_isoc_xwrapper_t *)
171 					EHCI_LOOKUP_ID((uint32_t)
172 					Get_ITD(itd->itd_trans_wrapper));
173 
174 				/* Obtain the pipe private structure */
175 				pp = itw->itw_pipe_private;
176 
177 				ehci_deallocate_itd(ehcip, itw, itd);
178 				ehci_deallocate_itw(ehcip, pp, itw);
179 
180 				mutex_exit(&ehcip->ehci_int_mutex);
181 			}
182 		}
183 
184 		/*
185 		 * If EHCI_ITD_POOL_BOUND flag is set, then unbind
186 		 * the handle for ITD pools.
187 		 */
188 		if ((ehcip->ehci_dma_addr_bind_flag &
189 		    EHCI_ITD_POOL_BOUND) == EHCI_ITD_POOL_BOUND) {
190 
191 			rval = ddi_dma_unbind_handle(
192 			    ehcip->ehci_itd_pool_dma_handle);
193 
194 			ASSERT(rval == DDI_SUCCESS);
195 		}
196 		ddi_dma_mem_free(&ehcip->ehci_itd_pool_mem_handle);
197 	}
198 
199 	/* Free the ITD pool */
200 	if (ehcip->ehci_itd_pool_dma_handle) {
201 		ddi_dma_free_handle(&ehcip->ehci_itd_pool_dma_handle);
202 	}
203 }
204 
205 
206 /*
207  * ehci_isoc_pipe_cleanup
208  *
209  * Cleanup ehci isoc pipes.
210  */
211 void ehci_isoc_pipe_cleanup(
212 	ehci_state_t		*ehcip,
213 	usba_pipe_handle_data_t *ph) {
214 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
215 	uint_t			pipe_state = pp->pp_state;
216 	usb_cr_t		completion_reason;
217 
218 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
219 	    "ehci_isoc_pipe_cleanup: ph = 0x%p", (void *)ph);
220 
221 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
222 
223 	/* Stop all further processing */
224 	ehci_mark_reclaim_isoc(ehcip, pp);
225 
226 	/*
227 	 * Wait for processing all completed transfers
228 	 * and send result upstream/
229 	 */
230 	ehci_wait_for_isoc_completion(ehcip, pp);
231 
232 	/* Go ahead and remove all remaining itds if there are any */
233 	ehci_remove_isoc_itds(ehcip, pp);
234 
235 	switch (pipe_state) {
236 	case EHCI_PIPE_STATE_CLOSE:
237 		completion_reason = USB_CR_PIPE_CLOSING;
238 		break;
239 	case EHCI_PIPE_STATE_RESET:
240 	case EHCI_PIPE_STATE_STOP_POLLING:
241 		/* Set completion reason */
242 		completion_reason = (pipe_state ==
243 		    EHCI_PIPE_STATE_RESET) ?
244 		    USB_CR_PIPE_RESET: USB_CR_STOPPED_POLLING;
245 
246 		/* Set pipe state to idle */
247 		pp->pp_state = EHCI_PIPE_STATE_IDLE;
248 
249 		break;
250 	}
251 
252 	/*
253 	 * Do the callback for the original client
254 	 * periodic IN request.
255 	 */
256 	if ((ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK) ==
257 	    USB_EP_DIR_IN) {
258 
259 		ehci_do_client_periodic_in_req_callback(
260 		    ehcip, pp, completion_reason);
261 	}
262 }
263 
264 
265 /*
266  * ehci_wait_for_transfers_completion:
267  *
268  * Wait for processing all completed transfers and to send results
269  * to upstream.
270  */
271 static void
272 ehci_wait_for_isoc_completion(
273 	ehci_state_t		*ehcip,
274 	ehci_pipe_private_t	*pp)
275 {
276 	clock_t			xfer_cmpl_time_wait;
277 
278 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
279 
280 	if (pp->pp_itw_head == NULL) {
281 
282 		return;
283 	}
284 
285 	/* Get the number of clock ticks to wait */
286 	xfer_cmpl_time_wait = drv_usectohz(EHCI_XFER_CMPL_TIMEWAIT * 1000000);
287 
288 	(void) cv_timedwait(&pp->pp_xfer_cmpl_cv,
289 	    &ehcip->ehci_int_mutex,
290 	    ddi_get_lbolt() + xfer_cmpl_time_wait);
291 
292 	if (pp->pp_itw_head) {
293 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
294 		    "ehci_wait_for_isoc_completion: "
295 		    "No transfers completion confirmation received");
296 	}
297 }
298 
299 
300 /*
301  *  Isochronous request functions
302  */
303 /*
304  * ehci_allocate_isoc_resources:
305  *
306  * Calculates the number of tds necessary for a isoch transfer, and
307  * allocates all the necessary resources.
308  *
309  * Returns NULL if there is insufficient resources otherwise ITW.
310  */
311 ehci_isoc_xwrapper_t *
312 ehci_allocate_isoc_resources(
313 	ehci_state_t		*ehcip,
314 	usba_pipe_handle_data_t *ph,
315 	usb_isoc_req_t		*isoc_reqp,
316 	usb_flags_t		usb_flags)
317 {
318 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
319 	int			pipe_dir;
320 	uint_t			max_ep_pkt_size, max_isoc_xfer_size;
321 	usb_isoc_pkt_descr_t	*isoc_pkt_descr;
322 	size_t			isoc_pkt_count, isoc_pkt_length;
323 	size_t 			itw_xfer_size;
324 	ehci_isoc_xwrapper_t	*itw;
325 
326 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
327 	    "ehci_allocate_isoc_resources: flags = 0x%x", usb_flags);
328 
329 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
330 
331 	/*
332 	 * Check whether pipe is in halted state.
333 	 */
334 	if (pp->pp_state == EHCI_PIPE_STATE_ERROR) {
335 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
336 		    "ehci_allocate_isoc_resources:"
337 		    "Pipe is in error state, need pipe reset to continue");
338 
339 		return (NULL);
340 	}
341 
342 	/* Calculate the maximum isochronous transfer size we allow */
343 	max_ep_pkt_size = ph->p_ep.wMaxPacketSize;
344 	max_isoc_xfer_size = EHCI_MAX_ISOC_PKTS_PER_XFER * max_ep_pkt_size;
345 
346 	/* Get the packet descriptor and number of packets to send */
347 	if (isoc_reqp) {
348 		isoc_pkt_descr = isoc_reqp->isoc_pkt_descr;
349 		isoc_pkt_count = isoc_reqp->isoc_pkts_count;
350 		isoc_pkt_length = isoc_reqp->isoc_pkts_length;
351 	} else {
352 		isoc_pkt_descr = ((usb_isoc_req_t *)
353 		    pp->pp_client_periodic_in_reqp)->isoc_pkt_descr;
354 
355 		isoc_pkt_count = ((usb_isoc_req_t *)
356 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_count;
357 		isoc_pkt_length = ((usb_isoc_req_t *)
358 		    pp->pp_client_periodic_in_reqp)->isoc_pkts_length;
359 	}
360 
361 	/* Calculate the size of the transfer. */
362 	pipe_dir = ph->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
363 	if (pipe_dir == USB_EP_DIR_IN) {
364 		itw_xfer_size = isoc_pkt_count * isoc_pkt_length;
365 		isoc_pkt_descr += isoc_pkt_count;
366 	} else {
367 		ASSERT(isoc_reqp != NULL);
368 		itw_xfer_size = isoc_reqp->isoc_data->b_wptr -
369 		    isoc_reqp->isoc_data->b_rptr;
370 	}
371 
372 	/* Check the size of isochronous request */
373 	if (itw_xfer_size > max_isoc_xfer_size) {
374 
375 		USB_DPRINTF_L2(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
376 		    "ehci_allocate_isoc_resources: Maximum isoc request"
377 		    "size 0x%x Given isoc request size 0x%x",
378 		    max_isoc_xfer_size, itw_xfer_size);
379 
380 		return (NULL);
381 	}
382 
383 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
384 	    "ehci_allocate_isoc_resources: length = 0x%x", itw_xfer_size);
385 
386 	/* Allocate the itw for this request */
387 	if ((itw = ehci_allocate_itw_resources(ehcip, pp, itw_xfer_size,
388 	    usb_flags, isoc_pkt_count)) == NULL) {
389 
390 		return (NULL);
391 	}
392 
393 	itw->itw_handle_callback_value = NULL;
394 
395 	if (pipe_dir == USB_EP_DIR_IN) {
396 		if (ehci_allocate_isoc_in_resource(ehcip, pp, itw, usb_flags) !=
397 		    USB_SUCCESS) {
398 
399 			ehci_deallocate_itw(ehcip, pp, itw);
400 
401 			return (NULL);
402 		}
403 	} else {
404 		if (itw->itw_length) {
405 			ASSERT(isoc_reqp->isoc_data != NULL);
406 
407 			/* Copy the data into the buffer */
408 			bcopy(isoc_reqp->isoc_data->b_rptr,
409 			    itw->itw_buf, itw->itw_length);
410 
411 			Sync_IO_Buffer_for_device(itw->itw_dmahandle,
412 			    itw->itw_length);
413 		}
414 		itw->itw_curr_xfer_reqp = isoc_reqp;
415 	}
416 
417 	return (itw);
418 }
419 
420 
421 /*
422  * ehci_insert_isoc_req:
423  *
424  * Insert an isochronous request into the Host Controller's
425  * isochronous list.
426  */
427 int
428 ehci_insert_isoc_req(
429 	ehci_state_t			*ehcip,
430 	ehci_pipe_private_t		*pp,
431 	ehci_isoc_xwrapper_t		*itw,
432 	usb_flags_t			usb_flags)
433 {
434 	int			error;
435 
436 	USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
437 	    "ehci_insert_isoc_req: flags = 0x%x port status = 0x%x",
438 	    usb_flags, itw->itw_port_status);
439 
440 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
441 
442 	ASSERT(itw->itw_curr_xfer_reqp != NULL);
443 	ASSERT(itw->itw_curr_xfer_reqp->isoc_pkt_descr != NULL);
444 
445 	/*
446 	 * Save address of first usb isochronous packet descriptor.
447 	 */
448 	itw->itw_curr_isoc_pktp = itw->itw_curr_xfer_reqp->isoc_pkt_descr;
449 
450 	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
451 		error = USB_NOT_SUPPORTED;
452 	} else {
453 		error = ehci_insert_sitd_req(ehcip, pp, itw, usb_flags);
454 	}
455 
456 	return (error);
457 }
458 
459 
460 /*
461  * ehci_insert_sitd_req:
462  *
463  * Insert an SITD request into the Host Controller's isochronous list.
464  */
465 /* ARGSUSED */
466 static int
467 ehci_insert_sitd_req(
468 	ehci_state_t		*ehcip,
469 	ehci_pipe_private_t	*pp,
470 	ehci_isoc_xwrapper_t	*itw,
471 	usb_flags_t		usb_flags)
472 {
473 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
474 	usb_isoc_req_t		*curr_isoc_reqp;
475 	usb_isoc_pkt_descr_t	*curr_isoc_pkt_descr;
476 	size_t			curr_isoc_xfer_offset;
477 	size_t			isoc_pkt_length;
478 	uint_t			count, error;
479 	uint32_t		ctrl, uframe_sched, xfer_state;
480 	uint32_t		page0, page1, prev_sitd;
481 	uint32_t		ssplit_count;
482 	ehci_itd_t		*new_sitd, *temp_sitd;
483 
484 	/*
485 	 * Get the current isochronous request and packet
486 	 * descriptor pointers.
487 	 */
488 	curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
489 
490 	/* Set the ctrl field */
491 	ctrl = 0;
492 	if (itw->itw_direction == USB_EP_DIR_IN) {
493 		ctrl |= EHCI_SITD_CTRL_DIR_IN;
494 	} else {
495 		ctrl |= EHCI_SITD_CTRL_DIR_OUT;
496 	}
497 
498 	ctrl |= (itw->itw_hub_port << EHCI_SITD_CTRL_PORT_SHIFT) &
499 	    EHCI_SITD_CTRL_PORT_MASK;
500 	ctrl |= (itw->itw_hub_addr << EHCI_SITD_CTRL_HUB_SHIFT) &
501 	    EHCI_SITD_CTRL_HUB_MASK;
502 	ctrl |= (itw->itw_endpoint_num << EHCI_SITD_CTRL_END_PT_SHIFT) &
503 	    EHCI_SITD_CTRL_END_PT_MASK;
504 	ctrl |= (itw->itw_device_addr << EHCI_SITD_CTRL_DEVICE_SHIFT) &
505 	    EHCI_SITD_CTRL_DEVICE_MASK;
506 
507 	/* Set the micro frame schedule */
508 	uframe_sched = 0;
509 	uframe_sched |= (pp->pp_smask << EHCI_SITD_UFRAME_SMASK_SHIFT) &
510 	    EHCI_SITD_UFRAME_SMASK_MASK;
511 	uframe_sched |= (pp->pp_cmask << EHCI_SITD_UFRAME_CMASK_SHIFT) &
512 	    EHCI_SITD_UFRAME_CMASK_MASK;
513 
514 	/* Set the default page information */
515 	page0 = itw->itw_cookie.dmac_address;
516 	page1 = 0;
517 
518 	prev_sitd = EHCI_ITD_LINK_PTR_INVALID;
519 
520 	/*
521 	 * Save the number of isochronous TDs needs
522 	 * to be insert to complete current isochronous request.
523 	 */
524 	itw->itw_num_itds = curr_isoc_reqp->isoc_pkts_count;
525 
526 	/* Insert all the isochronous TDs */
527 	for (count = 0, curr_isoc_xfer_offset = 0;
528 		count < itw->itw_num_itds; count++) {
529 
530 		curr_isoc_pkt_descr = itw->itw_curr_isoc_pktp;
531 
532 		isoc_pkt_length = curr_isoc_pkt_descr->isoc_pkt_length;
533 		curr_isoc_pkt_descr->isoc_pkt_actual_length = isoc_pkt_length;
534 
535 		/* Set the transfer state information */
536 		xfer_state = 0;
537 
538 		if (itw->itw_direction == USB_EP_DIR_IN) {
539 			/* Set the size to the max packet size */
540 			xfer_state |= (ph->p_ep.wMaxPacketSize <<
541 			    EHCI_SITD_XFER_TOTAL_SHIFT) &
542 			    EHCI_SITD_XFER_TOTAL_MASK;
543 		} else {
544 			/* Set the size to the packet length */
545 			xfer_state |= (isoc_pkt_length <<
546 			    EHCI_SITD_XFER_TOTAL_SHIFT) &
547 			    EHCI_SITD_XFER_TOTAL_MASK;
548 		}
549 		xfer_state |=  EHCI_SITD_XFER_ACTIVE;
550 
551 		/* Set IOC on the last TD. */
552 		if (count == (itw->itw_num_itds - 1)) {
553 			xfer_state |= EHCI_SITD_XFER_IOC_ON;
554 		}
555 
556 		ssplit_count = isoc_pkt_length / MAX_UFRAME_SITD_XFER;
557 		if (isoc_pkt_length % MAX_UFRAME_SITD_XFER) {
558 			ssplit_count++;
559 		}
560 
561 		page1 = (ssplit_count & EHCI_SITD_XFER_TCOUNT_MASK) <<
562 		    EHCI_SITD_XFER_TCOUNT_SHIFT;
563 		if (ssplit_count > 1) {
564 			page1 |= EHCI_SITD_XFER_TP_BEGIN;
565 		} else {
566 			page1 |= EHCI_SITD_XFER_TP_ALL;
567 		}
568 
569 		/* Grab a new sitd */
570 		new_sitd = itw->itw_itd_free_list;
571 
572 		ASSERT(new_sitd != NULL);
573 
574 		itw->itw_itd_free_list = ehci_itd_iommu_to_cpu(ehcip,
575 		    Get_ITD(new_sitd->itd_link_ptr));
576 		Set_ITD(new_sitd->itd_link_ptr, NULL);
577 
578 		/* Fill in the new sitd */
579 		Set_ITD_BODY(new_sitd, EHCI_SITD_CTRL, ctrl);
580 		Set_ITD_BODY(new_sitd, EHCI_SITD_UFRAME_SCHED, uframe_sched);
581 		Set_ITD_BODY(new_sitd, EHCI_SITD_XFER_STATE, xfer_state);
582 		Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER0,
583 		    page0 + curr_isoc_xfer_offset);
584 		Set_ITD_BODY(new_sitd, EHCI_SITD_BUFFER1, page1);
585 		Set_ITD_BODY(new_sitd, EHCI_SITD_PREV_SITD, prev_sitd);
586 
587 		Set_ITD(new_sitd->itd_state, EHCI_ITD_ACTIVE);
588 
589 		/*
590 		 * Add this itd to the itw before we add it in the PFL
591 		 * If adding it to the PFL fails, we will have to cleanup.
592 		 */
593 		ehci_insert_itd_on_itw(ehcip, itw, new_sitd);
594 
595 		itw->itw_curr_isoc_pktp++;
596 		curr_isoc_xfer_offset += isoc_pkt_length;
597 	}
598 
599 	/* Either all the isocs will be added or none of them will */
600 	error = ehci_insert_isoc_to_pfl(ehcip, pp, itw);
601 
602 	if (error != USB_SUCCESS) {
603 		/*
604 		 * Deallocate all the ITDs, otherwise they will be
605 		 * lost forever.
606 		 */
607 		new_sitd = itw->itw_itd_head;
608 		while (new_sitd) {
609 			temp_sitd = ehci_itd_iommu_to_cpu(ehcip,
610 			    Get_ITD(new_sitd->itd_itw_next_itd));
611 			ehci_deallocate_itd(ehcip, itw, new_sitd);
612 			new_sitd = temp_sitd;
613 		}
614 		if ((itw->itw_direction == USB_EP_DIR_IN)) {
615 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
616 
617 			if (pp->pp_cur_periodic_req_cnt) {
618 				/*
619 				 * Set pipe state to stop polling and
620 				 * error to no resource. Don't insert
621 				 * any more isoch polling requests.
622 				 */
623 				pp->pp_state =
624 				    EHCI_PIPE_STATE_STOP_POLLING;
625 				pp->pp_error = error;
626 			} else {
627 				/* Set periodic in pipe state to idle */
628 				pp->pp_state = EHCI_PIPE_STATE_IDLE;
629 			}
630 
631 			return (error);
632 		}
633 
634 		/* Save how many packets and data actually went */
635 		itw->itw_num_itds = 0;
636 		itw->itw_length  = 0;
637 	}
638 
639 	/*
640 	 * Reset back to the address of first usb isochronous
641 	 * packet descriptor.
642 	 */
643 	itw->itw_curr_isoc_pktp = curr_isoc_reqp->isoc_pkt_descr;
644 
645 	/* Reset the CONTINUE flag */
646 	pp->pp_flag &= ~EHCI_ISOC_XFER_CONTINUE;
647 
648 	return (USB_SUCCESS);
649 }
650 
651 
652 /*
653  * ehci_remove_isoc_itds:
654  *
655  * Remove all itds from the PFL.
656  */
657 static void
658 ehci_remove_isoc_itds(
659 	ehci_state_t		*ehcip,
660 	ehci_pipe_private_t	*pp)
661 {
662 	ehci_isoc_xwrapper_t	*curr_itw, *next_itw;
663 	ehci_itd_t		*curr_itd, *next_itd;
664 
665 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
666 	    "ehci_remove_isoc_itds: pp = 0x%p", pp);
667 
668 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
669 
670 	curr_itw = pp->pp_itw_head;
671 	while (curr_itw) {
672 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
673 		    "ehci_remove_isoc_itds: itw = 0x%p num itds = %d",
674 		    curr_itw, curr_itw->itw_num_itds);
675 
676 		next_itw = curr_itw->itw_next;
677 
678 		curr_itd = curr_itw->itw_itd_head;
679 		while (curr_itd) {
680 			next_itd = ehci_itd_iommu_to_cpu(ehcip,
681 			    Get_ITD(curr_itd->itd_itw_next_itd));
682 
683 			ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
684 
685 			curr_itd = next_itd;
686 		}
687 
688 		ehci_deallocate_itw(ehcip, pp, curr_itw);
689 
690 		curr_itw = next_itw;
691 	}
692 }
693 
694 
695 /*
696  * ehci_mark_reclaim_isoc:
697  *
698  * Set active ITDs to RECLAIM.
699  * Return number of ITD that need to be processed.
700  */
701 static void
702 ehci_mark_reclaim_isoc(
703 	ehci_state_t		*ehcip,
704 	ehci_pipe_private_t	*pp)
705 {
706 	usb_frame_number_t	current_frame_number;
707 	ehci_isoc_xwrapper_t	*curr_itw, *next_itw;
708 	ehci_itd_t		*curr_itd, *next_itd;
709 	uint_t			ctrl;
710 	uint_t			isActive;
711 
712 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
713 	    "ehci_mark_reclaim_isoc: pp = 0x%p", pp);
714 
715 	if (pp->pp_itw_head == NULL) {
716 
717 		return;
718 	}
719 
720 	/* Get the current frame number. */
721 	current_frame_number = ehci_get_current_frame_number(ehcip);
722 
723 	/* Traverse the list of transfer descriptors */
724 	curr_itw = pp->pp_itw_head;
725 	while (curr_itw) {
726 		next_itw = curr_itw->itw_next;
727 
728 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
729 		    "ehci_mark_reclaim_isoc: itw = 0x%p num itds = %d",
730 		    curr_itw, curr_itw->itw_num_itds);
731 
732 		curr_itd = curr_itw->itw_itd_head;
733 		while (curr_itd) {
734 			next_itd = ehci_itd_iommu_to_cpu(ehcip,
735 			    Get_ITD(curr_itd->itd_itw_next_itd));
736 
737 			if (curr_itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
738 
739 				/* For future use */
740 				return;
741 			} else {
742 				ctrl = Get_ITD_BODY(curr_itd,
743 				    EHCI_SITD_XFER_STATE);
744 				isActive = ctrl & EHCI_SITD_XFER_ACTIVE;
745 				/* If it is still active deactive it */
746 				if (isActive) {
747 					ctrl &= ~EHCI_SITD_XFER_ACTIVE;
748 					Set_ITD_BODY(curr_itd,
749 					    EHCI_SITD_XFER_STATE,
750 					    ctrl);
751 				}
752 			}
753 
754 			/*
755 			 * If the itd was active put it on the reclaim status,
756 			 * so the interrupt handler will know not to process it.
757 			 * Otherwise leave it alone and let the interrupt
758 			 * handler process it normally.
759 			 */
760 			if (isActive) {
761 				Set_ITD(curr_itd->itd_state, EHCI_ITD_RECLAIM);
762 				Set_ITD_FRAME(curr_itd->itd_reclaim_number,
763 				    current_frame_number);
764 				ehci_remove_isoc_from_pfl(ehcip, curr_itd);
765 			}
766 			curr_itd = next_itd;
767 		}
768 		curr_itw = next_itw;
769 	}
770 }
771 
772 
773 /*
774  * ehci_reclaim_isoc:
775  *
776  * "Reclaim" itds that were marked as RECLAIM.
777  */
778 static void
779 ehci_reclaim_isoc(
780 	ehci_state_t		*ehcip,
781 	ehci_isoc_xwrapper_t	*itw,
782 	ehci_itd_t		*itd,
783 	ehci_pipe_private_t	*pp)
784 {
785 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
786 	    "ehci_reclaim_isoc: itd = 0x%p", itd);
787 
788 	/*
789 	 * These are itds that were marked "RECLAIM"
790 	 * by the pipe cleanup.
791 	 *
792 	 * Decrement the num_itds and the periodic in
793 	 * request count if necessary.
794 	 */
795 	if ((--itw->itw_num_itds == 0) && (itw->itw_curr_xfer_reqp)) {
796 		if (itw->itw_direction == USB_EP_DIR_IN) {
797 
798 			pp->pp_cur_periodic_req_cnt--;
799 
800 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
801 		} else {
802 			ehci_hcdi_isoc_callback(pp->pp_pipe_handle, itw,
803 			    USB_CR_FLUSHED);
804 		}
805 	}
806 
807 	/* Deallocate this transfer descriptor */
808 	ehci_deallocate_itd(ehcip, itw, itd);
809 }
810 
811 
812 /*
813  * ehci_start_isoc_polling:
814  *
815  * Insert the number of periodic requests corresponding to polling
816  * interval as calculated during pipe open.
817  */
818 int
819 ehci_start_isoc_polling(
820 	ehci_state_t		*ehcip,
821 	usba_pipe_handle_data_t	*ph,
822 	usb_flags_t		flags)
823 {
824 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
825 	ehci_isoc_xwrapper_t	*itw_list, *itw;
826 	int			i, total_itws;
827 	int			error = USB_SUCCESS;
828 
829 	/* Allocate all the necessary resources for the IN transfer */
830 	itw_list = NULL;
831 	total_itws = pp->pp_max_periodic_req_cnt - pp->pp_cur_periodic_req_cnt;
832 	for (i = 0; i < total_itws; i += 1) {
833 		itw = ehci_allocate_isoc_resources(ehcip, ph, NULL, flags);
834 		if (itw == NULL) {
835 			error = USB_NO_RESOURCES;
836 			/* There are not enough resources deallocate the ITWs */
837 			itw = itw_list;
838 			while (itw != NULL) {
839 				itw_list = itw->itw_next;
840 				ehci_deallocate_isoc_in_resource(
841 					ehcip, pp, itw);
842 				ehci_deallocate_itw(ehcip, pp, itw);
843 				itw = itw_list;
844 			}
845 
846 			return (error);
847 		} else {
848 			if (itw_list == NULL) {
849 				itw_list = itw;
850 			}
851 		}
852 	}
853 
854 	i = 0;
855 	while (pp->pp_cur_periodic_req_cnt < pp->pp_max_periodic_req_cnt) {
856 
857 		USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
858 		    "ehci_start_isoc_polling: max = %d curr = %d itw = %p:",
859 		    pp->pp_max_periodic_req_cnt, pp->pp_cur_periodic_req_cnt,
860 		    itw_list);
861 
862 		itw = itw_list;
863 		itw_list = itw->itw_next;
864 
865 		error = ehci_insert_isoc_req(ehcip, pp, itw, flags);
866 
867 		if (error == USB_SUCCESS) {
868 			pp->pp_cur_periodic_req_cnt++;
869 		} else {
870 			/*
871 			 * Deallocate the remaining tw
872 			 * The current tw should have already been deallocated
873 			 */
874 			itw = itw_list;
875 			while (itw != NULL) {
876 				itw_list = itw->itw_next;
877 				ehci_deallocate_isoc_in_resource(
878 					ehcip, pp, itw);
879 				ehci_deallocate_itw(ehcip, pp, itw);
880 				itw = itw_list;
881 			}
882 			/*
883 			 * If this is the first req return an error.
884 			 * Otherwise return success.
885 			 */
886 			if (i != 0) {
887 				error = USB_SUCCESS;
888 			}
889 
890 			break;
891 		}
892 		i++;
893 	}
894 
895 	return (error);
896 }
897 
898 
899 /*
900  * Isochronronous handling functions.
901  */
902 /*
903  * ehci_traverse_active_isoc_list:
904  */
905 void
906 ehci_traverse_active_isoc_list(
907 	ehci_state_t		*ehcip)
908 {
909 	ehci_isoc_xwrapper_t	*curr_itw;
910 	ehci_itd_t		*curr_itd, *next_itd;
911 	uint_t			state;
912 	ehci_pipe_private_t	*pp;
913 
914 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
915 	    "ehci_traverse_active_isoc_list:");
916 
917 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
918 
919 	/* Sync ITD pool */
920 	Sync_ITD_Pool(ehcip);
921 
922 	/* Traverse the list of done itds */
923 	curr_itd = ehci_create_done_itd_list(ehcip);
924 
925 	while (curr_itd) {
926 		/* Save the next_itd */
927 		next_itd = ehci_itd_iommu_to_cpu(ehcip,
928 		    Get_ITD(curr_itd->itd_next_active_itd));
929 
930 		/* Get the transfer wrapper and the pp */
931 		curr_itw = (ehci_isoc_xwrapper_t *)EHCI_LOOKUP_ID(
932 			(uint32_t)Get_ITD(curr_itd->itd_trans_wrapper));
933 		pp = curr_itw->itw_pipe_private;
934 
935 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
936 		    "ehci_traverse_active_isoc_list:\t"
937 		    "pp = 0x%p itw = 0x%p itd = 0x%p",
938 		    pp, curr_itw, curr_itd);
939 
940 		ehci_print_itd(ehcip, curr_itd);
941 
942 		/* Get the ITD state */
943 		state = Get_ITD(curr_itd->itd_state);
944 
945 		/* Only process the ITDs marked as active. */
946 		if (state == EHCI_ITD_ACTIVE) {
947 			ehci_parse_isoc_error(ehcip, curr_itw, curr_itd);
948 			ehci_handle_isoc(ehcip, curr_itw, curr_itd);
949 		} else {
950 			ASSERT(state == EHCI_ITD_RECLAIM);
951 			ehci_reclaim_isoc(ehcip, curr_itw, curr_itd, pp);
952 		}
953 
954 		/*
955 		 * Deallocate the transfer wrapper if there are no more
956 		 * ITD's for the transfer wrapper.  ehci_deallocate_itw()
957 		 * will  not deallocate the tw for a periodic in endpoint
958 		 * since it will always have a ITD attached to it.
959 		 */
960 		ehci_deallocate_itw(ehcip, pp, curr_itw);
961 
962 		/* Check any ISOC is waiting for transfers completion event */
963 		if (pp->pp_itw_head == NULL) {
964 			USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
965 			    "ehci_traverse_active_isoc_list: "
966 			    "Sent transfers completion event pp = 0x%p", pp);
967 			cv_signal(&pp->pp_xfer_cmpl_cv);
968 		}
969 
970 		curr_itd = next_itd;
971 	}
972 }
973 
974 
975 static void
976 ehci_handle_isoc(
977 	ehci_state_t		*ehcip,
978 	ehci_isoc_xwrapper_t	*itw,
979 	ehci_itd_t		*itd)
980 {
981 	ehci_pipe_private_t	*pp;	/* Pipe private field */
982 
983 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
984 
985 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
986 	    "ehci_handle_isoc:");
987 
988 	/* Obtain the pipe private structure */
989 	pp = itw->itw_pipe_private;
990 
991 	if (itw->itw_port_status == USBA_HIGH_SPEED_DEV) {
992 		ehci_handle_itd(ehcip, pp, itw, itd,
993 		    itw->itw_handle_callback_value);
994 	} else {
995 		ehci_handle_sitd(ehcip, pp, itw, itd,
996 		    itw->itw_handle_callback_value);
997 	}
998 }
999 
1000 
1001 /*
1002  * ehci_handle_itd:
1003  *
1004  * Handle an isochronous transfer descriptor
1005  */
1006 /* ARGSUSED */
1007 static void
1008 ehci_handle_itd(
1009 	ehci_state_t		*ehcip,
1010 	ehci_pipe_private_t	*pp,
1011 	ehci_isoc_xwrapper_t	*itw,
1012 	ehci_itd_t		*itd,
1013 	void			*tw_handle_callback_value)
1014 {
1015 	/* For Future Use */
1016 }
1017 
1018 
1019 /*
1020  * ehci_handle_sitd:
1021  *
1022  * Handle an split isochronous transfer descriptor.
1023  * This function will deallocate the itd from the list as well.
1024  */
1025 /* ARGSUSED */
1026 static void
1027 ehci_handle_sitd(
1028 	ehci_state_t		*ehcip,
1029 	ehci_pipe_private_t	*pp,
1030 	ehci_isoc_xwrapper_t	*itw,
1031 	ehci_itd_t		*itd,
1032 	void			*tw_handle_callback_value)
1033 {
1034 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1035 	usb_isoc_req_t		*curr_isoc_reqp =
1036 				    (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
1037 	int			error = USB_SUCCESS;
1038 
1039 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1040 	    "ehci_handle_sitd: pp=0x%p itw=0x%p itd=0x%p "
1041 	    "isoc_reqp=0%p data=0x%p", pp, itw, itd, curr_isoc_reqp,
1042 	    curr_isoc_reqp->isoc_data);
1043 
1044 	/*
1045 	 * Decrement the ITDs counter and check whether all the isoc
1046 	 * data has been send or received. If ITDs counter reaches
1047 	 * zero then inform client driver about completion current
1048 	 * isoc request. Otherwise wait for completion of other isoc
1049 	 * ITDs or transactions on this pipe.
1050 	 */
1051 	if (--itw->itw_num_itds != 0) {
1052 		/* Deallocate this transfer descriptor */
1053 		ehci_deallocate_itd(ehcip, itw, itd);
1054 
1055 		return;
1056 	}
1057 
1058 	/*
1059 	 * If this is a isoc in pipe, return the data to the client.
1060 	 * For a isoc out pipe, there is no need to do anything.
1061 	 */
1062 	if (itw->itw_direction == USB_EP_DIR_OUT) {
1063 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1064 		    "ehci_handle_sitd: Isoc out pipe, isoc_reqp=0x%p,"
1065 		    "data=0x%p", curr_isoc_reqp, curr_isoc_reqp->isoc_data);
1066 
1067 		/* Do the callback */
1068 		ehci_hcdi_isoc_callback(ph, itw, USB_CR_OK);
1069 
1070 		/* Deallocate this transfer descriptor */
1071 		ehci_deallocate_itd(ehcip, itw, itd);
1072 
1073 		return;
1074 	}
1075 
1076 	/* Decrement number of IN isochronous request count */
1077 	pp->pp_cur_periodic_req_cnt--;
1078 
1079 	/* Call ehci_sendup_itd_message to send message to upstream */
1080 	ehci_sendup_itd_message(ehcip, pp, itw, itd, USB_CR_OK);
1081 
1082 	/* Deallocate this transfer descriptor */
1083 	ehci_deallocate_itd(ehcip, itw, itd);
1084 
1085 	/*
1086 	 * If isochronous pipe state is still active, insert next isochronous
1087 	 * request into the Host Controller's isochronous list.
1088 	 */
1089 	if (pp->pp_state != EHCI_PIPE_STATE_ACTIVE) {
1090 
1091 		return;
1092 	}
1093 
1094 	if ((error = ehci_allocate_isoc_in_resource(ehcip, pp, itw, 0)) ==
1095 	    USB_SUCCESS) {
1096 		curr_isoc_reqp = (usb_isoc_req_t *)itw->itw_curr_xfer_reqp;
1097 
1098 		ASSERT(curr_isoc_reqp != NULL);
1099 
1100 		itw->itw_num_itds = ehci_calc_num_itds(itw,
1101 		    curr_isoc_reqp->isoc_pkts_count);
1102 
1103 		if (ehci_allocate_itds_for_itw(ehcip, itw, itw->itw_num_itds) !=
1104 		    USB_SUCCESS) {
1105 			ehci_deallocate_isoc_in_resource(ehcip, pp, itw);
1106 			itw->itw_num_itds = 0;
1107 			error = USB_FAILURE;
1108 		}
1109 	}
1110 
1111 	if ((error != USB_SUCCESS) ||
1112 	    (ehci_insert_isoc_req(ehcip, pp, itw, 0) != USB_SUCCESS)) {
1113 		/*
1114 		 * Set pipe state to stop polling and error to no
1115 		 * resource. Don't insert any more isoch polling
1116 		 * requests.
1117 		 */
1118 		pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING;
1119 		pp->pp_error = USB_CR_NO_RESOURCES;
1120 
1121 	} else {
1122 		/* Increment number of IN isochronous request count */
1123 		pp->pp_cur_periodic_req_cnt++;
1124 
1125 		ASSERT(pp->pp_cur_periodic_req_cnt ==
1126 		    pp->pp_max_periodic_req_cnt);
1127 	}
1128 }
1129 
1130 
1131 /*
1132  * ehci_sendup_qtd_message:
1133  *	copy data, if necessary and do callback
1134  */
1135 /* ARGSUSED */
1136 static void
1137 ehci_sendup_itd_message(
1138 	ehci_state_t		*ehcip,
1139 	ehci_pipe_private_t	*pp,
1140 	ehci_isoc_xwrapper_t	*itw,
1141 	ehci_itd_t		*td,
1142 	usb_cr_t		error)
1143 {
1144 	usb_isoc_req_t		*isoc_reqp = itw->itw_curr_xfer_reqp;
1145 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1146 	size_t			length;
1147 	uchar_t			*buf;
1148 	mblk_t			*mp;
1149 
1150 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1151 
1152 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1153 	    "ehci_sendup_itd_message:");
1154 
1155 	ASSERT(itw != NULL);
1156 
1157 	length = itw->itw_length;
1158 
1159 	/* Copy the data into the mblk_t */
1160 	buf = (uchar_t *)itw->itw_buf;
1161 
1162 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1163 	    "ehci_sendup_itd_message: length %d error %d", length, error);
1164 
1165 	/* Get the message block */
1166 	mp = isoc_reqp->isoc_data;
1167 
1168 	ASSERT(mp != NULL);
1169 
1170 	if (length) {
1171 		/* Sync IO buffer */
1172 		Sync_IO_Buffer(itw->itw_dmahandle, length);
1173 
1174 		/* Copy the data into the message */
1175 		bcopy(buf, mp->b_rptr, length);
1176 
1177 		/* Increment the write pointer */
1178 		mp->b_wptr = mp->b_wptr + length;
1179 	} else {
1180 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1181 		    "ehci_sendup_itd_message: Zero length packet");
1182 	}
1183 
1184 	ehci_hcdi_isoc_callback(ph, itw, error);
1185 }
1186 
1187 
1188 /*
1189  * ehci_hcdi_isoc_callback:
1190  *
1191  * Convenience wrapper around usba_hcdi_cb() other than root hub.
1192  */
1193 void
1194 ehci_hcdi_isoc_callback(
1195 	usba_pipe_handle_data_t	*ph,
1196 	ehci_isoc_xwrapper_t	*itw,
1197 	usb_cr_t		completion_reason)
1198 {
1199 	ehci_state_t		*ehcip = ehci_obtain_state(
1200 				    ph->p_usba_device->usb_root_hub_dip);
1201 	ehci_pipe_private_t	*pp = (ehci_pipe_private_t *)ph->p_hcd_private;
1202 	usb_opaque_t		curr_xfer_reqp;
1203 	uint_t			pipe_state = 0;
1204 
1205 	USB_DPRINTF_L4(PRINT_MASK_HCDI, ehcip->ehci_log_hdl,
1206 	    "ehci_hcdi_isoc_callback: ph = 0x%p, itw = 0x%p, cr = 0x%x",
1207 	    (void *)ph, itw, completion_reason);
1208 
1209 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1210 
1211 	/* Set the pipe state as per completion reason */
1212 	switch (completion_reason) {
1213 	case USB_CR_OK:
1214 		pipe_state = pp->pp_state;
1215 		break;
1216 	case USB_CR_NO_RESOURCES:
1217 	case USB_CR_NOT_SUPPORTED:
1218 	case USB_CR_PIPE_RESET:
1219 	case USB_CR_STOPPED_POLLING:
1220 		pipe_state = EHCI_PIPE_STATE_IDLE;
1221 		break;
1222 	case USB_CR_PIPE_CLOSING:
1223 		break;
1224 	}
1225 
1226 	pp->pp_state = pipe_state;
1227 
1228 	if (itw && itw->itw_curr_xfer_reqp) {
1229 		curr_xfer_reqp = (usb_opaque_t)itw->itw_curr_xfer_reqp;
1230 		itw->itw_curr_xfer_reqp = NULL;
1231 	} else {
1232 		ASSERT(pp->pp_client_periodic_in_reqp != NULL);
1233 
1234 		curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
1235 		pp->pp_client_periodic_in_reqp = NULL;
1236 	}
1237 
1238 	ASSERT(curr_xfer_reqp != NULL);
1239 
1240 	mutex_exit(&ehcip->ehci_int_mutex);
1241 
1242 	usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
1243 
1244 	mutex_enter(&ehcip->ehci_int_mutex);
1245 }
1246