xref: /onnv-gate/usr/src/uts/common/io/usb/hcd/ehci/ehci_intr.c (revision 7425:e4dbffd35ebc)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51500Ssl147100  * Common Development and Distribution License (the "License").
61500Ssl147100  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
225789Ssl147100  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * EHCI Host Controller Driver (EHCI)
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * The EHCI driver is a software driver which interfaces to the Universal
310Sstevel@tonic-gate  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
320Sstevel@tonic-gate  * the Host Controller is defined by the EHCI Host Controller Interface.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * This module contains the EHCI driver interrupt code, which handles all
350Sstevel@tonic-gate  * Checking of status of USB transfers, error recovery and callbacks.
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
390Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
400Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_util.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * EHCI Interrupt Handling functions.
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate void		ehci_handle_ue(ehci_state_t		*ehcip);
460Sstevel@tonic-gate void		ehci_handle_frame_list_rollover(
470Sstevel@tonic-gate 				ehci_state_t		*ehcip);
480Sstevel@tonic-gate void		ehci_handle_endpoint_reclaimation(
490Sstevel@tonic-gate 				ehci_state_t		*ehcip);
500Sstevel@tonic-gate void		ehci_traverse_active_qtd_list(
510Sstevel@tonic-gate 				ehci_state_t		*ehcip);
520Sstevel@tonic-gate static ehci_qtd_t *ehci_create_done_qtd_list(
530Sstevel@tonic-gate 				ehci_state_t		*ehcip);
540Sstevel@tonic-gate static usb_cr_t ehci_parse_error(
550Sstevel@tonic-gate 				ehci_state_t		*ehcip,
560Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
570Sstevel@tonic-gate usb_cr_t	ehci_check_for_error(
580Sstevel@tonic-gate 				ehci_state_t		*ehcip,
590Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
600Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
610Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
620Sstevel@tonic-gate 				uint_t			ctrl);
630Sstevel@tonic-gate static usb_cr_t	ehci_check_for_short_xfer(
640Sstevel@tonic-gate 				ehci_state_t		*ehcip,
650Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
660Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
670Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
680Sstevel@tonic-gate void		ehci_handle_error(
690Sstevel@tonic-gate 				ehci_state_t		*ehcip,
700Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
710Sstevel@tonic-gate 				usb_cr_t		error);
720Sstevel@tonic-gate static void	ehci_cleanup_data_underrun(
730Sstevel@tonic-gate 				ehci_state_t		*ehcip,
740Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
750Sstevel@tonic-gate 				ehci_qtd_t		*qtd);
760Sstevel@tonic-gate static void	ehci_handle_normal_qtd(
770Sstevel@tonic-gate 				ehci_state_t		*ehcip,
780Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
790Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw);
800Sstevel@tonic-gate void		ehci_handle_ctrl_qtd(
810Sstevel@tonic-gate 				ehci_state_t		*ehcip,
820Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
830Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
840Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
850Sstevel@tonic-gate 				void			*);
860Sstevel@tonic-gate void		ehci_handle_bulk_qtd(
870Sstevel@tonic-gate 				ehci_state_t		*ehcip,
880Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
890Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
900Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
910Sstevel@tonic-gate 				void			*);
920Sstevel@tonic-gate void		ehci_handle_intr_qtd(
930Sstevel@tonic-gate 				ehci_state_t		*ehcip,
940Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
950Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
960Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
970Sstevel@tonic-gate 				void			*);
980Sstevel@tonic-gate static void	ehci_handle_one_xfer_completion(
990Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1000Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw);
1010Sstevel@tonic-gate static void	ehci_sendup_qtd_message(
1020Sstevel@tonic-gate 				ehci_state_t		*ehcip,
1030Sstevel@tonic-gate 				ehci_pipe_private_t	*pp,
1040Sstevel@tonic-gate 				ehci_trans_wrapper_t	*tw,
1050Sstevel@tonic-gate 				ehci_qtd_t		*qtd,
1060Sstevel@tonic-gate 				usb_cr_t		error);
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate /*
1100Sstevel@tonic-gate  * Interrupt Handling functions
1110Sstevel@tonic-gate  */
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * ehci_handle_ue:
1150Sstevel@tonic-gate  *
1160Sstevel@tonic-gate  * Handling of Unrecoverable Error interrupt (UE).
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate void
ehci_handle_ue(ehci_state_t * ehcip)1190Sstevel@tonic-gate ehci_handle_ue(ehci_state_t	*ehcip)
1200Sstevel@tonic-gate {
1210Sstevel@tonic-gate 	usb_frame_number_t	before_frame_number, after_frame_number;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1260Sstevel@tonic-gate 	    "ehci_handle_ue: Handling of UE interrupt");
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	/*
1290Sstevel@tonic-gate 	 * First check whether current UE error occurred due to USB or
1300Sstevel@tonic-gate 	 * due to some other subsystem. This can be verified by reading
1310Sstevel@tonic-gate 	 * usb frame numbers before & after a delay of few milliseconds.
1320Sstevel@tonic-gate 	 * If usb frame number read after delay is greater than the one
1330Sstevel@tonic-gate 	 * read before delay, then, USB subsystem is fine. In this case,
1340Sstevel@tonic-gate 	 * disable UE error interrupt and return without shutdowning the
1350Sstevel@tonic-gate 	 * USB subsystem.
1360Sstevel@tonic-gate 	 *
1370Sstevel@tonic-gate 	 * Otherwise, if usb frame number read after delay is less than
1380Sstevel@tonic-gate 	 * or equal to one read before the delay, then, current UE error
1390Sstevel@tonic-gate 	 * occurred from USB subsystem. In this case,go ahead with actual
1400Sstevel@tonic-gate 	 * UE error recovery procedure.
1410Sstevel@tonic-gate 	 *
1420Sstevel@tonic-gate 	 * Get the current usb frame number before waiting for few
1430Sstevel@tonic-gate 	 * milliseconds.
1440Sstevel@tonic-gate 	 */
1450Sstevel@tonic-gate 	before_frame_number = ehci_get_current_frame_number(ehcip);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	/* Wait for few milliseconds */
1480Sstevel@tonic-gate 	drv_usecwait(EHCI_TIMEWAIT);
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	/*
1510Sstevel@tonic-gate 	 * Get the current usb frame number after waiting for
1520Sstevel@tonic-gate 	 * milliseconds.
1530Sstevel@tonic-gate 	 */
1540Sstevel@tonic-gate 	after_frame_number = ehci_get_current_frame_number(ehcip);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1570Sstevel@tonic-gate 	    "ehci_handle_ue: Before Frame Number 0x%llx "
158*6898Sfb209375 	    "After Frame Number 0x%llx",
159*6898Sfb209375 	    (unsigned long long)before_frame_number,
160*6898Sfb209375 	    (unsigned long long)after_frame_number);
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	if (after_frame_number > before_frame_number) {
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 		/* Disable UE interrupt */
1650Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt, (Get_OpReg(ehci_interrupt) &
1660Sstevel@tonic-gate 		    ~EHCI_INTR_HOST_SYSTEM_ERROR));
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 		return;
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	/*
1720Sstevel@tonic-gate 	 * This UE is due to USB hardware error. Reset ehci controller
1730Sstevel@tonic-gate 	 * and reprogram to bring it back to functional state.
1740Sstevel@tonic-gate 	 */
1750Sstevel@tonic-gate 	if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) {
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 		USB_DPRINTF_L0(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1780Sstevel@tonic-gate 		    "Unrecoverable USB Hardware Error");
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 		/* Disable UE interrupt */
1810Sstevel@tonic-gate 		Set_OpReg(ehci_interrupt, (Get_OpReg(ehci_interrupt) &
1820Sstevel@tonic-gate 		    ~EHCI_INTR_HOST_SYSTEM_ERROR));
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 		/* Route all Root hub ports to Classic host controller */
1850Sstevel@tonic-gate 		Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 		/* Set host controller soft state to error */
1880Sstevel@tonic-gate 		ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate  * ehci_handle_frame_list_rollover:
1950Sstevel@tonic-gate  *
1960Sstevel@tonic-gate  * Update software based usb frame number part on every frame number
1970Sstevel@tonic-gate  * overflow interrupt.
1980Sstevel@tonic-gate  *
1990Sstevel@tonic-gate  * Refer ehci spec 1.0, section 2.3.2, page 21 for more details.
2000Sstevel@tonic-gate  *
2010Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
2020Sstevel@tonic-gate  */
2030Sstevel@tonic-gate void
ehci_handle_frame_list_rollover(ehci_state_t * ehcip)2040Sstevel@tonic-gate ehci_handle_frame_list_rollover(ehci_state_t *ehcip)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	ehcip->ehci_fno += (0x4000 -
2070Sstevel@tonic-gate 	    (((Get_OpReg(ehci_frame_index) & 0x3FFF) ^
2080Sstevel@tonic-gate 	    ehcip->ehci_fno) & 0x2000));
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
2110Sstevel@tonic-gate 	    "ehci_handle_frame_list_rollover:"
212*6898Sfb209375 	    "Frame Number Higher Part 0x%llx\n",
213*6898Sfb209375 	    (unsigned long long)(ehcip->ehci_fno));
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate /*
2180Sstevel@tonic-gate  * ehci_handle_endpoint_reclamation:
2190Sstevel@tonic-gate  *
2200Sstevel@tonic-gate  * Reclamation of Host Controller (HC) Endpoint Descriptors (QH).
2210Sstevel@tonic-gate  */
2220Sstevel@tonic-gate void
ehci_handle_endpoint_reclaimation(ehci_state_t * ehcip)2230Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehci_state_t	*ehcip)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate 	usb_frame_number_t	current_frame_number;
2260Sstevel@tonic-gate 	usb_frame_number_t	endpoint_frame_number;
2270Sstevel@tonic-gate 	ehci_qh_t		*reclaim_qh;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
2300Sstevel@tonic-gate 	    "ehci_handle_endpoint_reclamation:");
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	current_frame_number = ehci_get_current_frame_number(ehcip);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	/*
2370Sstevel@tonic-gate 	 * Deallocate all Endpoint Descriptors (QH) which are on the
2380Sstevel@tonic-gate 	 * reclamation list. These QH's are already removed from the
2390Sstevel@tonic-gate 	 * interrupt lattice tree.
2400Sstevel@tonic-gate 	 */
2410Sstevel@tonic-gate 	while (ehcip->ehci_reclaim_list) {
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 		reclaim_qh = ehcip->ehci_reclaim_list;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 		endpoint_frame_number = (usb_frame_number_t)(uintptr_t)
2460Sstevel@tonic-gate 		    (EHCI_LOOKUP_ID(Get_QH(reclaim_qh->qh_reclaim_frame)));
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
2490Sstevel@tonic-gate 		    "ehci_handle_endpoint_reclamation:"
2500Sstevel@tonic-gate 		    "current frame number 0x%llx endpoint frame number 0x%llx",
251*6898Sfb209375 		    (unsigned long long)current_frame_number,
252*6898Sfb209375 		    (unsigned long long)endpoint_frame_number);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		/*
2550Sstevel@tonic-gate 		 * Deallocate current endpoint only if endpoint's usb frame
2560Sstevel@tonic-gate 		 * number is less than or equal to current usb frame number.
2570Sstevel@tonic-gate 		 *
2580Sstevel@tonic-gate 		 * If endpoint's usb frame number is greater than the current
2590Sstevel@tonic-gate 		 * usb frame number, ignore rest of the endpoints in the list
2600Sstevel@tonic-gate 		 * since rest of the endpoints are inserted into the reclaim
2610Sstevel@tonic-gate 		 * list later than the current reclaim endpoint.
2620Sstevel@tonic-gate 		 */
2630Sstevel@tonic-gate 		if (endpoint_frame_number > current_frame_number) {
2640Sstevel@tonic-gate 			break;
2650Sstevel@tonic-gate 		}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 		/* Get the next endpoint from the rec. list */
2680Sstevel@tonic-gate 		ehcip->ehci_reclaim_list = ehci_qh_iommu_to_cpu(
2690Sstevel@tonic-gate 		    ehcip, Get_QH(reclaim_qh->qh_reclaim_next));
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 		/* Free 32bit ID */
2720Sstevel@tonic-gate 		EHCI_FREE_ID((uint32_t)Get_QH(reclaim_qh->qh_reclaim_frame));
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 		/* Deallocate the endpoint */
2750Sstevel@tonic-gate 		ehci_deallocate_qh(ehcip, reclaim_qh);
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate /*
2810Sstevel@tonic-gate  * ehci_traverse_active_qtd_list:
2820Sstevel@tonic-gate  */
2830Sstevel@tonic-gate void
ehci_traverse_active_qtd_list(ehci_state_t * ehcip)2840Sstevel@tonic-gate ehci_traverse_active_qtd_list(
2850Sstevel@tonic-gate 	ehci_state_t		*ehcip)
2860Sstevel@tonic-gate {
2870Sstevel@tonic-gate 	uint_t			state;		/* QTD state */
2880Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd = NULL; /* QTD pointers */
2890Sstevel@tonic-gate 	ehci_qtd_t		*next_qtd = NULL; /* QTD pointers */
2900Sstevel@tonic-gate 	usb_cr_t		error;		/* Error from QTD */
2910Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw = NULL;	/* Transfer wrapper */
2920Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = NULL;	/* Pipe private field */
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
2950Sstevel@tonic-gate 	    "ehci_traverse_active_qtd_list:");
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	/* Sync QH and QTD pool */
3000Sstevel@tonic-gate 	Sync_QH_QTD_Pool(ehcip);
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	/* Create done qtd list */
3030Sstevel@tonic-gate 	curr_qtd = ehci_create_done_qtd_list(ehcip);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	/* Traverse the list of transfer descriptors */
3060Sstevel@tonic-gate 	while (curr_qtd) {
3070Sstevel@tonic-gate 		/* Get next qtd from the active qtd list */
3080Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
3090Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 		/* Check for QTD state */
3120Sstevel@tonic-gate 		state = Get_QTD(curr_qtd->qtd_state);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3150Sstevel@tonic-gate 		    "ehci_traverse_active_qtd_list:\n\t"
3160Sstevel@tonic-gate 		    "curr_qtd = 0x%p state = 0x%x", (void *)curr_qtd, state);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		/* Obtain the  transfer wrapper  for this QTD */
3190Sstevel@tonic-gate 		tw = (ehci_trans_wrapper_t *)EHCI_LOOKUP_ID(
3200Sstevel@tonic-gate 		    (uint32_t)Get_QTD(curr_qtd->qtd_trans_wrapper));
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 		ASSERT(tw != NULL);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 		pp = tw->tw_pipe_private;
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3270Sstevel@tonic-gate 		    "ehci_traverse_active_qtd_list: "
328*6898Sfb209375 		    "PP = 0x%p TW = 0x%p", (void *)pp, (void *)tw);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 		/*
3310Sstevel@tonic-gate 		 * A QTD that is marked as RECLAIM has already been
3320Sstevel@tonic-gate 		 * processed by QTD timeout handler & client driver
3330Sstevel@tonic-gate 		 * has been informed through exception callback.
3340Sstevel@tonic-gate 		 */
3350Sstevel@tonic-gate 		if (state != EHCI_QTD_RECLAIM) {
3360Sstevel@tonic-gate 			/* Look at the error status */
3370Sstevel@tonic-gate 			error = ehci_parse_error(ehcip, curr_qtd);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 			if (error == USB_CR_OK) {
3400Sstevel@tonic-gate 				ehci_handle_normal_qtd(ehcip, curr_qtd, tw);
3410Sstevel@tonic-gate 			} else {
3420Sstevel@tonic-gate 				/* handle the error condition */
3430Sstevel@tonic-gate 				ehci_handle_error(ehcip, curr_qtd, error);
3440Sstevel@tonic-gate 			}
3450Sstevel@tonic-gate 		} else {
3460Sstevel@tonic-gate 			USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3470Sstevel@tonic-gate 			    "ehci_traverse_active_qtd_list: "
3480Sstevel@tonic-gate 			    "QTD State = %d", state);
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 		/* Deallocate this transfer descriptor */
3520Sstevel@tonic-gate 		ehci_deallocate_qtd(ehcip, curr_qtd);
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 		/*
3550Sstevel@tonic-gate 		 * Deallocate the transfer wrapper if there are no more
3560Sstevel@tonic-gate 		 * QTD's for the transfer wrapper.  ehci_deallocate_tw()
3570Sstevel@tonic-gate 		 * will  not deallocate the tw for a periodic  endpoint
3580Sstevel@tonic-gate 		 * since it will always have a QTD attached to it.
3590Sstevel@tonic-gate 		 */
3600Sstevel@tonic-gate 		ehci_deallocate_tw(ehcip, pp, tw);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		curr_qtd = next_qtd;
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate /*
3680Sstevel@tonic-gate  * ehci_create_done_qtd_list:
3690Sstevel@tonic-gate  *
3700Sstevel@tonic-gate  * Create done qtd list from active qtd list.
3710Sstevel@tonic-gate  */
3720Sstevel@tonic-gate ehci_qtd_t *
ehci_create_done_qtd_list(ehci_state_t * ehcip)3730Sstevel@tonic-gate ehci_create_done_qtd_list(
3740Sstevel@tonic-gate 	ehci_state_t		*ehcip)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	ehci_qtd_t		*curr_qtd = NULL, *next_qtd = NULL;
3770Sstevel@tonic-gate 	ehci_qtd_t		*done_qtd_list = NULL, *last_done_qtd = NULL;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
3800Sstevel@tonic-gate 	    "ehci_create_done_qtd_list:");
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	curr_qtd = ehcip->ehci_active_qtd_list;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	while (curr_qtd) {
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		/* Get next qtd from the active qtd list */
3890Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
3900Sstevel@tonic-gate 		    Get_QTD(curr_qtd->qtd_active_qtd_next));
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 		/* Check this QTD has been processed by Host Controller */
3930Sstevel@tonic-gate 		if (!(Get_QTD(curr_qtd->qtd_ctrl) &
3940Sstevel@tonic-gate 		    EHCI_QTD_CTRL_ACTIVE_XACT)) {
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 			/* Remove this QTD from active QTD list */
3970Sstevel@tonic-gate 			ehci_remove_qtd_from_active_qtd_list(ehcip, curr_qtd);
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 			Set_QTD(curr_qtd->qtd_active_qtd_next, NULL);
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 			if (done_qtd_list) {
4020Sstevel@tonic-gate 				Set_QTD(last_done_qtd->qtd_active_qtd_next,
4030Sstevel@tonic-gate 				    ehci_qtd_cpu_to_iommu(ehcip, curr_qtd));
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 				last_done_qtd = curr_qtd;
4060Sstevel@tonic-gate 			} else {
4070Sstevel@tonic-gate 				done_qtd_list = curr_qtd;
4080Sstevel@tonic-gate 				last_done_qtd = curr_qtd;
4090Sstevel@tonic-gate 			}
4100Sstevel@tonic-gate 		}
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 		curr_qtd = next_qtd;
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	return (done_qtd_list);
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate  * ehci_parse_error:
4210Sstevel@tonic-gate  *
4220Sstevel@tonic-gate  * Parse the result for any errors.
4230Sstevel@tonic-gate  */
4240Sstevel@tonic-gate static	usb_cr_t
ehci_parse_error(ehci_state_t * ehcip,ehci_qtd_t * qtd)4250Sstevel@tonic-gate ehci_parse_error(
4260Sstevel@tonic-gate 	ehci_state_t		*ehcip,
4270Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	uint_t			ctrl;
4300Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
4310Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
4320Sstevel@tonic-gate 	uint_t			flag;
4330Sstevel@tonic-gate 	usb_cr_t		error;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
4360Sstevel@tonic-gate 	    "ehci_parse_error:");
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	ASSERT(qtd != NULL);
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	/* Obtain the transfer wrapper from the QTD */
4430Sstevel@tonic-gate 	tw = (ehci_trans_wrapper_t *)
4440Sstevel@tonic-gate 	    EHCI_LOOKUP_ID((uint32_t)Get_QTD(qtd->qtd_trans_wrapper));
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	ASSERT(tw != NULL);
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	/* Obtain the pipe private structure */
4490Sstevel@tonic-gate 	pp = tw->tw_pipe_private;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
452*6898Sfb209375 	    "ehci_parse_error: PP 0x%p TW 0x%p", (void *)pp, (void *)tw);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	ctrl = (uint_t)Get_QTD(qtd->qtd_ctrl);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	/*
4570Sstevel@tonic-gate 	 * Check the condition code of completed QTD and report errors
4580Sstevel@tonic-gate 	 * if any. This checking will be done both for the general and
4590Sstevel@tonic-gate 	 * the isochronous QTDs.
4600Sstevel@tonic-gate 	 */
4610Sstevel@tonic-gate 	if ((error = ehci_check_for_error(ehcip, pp, tw, qtd, ctrl)) !=
4620Sstevel@tonic-gate 	    USB_CR_OK) {
4630Sstevel@tonic-gate 		flag = EHCI_REMOVE_XFER_ALWAYS;
4640Sstevel@tonic-gate 	} else {
4650Sstevel@tonic-gate 		flag  = EHCI_REMOVE_XFER_IFLAST;
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	/* Stop the transfer timer */
4690Sstevel@tonic-gate 	ehci_stop_xfer_timer(ehcip, tw, flag);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	return (error);
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate /*
4760Sstevel@tonic-gate  * ehci_check_for_error:
4770Sstevel@tonic-gate  *
4780Sstevel@tonic-gate  * Check for any errors.
4790Sstevel@tonic-gate  *
4800Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
4810Sstevel@tonic-gate  */
4820Sstevel@tonic-gate usb_cr_t
ehci_check_for_error(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_trans_wrapper_t * tw,ehci_qtd_t * qtd,uint_t ctrl)4830Sstevel@tonic-gate ehci_check_for_error(
4840Sstevel@tonic-gate 	ehci_state_t		*ehcip,
4850Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
4860Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
4870Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
4880Sstevel@tonic-gate 	uint_t			ctrl)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate 	usb_cr_t		error = USB_CR_OK;
4910Sstevel@tonic-gate 	uint_t			status, speed, mask;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
4940Sstevel@tonic-gate 	    "ehci_check_for_error: qtd = 0x%p ctrl = 0x%x",
495*6898Sfb209375 	    (void *)qtd, ctrl);
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	/*
4980Sstevel@tonic-gate 	 * Find the usb device speed and get the corresponding
4990Sstevel@tonic-gate 	 * error status mask.
5000Sstevel@tonic-gate 	 */
5010Sstevel@tonic-gate 	speed = Get_QH(pp->pp_qh->qh_ctrl) & EHCI_QH_CTRL_ED_SPEED;
5020Sstevel@tonic-gate 	mask = (speed == EHCI_QH_CTRL_ED_HIGH_SPEED)?
5030Sstevel@tonic-gate 	    EHCI_QTD_CTRL_HS_XACT_STATUS : EHCI_QTD_CTRL_NON_HS_XACT_STATUS;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/* Exclude halted transaction error condition */
5060Sstevel@tonic-gate 	status = ctrl & EHCI_QTD_CTRL_XACT_STATUS & ~EHCI_QTD_CTRL_HALTED_XACT;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	switch (status & mask) {
5090Sstevel@tonic-gate 	case EHCI_QTD_CTRL_NO_ERROR:
5100Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5110Sstevel@tonic-gate 		    "ehci_check_for_error: No Error");
5120Sstevel@tonic-gate 		error = USB_CR_OK;
5130Sstevel@tonic-gate 		break;
5140Sstevel@tonic-gate 	case EHCI_QTD_CTRL_ACTIVE_XACT:
5150Sstevel@tonic-gate 		USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5160Sstevel@tonic-gate 		    "ehci_check_for_error: Not accessed");
5170Sstevel@tonic-gate 		error = USB_CR_NOT_ACCESSED;
5180Sstevel@tonic-gate 		break;
5190Sstevel@tonic-gate 	case EHCI_QTD_CTRL_HALTED_XACT:
5200Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5210Sstevel@tonic-gate 		    "ehci_check_for_error: Halted");
5220Sstevel@tonic-gate 		error = USB_CR_STALL;
5230Sstevel@tonic-gate 		break;
5240Sstevel@tonic-gate 	case EHCI_QTD_CTRL_BABBLE_DETECTED:
5250Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5260Sstevel@tonic-gate 		    "ehci_check_for_error: Babble Detected");
5270Sstevel@tonic-gate 		error = USB_CR_DATA_OVERRUN;
5280Sstevel@tonic-gate 		break;
5290Sstevel@tonic-gate 	case EHCI_QTD_CTRL_XACT_ERROR:
5300Sstevel@tonic-gate 		/*
5310Sstevel@tonic-gate 		 * An xacterr bit of one is not necessarily an error,
5320Sstevel@tonic-gate 		 * the transaction might have completed successfully
5330Sstevel@tonic-gate 		 * after some retries.
5340Sstevel@tonic-gate 		 *
5350Sstevel@tonic-gate 		 * Try to detect the case when the queue is halted,
5360Sstevel@tonic-gate 		 * because the error counter was decremented from one
5370Sstevel@tonic-gate 		 * down to zero after a transaction error.
5380Sstevel@tonic-gate 		 */
5390Sstevel@tonic-gate 		if (ctrl & EHCI_QTD_CTRL_HALTED_XACT && (ctrl &
5400Sstevel@tonic-gate 		    EHCI_QTD_CTRL_ERR_COUNT_MASK) == 0) {
5410Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5420Sstevel@tonic-gate 			    "ehci_check_for_error: Transaction Error");
5430Sstevel@tonic-gate 			error = USB_CR_DEV_NOT_RESP;
5440Sstevel@tonic-gate 		} else {
5450Sstevel@tonic-gate 			USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5460Sstevel@tonic-gate 			    "ehci_check_for_error: No Error");
5470Sstevel@tonic-gate 			error = USB_CR_OK;
5480Sstevel@tonic-gate 		}
5490Sstevel@tonic-gate 		break;
5505789Ssl147100 	case EHCI_QTD_CTRL_DATA_BUFFER_ERROR:
5515789Ssl147100 		/*
5525789Ssl147100 		 * Data buffer error is not necessarily an error,
5535789Ssl147100 		 * the transaction might have completed successfully
5545789Ssl147100 		 * after some retries. It can be ignored if the
5555789Ssl147100 		 * queue is not halted.
5565789Ssl147100 		 */
5575789Ssl147100 		if (!(ctrl & EHCI_QTD_CTRL_HALTED_XACT)) {
5585789Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5595789Ssl147100 			    "ehci_check_for_error: Data buffer overrun or "
5605789Ssl147100 			    "underrun ignored");
5615789Ssl147100 			error = USB_CR_OK;
5625789Ssl147100 			break;
5635789Ssl147100 		}
5645789Ssl147100 
5655789Ssl147100 		if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) {
5665789Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5675789Ssl147100 			    "ehci_check_for_error: Buffer Overrun");
5685789Ssl147100 			error = USB_CR_BUFFER_OVERRUN;
5695789Ssl147100 		} else	{
5705789Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5715789Ssl147100 			    "ehci_check_for_error: Buffer Underrun");
5725789Ssl147100 			error = USB_CR_BUFFER_UNDERRUN;
5735789Ssl147100 		}
5745789Ssl147100 		break;
5750Sstevel@tonic-gate 	case EHCI_QTD_CTRL_MISSED_uFRAME:
5760Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5770Sstevel@tonic-gate 		    "ehci_check_for_error: Missed uFrame");
5780Sstevel@tonic-gate 		error = USB_CR_NOT_ACCESSED;
5790Sstevel@tonic-gate 		break;
5800Sstevel@tonic-gate 	case EHCI_QTD_CTRL_PRD_SPLIT_XACT_ERR:
5810Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5820Sstevel@tonic-gate 		    "ehci_check_for_error: Periodic split-transaction "
5830Sstevel@tonic-gate 		    "receives an error handshake");
5840Sstevel@tonic-gate 		error = USB_CR_UNSPECIFIED_ERR;
5850Sstevel@tonic-gate 		break;
5860Sstevel@tonic-gate 	default:
5870Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
5880Sstevel@tonic-gate 		    "ehci_check_for_error: Unspecified Error");
5890Sstevel@tonic-gate 		error = USB_CR_UNSPECIFIED_ERR;
5900Sstevel@tonic-gate 		break;
5910Sstevel@tonic-gate 	}
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	/*
5940Sstevel@tonic-gate 	 * Check for halted transaction error condition.
5950Sstevel@tonic-gate 	 * Under short xfer conditions, EHCI HC will not return an error
5960Sstevel@tonic-gate 	 * or halt the QH.  This is done manually later in
5970Sstevel@tonic-gate 	 * ehci_check_for_short_xfer.
5980Sstevel@tonic-gate 	 */
5990Sstevel@tonic-gate 	if ((ctrl & EHCI_QTD_CTRL_HALTED_XACT) && (error == USB_CR_OK)) {
6000Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
6010Sstevel@tonic-gate 		    "ehci_check_for_error: Halted");
6020Sstevel@tonic-gate 		error = USB_CR_STALL;
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	if (error == USB_CR_OK) {
6060Sstevel@tonic-gate 		error = ehci_check_for_short_xfer(ehcip, pp, tw, qtd);
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	if (error) {
6100Sstevel@tonic-gate 		uint_t qh_ctrl =  Get_QH(pp->pp_qh->qh_ctrl);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
6130Sstevel@tonic-gate 		    "ehci_check_for_error: Error %d Device address %d "
6140Sstevel@tonic-gate 		    "Endpoint number %d", error,
6150Sstevel@tonic-gate 		    (qh_ctrl & EHCI_QH_CTRL_DEVICE_ADDRESS),
6160Sstevel@tonic-gate 		    ((qh_ctrl & EHCI_QH_CTRL_ED_NUMBER) >>
6170Sstevel@tonic-gate 		    EHCI_QH_CTRL_ED_NUMBER_SHIFT));
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	return (error);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate /*
6240Sstevel@tonic-gate  * ehci_check_for_short_xfer:
6250Sstevel@tonic-gate  *
6260Sstevel@tonic-gate  * Check to see if there was a short xfer condition.
6270Sstevel@tonic-gate  *
6280Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
6290Sstevel@tonic-gate  *	 But it doesn't do anything.
6300Sstevel@tonic-gate  */
6310Sstevel@tonic-gate static usb_cr_t
ehci_check_for_short_xfer(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_trans_wrapper_t * tw,ehci_qtd_t * qtd)6320Sstevel@tonic-gate ehci_check_for_short_xfer(
6330Sstevel@tonic-gate 	ehci_state_t		*ehcip,
6340Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
6350Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
6360Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
6370Sstevel@tonic-gate {
6380Sstevel@tonic-gate 	usb_cr_t		error = USB_CR_OK;
6390Sstevel@tonic-gate 	usb_ep_descr_t		*eptd;
6400Sstevel@tonic-gate 	uchar_t			attributes;
6410Sstevel@tonic-gate 	uint32_t		residue = 0;
6420Sstevel@tonic-gate 	usb_req_attrs_t		xfer_attrs;
6430Sstevel@tonic-gate 	size_t			length;
6440Sstevel@tonic-gate 	mblk_t			*mp = NULL;
6450Sstevel@tonic-gate 	usb_opaque_t		xfer_reqp;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
6480Sstevel@tonic-gate 	    "ehci_check_for_short_xfer:");
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	if (pp->pp_flag == EHCI_POLLED_MODE_FLAG) {
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 		return (error);
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	/*
6560Sstevel@tonic-gate 	 * Check for short xfer error.	If this is a control pipe, only check
6570Sstevel@tonic-gate 	 * if it is in the data phase.
6580Sstevel@tonic-gate 	 */
6590Sstevel@tonic-gate 	eptd = &pp->pp_pipe_handle->p_ep;
6600Sstevel@tonic-gate 	attributes = eptd->bmAttributes & USB_EP_ATTR_MASK;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	switch (attributes) {
6630Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
6640Sstevel@tonic-gate 		if (Get_QTD(qtd->qtd_ctrl_phase) !=
6650Sstevel@tonic-gate 		    EHCI_CTRL_DATA_PHASE) {
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 			break;
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate 		/* FALLTHROUGH */
6700Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
6710Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
6720Sstevel@tonic-gate 		/*
6730Sstevel@tonic-gate 		 * If "Total bytes of xfer" in control field of
6740Sstevel@tonic-gate 		 * Transfer Descriptor (QTD) is not equal to zero,
6750Sstevel@tonic-gate 		 * then, we sent/received less data from the usb
6760Sstevel@tonic-gate 		 * device than requested. In that case, get the
6770Sstevel@tonic-gate 		 * actual received data size.
6780Sstevel@tonic-gate 		 */
6790Sstevel@tonic-gate 		residue = (Get_QTD(qtd->qtd_ctrl) &
6800Sstevel@tonic-gate 		    EHCI_QTD_CTRL_BYTES_TO_XFER) >>
6810Sstevel@tonic-gate 		    EHCI_QTD_CTRL_BYTES_TO_XFER_SHIFT;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 		break;
6840Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 		break;
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (residue) {
6900Sstevel@tonic-gate 		USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
6910Sstevel@tonic-gate 		    "ehci_check_for_short_xfer: residue=%d direction=0x%x",
6920Sstevel@tonic-gate 		    residue, tw->tw_direction);
6930Sstevel@tonic-gate 
6941500Ssl147100 		length = Get_QTD(qtd->qtd_xfer_offs) +
6951500Ssl147100 		    Get_QTD(qtd->qtd_xfer_len) - residue;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 		if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) {
6980Sstevel@tonic-gate 			xfer_attrs = ehci_get_xfer_attrs(ehcip, pp, tw);
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 			if (xfer_attrs & USB_ATTRS_SHORT_XFER_OK) {
7010Sstevel@tonic-gate 				ehci_cleanup_data_underrun(ehcip, tw, qtd);
7020Sstevel@tonic-gate 			} else {
7030Sstevel@tonic-gate 				/* Halt the pipe to mirror OHCI behavior */
7040Sstevel@tonic-gate 				Set_QH(pp->pp_qh->qh_status,
7050Sstevel@tonic-gate 				    ((Get_QH(pp->pp_qh->qh_status) &
7065100Ssl147100 				    ~EHCI_QH_STS_ACTIVE) |
7075100Ssl147100 				    EHCI_QH_STS_HALTED));
7080Sstevel@tonic-gate 				error = USB_CR_DATA_UNDERRUN;
7090Sstevel@tonic-gate 			}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7120Sstevel@tonic-gate 			    "ehci_check_for_short_xfer: requested data=%lu "
7130Sstevel@tonic-gate 			    "received data=%lu", tw->tw_length, length);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 			switch (attributes) {
7160Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
7170Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
7180Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
7190Sstevel@tonic-gate 				/* Save the actual received length */
7200Sstevel@tonic-gate 				tw->tw_length = length;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 				break;
7230Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
7240Sstevel@tonic-gate 			default:
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 				break;
7270Sstevel@tonic-gate 			}
7280Sstevel@tonic-gate 		} else {
7290Sstevel@tonic-gate 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7300Sstevel@tonic-gate 			    "ehci_check_for_short_xfer: requested data=%lu "
7310Sstevel@tonic-gate 			    "sent data=%lu", tw->tw_length, length);
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 			xfer_reqp = tw->tw_curr_xfer_reqp;
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 			switch (attributes) {
7360Sstevel@tonic-gate 			case USB_EP_ATTR_CONTROL:
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 				break;
7390Sstevel@tonic-gate 			case USB_EP_ATTR_BULK:
7400Sstevel@tonic-gate 				mp = (mblk_t *)((usb_bulk_req_t *)
7410Sstevel@tonic-gate 				    (xfer_reqp))->bulk_data;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 				/* Increment the read pointer */
7440Sstevel@tonic-gate 				mp->b_rptr = mp->b_rptr + length;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 				break;
7470Sstevel@tonic-gate 			case USB_EP_ATTR_INTR:
7480Sstevel@tonic-gate 				mp = (mblk_t *)((usb_intr_req_t *)
7490Sstevel@tonic-gate 				    (xfer_reqp))->intr_data;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 				/* Increment the read pointer */
7520Sstevel@tonic-gate 				mp->b_rptr = mp->b_rptr + length;
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 				break;
7550Sstevel@tonic-gate 			case USB_EP_ATTR_ISOCH:
7560Sstevel@tonic-gate 			default:
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 				break;
7590Sstevel@tonic-gate 			}
7600Sstevel@tonic-gate 		}
7610Sstevel@tonic-gate 	}
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	return (error);
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate /*
7670Sstevel@tonic-gate  * ehci_handle_error:
7680Sstevel@tonic-gate  *
7690Sstevel@tonic-gate  * Inform USBA about occurred transaction errors by calling the USBA callback
7700Sstevel@tonic-gate  * routine.
7710Sstevel@tonic-gate  */
7720Sstevel@tonic-gate void
ehci_handle_error(ehci_state_t * ehcip,ehci_qtd_t * qtd,usb_cr_t error)7730Sstevel@tonic-gate ehci_handle_error(
7740Sstevel@tonic-gate 	ehci_state_t		*ehcip,
7750Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
7760Sstevel@tonic-gate 	usb_cr_t		error)
7770Sstevel@tonic-gate {
7780Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw;
7790Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph;
7800Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;
7810Sstevel@tonic-gate 	ehci_qtd_t		*tw_qtd = qtd;
7820Sstevel@tonic-gate 	uchar_t			attributes;
7830Sstevel@tonic-gate 	usb_intr_req_t		*curr_intr_reqp;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
7860Sstevel@tonic-gate 	    "ehci_handle_error: error = 0x%x", error);
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	ASSERT(qtd != NULL);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	/* Print the values in the qtd */
7930Sstevel@tonic-gate 	ehci_print_qtd(ehcip, qtd);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	/* Obtain the transfer wrapper from the QTD */
7960Sstevel@tonic-gate 	tw = (ehci_trans_wrapper_t *)
7970Sstevel@tonic-gate 	    EHCI_LOOKUP_ID((uint32_t)Get_QTD(qtd->qtd_trans_wrapper));
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	ASSERT(tw != NULL);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	/* Obtain the pipe private structure */
8020Sstevel@tonic-gate 	pp = tw->tw_pipe_private;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	ph = tw->tw_pipe_private->pp_pipe_handle;
8050Sstevel@tonic-gate 	attributes = ph->p_ep.bmAttributes & USB_EP_ATTR_MASK;
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	/*
8080Sstevel@tonic-gate 	 * Mark all QTDs belongs to this TW as RECLAIM
8090Sstevel@tonic-gate 	 * so that we don't process them by mistake.
8100Sstevel@tonic-gate 	 */
8110Sstevel@tonic-gate 	while (tw_qtd) {
8120Sstevel@tonic-gate 		/* Set QTD state to RECLAIM */
8130Sstevel@tonic-gate 		Set_QTD(tw_qtd->qtd_state, EHCI_QTD_RECLAIM);
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 		/* Get the next QTD from the wrapper */
8160Sstevel@tonic-gate 		tw_qtd = ehci_qtd_iommu_to_cpu(ehcip,
8170Sstevel@tonic-gate 		    Get_QTD(tw_qtd->qtd_tw_next_qtd));
8180Sstevel@tonic-gate 	}
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * Special error handling
8220Sstevel@tonic-gate 	 */
8230Sstevel@tonic-gate 	if (tw->tw_direction == EHCI_QTD_CTRL_IN_PID) {
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 		switch (attributes) {
8260Sstevel@tonic-gate 		case USB_EP_ATTR_CONTROL:
8270Sstevel@tonic-gate 			if (((ph->p_ep.bmAttributes &
8280Sstevel@tonic-gate 			    USB_EP_ATTR_MASK) ==
8290Sstevel@tonic-gate 			    USB_EP_ATTR_CONTROL) &&
8300Sstevel@tonic-gate 			    (Get_QTD(qtd->qtd_ctrl_phase) ==
8310Sstevel@tonic-gate 			    EHCI_CTRL_SETUP_PHASE)) {
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 				break;
8340Sstevel@tonic-gate 			}
8350Sstevel@tonic-gate 			/* FALLTHROUGH */
8360Sstevel@tonic-gate 		case USB_EP_ATTR_BULK:
8370Sstevel@tonic-gate 			/*
8380Sstevel@tonic-gate 			 * Call ehci_sendup_qtd_message
8390Sstevel@tonic-gate 			 * to send message to upstream.
8400Sstevel@tonic-gate 			 */
8410Sstevel@tonic-gate 			ehci_sendup_qtd_message(ehcip, pp, tw, qtd, error);
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 			return;
8440Sstevel@tonic-gate 		case USB_EP_ATTR_INTR:
8450Sstevel@tonic-gate 			curr_intr_reqp =
8460Sstevel@tonic-gate 			    (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 			if (curr_intr_reqp->intr_attributes &
8490Sstevel@tonic-gate 			    USB_ATTRS_ONE_XFER) {
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 				ehci_handle_one_xfer_completion(ehcip, tw);
8520Sstevel@tonic-gate 			}
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 			/* Decrement periodic in request count */
8550Sstevel@tonic-gate 			pp->pp_cur_periodic_req_cnt--;
8560Sstevel@tonic-gate 			break;
8570Sstevel@tonic-gate 		case USB_EP_ATTR_ISOCH:
8580Sstevel@tonic-gate 			break;
8590Sstevel@tonic-gate 		}
8600Sstevel@tonic-gate 	}
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	ehci_hcdi_callback(ph, tw, error);
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	/* Check anybody is waiting for transfers completion event */
8650Sstevel@tonic-gate 	ehci_check_for_transfers_completion(ehcip, pp);
8660Sstevel@tonic-gate }
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate /*
8690Sstevel@tonic-gate  * ehci_cleanup_data_underrun:
8700Sstevel@tonic-gate  *
8710Sstevel@tonic-gate  * Cleans up resources when a short xfer occurs.  Will only do cleanup if
8720Sstevel@tonic-gate  * this pipe supports alternate_qtds.
8730Sstevel@tonic-gate  *
8740Sstevel@tonic-gate  * NOTE: This function is also called from POLLED MODE.
8750Sstevel@tonic-gate  */
8760Sstevel@tonic-gate static void
ehci_cleanup_data_underrun(ehci_state_t * ehcip,ehci_trans_wrapper_t * tw,ehci_qtd_t * qtd)8770Sstevel@tonic-gate ehci_cleanup_data_underrun(
8780Sstevel@tonic-gate 	ehci_state_t		*ehcip,
8790Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
8800Sstevel@tonic-gate 	ehci_qtd_t		*qtd)
8810Sstevel@tonic-gate {
8820Sstevel@tonic-gate 	ehci_qtd_t		*next_qtd, *temp_qtd;
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
885*6898Sfb209375 	    "ehci_cleanup_data_underrun: qtd=0x%p, tw=0x%p",
886*6898Sfb209375 	    (void *)qtd, (void *)tw);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	/*
8890Sstevel@tonic-gate 	 * Check if this transfer doesn't supports short_xfer or
8900Sstevel@tonic-gate 	 * if this QTD is the last qtd in the tw.  If so there is
8910Sstevel@tonic-gate 	 * no need for cleanup.
8920Sstevel@tonic-gate 	 */
8930Sstevel@tonic-gate 	if ((tw->tw_alt_qtd == NULL) || (qtd == tw->tw_qtd_tail)) {
8940Sstevel@tonic-gate 		/* There is no need for cleanup */
8950Sstevel@tonic-gate 		return;
8960Sstevel@tonic-gate 	}
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	/* Start removing all the unused QTDs from the TW */
8990Sstevel@tonic-gate 	next_qtd = (ehci_qtd_t *)ehci_qtd_iommu_to_cpu(ehcip,
9000Sstevel@tonic-gate 	    Get_QTD(qtd->qtd_tw_next_qtd));
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	while (next_qtd) {
9030Sstevel@tonic-gate 		tw->tw_num_qtds--;
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 		ehci_remove_qtd_from_active_qtd_list(ehcip, next_qtd);
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 		temp_qtd = next_qtd;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 		next_qtd = ehci_qtd_iommu_to_cpu(ehcip,
9100Sstevel@tonic-gate 		    Get_QTD(next_qtd->qtd_tw_next_qtd));
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 		ehci_deallocate_qtd(ehcip, temp_qtd);
9130Sstevel@tonic-gate 	}
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	ASSERT(tw->tw_num_qtds == 1);
9160Sstevel@tonic-gate }
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate /*
9190Sstevel@tonic-gate  * ehci_handle_normal_qtd:
9200Sstevel@tonic-gate  */
9210Sstevel@tonic-gate static void
ehci_handle_normal_qtd(ehci_state_t * ehcip,ehci_qtd_t * qtd,ehci_trans_wrapper_t * tw)9220Sstevel@tonic-gate ehci_handle_normal_qtd(
9230Sstevel@tonic-gate 	ehci_state_t		*ehcip,
9240Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
9250Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw)
9260Sstevel@tonic-gate {
9270Sstevel@tonic-gate 	ehci_pipe_private_t	*pp;	/* Pipe private field */
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
9300Sstevel@tonic-gate 	    "ehci_handle_normal_qtd:");
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
9330Sstevel@tonic-gate 	ASSERT(tw != NULL);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	/* Obtain the pipe private structure */
9360Sstevel@tonic-gate 	pp = tw->tw_pipe_private;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	(*tw->tw_handle_qtd)(ehcip, pp, tw,
9390Sstevel@tonic-gate 	    qtd, tw->tw_handle_callback_value);
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	/* Check anybody is waiting for transfers completion event */
9420Sstevel@tonic-gate 	ehci_check_for_transfers_completion(ehcip, pp);
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate /*
9470Sstevel@tonic-gate  * ehci_handle_ctrl_qtd:
9480Sstevel@tonic-gate  *
9490Sstevel@tonic-gate  * Handle a control Transfer Descriptor (QTD).
9500Sstevel@tonic-gate  */
9510Sstevel@tonic-gate /* ARGSUSED */
9520Sstevel@tonic-gate void
ehci_handle_ctrl_qtd(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_trans_wrapper_t * tw,ehci_qtd_t * qtd,void * tw_handle_callback_value)9530Sstevel@tonic-gate ehci_handle_ctrl_qtd(
9540Sstevel@tonic-gate 	ehci_state_t		*ehcip,
9550Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
9560Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
9570Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
9580Sstevel@tonic-gate 	void			*tw_handle_callback_value)
9590Sstevel@tonic-gate {
9600Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
9630Sstevel@tonic-gate 	    "ehci_handle_ctrl_qtd: pp = 0x%p tw = 0x%p qtd = 0x%p state = 0x%x",
9640Sstevel@tonic-gate 	    (void *)pp, (void *)tw, (void *)qtd, Get_QTD(qtd->qtd_ctrl_phase));
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	/*
9690Sstevel@tonic-gate 	 * A control transfer consists of three phases:
9700Sstevel@tonic-gate 	 *
9710Sstevel@tonic-gate 	 * Setup
9720Sstevel@tonic-gate 	 * Data (optional)
9730Sstevel@tonic-gate 	 * Status
9740Sstevel@tonic-gate 	 *
9750Sstevel@tonic-gate 	 * There is a QTD per phase. A QTD for a given phase isn't
9760Sstevel@tonic-gate 	 * enqueued until the previous phase is finished. EHCI
9770Sstevel@tonic-gate 	 * spec allows more than one  control transfer on a pipe
9780Sstevel@tonic-gate 	 * within a frame. However, we've found that some devices
9790Sstevel@tonic-gate 	 * can't handle this.
9800Sstevel@tonic-gate 	 */
9810Sstevel@tonic-gate 	tw->tw_num_qtds--;
9820Sstevel@tonic-gate 	switch (Get_QTD(qtd->qtd_ctrl_phase)) {
9830Sstevel@tonic-gate 	case EHCI_CTRL_SETUP_PHASE:
9840Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
9850Sstevel@tonic-gate 		    "Setup complete: pp 0x%p qtd 0x%p",
9860Sstevel@tonic-gate 		    (void *)pp, (void *)qtd);
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 		break;
9890Sstevel@tonic-gate 	case EHCI_CTRL_DATA_PHASE:
9900Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
9910Sstevel@tonic-gate 		    "Data complete: pp 0x%p qtd 0x%p",
9920Sstevel@tonic-gate 		    (void *)pp, (void *)qtd);
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 		break;
9950Sstevel@tonic-gate 	case EHCI_CTRL_STATUS_PHASE:
9965100Ssl147100 		/*
9975100Ssl147100 		 * On some particular hardware, status phase is seen to
9985100Ssl147100 		 * finish before data phase gets timeouted. Don't handle
9995100Ssl147100 		 * the transfer result here if not all qtds are finished.
10005100Ssl147100 		 * Let the timeout handler handle it.
10015100Ssl147100 		 */
10025100Ssl147100 		if (tw->tw_num_qtds != 0) {
10035100Ssl147100 			USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
10045100Ssl147100 			    "Status complete, but the transfer is not done: "
10055100Ssl147100 			    "tw 0x%p, qtd 0x%p, tw_num_qtd 0x%d",
10065100Ssl147100 			    (void *)tw, (void *)qtd, tw->tw_num_qtds);
10075100Ssl147100 
10085100Ssl147100 			ehci_print_qh(ehcip, pp->pp_qh);
10095100Ssl147100 			ehci_print_qtd(ehcip, qtd);
10105100Ssl147100 
10115100Ssl147100 			break;
10125100Ssl147100 		}
10135100Ssl147100 
10140Sstevel@tonic-gate 		if ((tw->tw_length) &&
10150Sstevel@tonic-gate 		    (tw->tw_direction == EHCI_QTD_CTRL_IN_PID)) {
10160Sstevel@tonic-gate 			/*
10170Sstevel@tonic-gate 			 * Call ehci_sendup_qtd_message
10180Sstevel@tonic-gate 			 * to send message to upstream.
10190Sstevel@tonic-gate 			 */
10200Sstevel@tonic-gate 			ehci_sendup_qtd_message(ehcip,
10210Sstevel@tonic-gate 			    pp, tw, qtd, USB_CR_OK);
10220Sstevel@tonic-gate 		} else {
10230Sstevel@tonic-gate 			ehci_hcdi_callback(ph, tw, USB_CR_OK);
10240Sstevel@tonic-gate 		}
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
10270Sstevel@tonic-gate 		    "Status complete: pp 0x%p qtd 0x%p",
10280Sstevel@tonic-gate 		    (void *)pp, (void *)qtd);
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 		break;
10310Sstevel@tonic-gate 	}
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate /*
10360Sstevel@tonic-gate  * ehci_handle_bulk_qtd:
10370Sstevel@tonic-gate  *
10380Sstevel@tonic-gate  * Handle a bulk Transfer Descriptor (QTD).
10390Sstevel@tonic-gate  */
10400Sstevel@tonic-gate /* ARGSUSED */
10410Sstevel@tonic-gate void
ehci_handle_bulk_qtd(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_trans_wrapper_t * tw,ehci_qtd_t * qtd,void * tw_handle_callback_value)10420Sstevel@tonic-gate ehci_handle_bulk_qtd(
10430Sstevel@tonic-gate 	ehci_state_t		*ehcip,
10440Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
10450Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
10460Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
10470Sstevel@tonic-gate 	void			*tw_handle_callback_value)
10480Sstevel@tonic-gate {
10490Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
10500Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
10530Sstevel@tonic-gate 	    "ehci_handle_bulk_qtd:");
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	/*
10580Sstevel@tonic-gate 	 * Decrement the QTDs counter and check whether all the bulk
10590Sstevel@tonic-gate 	 * data has been send or received. If QTDs counter reaches
10600Sstevel@tonic-gate 	 * zero then inform client driver about completion current
10610Sstevel@tonic-gate 	 * bulk request. Other wise wait for completion of other bulk
10620Sstevel@tonic-gate 	 * QTDs or transactions on this pipe.
10630Sstevel@tonic-gate 	 */
10640Sstevel@tonic-gate 	if (--tw->tw_num_qtds != 0) {
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
10670Sstevel@tonic-gate 		    "ehci_handle_bulk_qtd: Number of QTDs %d", tw->tw_num_qtds);
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 		return;
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	/*
10730Sstevel@tonic-gate 	 * If this is a bulk in pipe, return the data to the client.
10740Sstevel@tonic-gate 	 * For a bulk out pipe, there is no need to do anything.
10750Sstevel@tonic-gate 	 */
10760Sstevel@tonic-gate 	if ((eptd->bEndpointAddress &
10770Sstevel@tonic-gate 	    USB_EP_DIR_MASK) == USB_EP_DIR_OUT) {
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
10800Sstevel@tonic-gate 		    "ehci_handle_bulk_qtd: Bulk out pipe");
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 		/* Do the callback */
10830Sstevel@tonic-gate 		ehci_hcdi_callback(ph, tw, USB_CR_OK);
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 		return;
10860Sstevel@tonic-gate 	}
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	/* Call ehci_sendup_qtd_message to send message to upstream */
10890Sstevel@tonic-gate 	ehci_sendup_qtd_message(ehcip, pp, tw, qtd, USB_CR_OK);
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate /*
10940Sstevel@tonic-gate  * ehci_handle_intr_qtd:
10950Sstevel@tonic-gate  *
10960Sstevel@tonic-gate  * Handle a interrupt Transfer Descriptor (QTD).
10970Sstevel@tonic-gate  */
10980Sstevel@tonic-gate /* ARGSUSED */
10990Sstevel@tonic-gate void
ehci_handle_intr_qtd(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_trans_wrapper_t * tw,ehci_qtd_t * qtd,void * tw_handle_callback_value)11000Sstevel@tonic-gate ehci_handle_intr_qtd(
11010Sstevel@tonic-gate 	ehci_state_t		*ehcip,
11020Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
11030Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
11040Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
11050Sstevel@tonic-gate 	void			*tw_handle_callback_value)
11060Sstevel@tonic-gate {
11070Sstevel@tonic-gate 	usb_intr_req_t		*curr_intr_reqp =
11085100Ssl147100 	    (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
11090Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
11100Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &ph->p_ep;
11110Sstevel@tonic-gate 	usb_req_attrs_t		attrs;
11120Sstevel@tonic-gate 	int			error = USB_SUCCESS;
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
11150Sstevel@tonic-gate 	    "ehci_handle_intr_qtd:");
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	/* Get the interrupt xfer attributes */
11200Sstevel@tonic-gate 	attrs = curr_intr_reqp->intr_attributes;
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	/*
11230Sstevel@tonic-gate 	 * For a Interrupt OUT pipe, we just callback and we are done
11240Sstevel@tonic-gate 	 */
11250Sstevel@tonic-gate 	if ((eptd->bEndpointAddress & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) {
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
11280Sstevel@tonic-gate 		    "ehci_handle_intr_qtd: Intr out pipe, intr_reqp=0x%p,"
1129*6898Sfb209375 		    "data=0x%p", (void *)curr_intr_reqp,
1130*6898Sfb209375 		    (void *)curr_intr_reqp->intr_data);
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 		/* Do the callback */
11330Sstevel@tonic-gate 		ehci_hcdi_callback(ph, tw, USB_CR_OK);
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 		return;
11360Sstevel@tonic-gate 	}
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	/* Decrement number of interrupt request count */
11390Sstevel@tonic-gate 	pp->pp_cur_periodic_req_cnt--;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	/*
11420Sstevel@tonic-gate 	 * Check usb flag whether USB_FLAGS_ONE_XFER flag is set
11430Sstevel@tonic-gate 	 * and if so, free duplicate request.
11440Sstevel@tonic-gate 	 */
11450Sstevel@tonic-gate 	if (attrs & USB_ATTRS_ONE_XFER) {
11460Sstevel@tonic-gate 		ehci_handle_one_xfer_completion(ehcip, tw);
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	/* Call ehci_sendup_qtd_message to callback into client */
11500Sstevel@tonic-gate 	ehci_sendup_qtd_message(ehcip, pp, tw, qtd, USB_CR_OK);
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	/*
11530Sstevel@tonic-gate 	 * If interrupt pipe state is still active, insert next Interrupt
11540Sstevel@tonic-gate 	 * request into the Host Controller's Interrupt list.  Otherwise
11550Sstevel@tonic-gate 	 * you are done.
11560Sstevel@tonic-gate 	 */
11570Sstevel@tonic-gate 	if ((pp->pp_state != EHCI_PIPE_STATE_ACTIVE) ||
11580Sstevel@tonic-gate 	    (ehci_state_is_operational(ehcip) != USB_SUCCESS)) {
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 		return;
11610Sstevel@tonic-gate 	}
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	if ((error = ehci_allocate_intr_in_resource(ehcip, pp, tw, 0)) ==
11640Sstevel@tonic-gate 	    USB_SUCCESS) {
11650Sstevel@tonic-gate 		curr_intr_reqp = (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 		ASSERT(curr_intr_reqp != NULL);
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 		tw->tw_num_qtds = 1;
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 		if (ehci_allocate_tds_for_tw(ehcip, pp, tw, tw->tw_num_qtds) !=
11720Sstevel@tonic-gate 		    USB_SUCCESS) {
11730Sstevel@tonic-gate 			ehci_deallocate_intr_in_resource(ehcip, pp, tw);
11740Sstevel@tonic-gate 			error = USB_FAILURE;
11750Sstevel@tonic-gate 		}
11760Sstevel@tonic-gate 	}
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	if (error != USB_SUCCESS) {
11790Sstevel@tonic-gate 		/*
11800Sstevel@tonic-gate 		 * Set pipe state to stop polling and error to no
11810Sstevel@tonic-gate 		 * resource. Don't insert any more interrupt polling
11820Sstevel@tonic-gate 		 * requests.
11830Sstevel@tonic-gate 		 */
11840Sstevel@tonic-gate 		pp->pp_state = EHCI_PIPE_STATE_STOP_POLLING;
11850Sstevel@tonic-gate 		pp->pp_error = USB_CR_NO_RESOURCES;
11860Sstevel@tonic-gate 	} else {
11870Sstevel@tonic-gate 		ehci_insert_intr_req(ehcip, pp, tw, 0);
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 		/* Increment number of interrupt request count */
11900Sstevel@tonic-gate 		pp->pp_cur_periodic_req_cnt++;
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 		ASSERT(pp->pp_cur_periodic_req_cnt ==
11930Sstevel@tonic-gate 		    pp->pp_max_periodic_req_cnt);
11940Sstevel@tonic-gate 	}
11950Sstevel@tonic-gate }
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate /*
11990Sstevel@tonic-gate  * ehci_handle_one_xfer_completion:
12000Sstevel@tonic-gate  */
12010Sstevel@tonic-gate static void
ehci_handle_one_xfer_completion(ehci_state_t * ehcip,ehci_trans_wrapper_t * tw)12020Sstevel@tonic-gate ehci_handle_one_xfer_completion(
12030Sstevel@tonic-gate 	ehci_state_t		*ehcip,
12040Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw)
12050Sstevel@tonic-gate {
12060Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = tw->tw_pipe_private->pp_pipe_handle;
12070Sstevel@tonic-gate 	ehci_pipe_private_t	*pp = tw->tw_pipe_private;
12080Sstevel@tonic-gate 	usb_intr_req_t		*curr_intr_reqp =
12095100Ssl147100 	    (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
1212*6898Sfb209375 	    "ehci_handle_one_xfer_completion: tw = 0x%p", (void *)tw);
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
12150Sstevel@tonic-gate 	ASSERT(curr_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER);
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	pp->pp_state = EHCI_PIPE_STATE_IDLE;
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	/*
12200Sstevel@tonic-gate 	 * For one xfer, we need to copy back data ptr
12210Sstevel@tonic-gate 	 * and free current request
12220Sstevel@tonic-gate 	 */
12230Sstevel@tonic-gate 	((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))->
12240Sstevel@tonic-gate 	    intr_data = ((usb_intr_req_t *)
12250Sstevel@tonic-gate 	    (tw->tw_curr_xfer_reqp))->intr_data;
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	/* Now free duplicate current request */
12300Sstevel@tonic-gate 	usb_free_intr_req((usb_intr_req_t *)tw-> tw_curr_xfer_reqp);
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	mutex_enter(&ph->p_mutex);
12330Sstevel@tonic-gate 	ph->p_req_count--;
12340Sstevel@tonic-gate 	mutex_exit(&ph->p_mutex);
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	/* Make client's request the current request */
12370Sstevel@tonic-gate 	tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
12380Sstevel@tonic-gate 	pp->pp_client_periodic_in_reqp = NULL;
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate /*
12430Sstevel@tonic-gate  * ehci_sendup_qtd_message:
12440Sstevel@tonic-gate  *	copy data, if necessary and do callback
12450Sstevel@tonic-gate  */
12460Sstevel@tonic-gate /* ARGSUSED */
12470Sstevel@tonic-gate static void
ehci_sendup_qtd_message(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_trans_wrapper_t * tw,ehci_qtd_t * qtd,usb_cr_t error)12480Sstevel@tonic-gate ehci_sendup_qtd_message(
12490Sstevel@tonic-gate 	ehci_state_t		*ehcip,
12500Sstevel@tonic-gate 	ehci_pipe_private_t	*pp,
12510Sstevel@tonic-gate 	ehci_trans_wrapper_t	*tw,
12520Sstevel@tonic-gate 	ehci_qtd_t		*qtd,
12530Sstevel@tonic-gate 	usb_cr_t		error)
12540Sstevel@tonic-gate {
12550Sstevel@tonic-gate 	usb_ep_descr_t		*eptd = &pp->pp_pipe_handle->p_ep;
12560Sstevel@tonic-gate 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
12570Sstevel@tonic-gate 	usb_opaque_t		curr_xfer_reqp = tw->tw_curr_xfer_reqp;
12580Sstevel@tonic-gate 	size_t			skip_len = 0;
12590Sstevel@tonic-gate 	size_t			length;
12600Sstevel@tonic-gate 	uchar_t			*buf;
12610Sstevel@tonic-gate 	mblk_t			*mp;
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
12660Sstevel@tonic-gate 	    "ehci_sendup_qtd_message:");
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	ASSERT(tw != NULL);
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	length = tw->tw_length;
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	if ((eptd->bmAttributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_CONTROL) {
12730Sstevel@tonic-gate 		/* Get the correct length */
12741500Ssl147100 		if (((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_wLength)
12751500Ssl147100 			length = length - EHCI_MAX_QTD_BUF_SIZE;
12761500Ssl147100 		else
12771500Ssl147100 			length = length - SETUP_SIZE;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 		/* Set the length of the buffer to skip */
12801500Ssl147100 		skip_len = EHCI_MAX_QTD_BUF_SIZE;
12810Sstevel@tonic-gate 	}
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	/* Copy the data into the mblk_t */
12840Sstevel@tonic-gate 	buf = (uchar_t *)tw->tw_buf + skip_len;
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
12870Sstevel@tonic-gate 	    "ehci_sendup_qtd_message: length %ld error %d", length, error);
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	/* Get the message block */
12900Sstevel@tonic-gate 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
12910Sstevel@tonic-gate 	case USB_EP_ATTR_CONTROL:
12920Sstevel@tonic-gate 		mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data;
12930Sstevel@tonic-gate 		break;
12940Sstevel@tonic-gate 	case USB_EP_ATTR_BULK:
12950Sstevel@tonic-gate 		mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data;
12960Sstevel@tonic-gate 		break;
12970Sstevel@tonic-gate 	case USB_EP_ATTR_INTR:
12980Sstevel@tonic-gate 		mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data;
12990Sstevel@tonic-gate 		break;
13000Sstevel@tonic-gate 	case USB_EP_ATTR_ISOCH:
13010Sstevel@tonic-gate 		/* Isoc messages must not go through this path */
13020Sstevel@tonic-gate 		mp = NULL;
13030Sstevel@tonic-gate 		break;
13040Sstevel@tonic-gate 	}
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 	ASSERT(mp != NULL);
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	if (length) {
13090Sstevel@tonic-gate 		/*
13100Sstevel@tonic-gate 		 * Update kstat byte counts
13110Sstevel@tonic-gate 		 * The control endpoints don't have direction bits so in
13120Sstevel@tonic-gate 		 * order for control stats to be counted correctly an in
13130Sstevel@tonic-gate 		 * bit must be faked on a control read.
13140Sstevel@tonic-gate 		 */
13150Sstevel@tonic-gate 		if ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
13160Sstevel@tonic-gate 		    USB_EP_ATTR_CONTROL) {
13170Sstevel@tonic-gate 			ehci_do_byte_stats(ehcip, length,
13180Sstevel@tonic-gate 			    eptd->bmAttributes, USB_EP_DIR_IN);
13190Sstevel@tonic-gate 		} else {
13200Sstevel@tonic-gate 			ehci_do_byte_stats(ehcip, length,
13210Sstevel@tonic-gate 			    eptd->bmAttributes, eptd->bEndpointAddress);
13220Sstevel@tonic-gate 		}
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 		/* Sync IO buffer */
13251500Ssl147100 		Sync_IO_Buffer(tw->tw_dmahandle, (skip_len + length));
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 		/* since we specified NEVERSWAP, we can just use bcopy */
13280Sstevel@tonic-gate 		bcopy(buf, mp->b_rptr, length);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 		/* Increment the write pointer */
13310Sstevel@tonic-gate 		mp->b_wptr = mp->b_wptr + length;
13320Sstevel@tonic-gate 	} else {
13330Sstevel@tonic-gate 		USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
13340Sstevel@tonic-gate 		    "ehci_sendup_qtd_message: Zero length packet");
13350Sstevel@tonic-gate 	}
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	ehci_hcdi_callback(ph, tw, error);
13380Sstevel@tonic-gate }
1339