Beispiel #1
0
/* For preop search we do two things:
 * 1) based on the search base, we preselect the acls.
 * 2) also get hold of a acl_pblock for use 
 */
static int
aclplugin_preop_search ( Slapi_PBlock *pb )
{
	int 		scope;
	const char	*base = NULL;
	Slapi_DN	*sdn = NULL;
	int			optype;
	int			isRoot;
	int			isProxy = 0;
	int			rc = 0;
	char *errtxt = NULL;
	char *proxy_dn = NULL;
			
	TNF_PROBE_0_DEBUG(aclplugin_preop_search_start ,"ACL","");

	slapi_pblock_get ( pb, SLAPI_OPERATION_TYPE, &optype );
	slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );

	if (LDAP_SUCCESS == proxyauth_get_dn(pb, &proxy_dn, &errtxt) && proxy_dn) {
		isProxy = 1;
	}
	slapi_ch_free_string(&proxy_dn);

	if ( isRoot && !isProxy) {
		TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
							tnf_string,isroot,"");
		return rc;
	}

	slapi_pblock_get( pb, SLAPI_SEARCH_TARGET_SDN, &sdn );
	base = slapi_sdn_get_dn(sdn);
	/* For anonymous client  doing search nothing needs to be set up */
	if ( optype == SLAPI_OPERATION_SEARCH && aclanom_is_client_anonymous ( pb )  &&
			! slapi_dn_issuffix( base, "cn=monitor") ) {
				TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
									tnf_string,anon,"");
		return rc;
	}

	if ( 0 == ( rc = aclplugin_preop_common( pb ))) {
		slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
		acllist_init_scan ( pb, scope, base );
	}

	TNF_PROBE_0_DEBUG(aclplugin_preop_search_end ,"ACL","");

	return rc;
}
Beispiel #2
0
/*
 * nx1394_dma_allochdl()
 *    Merges the ddi_dma_attr_t passed in by the target (using
 *    ddi_dma_alloc_handle() call) with that of the hal and passes the alloc
 *    handle request up the device by calling ddi_dma_allochdl().
 */
static int
nx1394_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
    int (*waitfnp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
{
	s1394_hal_t *hal;
	ddi_dma_attr_t *hal_attr;
	int status;

	_NOTE(SCHEME_PROTECTS_DATA("unique (per thread)", ddi_dma_attr_t))

	TNF_PROBE_0_DEBUG(nx1394_dma_allochdl_enter, S1394_TNF_SL_NEXUS_STACK,
	    "");

	/*
	 * If hal calls ddi_dma_alloc_handle, dip == rdip == hal dip.
	 * Unfortunately, we cannot verify this (by way of looking up for hal
	 * dip) here because h1394_attach() may happen much later.
	 */
	if (dip != rdip) {
		hal = s1394_dip_to_hal(ddi_get_parent(rdip));
		ASSERT(hal);
		hal_attr = &hal->halinfo.dma_attr;
		ASSERT(hal_attr);
		ddi_dma_attr_merge(attr, hal_attr);
	}
	status = ddi_dma_allochdl(dip, rdip, attr, waitfnp, arg, handlep);
	TNF_PROBE_1_DEBUG(nx1394_dma_allochdl_exit, S1394_TNF_SL_NEXUS_STACK,
	    "", tnf_int, status, status);
	return (status);
}
/*
 * tavor_srq_refcnt_dec()
 *    Context: Can be called from interrupt or base context.
 */
void
tavor_srq_refcnt_dec(tavor_srqhdl_t srq)
{
	mutex_enter(&srq->srq_lock);
	srq->srq_refcnt--;
	TNF_PROBE_1_DEBUG(tavor_srq_refcnt_dec, TAVOR_TNF_TRACE, "",
	    tnf_uint, refcnt, srq->srq_refcnt);
	mutex_exit(&srq->srq_lock);
}
Beispiel #4
0
/*
 * nx1394_get_event_cookie()
 *    Called when a child node calls ddi_get_eventcookie().
 *    Returns event cookie corresponding to event "name".
 */
static int
nx1394_get_event_cookie(dev_info_t *dip, dev_info_t *rdip, char *name,
    ddi_eventcookie_t *event_cookiep)
{
	int ret;
	s1394_hal_t *hal;

	TNF_PROBE_1_DEBUG(nx1394_get_event_cookie_enter,
	    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, name, name);

	hal = s1394_dip_to_hal(dip);
	ASSERT(hal);

	ret = ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl,
	    rdip, name, event_cookiep, 0);

	TNF_PROBE_4_DEBUG(nx1394_get_event_cookie_exit,
	    S1394_TNF_SL_NEXUS_STACK, "", tnf_opaque, parent_dip, (void *)dip,
	    tnf_opaque, requestor_dip, (void *)rdip, tnf_string, event_name,
	    name, tnf_int, request_status, ret);

	return (ret);

}
Beispiel #5
0
/*
 * dhcp_lookup_dd_classify: perform lookup_dd(), or use existing records
 * if supplied, and classify the results based on the type of search criteria
 * being employed. Centralized policy for DN_FMANUAL and DN_FUNUSABLE flag
 * processing are implemented here. Classification is specialized
 * based on these specific search criteria:
 *
 *	S_CID		A CID match is requested. Perform DN_FMANUAL and
 *			DN_FUNUSABLE processing.
 *	S_FREE		A search for free records. Only examine first
 *			matching record.
 *	S_LRU		A search for lru records. Perform sort if needed,
 *			and only examine first matching record.
 *
 * A matching record is detached and returned if found (ok ||
 * manual + unusable). Other successful matches are returned in recordsp as
 * a cache.
 */
void *
dhcp_lookup_dd_classify(dsvc_dnet_t *pnd, boolean_t partial, uint_t query,
    int count, const dn_rec_t *targetp, void **recordsp, int searchtype)
{
	int		err;
	uint_t		rec_cnt = 0, manual = 0;
	dn_rec_t	*dnp;
	dn_rec_list_t	*nlp = NULL, *dnlp = NULL;
	dn_rec_list_t	*unulp = NULL;		/* list of unusables, !manual */
	dn_rec_list_t	*unu_m_lp = NULL;	/* list of unusable + manual */
	dn_rec_list_t	*m_lp = NULL;		/* list of manual records */
	dn_rec_list_t	*cachep = NULL;		/* match cache */
	struct in_addr	swapaddr;
	char		ntoab[INET_ADDRSTRLEN];

	/*
	 * Lookup records matching the specified criteria, or use
	 * records from a previous lookup supplied for classification.
	 */
	if (*recordsp == NULL) {

		TNF_PROBE_1_DEBUG(classify, "classify classify",
		    "classify_query%debug 'in func classify'",
		    tnf_long, query, query);

		err = dhcp_lookup_dd(pnd->dh, partial, query, count, targetp,
		    (void **)recordsp, &rec_cnt);

		TNF_PROBE_1_DEBUG(classify_cid_end, "classify classify_end",
		    "classify_end%debug 'in func classify'",
		    tnf_long, rec_cnt, rec_cnt);

		/*
		 * If any error occurs, mark the dsvc_dnet_t table
		 * for immediate close and reopen. Let the protocol
		 * perform recover, rather than attempting time-consuming
		 * in-place error recovery.
		 */
		if (err != DSVC_SUCCESS) {
			(void) mutex_lock(&pnd->pnd_mtx);
			pnd->flags |= DHCP_PND_ERROR;
			hash_Dtime(pnd->hand, 0);
			(void) mutex_unlock(&pnd->pnd_mtx);
#ifdef	DEBUG
			dhcpmsg(LOG_DEBUG, "classify failure %s\n",
				dhcpsvc_errmsg(err));
#endif	/* DEBUG */
			*recordsp = NULL;
			return (NULL);
		}

		/*
		 * For LRU classification, sort returned records based
		 * on dn_lease field. Discards records with valid lease
		 * times; adjusts rec_cnt accordingly.
		 */
		if (searchtype & S_LRU)
			*recordsp = get_lrusort(pnd, *recordsp, &rec_cnt);

	}

	/*
	 * Record classification: scan through all records, performing
	 * DN_FUNUSABLE and DN_FMANUAL processing. Note that most of the
	 * work has been performed by the datastore query. Remove the matching
	 * entry from the singlely-linked record list, for return. Free any
	 * non-matching entries prior to the match. Pass back any additional
	 * entries after the match in the recordsp pointer for possible re-use
	 * by the caching code.
	 */

	for (nlp = detach_dnrec_from_list(NULL, *recordsp,
	    (dn_rec_list_t **)recordsp); nlp != NULL;
	    nlp = detach_dnrec_from_list(NULL, *recordsp,
	    (dn_rec_list_t **)recordsp)) {
		/*
		 * If we find that there is a DN_FMANUAL entry that is
		 * DN_FUNUSABLE, we fail the request, when performing a
		 * CID search, even though there may be other CID matches. In
		 * the CID case, those other CID matches are errors, because
		 * there should be one and only one record for a client if that
		 * record is marked as being DN_FMANUALly assigned. We tell
		 * the user how many of those CID matches there are. If there
		 * are no DN_FMANUAL records, the first matching record which
		 * is USABLE wins.
		 */
		dnp = nlp->dnl_rec;
		if (dnp->dn_flags & DN_FUNUSABLE) {
			if ((searchtype & (S_CID|S_FREE|S_LRU)) == S_CID) {
				char	cidbuf[DHCP_MAX_OPT_SIZE];
				uint_t	blen = sizeof (cidbuf);

				(void) octet_to_hexascii(targetp->dn_cid,
				    targetp->dn_cid_len,
				    cidbuf, &blen);

				swapaddr.s_addr = htonl(dnp->dn_cip.s_addr);

				dhcpmsg(LOG_NOTICE, "(%1$s,%2$s) "
				    "currently marked as unusable.\n", cidbuf,
				    inet_ntop(AF_INET, &swapaddr, ntoab,
				    sizeof (ntoab)));
			}

			/* build list of unusable records */
			if (dnp->dn_flags & DN_FMANUAL) {
				attach_dnrec_to_list(nlp, &unu_m_lp);
				manual++;
			} else
				attach_dnrec_to_list(nlp, &unulp);
		} else {
			if (dnp->dn_flags & DN_FMANUAL) {
				attach_dnrec_to_list(nlp, &m_lp);
				manual++;
			} else
				attach_dnrec_to_list(nlp, &cachep);
			/*
			 * These searches do not require examining all
			 * matches.
			 */
			if (searchtype & (S_FREE|S_LRU))
				break;
		}
	}

	/*
	 * Warnings are printed for CID searches which end with
	 * DN_FUNUSABLE|DN_FMANUAL match(es).
	 */
	if (m_lp != NULL || unu_m_lp != NULL) {
		if (manual > 1) {
			char	cidbuf[DHCP_MAX_OPT_SIZE];
			uint_t	blen = sizeof (cidbuf);

			(void) octet_to_hexascii(targetp->dn_cid,
				targetp->dn_cid_len,
				cidbuf, &blen);
			dhcpmsg(LOG_WARNING,
			    "Manual allocation (%1$s) has %2$d other MANUAL"
			    " records. It should have 0.\n", cidbuf,
			    manual - 1);
		}
		if (unu_m_lp != NULL) {
			dnlp = detach_dnrec_from_list(NULL, unu_m_lp,
			    &unu_m_lp);
		} else
			dnlp = detach_dnrec_from_list(NULL, m_lp, &m_lp);
	}

	/* Free any unusable entries */
	if (unulp != NULL)
		dhcp_free_dd_list(pnd->dh, unulp);

	/* any other... */
	if (dnlp == NULL)
		dnlp = detach_dnrec_from_list(NULL, cachep, &cachep);

	/*
	 * Return any unused elements for possible caching use. These are
	 * the  additional manual + unusable (as punishment for having
	 * multiple items), manual, and and any others.
	 */
	if (cachep != NULL)
		attach_dnrec_to_list(cachep, (dn_rec_list_t **)recordsp);
	if (m_lp != NULL)
		attach_dnrec_to_list(m_lp, (dn_rec_list_t **)recordsp);
	if (unu_m_lp != NULL)
		attach_dnrec_to_list(unu_m_lp, (dn_rec_list_t **)recordsp);

	/*
	 * Return one of the matching record(s).
	 */
	return (dnlp);
}
Beispiel #6
0
/*
 * Common function that is called by aclplugin_preop_search() and
 * aclplugin_preop_modify().
 *
 * Return values:
 *	0 - all is well; proceed.
 *  1 - fatal error; result has been sent to client.
 */ 
int
aclplugin_preop_common( Slapi_PBlock *pb )
{
	char		*proxy_dn = NULL;	/* id being assumed */
	char		*dn;		/* proxy master */
	char		*errtext = NULL;
	int			lderr;
	Acl_PBlock	*aclpb;

	TNF_PROBE_0_DEBUG(aclplugin_preop_common_start ,"ACL","");

	aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );

	if (aclpb == NULL) {
		slapi_log_err(SLAPI_LOG_ACL, plugin_name, "aclplugin_preop_common - Error: aclpb is NULL\n" );
		slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
		return 1;
	}

        /* See if we have initialized already */
        if ( aclpb->aclpb_state & ACLPB_INITIALIZED ) goto done;

	/*
	 * The following mallocs memory for proxy_dn, but not the dn.
	 * The proxy_dn is the id being assumed, while dn
	 * is the "proxy master".
	*/
	if ( LDAP_SUCCESS != ( lderr = proxyauth_get_dn( pb, &proxy_dn, &errtext ))) {
		/*
		 * Fatal error -- send a result to the client and arrange to skip
		 * any further processing.
		 */
		slapi_send_ldap_result( pb, lderr, NULL, errtext, 0, NULL );
		TNF_PROBE_1_DEBUG(aclplugin_preop_common_end ,"ACL","",
						tnf_string,proxid_error,"");
		slapi_ch_free_string(&proxy_dn);
		return 1;	/* skip any further processing */
	}
	slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &dn );


	/*
	 * The dn is copied into the aclpb during initialization.
	*/
	if ( proxy_dn) {
		TNF_PROBE_0_DEBUG(proxyacpb_init_start,"ACL","");

		slapi_log_err(SLAPI_LOG_ACL, plugin_name,
				"aclplugin_preop_common - Proxied authorization dn is (%s)\n", proxy_dn );
		acl_init_aclpb ( pb, aclpb, proxy_dn, 1 );
		aclpb = acl_new_proxy_aclpb ( pb );
		acl_init_aclpb ( pb, aclpb, dn, 0 );
		slapi_ch_free ( (void **) &proxy_dn );
		
		TNF_PROBE_0_DEBUG(proxyacpb_init_end,"ACL","");
 
	} else {
		TNF_PROBE_0_DEBUG(aclpb_init_start,"ACL","");
		acl_init_aclpb ( pb, aclpb, dn, 1 );
		TNF_PROBE_0_DEBUG(aclpb_init_end,"ACL","");

	}

done:
	TNF_PROBE_0_DEBUG(aclplugin_preop_common_end ,"ACL","");

	return 0;
}
Beispiel #7
0
/*
 * nx1394_bus_ctl()
 *    This routine implements nexus bus ctl operations. Of importance are
 *    DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD
 *    and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup
 *    reg property on the child node and builds and sets the name
 *    (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where
 *    GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit
 *    address).
 */
static int
nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
    void *result)
{
	int status;

	TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter, S1394_TNF_SL_NEXUS_STACK, "");

	switch (op) {
	case DDI_CTLOPS_REPORTDEV: {
		dev_info_t *pdip = ddi_get_parent(rdip);
		cmn_err(CE_CONT, "?%s%d at %s%d",
		    ddi_node_name(rdip), ddi_get_instance(rdip),
		    ddi_node_name(pdip), ddi_get_instance(pdip));
		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "");
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_INITCHILD: {
		dev_info_t *ocdip, *cdip = (dev_info_t *)arg;
		dev_info_t *pdip = ddi_get_parent(cdip);
		int reglen, i;
		uint32_t *regptr;
		char addr[MAXNAMELEN];

		TNF_PROBE_1(nx1394_bus_ctl_init_child,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque, dip, cdip);

		i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
		    DDI_PROP_DONTPASS, "reg", (int **)&regptr,
		    (uint_t *)&reglen);

		if (i != DDI_PROP_SUCCESS) {
			cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found",
			    ddi_node_name(cdip), ddi_get_instance(cdip));
			TNF_PROBE_2(nx1394_bus_ctl,
			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg,
			    "Reg property not found", tnf_int, reason, i);
			TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
			    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op,
			    "initchild");
			return (DDI_NOT_WELL_FORMED);
		}

		ASSERT(reglen != 0);

		/*
		 * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA]
		 */
		if (regptr[2] || regptr[3]) {
			(void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
			    regptr[1], regptr[2], regptr[3]);
		} else {
			(void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
		}
		ddi_prop_free(regptr);
		ddi_set_name_addr(cdip, addr);

		/*
		 * Check for a node with the same name & addr as the current
		 * node. If such a node exists, return failure.
		 */
		if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) !=
		    NULL && ocdip != cdip) {
			cmn_err(CE_NOTE,
			    "!%s(%d): Duplicate dev_info node found %s@%s",
			    ddi_node_name(cdip), ddi_get_instance(cdip),
			    ddi_node_name(ocdip), addr);
			TNF_PROBE_1(nx1394_bus_ctl,
			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg,
			    "Duplicate nodes");
			TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
			    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op,
			    "initchild");
			ddi_set_name_addr(cdip, NULL);
			return (DDI_NOT_WELL_FORMED);
		}

		/*
		 * If HAL (parent dip) has "active-dma-flush" property, then
		 * add property to child as well.  Workaround for active
		 * context flushing bug in Schizo rev 2.1 and 2.2.
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
		    "active-dma-flush") != 0) {
			status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
			    "active-dma-flush", 1);
			if (status != NDI_SUCCESS) {
				cmn_err(CE_NOTE, "!%s(%d): Unable to add "
				    "\"active-dma-flush\" property",
				    ddi_node_name(cdip),
				    ddi_get_instance(cdip));
				TNF_PROBE_1(nx1394_bus_ctl,
				    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string,
				    msg, "Unable to add \"active-dma-flush\" "
				    "property");
				TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
				    S1394_TNF_SL_NEXUS_STACK, "", tnf_string,
				    op, "initchild");
				ddi_set_name_addr(cdip, NULL);
				return (DDI_NOT_WELL_FORMED);
			}
		}

		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
		    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild");
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_UNINITCHILD: {
		ddi_prop_remove_all((dev_info_t *)arg);
		ddi_set_name_addr((dev_info_t *)arg, NULL);
		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "", tnf_string, op, "uninitchild");
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_IOMIN: {
		status = ddi_ctlops(dip, rdip, op, arg, result);
		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "", tnf_string, op, "iomin");
		return (status);
	}

	case DDI_CTLOPS_POWER: {
		return (DDI_SUCCESS);
	}

	/*
	 * These ops correspond to functions that "shouldn't" be called
	 * by a 1394 client driver.
	 */
	case DDI_CTLOPS_DMAPMAPC:
	case DDI_CTLOPS_REPORTINT:
	case DDI_CTLOPS_REGSIZE:
	case DDI_CTLOPS_NREGS:
	case DDI_CTLOPS_SIDDEV:
	case DDI_CTLOPS_SLAVEONLY:
	case DDI_CTLOPS_AFFINITY:
	case DDI_CTLOPS_POKE:
	case DDI_CTLOPS_PEEK: {
		cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)",
		    ddi_node_name(dip), ddi_get_instance(dip),
		    op, ddi_node_name(rdip), ddi_get_instance(rdip));
		TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "",
		    tnf_string, msg, "invalid op", tnf_int, op, op);
		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "");
		return (DDI_FAILURE);
	}

	/*
	 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
	 */
	default: {
		status = ddi_ctlops(dip, rdip, op, arg, result);
		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "");
		return (status);
	}
	}
}
/*
 * hci1394_ixl_interrupt
 *    main entry point (front-end) into interrupt processing.
 *    acquires mutex, checks if update in progress, sets flags accordingly,
 *    and calls to do real interrupt processing.
 */
void
hci1394_ixl_interrupt(hci1394_state_t *soft_statep,
    hci1394_iso_ctxt_t *ctxtp, boolean_t in_stop)
{
	uint_t	status;
	int	retcode;

	TNF_PROBE_0_DEBUG(hci1394_ixl_interrupt_enter,
	    HCI1394_TNF_HAL_STACK_ISOCH, "");

	status = 1;

	/* acquire the interrupt processing context mutex */
	mutex_enter(&ctxtp->intrprocmutex);

	/* set flag to indicate that interrupt processing is required */
	ctxtp->intr_flags |= HCI1394_ISO_CTXT_INTRSET;

	/* if update proc already in progress, let it handle intr processing */
	if (ctxtp->intr_flags & HCI1394_ISO_CTXT_INUPDATE) {
		retcode = HCI1394_IXL_INTR_INUPDATE;
		status = 0;
		TNF_PROBE_1_DEBUG(hci1394_ixl_interrupt_error,
		    HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
		    "HCI1394_IXL_INTR_INUPDATE");

	} else if (ctxtp->intr_flags & HCI1394_ISO_CTXT_ININTR) {
		/* else fatal error if inter processing already in progress */
		retcode = HCI1394_IXL_INTR_ININTR;
		status = 0;
		TNF_PROBE_1(hci1394_ixl_interrupt_error,
		    HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
		    "HCI1394_IXL_INTR_ININTR");

	} else if (ctxtp->intr_flags & HCI1394_ISO_CTXT_INCALL) {
		/* else fatal error if callback in progress flag is set */
		retcode = HCI1394_IXL_INTR_INCALL;
		status = 0;
		TNF_PROBE_1_DEBUG(hci1394_ixl_interrupt_error,
		    HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
		    "HCI1394_IXL_INTR_INCALL");
	} else if (!in_stop && (ctxtp->intr_flags & HCI1394_ISO_CTXT_STOP)) {
		/* context is being stopped */
		retcode = HCI1394_IXL_INTR_STOP;
		status = 0;
		TNF_PROBE_1_DEBUG(hci1394_ixl_interrupt_error,
		    HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
		    "HCI1394_IXL_INTR_STOP");
	}

	/*
	 * if context is available, reserve it, do interrupt processing
	 * and free it
	 */
	if (status) {
		ctxtp->intr_flags |= HCI1394_ISO_CTXT_ININTR;
		ctxtp->intr_flags &= ~HCI1394_ISO_CTXT_INTRSET;
		mutex_exit(&ctxtp->intrprocmutex);

		retcode = hci1394_ixl_dma_sync(soft_statep, ctxtp);

		mutex_enter(&ctxtp->intrprocmutex);
		ctxtp->intr_flags &= ~HCI1394_ISO_CTXT_ININTR;

		/* notify stop thread that the interrupt is finished */
		if ((ctxtp->intr_flags & HCI1394_ISO_CTXT_STOP) && !in_stop) {
			cv_signal(&ctxtp->intr_cv);
		}
	};

	/* free the intr processing context mutex before error checks */
	mutex_exit(&ctxtp->intrprocmutex);

	/* if context stopped, invoke callback */
	if (retcode == HCI1394_IXL_INTR_DMASTOP) {
		hci1394_do_stop(soft_statep, ctxtp, B_TRUE, ID1394_DONE);
	}
	/* if error, stop and invoke callback */
	if (retcode == HCI1394_IXL_INTR_DMALOST) {
		hci1394_do_stop(soft_statep, ctxtp, B_TRUE, ID1394_FAIL);
	}

	TNF_PROBE_0_DEBUG(hci1394_ixl_interrupt_exit,
	    HCI1394_TNF_HAL_STACK_ISOCH, "");
}
/*
 * hci1394_ixl_intr_check_done()
 *    checks if context has stopped, or if able to match hardware location
 *    with an expected IXL program location.
 */
static int
hci1394_ixl_intr_check_done(hci1394_state_t *soft_statep,
    hci1394_iso_ctxt_t *ctxtp)
{
	ixl1394_command_t   *ixlp;
	hci1394_xfer_ctl_t  *xferctlp;
	uint_t		    ixldepth;
	hci1394_xfer_ctl_dma_t *dma;
	ddi_acc_handle_t    acc_hdl;
	ddi_dma_handle_t    dma_hdl;
	uint32_t	    desc_status;
	hci1394_desc_t	    *hcidescp;
	off_t		    hcidesc_off;
	int		    err;
	uint32_t	    dma_cmd_cur_loc;
	uint32_t	    dma_cmd_last_loc;
	uint32_t	    dma_loc_check_enabled;
	uint32_t	    dmastartp;
	uint32_t	    dmaendp;

	uint_t		    rem_dma_skips;
	uint16_t	    skipmode;
	uint16_t	    skipdepth;
	ixl1394_command_t   *skipdestp;
	ixl1394_command_t   *skipxferp;

	TNF_PROBE_0_DEBUG(hci1394_ixl_intr_check_done_enter,
	    HCI1394_TNF_HAL_STACK_ISOCH, "");

	/*
	 * start looking through the IXL list from the xfer start command where
	 * we last left off (for composite opcodes, need to start from the
	 * appropriate depth).
	 */

	ixlp = ctxtp->ixl_execp;
	ixldepth = ctxtp->ixl_exec_depth;

	/* control struct for xfer start IXL command */
	xferctlp = (hci1394_xfer_ctl_t *)ixlp->compiler_privatep;
	dma = &xferctlp->dma[ixldepth];

	/* determine if dma location checking is enabled */
	if ((dma_loc_check_enabled =
	    (ctxtp->ctxt_flags & HCI1394_ISO_CTXT_CMDREG)) != 0) {

		/* if so, get current dma command location */
		dma_cmd_last_loc = 0xFFFFFFFF;

		while ((dma_cmd_cur_loc = HCI1394_ISOCH_CTXT_CMD_PTR(
		    soft_statep, ctxtp)) != dma_cmd_last_loc) {

			/* retry get until location register stabilizes */
			dma_cmd_last_loc = dma_cmd_cur_loc;
		}
	}

	/*
	 * compare the (bound) address of the DMA descriptor corresponding to
	 * the current xfer IXL command against the current value in the
	 * DMA location register.  If exists and if matches, then
	 *    if context stopped, return stopped, else return done.
	 *
	 * The dma start address is the first address of the descriptor block.
	 * Since "Z" is a count of 16-byte descriptors in the block, calculate
	 * the end address by adding Z*16 to the start addr.
	 */
	dmastartp = dma->dma_bound & ~DESC_Z_MASK;
	dmaendp = dmastartp + ((dma->dma_bound & DESC_Z_MASK) << 4);

	if (dma_loc_check_enabled &&
	    ((dma_cmd_cur_loc >= dmastartp) && (dma_cmd_cur_loc < dmaendp))) {

		if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0) {
			TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
			    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
			    "CHECK_STOP");
			return (IXL_CHECK_STOP);
		}

		TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
		    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
		    "CHECK_DONE");
		return (IXL_CHECK_DONE);
	}

	/*
	 * if receive mode:
	 */
	if ((ixlp->ixl_opcode & IXL1394_OPF_ONXMIT) == 0)  {
		/*
		 * if context stopped, return stopped, else,
		 * if there is no current dma location reg, return done
		 * else return location indeterminate
		 */
		if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0) {
			TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
			    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
			    "CHECK_STOP");
			return (IXL_CHECK_STOP);
		}
		if (!dma_loc_check_enabled) {
			TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
			    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
			    "CHECK_DONE");
			return (IXL_CHECK_DONE);
		}

		TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
		    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
		    "CHECK_LOST");
		return (IXL_CHECK_LOST);
	}

	/*
	 * else is xmit mode:
	 * check status of current xfer IXL command's dma descriptor
	 */
	acc_hdl  = dma->dma_buf->bi_handle;
	dma_hdl  = dma->dma_buf->bi_dma_handle;
	hcidescp = (hci1394_desc_t *)dma->dma_descp;
	hcidesc_off = (off_t)hcidescp - (off_t)dma->dma_buf->bi_kaddr;

	/* Sync the descriptor before we get the status */
	err = ddi_dma_sync(dma_hdl, hcidesc_off, sizeof (hci1394_desc_t),
	    DDI_DMA_SYNC_FORCPU);
	if (err != DDI_SUCCESS) {
		TNF_PROBE_1(hci1394_ixl_intr_check_done_error,
		    HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
		    "dma_sync() failed");
	}
	desc_status = ddi_get32(acc_hdl, &hcidescp->status);

	if ((desc_status & DESC_XFER_ACTIVE_MASK) != 0) {

		/*
		 * if status is now set here, return skipped, to cause calling
		 * function to continue, even though location hasn't changed
		 */
		TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
		    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
		    "CHECK_SKIP");
		return (IXL_CHECK_SKIP);
	}

	/*
	 * At this point, we have gotten to a DMA descriptor with an empty
	 * status.  This is not enough information however to determine that
	 * we've found all processed DMA descriptors because during cycle-lost
	 * conditions, the HW will skip over some descriptors without writing
	 * status.  So we have to look ahead until we're convinced that the HW
	 * hasn't jumped ahead.
	 *
	 * Follow the IXL skip-to links until find one whose status is set
	 * or until dma location register (if any) matches an xfer IXL
	 * command's dma location or until have examined max_dma_skips
	 * IXL commands.
	 */
	rem_dma_skips = ctxtp->max_dma_skips;

	while (rem_dma_skips-- > 0) {

		/*
		 * get either IXL command specific or
		 * system default skipmode info
		 */
		skipdepth = 0;
		if (xferctlp->skipmodep != NULL) {
			skipmode  = xferctlp->skipmodep->skipmode;
			skipdestp = xferctlp->skipmodep->label;
			skipxferp = (ixl1394_command_t *)
			    xferctlp->skipmodep->compiler_privatep;
		} else {
			skipmode  = ctxtp->default_skipmode;
			skipdestp = ctxtp->default_skiplabelp;
			skipxferp = ctxtp->default_skipxferp;
		}

		switch (skipmode) {

		case IXL1394_SKIP_TO_SELF:
			/*
			 * mode is skip to self:
			 *   if context is stopped, return stopped, else
			 *   if dma location reg not enabled, return done
			 *   else, return location indeterminate
			 */
			if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) ==
			    0) {
				TNF_PROBE_1_DEBUG(
					hci1394_ixl_intr_check_done_exit,
					HCI1394_TNF_HAL_STACK_ISOCH, "",
					tnf_string, msg, "CHECK_STOP");
				return (IXL_CHECK_STOP);
			}

			if (!dma_loc_check_enabled) {
				TNF_PROBE_1_DEBUG(
					hci1394_ixl_intr_check_done_exit,
					HCI1394_TNF_HAL_STACK_ISOCH, "",
					tnf_string, msg, "CHECK_DONE");
				return (IXL_CHECK_DONE);
			}

			TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
			    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
			    "CHECK_LOST");
			return (IXL_CHECK_LOST);

		case IXL1394_SKIP_TO_NEXT:
			/*
			 * mode is skip to next:
			 *    set potential skip target to current command at
			 *    next depth
			 */
			skipdestp = ixlp;
			skipxferp = ixlp;
			skipdepth = ixldepth + 1;

			/*
			 * else if at max depth at current cmd adjust to next
			 * IXL command.
			 *
			 * (NOTE: next means next IXL command along execution
			 * path,  whatever IXL command it might be.  e.g. store
			 * timestamp or callback or label or jump or send... )
			 */
			if (skipdepth >= xferctlp->cnt) {
				skipdepth = 0;
				skipdestp = ixlp->next_ixlp;
				skipxferp = xferctlp->execp;
			}

			/* evaluate skip to status further, below */
			break;


		case IXL1394_SKIP_TO_LABEL:
			/*
			 * mode is skip to label:
			 *    set skip destination depth to 0 (should be
			 *    redundant)
			 */
			skipdepth = 0;

			/* evaluate skip to status further, below */
			break;

		case IXL1394_SKIP_TO_STOP:
			/*
			 * mode is skip to stop:
			 *    set all xfer and destination skip to locations to
			 *    null
			 */
			skipxferp = NULL;
			skipdestp = NULL;
			skipdepth = 0;

			/* evaluate skip to status further, below */
			break;

		} /* end switch */

		/*
		 * if no xfer IXL command follows at or after current skip-to
		 * location
		 */
		if (skipxferp == NULL) {
			/*
			 *   if context is stopped, return stopped, else
			 *   if dma location reg not enabled, return done
			 *   else, return location indeterminate
			 */
			if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) ==
			    0) {
				TNF_PROBE_1_DEBUG(
					hci1394_ixl_intr_check_done_exit,
					HCI1394_TNF_HAL_STACK_ISOCH, "",
					tnf_string, msg, "CHECK_STOP");
				return (IXL_CHECK_STOP);
			}

			if (!dma_loc_check_enabled) {
				TNF_PROBE_1_DEBUG(
					hci1394_ixl_intr_check_done_exit,
					HCI1394_TNF_HAL_STACK_ISOCH, "",
					tnf_string, msg, "CHECK_DONE");
				return (IXL_CHECK_DONE);
			}
			TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
			    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
			    "CHECK_LOST");
			return (IXL_CHECK_LOST);
		}

		/*
		 * if the skip to xfer IXL dma descriptor's status is set,
		 * then execution did skip
		 */
		xferctlp = (hci1394_xfer_ctl_t *)skipxferp->compiler_privatep;
		dma	 = &xferctlp->dma[skipdepth];
		acc_hdl  = dma->dma_buf->bi_handle;
		dma_hdl  = dma->dma_buf->bi_dma_handle;
		hcidescp = (hci1394_desc_t *)dma->dma_descp;
		hcidesc_off = (off_t)hcidescp - (off_t)dma->dma_buf->bi_kaddr;

		/* Sync the descriptor before we get the status */
		err = ddi_dma_sync(dma_hdl, hcidesc_off,
		    sizeof (hci1394_desc_t), DDI_DMA_SYNC_FORCPU);
		if (err != DDI_SUCCESS) {
			TNF_PROBE_1(hci1394_ixl_intr_check_done_error,
			    HCI1394_TNF_HAL_ERROR_ISOCH, "", tnf_string, errmsg,
			    "dma_sync() failed");
		}
		desc_status = ddi_get32(acc_hdl, &hcidescp->status);

		if ((desc_status & DESC_XFER_ACTIVE_MASK) != 0) {

			/*
			 * adjust to continue from skip to IXL command and
			 * return skipped, to have calling func continue.
			 * (Note: next IXL command may be any allowed IXL
			 * command)
			 */
			ctxtp->ixl_execp = skipdestp;
			ctxtp->ixl_exec_depth = skipdepth;

			TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
			    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
			    "CHECK_SKIP");
			return (IXL_CHECK_SKIP);
		}

		/*
		 * if dma location command register checking is enabled,
		 * and the skip to xfer IXL dma location matches current
		 * dma location register value, execution did skip
		 */
		dmastartp = dma->dma_bound & ~DESC_Z_MASK;
		dmaendp = dmastartp + ((dma->dma_bound & DESC_Z_MASK) << 4);

		if (dma_loc_check_enabled && ((dma_cmd_cur_loc >= dmastartp) &&
		    (dma_cmd_cur_loc < dmaendp))) {

			/* if the context is stopped, return stopped */
			if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) ==
			    0) {
				TNF_PROBE_1_DEBUG(
					hci1394_ixl_intr_check_done_exit,
					HCI1394_TNF_HAL_STACK_ISOCH, "",
					tnf_string, msg, "CHECK STOP");
				return (IXL_CHECK_STOP);
			}
			/*
			 * adjust to continue from skip to IXL command and
			 * return skipped, to have calling func continue
			 * (Note: next IXL command may be any allowed IXL cmd)
			 */
			ctxtp->ixl_execp = skipdestp;
			ctxtp->ixl_exec_depth = skipdepth;

			TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
			    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
			    "CHECK_SKIP");
			return (IXL_CHECK_SKIP);
		}

		/*
		 * else, advance working current locn to skipxferp and
		 * skipdepth and continue skip evaluation loop processing
		 */
		ixlp = skipxferp;
		ixldepth = skipdepth;

	} /* end while */

	/*
	 * didn't find dma status set, nor location reg match, along skip path
	 *
	 * if context is stopped, return stopped,
	 *
	 * else if no current location reg active don't change context values,
	 * just return done (no skip)
	 *
	 * else, return location indeterminate
	 */

	if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0) {
		TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
		    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
		    "CHECK_STOP");
		return (IXL_CHECK_STOP);
	}
	if (!dma_loc_check_enabled) {
		TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
		    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
		    "CHECK_DONE");
		return (IXL_CHECK_DONE);
	}

	TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_done_exit,
	    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg, "CHECK_LOST");
	return (IXL_CHECK_LOST);
}
/*
 * hci1394_ixl_intr_check_xfer()
 *    Process given IXL xfer cmd, checking status of each dma descriptor block
 *    for the command until find one whose status isn't set or until full depth
 *    reached at current IXL command or until find hardware skip has occurred.
 *
 *    Returns B_TRUE if processing should terminate (either have stopped
 *    or encountered an error), and B_FALSE if it should continue looking.
 *    If B_TRUE, donecodep contains the reason: HCI1394_IXL_INTR_DMALOST,
 *    HCI1394_IXL_INTR_DMASTOP, HCI1394_IXL_INTR_NOADV, or
 *    HCI1394_IXL_INTR_NOERROR.  NOERROR means that the current location
 *    has been determined and do not need to look further.
 */
static boolean_t
hci1394_ixl_intr_check_xfer(hci1394_state_t *soft_statep,
    hci1394_iso_ctxt_t *ctxtp, ixl1394_command_t *ixlp,
    ixl1394_command_t **ixlnextpp, uint16_t *timestampp, int *donecodep)
{
	uint_t		    dma_advances;
	int		    intrstatus;
	uint_t		    skipped;
	hci1394_xfer_ctl_t  *xferctlp;
	uint16_t	    ixldepth;
	uint16_t	    ixlopcode;


	TNF_PROBE_0_DEBUG(hci1394_ixl_intr_check_xfer_enter,
	    HCI1394_TNF_HAL_STACK_ISOCH, "");

	*donecodep = 0;
	dma_advances = 0;
	ixldepth = ctxtp->ixl_exec_depth;
	ixlopcode = ixlp->ixl_opcode & ~IXL1394_OPF_UPDATE;

	/* get control struct for this xfer start IXL command */
	xferctlp = (hci1394_xfer_ctl_t *)ixlp->compiler_privatep;

	skipped = 0;
	while ((skipped == 0) && (ixldepth < xferctlp->cnt)) {
		/*
		 * check if status is set in dma descriptor
		 * block at cur depth in cur xfer start IXL cmd
		 */
		if (hci1394_ixl_check_status(&xferctlp->dma[ixldepth],
		    ixlopcode, timestampp, B_TRUE) != 0) {

			/* advance depth to next desc block in cur IXL cmd */
			ixldepth++;

			/*
			 * count dma desc blks whose status was set
			 * (i.e. advanced to next dma desc)
			 */
			dma_advances++;
			continue;
		}

		/* if get to here, status is not set */

		/*
		 * cur IXL cmd dma desc status not set.  save IXL cur cmd
		 * and depth and last timestamp for next time.
		 */
		ctxtp->ixl_execp = ixlp;
		ctxtp->ixl_exec_depth = ixldepth;
		ctxtp->dma_last_time = *timestampp;

		/*
		 * check if dma descriptor processing location is indeterminate
		 * (lost), context has either stopped, is done, or has skipped
		 */
		intrstatus = hci1394_ixl_intr_check_done(soft_statep, ctxtp);
		if (intrstatus == IXL_CHECK_LOST) {
			/*
			 * location indeterminate, try once more to determine
			 * current state.  First, recheck if status has become
			 * set in cur dma descriptor block.  (don't reset status
			 * here if is set)
			 */
			if (hci1394_ixl_check_status(&xferctlp->dma[ixldepth],
			    ixlopcode, timestampp, 1) != B_TRUE) {
				/* resume from where we left off */
				skipped = 0;
				continue;
			}

			/*
			 * status not set, check intr processing
			 * completion status again
			 */
			if ((intrstatus = hci1394_ixl_intr_check_done(
				soft_statep, ctxtp)) == IXL_CHECK_LOST) {
				/*
				 * location still indeterminate,
				 * processing is lost
				 */
				*donecodep = HCI1394_IXL_INTR_DMALOST;

				TNF_PROBE_1_DEBUG(
				    hci1394_ixl_intr_check_xfer_exit,
				    HCI1394_TNF_HAL_STACK_ISOCH, "",
				    tnf_string, msg, "INTR_DMALOST");
				return (B_TRUE);
			}
		}

		/*
		 * if dma processing stopped. current location has been
		 * determined.
		 */
		if (intrstatus == IXL_CHECK_STOP) {
			/*
			 * save timestamp, clear currently executing IXL
			 * command and depth. return stopped.
			 */
			ctxtp->ixl_execp = NULL;
			ctxtp->ixl_exec_depth = 0;
			ctxtp->dma_last_time = *timestampp;
			ctxtp->rem_noadv_intrs = 0;

			*donecodep = HCI1394_IXL_INTR_DMASTOP;

			TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_xfer_exit,
			    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
			    "INTR_DMASTOP");
			return (B_TRUE);
		}

		/*
		 * dma processing done for now. current location has
		 * has been determined
		 */
		if (intrstatus == IXL_CHECK_DONE) {
			/*
			 * if in update processing call:
			 *    clear update processing flag & return ok.
			 *    if dma advances happened, reset to max allowed.
			 *    however, if none have, don't reduce remaining
			 *    amount - that's for real interrupt call to adjust.
			 */
			if (ctxtp->intr_flags & HCI1394_ISO_CTXT_INUPDATE) {

				if (dma_advances > 0) {
					ctxtp->rem_noadv_intrs =
					    ctxtp->max_noadv_intrs;
				}

				*donecodep = HCI1394_IXL_INTR_NOERROR;

				TNF_PROBE_1_DEBUG(
				    hci1394_ixl_intr_check_xfer_exit,
				    HCI1394_TNF_HAL_STACK_ISOCH, "",
				    tnf_string, msg, "INTR_NOERROR");
				return (B_TRUE);
			}

			/*
			 * else, not in update call processing, are in normal
			 * intr call.  if no dma statuses were found set
			 * (i.e. no dma advances), reduce remaining count of
			 * interrupts allowed with no I/O completions
			 */
			if (dma_advances == 0) {
				ctxtp->rem_noadv_intrs--;
			} else {
				/*
				 * else some dma statuses were found set.
				 * reinit remaining count of interrupts allowed
				 * with no I/O completions
				 */
				ctxtp->rem_noadv_intrs = ctxtp->max_noadv_intrs;
			}

			/*
			 * if no remaining count of interrupts allowed with no
			 * I/O completions, return failure (no dma advance after
			 * max retries), else return ok
			 */
			if (ctxtp->rem_noadv_intrs == 0) {
				*donecodep = HCI1394_IXL_INTR_NOADV;

				TNF_PROBE_1_DEBUG(
				    hci1394_ixl_intr_check_xfer_exit,
				    HCI1394_TNF_HAL_STACK_ISOCH, "",
				    tnf_string, msg, "INTR_NOADV");
				return (B_TRUE);
			}

			*donecodep = HCI1394_IXL_INTR_NOERROR;

			TNF_PROBE_1_DEBUG(hci1394_ixl_intr_check_xfer_exit,
			    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
			    "INTR_NOERROR2");
			return (B_TRUE);
		}

		/*
		 * else (intrstatus == IXL_CHECK_SKIP) indicating skip has
		 * occured, retrieve current IXL cmd, depth, and timestamp and
		 * continue interrupt processing
		 */
		skipped = 1;
		*ixlnextpp = ctxtp->ixl_execp;
		ixldepth = ctxtp->ixl_exec_depth;
		*timestampp = ctxtp->dma_last_time;

		/*
		 * also count as 1, intervening skips to next posted
		 * dma descriptor.
		 */
		dma_advances++;
	}

	/*
	 * if full depth reached at current IXL cmd, set back to start for next
	 * IXL xfer command that will be processed
	 */
	if ((skipped == 0) && (ixldepth >= xferctlp->cnt)) {
		ctxtp->ixl_exec_depth = 0;
	}

	/*
	 * make sure rem_noadv_intrs is reset to max if we advanced.
	 */
	if (dma_advances > 0) {
		ctxtp->rem_noadv_intrs = ctxtp->max_noadv_intrs;
	}

	TNF_PROBE_0_DEBUG(hci1394_ixl_intr_check_xfer_exit,
	    HCI1394_TNF_HAL_STACK_ISOCH, "");

	/* continue to process next IXL command */
	return (B_FALSE);
}
/*
 * hci1394_ixl_dma_sync()
 *    the heart of interrupt processing, this routine correlates where the
 *    hardware is for the specified context with the IXL program.  Invokes
 *    callbacks as needed.  Also called by "update" to make sure ixl is
 *    sync'ed up with where the hardware is.
 *    Returns one of the ixl_intr defined return codes - HCI1394_IXL_INTR...
 *    {..._DMALOST, ..._DMASTOP, ..._NOADV,... _NOERROR}
 */
int
hci1394_ixl_dma_sync(hci1394_state_t *soft_statep, hci1394_iso_ctxt_t *ctxtp)
{
	ixl1394_command_t *ixlp = NULL;	/* current ixl command */
	ixl1394_command_t *ixlnextp;	/* next ixl command */
	uint16_t	ixlopcode;
	uint16_t	timestamp;
	int		donecode;
	boolean_t	isdone;

	void (*callback)(opaque_t, struct ixl1394_callback *);

	TNF_PROBE_0_DEBUG(hci1394_ixl_dma_sync_enter,
	    HCI1394_TNF_HAL_STACK_ISOCH, "");

	ASSERT(MUTEX_NOT_HELD(&ctxtp->intrprocmutex));

	/* xfer start ixl cmd where last left off */
	ixlnextp = ctxtp->ixl_execp;

	/* last completed descriptor block's timestamp  */
	timestamp = ctxtp->dma_last_time;

	/*
	 * follow execution path in IXL, until find dma descriptor in IXL
	 * xfer command whose status isn't set or until run out of IXL cmds
	 */
	while (ixlnextp != NULL) {
		ixlp = ixlnextp;
		ixlnextp = ixlp->next_ixlp;
		ixlopcode = ixlp->ixl_opcode & ~IXL1394_OPF_UPDATE;

		/*
		 * process IXL commands: xfer start, callback, store timestamp
		 * and jump and ignore the others
		 */

		/* determine if this is an xfer start IXL command */
		if (((ixlopcode & IXL1394_OPF_ISXFER) != 0) &&
		    ((ixlopcode & IXL1394_OPTY_MASK) != 0)) {

			/* process xfer cmd to see if HW has been here */
			isdone = hci1394_ixl_intr_check_xfer(soft_statep, ctxtp,
			    ixlp, &ixlnextp, &timestamp, &donecode);

			if (isdone == B_TRUE) {
				TNF_PROBE_0_DEBUG(hci1394_ixl_dma_sync_exit,
					HCI1394_TNF_HAL_STACK_ISOCH, "");
				return (donecode);
			}

			/* continue to process next IXL command */
			continue;
		}

		/* else check if IXL cmd - jump, callback or store timestamp */
		switch (ixlopcode) {
		case IXL1394_OP_JUMP:
			/*
			 * set next IXL cmd to label ptr in current IXL jump cmd
			 */
			ixlnextp = ((ixl1394_jump_t *)ixlp)->label;
			break;

		case IXL1394_OP_STORE_TIMESTAMP:
			/*
			 * set last timestamp value recorded into current IXL
			 * cmd
			 */
			((ixl1394_store_timestamp_t *)ixlp)->timestamp =
			    timestamp;
			break;

		case IXL1394_OP_CALLBACK:
			/*
			 * if callback function is specified, call it with IXL
			 * cmd addr.  Make sure to grab the lock before setting
			 * the "in callback" flag in intr_flags.
			 */
			mutex_enter(&ctxtp->intrprocmutex);
			ctxtp->intr_flags |= HCI1394_ISO_CTXT_INCALL;
			mutex_exit(&ctxtp->intrprocmutex);

			callback = ((ixl1394_callback_t *)ixlp)->callback;
			if (callback != NULL) {
				callback(ctxtp->global_callback_arg,
				    (ixl1394_callback_t *)ixlp);
			}

			/*
			 * And grab the lock again before clearing
			 * the "in callback" flag.
			 */
			mutex_enter(&ctxtp->intrprocmutex);
			ctxtp->intr_flags &= ~HCI1394_ISO_CTXT_INCALL;
			mutex_exit(&ctxtp->intrprocmutex);
			break;
		}
	}

	/*
	 * If we jumped to NULL because of an updateable JUMP, set ixl_execp
	 * back to ixlp.  The destination label might get updated to a
	 * non-NULL value.
	 */
	if ((ixlp != NULL) && (ixlp->ixl_opcode == IXL1394_OP_JUMP_U)) {
		ctxtp->ixl_execp = ixlp;
		TNF_PROBE_1_DEBUG(hci1394_ixl_dma_sync_exit,
		    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
		    "INTR_NOERROR");
		return (HCI1394_IXL_INTR_NOERROR);
	}

	/* save null IXL cmd and depth and last timestamp */
	ctxtp->ixl_execp = NULL;
	ctxtp->ixl_exec_depth = 0;
	ctxtp->dma_last_time = timestamp;

	ctxtp->rem_noadv_intrs = 0;


	/* return stopped status if at end of IXL cmds & context stopped */
	if (HCI1394_ISOCH_CTXT_ACTIVE(soft_statep, ctxtp) == 0) {
		TNF_PROBE_1_DEBUG(hci1394_ixl_dma_sync_exit,
		    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg,
		    "INTR_DMASTOP");
		return (HCI1394_IXL_INTR_DMASTOP);
	}

	/* else interrupt processing is lost */
	TNF_PROBE_1_DEBUG(hci1394_ixl_dma_sync_exit,
	    HCI1394_TNF_HAL_STACK_ISOCH, "", tnf_string, msg, "INTR_DMALOST");
	return (HCI1394_IXL_INTR_DMALOST);
}