xref: /onnv-gate/usr/src/uts/common/io/1394/t1394.c (revision 2273:965cd64c1689)
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
5*2273Sap25164  * Common Development and Distribution License (the "License").
6*2273Sap25164  * 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 /*
22*2273Sap25164  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * t1394.c
300Sstevel@tonic-gate  *    1394 Target Driver Interface
310Sstevel@tonic-gate  *    This file contains all of the 1394 Software Framework routines called
320Sstevel@tonic-gate  *    by target drivers
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <sys/conf.h>
360Sstevel@tonic-gate #include <sys/ddi.h>
370Sstevel@tonic-gate #include <sys/sunddi.h>
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <sys/kmem.h>
40*2273Sap25164 #include <sys/disp.h>
410Sstevel@tonic-gate #include <sys/tnf_probe.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include <sys/1394/t1394.h>
440Sstevel@tonic-gate #include <sys/1394/s1394.h>
450Sstevel@tonic-gate #include <sys/1394/h1394.h>
460Sstevel@tonic-gate #include <sys/1394/ieee1394.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static int s1394_allow_detach = 0;
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * Function:    t1394_attach()
520Sstevel@tonic-gate  * Input(s):    dip			The dip given to the target driver
530Sstevel@tonic-gate  *					    in it's attach() routine
540Sstevel@tonic-gate  *		version			The version of the target driver -
550Sstevel@tonic-gate  *					    T1394_VERSION_V1
560Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
570Sstevel@tonic-gate  *
580Sstevel@tonic-gate  * Output(s):	attachinfo		Used to pass info back to target,
590Sstevel@tonic-gate  *					    including bus generation, local
600Sstevel@tonic-gate  *					    node ID, dma attribute, etc.
610Sstevel@tonic-gate  *		t1394_hdl		The target "handle" to be used for
620Sstevel@tonic-gate  *					    all subsequent calls into the
630Sstevel@tonic-gate  *					    1394 Software Framework
640Sstevel@tonic-gate  *
650Sstevel@tonic-gate  * Description:	t1394_attach() registers the target (based on its dip) with
660Sstevel@tonic-gate  *		the 1394 Software Framework.  It returns the bus_generation,
670Sstevel@tonic-gate  *		local_nodeID, iblock_cookie and other useful information to
680Sstevel@tonic-gate  *		the target, as well as a handle (t1394_hdl) that will be used
690Sstevel@tonic-gate  *		in all subsequent calls into this framework.
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate /* ARGSUSED */
720Sstevel@tonic-gate int
t1394_attach(dev_info_t * dip,int version,uint_t flags,t1394_attachinfo_t * attachinfo,t1394_handle_t * t1394_hdl)730Sstevel@tonic-gate t1394_attach(dev_info_t *dip, int version, uint_t flags,
740Sstevel@tonic-gate     t1394_attachinfo_t *attachinfo, t1394_handle_t *t1394_hdl)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	s1394_hal_t	*hal;
770Sstevel@tonic-gate 	s1394_target_t	*target;
780Sstevel@tonic-gate 	uint_t		dev;
790Sstevel@tonic-gate 	uint_t		curr;
800Sstevel@tonic-gate 	uint_t		unit_dir;
810Sstevel@tonic-gate 	int		hp_node = 0;
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
840Sstevel@tonic-gate 	ASSERT(attachinfo != NULL);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_attach_enter, S1394_TNF_SL_HOTPLUG_STACK, "");
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	*t1394_hdl = NULL;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	if (version != T1394_VERSION_V1) {
910Sstevel@tonic-gate 		TNF_PROBE_1(t1394_attach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
920Sstevel@tonic-gate 		    tnf_string, msg, "Invalid version");
930Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_attach_exit,
940Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
950Sstevel@tonic-gate 		return (DDI_FAILURE);
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	hal = s1394_dip_to_hal(ddi_get_parent(dip));
990Sstevel@tonic-gate 	if (hal == NULL) {
1000Sstevel@tonic-gate 		TNF_PROBE_1(t1394_attach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
1010Sstevel@tonic-gate 		    tnf_string, msg, "No parent dip found for target");
1020Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_attach_exit,
1030Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
1040Sstevel@tonic-gate 		return (DDI_FAILURE);
1050Sstevel@tonic-gate 	}
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	hp_node = ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1100Sstevel@tonic-gate 	    "hp-node");
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/* Allocate space for s1394_target_t */
1130Sstevel@tonic-gate 	target = kmem_zalloc(sizeof (s1394_target_t), KM_SLEEP);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	target->target_version = version;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	/* Copy in the params */
1200Sstevel@tonic-gate 	target->target_dip = dip;
1210Sstevel@tonic-gate 	target->on_hal	   = hal;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	/* Place the target on the appropriate node */
1240Sstevel@tonic-gate 	target->on_node	= NULL;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	rw_enter(&target->on_hal->target_list_rwlock, RW_WRITER);
1270Sstevel@tonic-gate 	if (hp_node != 0) {
1280Sstevel@tonic-gate 		s1394_add_target_to_node(target);
1290Sstevel@tonic-gate 		/*
1300Sstevel@tonic-gate 		 * on_node can be NULL if the node got unplugged
1310Sstevel@tonic-gate 		 * while the target driver is in its attach routine.
1320Sstevel@tonic-gate 		 */
1330Sstevel@tonic-gate 		if (target->on_node == NULL) {
1340Sstevel@tonic-gate 			s1394_remove_target_from_node(target);
1350Sstevel@tonic-gate 			rw_exit(&target->on_hal->target_list_rwlock);
1360Sstevel@tonic-gate 			mutex_exit(&hal->topology_tree_mutex);
1370Sstevel@tonic-gate 			kmem_free(target, sizeof (s1394_target_t));
1380Sstevel@tonic-gate 			TNF_PROBE_1(t1394_attach_error,
1390Sstevel@tonic-gate 			    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
1400Sstevel@tonic-gate 			    "on_node == NULL");
1410Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_attach_exit,
1420Sstevel@tonic-gate 			    S1394_TNF_SL_HOTPLUG_STACK, "");
1430Sstevel@tonic-gate 			return (DDI_FAILURE);
1440Sstevel@tonic-gate 		}
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 		target->target_state = S1394_TARG_HP_NODE;
1470Sstevel@tonic-gate 		if (S1394_NODE_BUS_PWR_CONSUMER(target->on_node) == B_TRUE)
1480Sstevel@tonic-gate 			target->target_state |= S1394_TARG_BUS_PWR_CONSUMER;
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	/* Return the current generation */
1520Sstevel@tonic-gate 	attachinfo->localinfo.bus_generation = target->on_hal->generation_count;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	/* Fill in hal node id */
1550Sstevel@tonic-gate 	attachinfo->localinfo.local_nodeID = target->on_hal->node_id;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	/* Give the target driver the iblock_cookie */
1580Sstevel@tonic-gate 	attachinfo->iblock_cookie = target->on_hal->halinfo.hw_interrupt;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	/* Give the target driver the attributes */
1610Sstevel@tonic-gate 	attachinfo->acc_attr	= target->on_hal->halinfo.acc_attr;
1620Sstevel@tonic-gate 	attachinfo->dma_attr	= target->on_hal->halinfo.dma_attr;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	unit_dir = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
1650Sstevel@tonic-gate 		DDI_PROP_DONTPASS, "unit-dir-offset", 0);
1660Sstevel@tonic-gate 	target->unit_dir = unit_dir;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	/* By default, disable all physical AR requests */
1690Sstevel@tonic-gate 	target->physical_arreq_enabled = 0;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	/* Get dev_max_payload & current_max_payload */
1730Sstevel@tonic-gate 	s1394_get_maxpayload(target, &dev, &curr);
1740Sstevel@tonic-gate 	target->dev_max_payload		= dev;
1750Sstevel@tonic-gate 	target->current_max_payload	= curr;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	/* Add into linked list */
1780Sstevel@tonic-gate 	if ((target->on_hal->target_head == NULL) &&
1790Sstevel@tonic-gate 	    (target->on_hal->target_tail == NULL)) {
1800Sstevel@tonic-gate 		target->on_hal->target_head = target;
1810Sstevel@tonic-gate 		target->on_hal->target_tail = target;
1820Sstevel@tonic-gate 	} else {
1830Sstevel@tonic-gate 		target->on_hal->target_tail->target_next = target;
1840Sstevel@tonic-gate 		target->target_prev = target->on_hal->target_tail;
1850Sstevel@tonic-gate 		target->on_hal->target_tail = target;
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate 	rw_exit(&target->on_hal->target_list_rwlock);
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/* Fill in services layer private info */
1900Sstevel@tonic-gate 	*t1394_hdl = (t1394_handle_t)target;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_attach_exit, S1394_TNF_SL_HOTPLUG_STACK, "");
1950Sstevel@tonic-gate 	return (DDI_SUCCESS);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate  * Function:    t1394_detach()
2000Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
2010Sstevel@tonic-gate  *					    t1394_attach()
2020Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
2030Sstevel@tonic-gate  *
2040Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully detached
2050Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to detach
2060Sstevel@tonic-gate  *
2070Sstevel@tonic-gate  * Description:	t1394_detach() unregisters the target from the 1394 Software
2080Sstevel@tonic-gate  *		Framework.  t1394_detach() can fail if the target has any
2090Sstevel@tonic-gate  *		allocated commands that haven't been freed.
2100Sstevel@tonic-gate  */
2110Sstevel@tonic-gate /* ARGSUSED */
2120Sstevel@tonic-gate int
t1394_detach(t1394_handle_t * t1394_hdl,uint_t flags)2130Sstevel@tonic-gate t1394_detach(t1394_handle_t *t1394_hdl, uint_t flags)
2140Sstevel@tonic-gate {
2150Sstevel@tonic-gate 	s1394_target_t	*target;
2160Sstevel@tonic-gate 	uint_t		num_cmds;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_detach_enter, S1394_TNF_SL_HOTPLUG_STACK, "");
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	target = (s1394_target_t *)(*t1394_hdl);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	ASSERT(target->on_hal);
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	mutex_enter(&target->on_hal->topology_tree_mutex);
2270Sstevel@tonic-gate 	rw_enter(&target->on_hal->target_list_rwlock, RW_WRITER);
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	/* How many cmds has this target allocated? */
2300Sstevel@tonic-gate 	num_cmds = target->target_num_cmds;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	if (num_cmds != 0) {
2330Sstevel@tonic-gate 		rw_exit(&target->on_hal->target_list_rwlock);
2340Sstevel@tonic-gate 		mutex_exit(&target->on_hal->topology_tree_mutex);
2350Sstevel@tonic-gate 		TNF_PROBE_1(t1394_detach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
2360Sstevel@tonic-gate 		    tnf_string, msg, "Must free all commands before detach()");
2370Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_detach_exit,
2380Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
2390Sstevel@tonic-gate 		return (DDI_FAILURE);
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	/*
2430Sstevel@tonic-gate 	 * Remove from linked lists. Topology tree is already locked
2440Sstevel@tonic-gate 	 * so that the node won't go away while we are looking at it.
2450Sstevel@tonic-gate 	 */
2460Sstevel@tonic-gate 	if ((target->on_hal->target_head == target) &&
2470Sstevel@tonic-gate 	    (target->on_hal->target_tail == target)) {
2480Sstevel@tonic-gate 		target->on_hal->target_head = NULL;
2490Sstevel@tonic-gate 		target->on_hal->target_tail = NULL;
2500Sstevel@tonic-gate 	} else {
2510Sstevel@tonic-gate 		if (target->target_prev)
2520Sstevel@tonic-gate 			target->target_prev->target_next = target->target_next;
2530Sstevel@tonic-gate 		if (target->target_next)
2540Sstevel@tonic-gate 			target->target_next->target_prev = target->target_prev;
2550Sstevel@tonic-gate 		if (target->on_hal->target_head == target)
2560Sstevel@tonic-gate 			target->on_hal->target_head = target->target_next;
2570Sstevel@tonic-gate 		if (target->on_hal->target_tail == target)
2580Sstevel@tonic-gate 			target->on_hal->target_tail = target->target_prev;
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	s1394_remove_target_from_node(target);
2620Sstevel@tonic-gate 	rw_exit(&target->on_hal->target_list_rwlock);
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	mutex_exit(&target->on_hal->topology_tree_mutex);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	/* Free memory */
2670Sstevel@tonic-gate 	kmem_free(target, sizeof (s1394_target_t));
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	*t1394_hdl = NULL;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_detach_exit, S1394_TNF_SL_HOTPLUG_STACK, "");
2720Sstevel@tonic-gate 	return (DDI_SUCCESS);
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate  * Function:    t1394_alloc_cmd()
2770Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
2780Sstevel@tonic-gate  *					    t1394_attach()
2790Sstevel@tonic-gate  *		flags			The flags parameter is described below
2800Sstevel@tonic-gate  *
2810Sstevel@tonic-gate  * Output(s):	cmdp			Pointer to the newly allocated command
2820Sstevel@tonic-gate  *
2830Sstevel@tonic-gate  * Description:	t1394_alloc_cmd() allocates a command for use with the
2840Sstevel@tonic-gate  *		t1394_read(), t1394_write(), or t1394_lock() interfaces
2850Sstevel@tonic-gate  *		of the 1394 Software Framework.  By default, t1394_alloc_cmd()
2860Sstevel@tonic-gate  *		may sleep while allocating memory for the command structure.
2870Sstevel@tonic-gate  *		If this is undesirable, the target may set the
2880Sstevel@tonic-gate  *		T1394_ALLOC_CMD_NOSLEEP bit in the flags parameter.  Also,
2890Sstevel@tonic-gate  *		this call may fail because a target driver has already
2900Sstevel@tonic-gate  *		allocated MAX_NUMBER_ALLOC_CMDS commands.
2910Sstevel@tonic-gate  */
2920Sstevel@tonic-gate int
t1394_alloc_cmd(t1394_handle_t t1394_hdl,uint_t flags,cmd1394_cmd_t ** cmdp)2930Sstevel@tonic-gate t1394_alloc_cmd(t1394_handle_t t1394_hdl, uint_t flags, cmd1394_cmd_t **cmdp)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate 	s1394_hal_t	 *hal;
2960Sstevel@tonic-gate 	s1394_target_t	 *target;
2970Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
2980Sstevel@tonic-gate 	uint_t		 num_cmds;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_cmd_enter, S1394_TNF_SL_ATREQ_STACK, "");
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	/* Find the HAL this target resides on */
3070Sstevel@tonic-gate 	hal = target->on_hal;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	rw_enter(&hal->target_list_rwlock, RW_WRITER);
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	/* How many cmds has this target allocated? */
3120Sstevel@tonic-gate 	num_cmds = target->target_num_cmds;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	if (num_cmds >= MAX_NUMBER_ALLOC_CMDS) {
3150Sstevel@tonic-gate 		rw_exit(&hal->target_list_rwlock);
3160Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_cmd_error, S1394_TNF_SL_ATREQ_ERROR,
3170Sstevel@tonic-gate 		    "", tnf_string, msg, "Attempted to alloc > "
3180Sstevel@tonic-gate 		    "MAX_NUMBER_ALLOC_CMDS");
3190Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit,
3200Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
3210Sstevel@tonic-gate 		/* kstats - cmd alloc failures */
3220Sstevel@tonic-gate 		hal->hal_kstats->cmd_alloc_fail++;
3230Sstevel@tonic-gate 		return (DDI_FAILURE);
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	/* Increment the number of cmds this target has allocated? */
3270Sstevel@tonic-gate 	target->target_num_cmds = num_cmds + 1;
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	if (s1394_alloc_cmd(hal, flags, cmdp) != DDI_SUCCESS) {
3300Sstevel@tonic-gate 		target->target_num_cmds = num_cmds;	/* Undo increment */
3310Sstevel@tonic-gate 		rw_exit(&hal->target_list_rwlock);
3320Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
3330Sstevel@tonic-gate 		    tnf_string, msg, "Failed to allocate command structure");
3340Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit,
3350Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
3360Sstevel@tonic-gate 		/* kstats - cmd alloc failures */
3370Sstevel@tonic-gate 		hal->hal_kstats->cmd_alloc_fail++;
3380Sstevel@tonic-gate 		return (DDI_FAILURE);
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	rw_exit(&hal->target_list_rwlock);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	/* Get the Services Layer private area */
3440Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(*cmdp);
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	/* Initialize the command's blocking mutex */
3470Sstevel@tonic-gate 	mutex_init(&s_priv->blocking_mutex, NULL, MUTEX_DRIVER,
3480Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	/* Initialize the command's blocking condition variable */
3510Sstevel@tonic-gate 	cv_init(&s_priv->blocking_cv, NULL, CV_DRIVER, NULL);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit, S1394_TNF_SL_ATREQ_STACK, "");
3540Sstevel@tonic-gate 	return (DDI_SUCCESS);
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate /*
3580Sstevel@tonic-gate  * Function:    t1394_free_cmd()
3590Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
3600Sstevel@tonic-gate  *					    t1394_attach()
3610Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
3620Sstevel@tonic-gate  *		cmdp			Pointer to the command to be freed
3630Sstevel@tonic-gate  *
3640Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully freed command
3650Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to free command
3660Sstevel@tonic-gate  *
3670Sstevel@tonic-gate  * Description:	t1394_free_cmd() attempts to free a command that has previously
3680Sstevel@tonic-gate  *		been allocated by the target driver.  It is possible for
3690Sstevel@tonic-gate  *		t1394_free_cmd() to fail because the command is currently
3700Sstevel@tonic-gate  *		in-use by the 1394 Software Framework.
3710Sstevel@tonic-gate  */
3720Sstevel@tonic-gate /* ARGSUSED */
3730Sstevel@tonic-gate int
t1394_free_cmd(t1394_handle_t t1394_hdl,uint_t flags,cmd1394_cmd_t ** cmdp)3740Sstevel@tonic-gate t1394_free_cmd(t1394_handle_t t1394_hdl, uint_t flags, cmd1394_cmd_t **cmdp)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	s1394_hal_t	 *hal;
3770Sstevel@tonic-gate 	s1394_target_t	 *target;
3780Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
3790Sstevel@tonic-gate 	uint_t		 num_cmds;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_cmd_enter, S1394_TNF_SL_ATREQ_STACK, "");
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	/* Find the HAL this target resides on */
3880Sstevel@tonic-gate 	hal = target->on_hal;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	rw_enter(&hal->target_list_rwlock, RW_WRITER);
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	/* How many cmds has this target allocated? */
3930Sstevel@tonic-gate 	num_cmds = target->target_num_cmds;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	if (num_cmds == 0) {
3960Sstevel@tonic-gate 		rw_exit(&hal->target_list_rwlock);
3970Sstevel@tonic-gate 		TNF_PROBE_2(t1394_free_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
3980Sstevel@tonic-gate 		    tnf_string, msg, "No commands left to be freed "
3990Sstevel@tonic-gate 		    "(num_cmds <= 0)", tnf_uint, num_cmds, num_cmds);
4000Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_cmd_exit,
4010Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
4020Sstevel@tonic-gate 		ASSERT(num_cmds != 0);
4030Sstevel@tonic-gate 		return (DDI_FAILURE);
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	/* Get the Services Layer private area */
4070Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(*cmdp);
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	/* Check that command isn't in use */
4100Sstevel@tonic-gate 	if (s_priv->cmd_in_use == B_TRUE) {
4110Sstevel@tonic-gate 		rw_exit(&hal->target_list_rwlock);
4120Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
4130Sstevel@tonic-gate 		    tnf_string, msg, "Attempted to free an in-use command");
4140Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_cmd_exit,
4150Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
4160Sstevel@tonic-gate 		ASSERT(s_priv->cmd_in_use == B_FALSE);
4170Sstevel@tonic-gate 		return (DDI_FAILURE);
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/* Decrement the number of cmds this target has allocated */
4210Sstevel@tonic-gate 	target->target_num_cmds--;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	rw_exit(&hal->target_list_rwlock);
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	/* Destroy the command's blocking condition variable */
4260Sstevel@tonic-gate 	cv_destroy(&s_priv->blocking_cv);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	/* Destroy the command's blocking mutex */
4290Sstevel@tonic-gate 	mutex_destroy(&s_priv->blocking_mutex);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	kmem_cache_free(hal->hal_kmem_cachep, *cmdp);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/* Command pointer is set to NULL before returning */
4340Sstevel@tonic-gate 	*cmdp = NULL;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	/* kstats - number of cmd frees */
4370Sstevel@tonic-gate 	hal->hal_kstats->cmd_free++;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_cmd_exit, S1394_TNF_SL_ATREQ_STACK, "");
4400Sstevel@tonic-gate 	return (DDI_SUCCESS);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate /*
4440Sstevel@tonic-gate  * Function:    t1394_read()
4450Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
4460Sstevel@tonic-gate  *					    t1394_attach()
4470Sstevel@tonic-gate  *		cmd			Pointer to the command to send
4480Sstevel@tonic-gate  *
4490Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successful sent the command
4500Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to send command
4510Sstevel@tonic-gate  *
4520Sstevel@tonic-gate  * Description:	t1394_read() attempts to send an asynchronous read request
4530Sstevel@tonic-gate  *		onto the 1394 bus.
4540Sstevel@tonic-gate  */
4550Sstevel@tonic-gate int
t1394_read(t1394_handle_t t1394_hdl,cmd1394_cmd_t * cmd)4560Sstevel@tonic-gate t1394_read(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
4570Sstevel@tonic-gate {
4580Sstevel@tonic-gate 	s1394_hal_t	  *to_hal;
4590Sstevel@tonic-gate 	s1394_target_t	  *target;
4600Sstevel@tonic-gate 	s1394_cmd_priv_t  *s_priv;
4610Sstevel@tonic-gate 	s1394_hal_state_t state;
4620Sstevel@tonic-gate 	int		  ret;
4630Sstevel@tonic-gate 	int		  err;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_read_enter, S1394_TNF_SL_ATREQ_STACK, "");
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
4680Sstevel@tonic-gate 	ASSERT(cmd != NULL);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	/* Get the Services Layer private area */
4710Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	/* Is this command currently in use? */
4740Sstevel@tonic-gate 	if (s_priv->cmd_in_use == B_TRUE) {
4750Sstevel@tonic-gate 		TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
4760Sstevel@tonic-gate 		    tnf_string, msg, "Attempted to resend an in-use command");
4770Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_read_exit, S1394_TNF_SL_ATREQ_STACK,
4780Sstevel@tonic-gate 		    "");
4790Sstevel@tonic-gate 		ASSERT(s_priv->cmd_in_use == B_FALSE);
4800Sstevel@tonic-gate 		return (DDI_FAILURE);
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	/* Set-up the destination of the command */
4860Sstevel@tonic-gate 	to_hal = target->on_hal;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	/* No status (default) */
4890Sstevel@tonic-gate 	cmd->cmd_result = CMD1394_NOSTATUS;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	/* Check for proper command type */
4920Sstevel@tonic-gate 	if ((cmd->cmd_type != CMD1394_ASYNCH_RD_QUAD) &&
4930Sstevel@tonic-gate 	    (cmd->cmd_type != CMD1394_ASYNCH_RD_BLOCK)) {
4940Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_COMMAND;
4950Sstevel@tonic-gate 		TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
4960Sstevel@tonic-gate 		    tnf_string, msg, "Invalid command type specified");
4970Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_read_exit,
4980Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
4990Sstevel@tonic-gate 		return (DDI_FAILURE);
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	/* Is this a blocking command on interrupt stack? */
5030Sstevel@tonic-gate 	if ((cmd->cmd_options & CMD1394_BLOCKING) &&
504*2273Sap25164 	    (servicing_interrupt())) {
5050Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
5060Sstevel@tonic-gate 		TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
5070Sstevel@tonic-gate 		    tnf_string, msg, "Tried to use CMD1394_BLOCKING in "
5080Sstevel@tonic-gate 		    "intr context");
5090Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_read_exit,
5100Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
5110Sstevel@tonic-gate 		return (DDI_FAILURE);
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	mutex_enter(&to_hal->topology_tree_mutex);
5150Sstevel@tonic-gate 	state = to_hal->hal_state;
5160Sstevel@tonic-gate 	if (state != S1394_HAL_NORMAL) {
5170Sstevel@tonic-gate 		ret = s1394_HAL_asynch_error(to_hal, cmd, state);
5180Sstevel@tonic-gate 		if (ret != CMD1394_CMDSUCCESS) {
5190Sstevel@tonic-gate 			cmd->cmd_result = ret;
5200Sstevel@tonic-gate 			mutex_exit(&to_hal->topology_tree_mutex);
5210Sstevel@tonic-gate 			return (DDI_FAILURE);
5220Sstevel@tonic-gate 		}
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	ret = s1394_setup_asynch_command(to_hal, target, cmd,
5260Sstevel@tonic-gate 	    S1394_CMD_READ, &err);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	/* Command has now been put onto the queue! */
5290Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
5300Sstevel@tonic-gate 		/* Copy error code into result */
5310Sstevel@tonic-gate 		cmd->cmd_result = err;
5320Sstevel@tonic-gate 		mutex_exit(&to_hal->topology_tree_mutex);
5330Sstevel@tonic-gate 		TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
5340Sstevel@tonic-gate 		    tnf_string, msg, "Failed in s1394_setup_asynch_command()");
5350Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_read_exit,
5360Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
5370Sstevel@tonic-gate 		return (DDI_FAILURE);
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/*
5410Sstevel@tonic-gate 	 * If this command was sent during a bus reset,
5420Sstevel@tonic-gate 	 * then put it onto the pending Q.
5430Sstevel@tonic-gate 	 */
5440Sstevel@tonic-gate 	if (state == S1394_HAL_RESET) {
5450Sstevel@tonic-gate 		/* Remove cmd from outstanding request Q */
5460Sstevel@tonic-gate 		s1394_remove_q_asynch_cmd(to_hal, cmd);
5470Sstevel@tonic-gate 		/* Are we on the bus reset event stack? */
5480Sstevel@tonic-gate 		if (s1394_on_br_thread(to_hal) == B_TRUE) {
5490Sstevel@tonic-gate 			/* Blocking commands are not allowed */
5500Sstevel@tonic-gate 			if (cmd->cmd_options & CMD1394_BLOCKING) {
5510Sstevel@tonic-gate 				mutex_exit(&to_hal->topology_tree_mutex);
5520Sstevel@tonic-gate 				s_priv->cmd_in_use = B_FALSE;
5530Sstevel@tonic-gate 				cmd->cmd_result	   = CMD1394_EINVALID_CONTEXT;
5540Sstevel@tonic-gate 				TNF_PROBE_1(t1394_read_error,
5550Sstevel@tonic-gate 				    S1394_TNF_SL_ATREQ_ERROR, "", tnf_string,
5560Sstevel@tonic-gate 				    msg, "CMD1394_BLOCKING in bus reset "
5570Sstevel@tonic-gate 				    "context");
5580Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_read_exit,
5590Sstevel@tonic-gate 				    S1394_TNF_SL_ATREQ_STACK, "");
5600Sstevel@tonic-gate 				return (DDI_FAILURE);
5610Sstevel@tonic-gate 			}
5620Sstevel@tonic-gate 		}
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 		s1394_pending_q_insert(to_hal, cmd, S1394_PENDING_Q_FRONT);
5650Sstevel@tonic-gate 		mutex_exit(&to_hal->topology_tree_mutex);
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 		/* Block (if necessary) */
5680Sstevel@tonic-gate 		goto block_on_asynch_cmd;
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate 	mutex_exit(&to_hal->topology_tree_mutex);
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	/* Send the command out */
5730Sstevel@tonic-gate 	ret = s1394_xfer_asynch_command(to_hal, cmd, &err);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
5760Sstevel@tonic-gate 		if (err == CMD1394_ESTALE_GENERATION) {
5770Sstevel@tonic-gate 			/* Remove cmd from outstanding request Q */
5780Sstevel@tonic-gate 			s1394_remove_q_asynch_cmd(to_hal, cmd);
5790Sstevel@tonic-gate 			s1394_pending_q_insert(to_hal, cmd,
5800Sstevel@tonic-gate 			    S1394_PENDING_Q_FRONT);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 			/* Block (if necessary) */
5830Sstevel@tonic-gate 			goto block_on_asynch_cmd;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 		} else {
5860Sstevel@tonic-gate 			/* Remove cmd from outstanding request Q */
5870Sstevel@tonic-gate 			s1394_remove_q_asynch_cmd(to_hal, cmd);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 			s_priv->cmd_in_use = B_FALSE;
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 			/* Copy error code into result */
5920Sstevel@tonic-gate 			cmd->cmd_result    = err;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 			TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR,
5950Sstevel@tonic-gate 			    "", tnf_string, msg, "Failed in "
5960Sstevel@tonic-gate 			    "s1394_xfer_asynch_command()");
5970Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_read_exit,
5980Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_STACK, "");
5990Sstevel@tonic-gate 			return (DDI_FAILURE);
6000Sstevel@tonic-gate 		}
6010Sstevel@tonic-gate 	} else {
6020Sstevel@tonic-gate 		/* Block (if necessary) */
6030Sstevel@tonic-gate 		goto block_on_asynch_cmd;
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate block_on_asynch_cmd:
6070Sstevel@tonic-gate 	s1394_block_on_asynch_cmd(cmd);
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_read_exit,
6100Sstevel@tonic-gate 	    S1394_TNF_SL_ATREQ_STACK, "");
6110Sstevel@tonic-gate 	return (DDI_SUCCESS);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate /*
6150Sstevel@tonic-gate  * Function:    t1394_write()
6160Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
6170Sstevel@tonic-gate  *					    t1394_attach()
6180Sstevel@tonic-gate  *		cmd			Pointer to the command to send
6190Sstevel@tonic-gate  *
6200Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successful sent the command
6210Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to send command
6220Sstevel@tonic-gate  *
6230Sstevel@tonic-gate  * Description:	t1394_write() attempts to send an asynchronous write request
6240Sstevel@tonic-gate  *		onto the 1394 bus.
6250Sstevel@tonic-gate  */
6260Sstevel@tonic-gate int
t1394_write(t1394_handle_t t1394_hdl,cmd1394_cmd_t * cmd)6270Sstevel@tonic-gate t1394_write(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	s1394_hal_t	  *to_hal;
6300Sstevel@tonic-gate 	s1394_target_t	  *target;
6310Sstevel@tonic-gate 	s1394_cmd_priv_t  *s_priv;
6320Sstevel@tonic-gate 	s1394_hal_state_t state;
6330Sstevel@tonic-gate 	int		  ret;
6340Sstevel@tonic-gate 	int		  err;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_write_enter, S1394_TNF_SL_ATREQ_STACK, "");
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
6390Sstevel@tonic-gate 	ASSERT(cmd != NULL);
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	/* Get the Services Layer private area */
6420Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	/* Is this command currently in use? */
6450Sstevel@tonic-gate 	if (s_priv->cmd_in_use == B_TRUE) {
6460Sstevel@tonic-gate 		TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
6470Sstevel@tonic-gate 		    tnf_string, msg, "Attempted to resend an in-use command");
6480Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
6490Sstevel@tonic-gate 		    "");
6500Sstevel@tonic-gate 		ASSERT(s_priv->cmd_in_use == B_FALSE);
6510Sstevel@tonic-gate 		return (DDI_FAILURE);
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	/* Set-up the destination of the command */
6570Sstevel@tonic-gate 	to_hal = target->on_hal;
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	/* Is this an FA request? */
6600Sstevel@tonic-gate 	if (s_priv->cmd_ext_type == S1394_CMD_EXT_FA) {
6610Sstevel@tonic-gate 		if (S1394_IS_CMD_FCP(s_priv) &&
6620Sstevel@tonic-gate 		    (s1394_fcp_write_check_cmd(cmd) != DDI_SUCCESS)) {
6630Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_write_exit,
6640Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_STACK, "");
6650Sstevel@tonic-gate 			return (DDI_FAILURE);
6660Sstevel@tonic-gate 		}
6670Sstevel@tonic-gate 		s1394_fa_convert_cmd(to_hal, cmd);
6680Sstevel@tonic-gate 	}
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	/* No status (default) */
6710Sstevel@tonic-gate 	cmd->cmd_result = CMD1394_NOSTATUS;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	/* Check for proper command type */
6740Sstevel@tonic-gate 	if ((cmd->cmd_type != CMD1394_ASYNCH_WR_QUAD) &&
6750Sstevel@tonic-gate 	    (cmd->cmd_type != CMD1394_ASYNCH_WR_BLOCK)) {
6760Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_COMMAND;
6770Sstevel@tonic-gate 		s1394_fa_check_restore_cmd(to_hal, cmd);
6780Sstevel@tonic-gate 		TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
6790Sstevel@tonic-gate 		    tnf_string, msg, "Invalid command type specified");
6800Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
6810Sstevel@tonic-gate 		    "");
6820Sstevel@tonic-gate 		return (DDI_FAILURE);
6830Sstevel@tonic-gate 	}
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	/* Is this a blocking command on interrupt stack? */
6860Sstevel@tonic-gate 	if ((cmd->cmd_options & CMD1394_BLOCKING) &&
687*2273Sap25164 	    (servicing_interrupt())) {
6880Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
6890Sstevel@tonic-gate 		s1394_fa_check_restore_cmd(to_hal, cmd);
6900Sstevel@tonic-gate 		TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
6910Sstevel@tonic-gate 		    tnf_string, msg, "Tried to use CMD1394_BLOCKING in intr "
6920Sstevel@tonic-gate 		    "context");
6930Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
6940Sstevel@tonic-gate 		    "");
6950Sstevel@tonic-gate 		return (DDI_FAILURE);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	mutex_enter(&to_hal->topology_tree_mutex);
6990Sstevel@tonic-gate 	state = to_hal->hal_state;
7000Sstevel@tonic-gate 	if (state != S1394_HAL_NORMAL) {
7010Sstevel@tonic-gate 		ret = s1394_HAL_asynch_error(to_hal, cmd, state);
7020Sstevel@tonic-gate 		if (ret != CMD1394_CMDSUCCESS) {
7030Sstevel@tonic-gate 			cmd->cmd_result = ret;
7040Sstevel@tonic-gate 			mutex_exit(&to_hal->topology_tree_mutex);
7050Sstevel@tonic-gate 			s1394_fa_check_restore_cmd(to_hal, cmd);
7060Sstevel@tonic-gate 			return (DDI_FAILURE);
7070Sstevel@tonic-gate 		}
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	ret = s1394_setup_asynch_command(to_hal, target, cmd,
7110Sstevel@tonic-gate 	    S1394_CMD_WRITE, &err);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	/* Command has now been put onto the queue! */
7140Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
7150Sstevel@tonic-gate 		/* Copy error code into result */
7160Sstevel@tonic-gate 		cmd->cmd_result = err;
7170Sstevel@tonic-gate 		mutex_exit(&to_hal->topology_tree_mutex);
7180Sstevel@tonic-gate 		s1394_fa_check_restore_cmd(to_hal, cmd);
7190Sstevel@tonic-gate 		TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
7200Sstevel@tonic-gate 		    tnf_string, msg, "Failed in s1394_setup_asynch_command()");
7210Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
7220Sstevel@tonic-gate 		    "");
7230Sstevel@tonic-gate 		return (DDI_FAILURE);
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	/*
7270Sstevel@tonic-gate 	 * If this command was sent during a bus reset,
7280Sstevel@tonic-gate 	 * then put it onto the pending Q.
7290Sstevel@tonic-gate 	 */
7300Sstevel@tonic-gate 	if (state == S1394_HAL_RESET) {
7310Sstevel@tonic-gate 		/* Remove cmd from outstanding request Q */
7320Sstevel@tonic-gate 		s1394_remove_q_asynch_cmd(to_hal, cmd);
7330Sstevel@tonic-gate 		/* Are we on the bus reset event stack? */
7340Sstevel@tonic-gate 		if (s1394_on_br_thread(to_hal) == B_TRUE) {
7350Sstevel@tonic-gate 			/* Blocking commands are not allowed */
7360Sstevel@tonic-gate 			if (cmd->cmd_options & CMD1394_BLOCKING) {
7370Sstevel@tonic-gate 				mutex_exit(&to_hal->topology_tree_mutex);
7380Sstevel@tonic-gate 				s_priv->cmd_in_use = B_FALSE;
7390Sstevel@tonic-gate 				cmd->cmd_result    = CMD1394_EINVALID_CONTEXT;
7400Sstevel@tonic-gate 				s1394_fa_check_restore_cmd(to_hal, cmd);
7410Sstevel@tonic-gate 				TNF_PROBE_1(t1394_write_error,
7420Sstevel@tonic-gate 				    S1394_TNF_SL_ATREQ_ERROR, "", tnf_string,
7430Sstevel@tonic-gate 				    msg, "CMD1394_BLOCKING in bus reset cntxt");
7440Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_write_exit,
7450Sstevel@tonic-gate 				    S1394_TNF_SL_ATREQ_STACK, "");
7460Sstevel@tonic-gate 				return (DDI_FAILURE);
7470Sstevel@tonic-gate 			}
7480Sstevel@tonic-gate 		}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 		s1394_pending_q_insert(to_hal, cmd, S1394_PENDING_Q_FRONT);
7510Sstevel@tonic-gate 		mutex_exit(&to_hal->topology_tree_mutex);
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 		/* Block (if necessary) */
7540Sstevel@tonic-gate 		s1394_block_on_asynch_cmd(cmd);
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
7570Sstevel@tonic-gate 		    "");
7580Sstevel@tonic-gate 		return (DDI_SUCCESS);
7590Sstevel@tonic-gate 	}
7600Sstevel@tonic-gate 	mutex_exit(&to_hal->topology_tree_mutex);
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	/* Send the command out */
7630Sstevel@tonic-gate 	ret = s1394_xfer_asynch_command(to_hal, cmd, &err);
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
7660Sstevel@tonic-gate 		if (err == CMD1394_ESTALE_GENERATION) {
7670Sstevel@tonic-gate 			/* Remove cmd from outstanding request Q */
7680Sstevel@tonic-gate 			s1394_remove_q_asynch_cmd(to_hal, cmd);
7690Sstevel@tonic-gate 			s1394_pending_q_insert(to_hal, cmd,
7700Sstevel@tonic-gate 			    S1394_PENDING_Q_FRONT);
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 			/* Block (if necessary) */
7730Sstevel@tonic-gate 			s1394_block_on_asynch_cmd(cmd);
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_write_exit,
7760Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_STACK, "");
7770Sstevel@tonic-gate 			return (DDI_SUCCESS);
7780Sstevel@tonic-gate 		} else {
7790Sstevel@tonic-gate 			/* Remove cmd from outstanding request Q */
7800Sstevel@tonic-gate 			s1394_remove_q_asynch_cmd(to_hal, cmd);
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 			s_priv->cmd_in_use = B_FALSE;
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 			/* Copy error code into result */
7850Sstevel@tonic-gate 			cmd->cmd_result = err;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 			s1394_fa_check_restore_cmd(to_hal, cmd);
7880Sstevel@tonic-gate 			TNF_PROBE_1(t1394_write_error,
7890Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_ERROR, "", tnf_string, msg,
7900Sstevel@tonic-gate 			    "Failed in s1394_xfer_asynch_command()");
7910Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_write_exit,
7920Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_STACK, "");
7930Sstevel@tonic-gate 			return (DDI_FAILURE);
7940Sstevel@tonic-gate 		}
7950Sstevel@tonic-gate 	} else {
7960Sstevel@tonic-gate 		/* Block (if necessary) */
7970Sstevel@tonic-gate 		s1394_block_on_asynch_cmd(cmd);
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
8000Sstevel@tonic-gate 		    "");
8010Sstevel@tonic-gate 		return (DDI_SUCCESS);
8020Sstevel@tonic-gate 	}
8030Sstevel@tonic-gate }
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate /*
8060Sstevel@tonic-gate  * Function:    t1394_lock()
8070Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
8080Sstevel@tonic-gate  *					    t1394_attach()
8090Sstevel@tonic-gate  *		cmd			Pointer to the command to send
8100Sstevel@tonic-gate  *
8110Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successful sent the command
8120Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to send command
8130Sstevel@tonic-gate  *
8140Sstevel@tonic-gate  * Description:	t1394_lock() attempts to send an asynchronous lock request
8150Sstevel@tonic-gate  *		onto the 1394 bus.
8160Sstevel@tonic-gate  */
8170Sstevel@tonic-gate int
t1394_lock(t1394_handle_t t1394_hdl,cmd1394_cmd_t * cmd)8180Sstevel@tonic-gate t1394_lock(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
8190Sstevel@tonic-gate {
8200Sstevel@tonic-gate 	s1394_hal_t	    *to_hal;
8210Sstevel@tonic-gate 	s1394_target_t	    *target;
8220Sstevel@tonic-gate 	s1394_cmd_priv_t    *s_priv;
8230Sstevel@tonic-gate 	s1394_hal_state_t   state;
8240Sstevel@tonic-gate 	cmd1394_lock_type_t lock_type;
8250Sstevel@tonic-gate 	uint_t		    num_retries;
8260Sstevel@tonic-gate 	int		    ret;
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_lock_enter, S1394_TNF_SL_ATREQ_STACK, "");
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
8310Sstevel@tonic-gate 	ASSERT(cmd != NULL);
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	/* Get the Services Layer private area */
8340Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	/* Is this command currently in use? */
8370Sstevel@tonic-gate 	if (s_priv->cmd_in_use == B_TRUE) {
8380Sstevel@tonic-gate 		TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
8390Sstevel@tonic-gate 		    tnf_string, msg, "Attempted to resend an in-use command");
8400Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
8410Sstevel@tonic-gate 		    "");
8420Sstevel@tonic-gate 		ASSERT(s_priv->cmd_in_use == B_FALSE);
8430Sstevel@tonic-gate 		return (DDI_FAILURE);
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	/* Set-up the destination of the command */
8490Sstevel@tonic-gate 	to_hal = target->on_hal;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	mutex_enter(&to_hal->topology_tree_mutex);
8520Sstevel@tonic-gate 	state = to_hal->hal_state;
8530Sstevel@tonic-gate 	if (state != S1394_HAL_NORMAL) {
8540Sstevel@tonic-gate 		ret = s1394_HAL_asynch_error(to_hal, cmd, state);
8550Sstevel@tonic-gate 		if (ret != CMD1394_CMDSUCCESS) {
8560Sstevel@tonic-gate 			cmd->cmd_result = ret;
8570Sstevel@tonic-gate 			mutex_exit(&to_hal->topology_tree_mutex);
8580Sstevel@tonic-gate 			return (DDI_FAILURE);
8590Sstevel@tonic-gate 		}
8600Sstevel@tonic-gate 	}
8610Sstevel@tonic-gate 	mutex_exit(&to_hal->topology_tree_mutex);
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	/* Check for proper command type */
8640Sstevel@tonic-gate 	if ((cmd->cmd_type != CMD1394_ASYNCH_LOCK_32) &&
8650Sstevel@tonic-gate 	    (cmd->cmd_type != CMD1394_ASYNCH_LOCK_64)) {
8660Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_COMMAND;
8670Sstevel@tonic-gate 		TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
8680Sstevel@tonic-gate 		    tnf_string, msg, "Invalid command type sent to "
8690Sstevel@tonic-gate 		    "t1394_lock()");
8700Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
8710Sstevel@tonic-gate 		    "");
8720Sstevel@tonic-gate 		return (DDI_FAILURE);
8730Sstevel@tonic-gate 	}
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	/* No status (default) */
8760Sstevel@tonic-gate 	cmd->cmd_result = CMD1394_NOSTATUS;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/* Is this a blocking command on interrupt stack? */
8790Sstevel@tonic-gate 	if ((cmd->cmd_options & CMD1394_BLOCKING) &&
880*2273Sap25164 	    (servicing_interrupt())) {
8810Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
8820Sstevel@tonic-gate 		TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
8830Sstevel@tonic-gate 		    tnf_string, msg, "Tried to use CMD1394_BLOCKING in intr "
8840Sstevel@tonic-gate 		    "context");
8850Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
8860Sstevel@tonic-gate 		    "");
8870Sstevel@tonic-gate 		return (DDI_FAILURE);
8880Sstevel@tonic-gate 	}
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
8910Sstevel@tonic-gate 		lock_type	= cmd->cmd_u.l32.lock_type;
8920Sstevel@tonic-gate 		num_retries	= cmd->cmd_u.l32.num_retries;
8930Sstevel@tonic-gate 	} else {	/* (cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) */
8940Sstevel@tonic-gate 		lock_type	= cmd->cmd_u.l64.lock_type;
8950Sstevel@tonic-gate 		num_retries	= cmd->cmd_u.l64.num_retries;
8960Sstevel@tonic-gate 	}
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	/* Make sure num_retries is reasonable */
8990Sstevel@tonic-gate 	ASSERT(num_retries <= MAX_NUMBER_OF_LOCK_RETRIES);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	switch (lock_type) {
9020Sstevel@tonic-gate 	case CMD1394_LOCK_MASK_SWAP:
9030Sstevel@tonic-gate 	case CMD1394_LOCK_FETCH_ADD:
9040Sstevel@tonic-gate 	case CMD1394_LOCK_LITTLE_ADD:
9050Sstevel@tonic-gate 	case CMD1394_LOCK_BOUNDED_ADD:
9060Sstevel@tonic-gate 	case CMD1394_LOCK_WRAP_ADD:
9070Sstevel@tonic-gate 	case CMD1394_LOCK_COMPARE_SWAP:
9080Sstevel@tonic-gate 		ret = s1394_compare_swap(to_hal, target, cmd);
9090Sstevel@tonic-gate 		break;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	case CMD1394_LOCK_BIT_AND:
9120Sstevel@tonic-gate 	case CMD1394_LOCK_BIT_OR:
9130Sstevel@tonic-gate 	case CMD1394_LOCK_BIT_XOR:
9140Sstevel@tonic-gate 	case CMD1394_LOCK_INCREMENT:
9150Sstevel@tonic-gate 	case CMD1394_LOCK_DECREMENT:
9160Sstevel@tonic-gate 	case CMD1394_LOCK_ADD:
9170Sstevel@tonic-gate 	case CMD1394_LOCK_SUBTRACT:
9180Sstevel@tonic-gate 	case CMD1394_LOCK_THRESH_ADD:
9190Sstevel@tonic-gate 	case CMD1394_LOCK_THRESH_SUBTRACT:
9200Sstevel@tonic-gate 	case CMD1394_LOCK_CLIP_ADD:
9210Sstevel@tonic-gate 	case CMD1394_LOCK_CLIP_SUBTRACT:
9220Sstevel@tonic-gate 		ret = s1394_split_lock_req(to_hal, target, cmd);
9230Sstevel@tonic-gate 		break;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	default:
9260Sstevel@tonic-gate 		TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
9270Sstevel@tonic-gate 		    tnf_string, msg, "Invalid lock_type in command");
9280Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_COMMAND;
9290Sstevel@tonic-gate 		ret = DDI_FAILURE;
9300Sstevel@tonic-gate 		break;
9310Sstevel@tonic-gate 	}
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK, "");
9340Sstevel@tonic-gate 	return (ret);
9350Sstevel@tonic-gate }
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate /*
9380Sstevel@tonic-gate  * Function:    t1394_alloc_addr()
9390Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
9400Sstevel@tonic-gate  *					    t1394_attach()
9410Sstevel@tonic-gate  *		addr_allocp		The structure used to specify the type,
9420Sstevel@tonic-gate  *					    size, permissions, and callbacks
9430Sstevel@tonic-gate  *					    (if any) for the requested block
9440Sstevel@tonic-gate  *					    of 1394 address space
9450Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
9460Sstevel@tonic-gate  *
9470Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
9480Sstevel@tonic-gate  *					    to target
9490Sstevel@tonic-gate  *
9500Sstevel@tonic-gate  * Description:	t1394_alloc_addr() requests that part of the 1394 Address Space
9510Sstevel@tonic-gate  *		on the local node be set aside for this target driver, and
9520Sstevel@tonic-gate  *		associated with this address space should be some permissions
9530Sstevel@tonic-gate  *		and callbacks.  If the request is unable to be fulfilled,
9540Sstevel@tonic-gate  *		t1394_alloc_addr() will return DDI_FAILURE and result will
9550Sstevel@tonic-gate  *		indicate the reason.  T1394_EINVALID_PARAM indicates that the
9560Sstevel@tonic-gate  *		combination of flags given is invalid, and T1394_EALLOC_ADDR
9570Sstevel@tonic-gate  *		indicates that the requested type of address space is
9580Sstevel@tonic-gate  *		unavailable.
9590Sstevel@tonic-gate  */
9600Sstevel@tonic-gate /* ARGSUSED */
9610Sstevel@tonic-gate int
t1394_alloc_addr(t1394_handle_t t1394_hdl,t1394_alloc_addr_t * addr_allocp,uint_t flags,int * result)9620Sstevel@tonic-gate t1394_alloc_addr(t1394_handle_t t1394_hdl, t1394_alloc_addr_t *addr_allocp,
9630Sstevel@tonic-gate     uint_t flags, int *result)
9640Sstevel@tonic-gate {
9650Sstevel@tonic-gate 	s1394_hal_t	*hal;
9660Sstevel@tonic-gate 	s1394_target_t	*target;
9670Sstevel@tonic-gate 	uint64_t	addr_lo;
9680Sstevel@tonic-gate 	uint64_t	addr_hi;
9690Sstevel@tonic-gate 	int		err;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_addr_enter, S1394_TNF_SL_ARREQ_STACK,
9720Sstevel@tonic-gate 	    "");
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
9750Sstevel@tonic-gate 	ASSERT(addr_allocp != NULL);
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	/* Find the HAL this target resides on */
9800Sstevel@tonic-gate 	hal = target->on_hal;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	/* Get the bounds of the request */
9830Sstevel@tonic-gate 	addr_lo = addr_allocp->aa_address;
9840Sstevel@tonic-gate 	addr_hi = addr_lo + addr_allocp->aa_length;
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	/* Check combination of flags */
9870Sstevel@tonic-gate 	if ((addr_allocp->aa_enable & T1394_ADDR_RDENBL) &&
9880Sstevel@tonic-gate 	    (addr_allocp->aa_evts.recv_read_request == NULL) &&
9890Sstevel@tonic-gate 	    (addr_allocp->aa_kmem_bufp == NULL)) {
9900Sstevel@tonic-gate 		if ((addr_allocp->aa_type != T1394_ADDR_FIXED)	||
9910Sstevel@tonic-gate 		    (addr_lo < hal->physical_addr_lo)		||
9920Sstevel@tonic-gate 		    (addr_hi > hal->physical_addr_hi)) {
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 			/*
9950Sstevel@tonic-gate 			 * Reads are enabled, but target doesn't want to
9960Sstevel@tonic-gate 			 * be notified and hasn't given backing store
9970Sstevel@tonic-gate 			 */
9980Sstevel@tonic-gate 			*result = T1394_EINVALID_PARAM;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_addr_error,
10010Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
10020Sstevel@tonic-gate 			    "Invalid flags "
10030Sstevel@tonic-gate 			    "(RDs on, notify off, no backing store)");
10040Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
10050Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_STACK, "");
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10080Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10090Sstevel@tonic-gate 			return (DDI_FAILURE);
10100Sstevel@tonic-gate 		} else {
10110Sstevel@tonic-gate 			addr_allocp->aa_enable &= ~T1394_ADDR_RDENBL;
10120Sstevel@tonic-gate 		}
10130Sstevel@tonic-gate 	}
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	if ((addr_allocp->aa_enable & T1394_ADDR_WRENBL) &&
10160Sstevel@tonic-gate 	    (addr_allocp->aa_evts.recv_write_request == NULL) &&
10170Sstevel@tonic-gate 	    (addr_allocp->aa_kmem_bufp == NULL)) {
10180Sstevel@tonic-gate 		if ((addr_allocp->aa_type != T1394_ADDR_FIXED)	||
10190Sstevel@tonic-gate 		    (addr_lo < hal->physical_addr_lo)		||
10200Sstevel@tonic-gate 		    (addr_hi > hal->physical_addr_hi)) {
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 			/*
10230Sstevel@tonic-gate 			 * Writes are enabled, but target doesn't want to
10240Sstevel@tonic-gate 			 * be notified and hasn't given backing store
10250Sstevel@tonic-gate 			 */
10260Sstevel@tonic-gate 			*result = T1394_EINVALID_PARAM;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_addr_error,
10290Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
10300Sstevel@tonic-gate 			    "Invalid flags "
10310Sstevel@tonic-gate 			    "(WRs on, notify off, no backing store)");
10320Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
10330Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_STACK, "");
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10360Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10370Sstevel@tonic-gate 			return (DDI_FAILURE);
10380Sstevel@tonic-gate 		} else {
10390Sstevel@tonic-gate 			addr_allocp->aa_enable &= ~T1394_ADDR_WRENBL;
10400Sstevel@tonic-gate 		}
10410Sstevel@tonic-gate 	}
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	if ((addr_allocp->aa_enable & T1394_ADDR_LKENBL) &&
10440Sstevel@tonic-gate 	    (addr_allocp->aa_evts.recv_lock_request == NULL) &&
10450Sstevel@tonic-gate 	    (addr_allocp->aa_kmem_bufp == NULL)) {
10460Sstevel@tonic-gate 		if ((addr_allocp->aa_type != T1394_ADDR_FIXED)	||
10470Sstevel@tonic-gate 		    (addr_lo < hal->physical_addr_lo)		||
10480Sstevel@tonic-gate 		    (addr_hi > hal->physical_addr_hi)) {
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 			/*
10510Sstevel@tonic-gate 			 * Locks are enabled, but target doesn't want to
10520Sstevel@tonic-gate 			 * be notified and hasn't given backing store
10530Sstevel@tonic-gate 			 */
10540Sstevel@tonic-gate 			*result = T1394_EINVALID_PARAM;
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_addr_error,
10570Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
10580Sstevel@tonic-gate 			    "Invalid flags "
10590Sstevel@tonic-gate 			    "(LKs on, notify off, no backing store)");
10600Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
10610Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_STACK, "");
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10640Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10650Sstevel@tonic-gate 			return (DDI_FAILURE);
10660Sstevel@tonic-gate 		} else {
10670Sstevel@tonic-gate 			addr_allocp->aa_enable &= ~T1394_ADDR_LKENBL;
10680Sstevel@tonic-gate 		}
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	/* If not T1394_ADDR_FIXED, then allocate a block */
10720Sstevel@tonic-gate 	if (addr_allocp->aa_type != T1394_ADDR_FIXED) {
10730Sstevel@tonic-gate 		err = s1394_request_addr_blk((s1394_hal_t *)target->on_hal,
10740Sstevel@tonic-gate 					addr_allocp);
10750Sstevel@tonic-gate 		if (err != DDI_SUCCESS) {
10760Sstevel@tonic-gate 			*result = T1394_EALLOC_ADDR;
10770Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10780Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10790Sstevel@tonic-gate 		} else {
10800Sstevel@tonic-gate 			*result = T1394_NOERROR;
10810Sstevel@tonic-gate 		}
10820Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
10830Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
10840Sstevel@tonic-gate 		return (err);
10850Sstevel@tonic-gate 	} else {
10860Sstevel@tonic-gate 		err = s1394_claim_addr_blk((s1394_hal_t *)target->on_hal,
10870Sstevel@tonic-gate 					addr_allocp);
10880Sstevel@tonic-gate 		if (err != DDI_SUCCESS) {
10890Sstevel@tonic-gate 			*result = T1394_EALLOC_ADDR;
10900Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10910Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10920Sstevel@tonic-gate 		} else {
10930Sstevel@tonic-gate 			*result = T1394_NOERROR;
10940Sstevel@tonic-gate 			/* If physical, update the AR request counter */
10950Sstevel@tonic-gate 			if ((addr_lo >= hal->physical_addr_lo) &&
10960Sstevel@tonic-gate 			    (addr_hi <= hal->physical_addr_hi)) {
10970Sstevel@tonic-gate 				rw_enter(&hal->target_list_rwlock, RW_WRITER);
10980Sstevel@tonic-gate 				target->physical_arreq_enabled++;
10990Sstevel@tonic-gate 				rw_exit(&hal->target_list_rwlock);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 				s1394_physical_arreq_set_one(target);
11020Sstevel@tonic-gate 			}
11030Sstevel@tonic-gate 		}
11040Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
11050Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
11060Sstevel@tonic-gate 		return (err);
11070Sstevel@tonic-gate 	}
11080Sstevel@tonic-gate }
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate /*
11110Sstevel@tonic-gate  * Function:    t1394_free_addr()
11120Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
11130Sstevel@tonic-gate  *					    t1394_attach()
11140Sstevel@tonic-gate  *		addr_hdl		The address "handle" returned by the
11150Sstevel@tonic-gate  *					   the t1394_alloc_addr() routine
11160Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
11170Sstevel@tonic-gate  *
11180Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully freed memory
11190Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to free the memory block
11200Sstevel@tonic-gate  *
11210Sstevel@tonic-gate  * Description:	t1394_free_addr() attempts to free up memory that has been
11220Sstevel@tonic-gate  *		allocated by the target using t1394_alloc_addr().
11230Sstevel@tonic-gate  */
11240Sstevel@tonic-gate /* ARGSUSED */
11250Sstevel@tonic-gate int
t1394_free_addr(t1394_handle_t t1394_hdl,t1394_addr_handle_t * addr_hdl,uint_t flags)11260Sstevel@tonic-gate t1394_free_addr(t1394_handle_t t1394_hdl, t1394_addr_handle_t *addr_hdl,
11270Sstevel@tonic-gate     uint_t flags)
11280Sstevel@tonic-gate {
11290Sstevel@tonic-gate 	s1394_addr_space_blk_t	*curr_blk;
11300Sstevel@tonic-gate 	s1394_hal_t		*hal;
11310Sstevel@tonic-gate 	s1394_target_t		*target;
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_addr_enter, S1394_TNF_SL_ARREQ_STACK, "");
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
11360Sstevel@tonic-gate 	ASSERT(addr_hdl != NULL);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	/* Find the HAL this target resides on */
11410Sstevel@tonic-gate 	hal = target->on_hal;
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	curr_blk = (s1394_addr_space_blk_t *)(*addr_hdl);
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	if (s1394_free_addr_blk(hal, curr_blk) != DDI_SUCCESS) {
11460Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_addr_exit,
11470Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
11480Sstevel@tonic-gate 		return (DDI_FAILURE);
11490Sstevel@tonic-gate 	}
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	/* If physical, update the AR request counter */
11520Sstevel@tonic-gate 	if (curr_blk->addr_type == T1394_ADDR_FIXED) {
11530Sstevel@tonic-gate 		target->physical_arreq_enabled--;
11540Sstevel@tonic-gate 		s1394_physical_arreq_clear_one(target);
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	*addr_hdl = NULL;
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 	/* kstats - number of addr frees */
11600Sstevel@tonic-gate 	hal->hal_kstats->addr_space_free++;
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_addr_exit, S1394_TNF_SL_ARREQ_STACK, "");
11630Sstevel@tonic-gate 	return (DDI_SUCCESS);
11640Sstevel@tonic-gate }
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate /*
11670Sstevel@tonic-gate  * Function:    t1394_recv_request_done()
11680Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
11690Sstevel@tonic-gate  *					    t1394_attach()
11700Sstevel@tonic-gate  *		resp			Pointer to the command which the
11710Sstevel@tonic-gate  *					    target received in it's callback
11720Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
11730Sstevel@tonic-gate  *
11740Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully returned command
11750Sstevel@tonic-gate  *					    to the 1394 Software Framework,
11760Sstevel@tonic-gate  *					    and, if necessary, sent response
11770Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to return the command to
11780Sstevel@tonic-gate  *					    the 1394 Software Framework
11790Sstevel@tonic-gate  *
11800Sstevel@tonic-gate  * Description:	t1394_recv_request_done() takes the command that is given and
11810Sstevel@tonic-gate  *		determines whether that command requires a response to be
11820Sstevel@tonic-gate  *		sent on the 1394 bus.  If it is necessary and it's response
11830Sstevel@tonic-gate  *		code (cmd_result) has been set appropriately, then a response
11840Sstevel@tonic-gate  *		will be sent.  If no response is necessary (broadcast or
11850Sstevel@tonic-gate  *		posted write), then the command resources are reclaimed.
11860Sstevel@tonic-gate  */
11870Sstevel@tonic-gate /* ARGSUSED */
11880Sstevel@tonic-gate int
t1394_recv_request_done(t1394_handle_t t1394_hdl,cmd1394_cmd_t * resp,uint_t flags)11890Sstevel@tonic-gate t1394_recv_request_done(t1394_handle_t t1394_hdl, cmd1394_cmd_t *resp,
11900Sstevel@tonic-gate     uint_t flags)
11910Sstevel@tonic-gate {
11920Sstevel@tonic-gate 	s1394_hal_t	 *hal;
11930Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
11940Sstevel@tonic-gate 	h1394_cmd_priv_t *h_priv;
11950Sstevel@tonic-gate 	mblk_t		 *curr_blk;
11960Sstevel@tonic-gate 	size_t		 msgb_len;
11970Sstevel@tonic-gate 	size_t		 size;
11980Sstevel@tonic-gate 	int		 ret;
11990Sstevel@tonic-gate 	boolean_t	 response = B_TRUE;
12000Sstevel@tonic-gate 	boolean_t	 posted_write = B_FALSE;
12010Sstevel@tonic-gate 	boolean_t	 write_cmd = B_FALSE;
12020Sstevel@tonic-gate 	boolean_t	 mblk_too_small;
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_recv_request_done_enter,
12050Sstevel@tonic-gate 	    S1394_TNF_SL_ARREQ_STACK, "");
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
12080Sstevel@tonic-gate 	ASSERT(resp != NULL);
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	/* Find the HAL this target resides on */
12110Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	/* Get the Services Layer private area */
12140Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(resp);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	/* Get a pointer to the HAL private struct */
12170Sstevel@tonic-gate 	h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	/* Is this an FA request? */
12200Sstevel@tonic-gate 	if (s_priv->cmd_ext_type == S1394_CMD_EXT_FA) {
12210Sstevel@tonic-gate 		s1394_fa_convert_cmd(hal, resp);
12220Sstevel@tonic-gate 	}
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	/* Is this a write request? */
12250Sstevel@tonic-gate 	if ((resp->cmd_type == CMD1394_ASYNCH_WR_QUAD) ||
12260Sstevel@tonic-gate 	    (resp->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
12270Sstevel@tonic-gate 		write_cmd = B_TRUE;
12280Sstevel@tonic-gate 		/* Is this a posted write request? */
12290Sstevel@tonic-gate 		posted_write = s_priv->posted_write;
12300Sstevel@tonic-gate 	}
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	/* If broadcast or posted write cmd, don't send response */
12330Sstevel@tonic-gate 	if ((resp->broadcast == 1) ||
12340Sstevel@tonic-gate 	    ((write_cmd == B_TRUE) && (posted_write == B_TRUE)))
12350Sstevel@tonic-gate 		response = B_FALSE;
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	if (response == B_FALSE) {
12380Sstevel@tonic-gate 		if ((write_cmd == B_TRUE) && (posted_write == B_TRUE)) {
12390Sstevel@tonic-gate 			/* kstats - Posted Write error */
12400Sstevel@tonic-gate 			hal->hal_kstats->arreq_posted_write_error++;
12410Sstevel@tonic-gate 		}
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 		/* Free the command - Pass it back to the HAL */
12440Sstevel@tonic-gate 		HAL_CALL(hal).response_complete(hal->halinfo.hal_private, resp,
12450Sstevel@tonic-gate 		    h_priv);
12460Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
12470Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
12480Sstevel@tonic-gate 		return (DDI_SUCCESS);
12490Sstevel@tonic-gate 	}
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	ASSERT(response == B_TRUE);
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	/* Verify valid response code */
12540Sstevel@tonic-gate 	switch (resp->cmd_result) {
12550Sstevel@tonic-gate 	case IEEE1394_RESP_COMPLETE:
12560Sstevel@tonic-gate 		/* Is the mblk_t too small? */
12570Sstevel@tonic-gate 		if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK) {
12580Sstevel@tonic-gate 			curr_blk = resp->cmd_u.b.data_block;
12590Sstevel@tonic-gate 			size	 = resp->cmd_u.b.blk_length;
12600Sstevel@tonic-gate 			msgb_len = 0;
12610Sstevel@tonic-gate 			mblk_too_small = B_TRUE;
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 			if (curr_blk == NULL) {
12640Sstevel@tonic-gate 				TNF_PROBE_1(t1394_recv_request_done_error,
12650Sstevel@tonic-gate 				    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string,
12660Sstevel@tonic-gate 				    msg, "mblk_t is NULL in response");
12670Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
12680Sstevel@tonic-gate 				    S1394_TNF_SL_ARREQ_STACK, "");
12690Sstevel@tonic-gate 				/*
12700Sstevel@tonic-gate 				 * Free the command - Pass it back
12710Sstevel@tonic-gate 				 * to the HAL
12720Sstevel@tonic-gate 				 */
12730Sstevel@tonic-gate 				HAL_CALL(hal).response_complete(
12740Sstevel@tonic-gate 				    hal->halinfo.hal_private, resp, h_priv);
12750Sstevel@tonic-gate 				ASSERT(curr_blk != NULL);
12760Sstevel@tonic-gate 				return (DDI_FAILURE);
12770Sstevel@tonic-gate 			}
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 			while (curr_blk != NULL) {
12800Sstevel@tonic-gate 				msgb_len +=
12810Sstevel@tonic-gate 				    (curr_blk->b_wptr - curr_blk->b_rptr);
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 				if (msgb_len >= size) {
12840Sstevel@tonic-gate 					mblk_too_small = B_FALSE;
12850Sstevel@tonic-gate 					break;
12860Sstevel@tonic-gate 				}
12870Sstevel@tonic-gate 				curr_blk = curr_blk->b_cont;
12880Sstevel@tonic-gate 			}
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 			if (mblk_too_small == B_TRUE) {
12910Sstevel@tonic-gate 				TNF_PROBE_1(t1394_recv_request_done_error,
12920Sstevel@tonic-gate 				    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string,
12930Sstevel@tonic-gate 				    msg, "mblk_t too small in response");
12940Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
12950Sstevel@tonic-gate 				    S1394_TNF_SL_ARREQ_STACK, "");
12960Sstevel@tonic-gate 				/*
12970Sstevel@tonic-gate 				 * Free the command - Pass it back
12980Sstevel@tonic-gate 				 * to the HAL
12990Sstevel@tonic-gate 				 */
13000Sstevel@tonic-gate 				HAL_CALL(hal).response_complete(
13010Sstevel@tonic-gate 				    hal->halinfo.hal_private, resp, h_priv);
13020Sstevel@tonic-gate 				ASSERT(mblk_too_small != B_TRUE);
13030Sstevel@tonic-gate 				return (DDI_FAILURE);
13040Sstevel@tonic-gate 			}
13050Sstevel@tonic-gate 		}
13060Sstevel@tonic-gate 		/* FALLTHROUGH */
13070Sstevel@tonic-gate 	case IEEE1394_RESP_CONFLICT_ERROR:
13080Sstevel@tonic-gate 	case IEEE1394_RESP_DATA_ERROR:
13090Sstevel@tonic-gate 	case IEEE1394_RESP_TYPE_ERROR:
13100Sstevel@tonic-gate 	case IEEE1394_RESP_ADDRESS_ERROR:
13110Sstevel@tonic-gate 		ret = s1394_send_response(hal, resp);
13120Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
13130Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
13140Sstevel@tonic-gate 		return (ret);
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 	default:
13170Sstevel@tonic-gate 		TNF_PROBE_1(t1394_recv_request_done_error,
13180Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
13190Sstevel@tonic-gate 		    "Invalid response code");
13200Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
13210Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
13220Sstevel@tonic-gate 		return (DDI_FAILURE);
13230Sstevel@tonic-gate 	}
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate /*
13280Sstevel@tonic-gate  * Function:    t1394_fcp_register_controller()
13290Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
13300Sstevel@tonic-gate  *					    t1394_attach()
13310Sstevel@tonic-gate  *		evts			The structure in which the target
13320Sstevel@tonic-gate  *					    specifies its callback routines
13330Sstevel@tonic-gate  *
13340Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
13350Sstevel@tonic-gate  *
13360Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
13370Sstevel@tonic-gate  *
13380Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
13390Sstevel@tonic-gate  *
13400Sstevel@tonic-gate  * Description:	Used to register the target within the Framework as an FCP
13410Sstevel@tonic-gate  *		controller.
13420Sstevel@tonic-gate  */
13430Sstevel@tonic-gate /* ARGSUSED */
13440Sstevel@tonic-gate int
t1394_fcp_register_controller(t1394_handle_t t1394_hdl,t1394_fcp_evts_t * evts,uint_t flags)13450Sstevel@tonic-gate t1394_fcp_register_controller(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
13460Sstevel@tonic-gate     uint_t flags)
13470Sstevel@tonic-gate {
13480Sstevel@tonic-gate 	int		result;
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_register_controller_enter,
13510Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	result = s1394_fcp_register_ctl((s1394_target_t *)t1394_hdl, evts);
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_register_controller_exit,
13580Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
13590Sstevel@tonic-gate 	return (result);
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate /*
13630Sstevel@tonic-gate  * Function:    t1394_fcp_unregister_controller()
13640Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
13650Sstevel@tonic-gate  *					    t1394_attach()
13660Sstevel@tonic-gate  *
13670Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully unregistered.
13680Sstevel@tonic-gate  *
13690Sstevel@tonic-gate  *		DDI_FAILURE		Not unregistered due to failure.
13700Sstevel@tonic-gate  *
13710Sstevel@tonic-gate  * Description:	Used to unregister the target within the Framework as an FCP
13720Sstevel@tonic-gate  *		controller.
13730Sstevel@tonic-gate  */
13740Sstevel@tonic-gate int
t1394_fcp_unregister_controller(t1394_handle_t t1394_hdl)13750Sstevel@tonic-gate t1394_fcp_unregister_controller(t1394_handle_t t1394_hdl)
13760Sstevel@tonic-gate {
13770Sstevel@tonic-gate 	int		result;
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_unregister_controller_enter,
13800Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	result = s1394_fcp_unregister_ctl((s1394_target_t *)t1394_hdl);
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_unregister_controller_exit,
13870Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
13880Sstevel@tonic-gate 	return (result);
13890Sstevel@tonic-gate }
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate /*
13920Sstevel@tonic-gate  * Function:    t1394_fcp_register_target()
13930Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
13940Sstevel@tonic-gate  *					    t1394_attach()
13950Sstevel@tonic-gate  *		evts			The structure in which the target
13960Sstevel@tonic-gate  *					    specifies its callback routines
13970Sstevel@tonic-gate  *
13980Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
13990Sstevel@tonic-gate  *
14000Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
14010Sstevel@tonic-gate  *
14020Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
14030Sstevel@tonic-gate  *
14040Sstevel@tonic-gate  * Description:	Used to register the target within the Framework as an FCP
14050Sstevel@tonic-gate  *		target.
14060Sstevel@tonic-gate  */
14070Sstevel@tonic-gate /* ARGSUSED */
14080Sstevel@tonic-gate int
t1394_fcp_register_target(t1394_handle_t t1394_hdl,t1394_fcp_evts_t * evts,uint_t flags)14090Sstevel@tonic-gate t1394_fcp_register_target(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
14100Sstevel@tonic-gate     uint_t flags)
14110Sstevel@tonic-gate {
14120Sstevel@tonic-gate 	int		result;
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_register_target_enter,
14150Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 	result = s1394_fcp_register_tgt((s1394_target_t *)t1394_hdl, evts);
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_register_target_exit,
14220Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
14230Sstevel@tonic-gate 	return (result);
14240Sstevel@tonic-gate }
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate /*
14270Sstevel@tonic-gate  * Function:    t1394_fcp_unregister_target()
14280Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
14290Sstevel@tonic-gate  *					    t1394_attach()
14300Sstevel@tonic-gate  *
14310Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully unregistered.
14320Sstevel@tonic-gate  *
14330Sstevel@tonic-gate  *		DDI_FAILURE		Not unregistered due to failure.
14340Sstevel@tonic-gate  *
14350Sstevel@tonic-gate  * Description:	Used to unregister the target within the Framework as an FCP
14360Sstevel@tonic-gate  *		target.
14370Sstevel@tonic-gate  */
14380Sstevel@tonic-gate int
t1394_fcp_unregister_target(t1394_handle_t t1394_hdl)14390Sstevel@tonic-gate t1394_fcp_unregister_target(t1394_handle_t t1394_hdl)
14400Sstevel@tonic-gate {
14410Sstevel@tonic-gate 	int		result;
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_unregister_target_enter,
14440Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 	result = s1394_fcp_unregister_tgt((s1394_target_t *)t1394_hdl);
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_unregister_target_exit,
14510Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
14520Sstevel@tonic-gate 	return (result);
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate /*
14560Sstevel@tonic-gate  * Function:    t1394_cmp_register()
14570Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
14580Sstevel@tonic-gate  *					    t1394_attach()
14590Sstevel@tonic-gate  *		evts			The structure in which the target
14600Sstevel@tonic-gate  *					    specifies its callback routines
14610Sstevel@tonic-gate  *
14620Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
14630Sstevel@tonic-gate  *
14640Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
14650Sstevel@tonic-gate  *
14660Sstevel@tonic-gate  * Description:	Used to register the target within the Framework as a CMP
14670Sstevel@tonic-gate  *		device.
14680Sstevel@tonic-gate  */
14690Sstevel@tonic-gate /* ARGSUSED */
14700Sstevel@tonic-gate int
t1394_cmp_register(t1394_handle_t t1394_hdl,t1394_cmp_evts_t * evts,uint_t flags)14710Sstevel@tonic-gate t1394_cmp_register(t1394_handle_t t1394_hdl, t1394_cmp_evts_t *evts,
14720Sstevel@tonic-gate     uint_t flags)
14730Sstevel@tonic-gate {
14740Sstevel@tonic-gate 	int		result;
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_register_enter, S1394_TNF_SL_CMP_STACK, "");
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	result = s1394_cmp_register((s1394_target_t *)t1394_hdl, evts);
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_register_exit, S1394_TNF_SL_CMP_STACK, "");
14830Sstevel@tonic-gate 	return (result);
14840Sstevel@tonic-gate }
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate /*
14870Sstevel@tonic-gate  * Function:    t1394_cmp_unregister()
14880Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
14890Sstevel@tonic-gate  *					    t1394_attach()
14900Sstevel@tonic-gate  *		evts			The structure in which the target
14910Sstevel@tonic-gate  *					    specifies its callback routines
14920Sstevel@tonic-gate  *
14930Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
14940Sstevel@tonic-gate  *
14950Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
14960Sstevel@tonic-gate  *
14970Sstevel@tonic-gate  * Description:	Used to unregister the target within the Framework as a CMP
14980Sstevel@tonic-gate  *		device.
14990Sstevel@tonic-gate  */
15000Sstevel@tonic-gate int
t1394_cmp_unregister(t1394_handle_t t1394_hdl)15010Sstevel@tonic-gate t1394_cmp_unregister(t1394_handle_t t1394_hdl)
15020Sstevel@tonic-gate {
15030Sstevel@tonic-gate 	int		result;
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_unregister_enter, S1394_TNF_SL_CMP_STACK,
15060Sstevel@tonic-gate 	    "");
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	result = s1394_cmp_unregister((s1394_target_t *)t1394_hdl);
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_unregister_exit, S1394_TNF_SL_CMP_STACK,
15130Sstevel@tonic-gate 	    "");
15140Sstevel@tonic-gate 	return (result);
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate /*
15180Sstevel@tonic-gate  * Function:    t1394_cmp_read()
15190Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
15200Sstevel@tonic-gate  *					    t1394_attach()
15210Sstevel@tonic-gate  *		reg			Register type.
15220Sstevel@tonic-gate  *		valp			Returned register value.
15230Sstevel@tonic-gate  *
15240Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
15250Sstevel@tonic-gate  *
15260Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
15270Sstevel@tonic-gate  *
15280Sstevel@tonic-gate  * Description:	Used to read a CMP register value.
15290Sstevel@tonic-gate  */
15300Sstevel@tonic-gate int
t1394_cmp_read(t1394_handle_t t1394_hdl,t1394_cmp_reg_t reg,uint32_t * valp)15310Sstevel@tonic-gate t1394_cmp_read(t1394_handle_t t1394_hdl, t1394_cmp_reg_t reg, uint32_t *valp)
15320Sstevel@tonic-gate {
15330Sstevel@tonic-gate 	int		result;
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_read_enter, S1394_TNF_SL_CMP_STACK, "");
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate 	result = s1394_cmp_read((s1394_target_t *)t1394_hdl, reg, valp);
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_read_exit, S1394_TNF_SL_CMP_STACK, "");
15420Sstevel@tonic-gate 	return (result);
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate /*
15460Sstevel@tonic-gate  * Function:    t1394_cmp_cas()
15470Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
15480Sstevel@tonic-gate  *					    t1394_attach()
15490Sstevel@tonic-gate  *		reg			Register type.
15500Sstevel@tonic-gate  *		arg_val			Compare argument.
15510Sstevel@tonic-gate  *		new_val			New register value.
15520Sstevel@tonic-gate  *		old_valp		Returned original register value.
15530Sstevel@tonic-gate  *
15540Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
15550Sstevel@tonic-gate  *
15560Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
15570Sstevel@tonic-gate  *
15580Sstevel@tonic-gate  * Description:	Used to compare-swap a CMP register value.
15590Sstevel@tonic-gate  */
15600Sstevel@tonic-gate int
t1394_cmp_cas(t1394_handle_t t1394_hdl,t1394_cmp_reg_t reg,uint32_t arg_val,uint32_t new_val,uint32_t * old_valp)15610Sstevel@tonic-gate t1394_cmp_cas(t1394_handle_t t1394_hdl, t1394_cmp_reg_t reg, uint32_t arg_val,
15620Sstevel@tonic-gate     uint32_t new_val, uint32_t *old_valp)
15630Sstevel@tonic-gate {
15640Sstevel@tonic-gate 	int		result;
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_read_enter, S1394_TNF_SL_CMP_STACK, "");
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	result = s1394_cmp_cas((s1394_target_t *)t1394_hdl, reg, arg_val,
15710Sstevel@tonic-gate 				new_val, old_valp);
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_read_exit, S1394_TNF_SL_CMP_STACK, "");
15740Sstevel@tonic-gate 	return (result);
15750Sstevel@tonic-gate }
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate /*
15780Sstevel@tonic-gate  * Function:    t1394_alloc_isoch_single()
15790Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
15800Sstevel@tonic-gate  *					    t1394_attach()
15810Sstevel@tonic-gate  *		sii			The structure used to set up the
15820Sstevel@tonic-gate  *					    overall characteristics of the
15830Sstevel@tonic-gate  *					    isochronous stream
15840Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
15850Sstevel@tonic-gate  *
15860Sstevel@tonic-gate  * Output(s):	setup_args		Contains the channel number that was
15870Sstevel@tonic-gate  *					    allocated
15880Sstevel@tonic-gate  *		t1394_single_hdl	This in the isoch "handle" used in
15890Sstevel@tonic-gate  *					    t1394_free_isoch_single()
15900Sstevel@tonic-gate  *		result			Used to pass more specific info back
15910Sstevel@tonic-gate  *					    to target
15920Sstevel@tonic-gate  *
15930Sstevel@tonic-gate  * Description:	t1394_alloc_isoch_single() is used to direct the 1394 Software
15940Sstevel@tonic-gate  *		Framework to allocate an isochronous channel and bandwidth
15950Sstevel@tonic-gate  *		from the Isochronous Resource Manager (IRM).  If a bus reset
15960Sstevel@tonic-gate  *		occurs, the 1394 Software Framework attempts to reallocate the
15970Sstevel@tonic-gate  *		same resources, calling the rsrc_fail_target() callback if
15980Sstevel@tonic-gate  *		it is unsuccessful.
15990Sstevel@tonic-gate  */
16000Sstevel@tonic-gate /* ARGSUSED */
16010Sstevel@tonic-gate int
t1394_alloc_isoch_single(t1394_handle_t t1394_hdl,t1394_isoch_singleinfo_t * sii,uint_t flags,t1394_isoch_single_out_t * output_args,t1394_isoch_single_handle_t * t1394_single_hdl,int * result)16020Sstevel@tonic-gate t1394_alloc_isoch_single(t1394_handle_t t1394_hdl,
16030Sstevel@tonic-gate     t1394_isoch_singleinfo_t *sii, uint_t flags,
16040Sstevel@tonic-gate     t1394_isoch_single_out_t *output_args,
16050Sstevel@tonic-gate     t1394_isoch_single_handle_t	*t1394_single_hdl, int *result)
16060Sstevel@tonic-gate {
16070Sstevel@tonic-gate 	s1394_hal_t		*hal;
16080Sstevel@tonic-gate 	s1394_isoch_cec_t	*cec_new;
16090Sstevel@tonic-gate 	t1394_join_isochinfo_t	jii;
16100Sstevel@tonic-gate 	int			ret;
16110Sstevel@tonic-gate 	int			err;
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_enter,
16140Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
16170Sstevel@tonic-gate 	ASSERT(t1394_single_hdl != NULL);
16180Sstevel@tonic-gate 	ASSERT(sii != NULL);
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 	/* Check for invalid channel_mask */
16230Sstevel@tonic-gate 	if (sii->si_channel_mask == 0) {
16240Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
16250Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
16260Sstevel@tonic-gate 		    "Invalid channel mask");
16270Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
16280Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
16290Sstevel@tonic-gate 		return (DDI_FAILURE);
16300Sstevel@tonic-gate 	}
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 	/* Check for invalid bandwidth */
16330Sstevel@tonic-gate 	if ((sii->si_bandwidth <= IEEE1394_BANDWIDTH_MIN) ||
16340Sstevel@tonic-gate 	    (sii->si_bandwidth > IEEE1394_BANDWIDTH_MAX)) {
16350Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
16360Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
16370Sstevel@tonic-gate 		    "Invalid bandwidth requirements");
16380Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
16390Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
16400Sstevel@tonic-gate 		return (DDI_FAILURE);
16410Sstevel@tonic-gate 	}
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 	/* Verify that rsrc_fail_target() callback is non-NULL */
16440Sstevel@tonic-gate 	if (sii->rsrc_fail_target == NULL) {
16450Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
16460Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
16470Sstevel@tonic-gate 		    "Invalid callback specified");
16480Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
16490Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
16500Sstevel@tonic-gate 		return (DDI_FAILURE);
16510Sstevel@tonic-gate 	}
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 	/*
16540Sstevel@tonic-gate 	 * Allocate an Isoch CEC of type S1394_SINGLE
16550Sstevel@tonic-gate 	 */
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 	/* Allocate the Isoch CEC structure */
16580Sstevel@tonic-gate 	cec_new = kmem_zalloc(sizeof (s1394_isoch_cec_t), KM_SLEEP);
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 	/* Initialize the structure type */
16610Sstevel@tonic-gate 	cec_new->cec_type = S1394_SINGLE;
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 	/* Create the mutex and "in_callbacks" cv */
16640Sstevel@tonic-gate 	mutex_init(&cec_new->isoch_cec_mutex, NULL, MUTEX_DRIVER,
16650Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
16660Sstevel@tonic-gate 	cv_init(&cec_new->in_callbacks_cv, NULL, CV_DRIVER,
16670Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 	/* Initialize the Isoch CEC's member list */
16700Sstevel@tonic-gate 	cec_new->cec_member_list_head = NULL;
16710Sstevel@tonic-gate 	cec_new->cec_member_list_tail = NULL;
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 	/* Initialize the filters */
16740Sstevel@tonic-gate 	cec_new->filter_min_speed	= sii->si_speed;
16750Sstevel@tonic-gate 	cec_new->filter_max_speed	= sii->si_speed;
16760Sstevel@tonic-gate 	cec_new->filter_current_speed	= cec_new->filter_max_speed;
16770Sstevel@tonic-gate 	cec_new->filter_channel_mask	= sii->si_channel_mask;
16780Sstevel@tonic-gate 	cec_new->bandwidth		= sii->si_bandwidth;
16790Sstevel@tonic-gate 	cec_new->state_transitions	= ISOCH_CEC_FREE | ISOCH_CEC_JOIN |
16800Sstevel@tonic-gate 					    ISOCH_CEC_SETUP;
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	mutex_enter(&hal->isoch_cec_list_mutex);
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	/* Insert Isoch CEC into the HAL's list */
16850Sstevel@tonic-gate 	s1394_isoch_cec_list_insert(hal, cec_new);
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 	mutex_exit(&hal->isoch_cec_list_mutex);
16880Sstevel@tonic-gate 
16890Sstevel@tonic-gate 	/*
16900Sstevel@tonic-gate 	 * Join the newly created Isoch CEC
16910Sstevel@tonic-gate 	 */
16920Sstevel@tonic-gate 	jii.req_channel_mask	= sii->si_channel_mask;
16930Sstevel@tonic-gate 	jii.req_max_speed	= sii->si_speed;
16940Sstevel@tonic-gate 	jii.jii_options		= T1394_TALKER;
16950Sstevel@tonic-gate 	jii.isoch_cec_evts_arg	= sii->single_evt_arg;
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	/* All events are NULL except rsrc_fail_target() */
16980Sstevel@tonic-gate 	jii.isoch_cec_evts.setup_target	    = NULL;
16990Sstevel@tonic-gate 	jii.isoch_cec_evts.start_target	    = NULL;
17000Sstevel@tonic-gate 	jii.isoch_cec_evts.stop_target	    = NULL;
17010Sstevel@tonic-gate 	jii.isoch_cec_evts.stop_target	    = NULL;
17020Sstevel@tonic-gate 	jii.isoch_cec_evts.teardown_target  = NULL;
17030Sstevel@tonic-gate 	jii.isoch_cec_evts.rsrc_fail_target = sii->rsrc_fail_target;
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	ret = t1394_join_isoch_cec(t1394_hdl,
17060Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t)cec_new, 0, &jii);
17070Sstevel@tonic-gate 
17080Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
17090Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
17100Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17110Sstevel@tonic-gate 		    "Unexpected error from t1394_join_isoch_cec()");
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 		ret = t1394_free_isoch_cec(t1394_hdl, flags,
17140Sstevel@tonic-gate 		    (t1394_isoch_cec_handle_t *)&cec_new);
17150Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
17160Sstevel@tonic-gate 			/* Unable to free the Isoch CEC */
17170Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_single_error,
17180Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17190Sstevel@tonic-gate 			    "Unexpected error from t1394_free_isoch_cec()");
17200Sstevel@tonic-gate 			ASSERT(0);
17210Sstevel@tonic-gate 		}
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 		/* Handle is nulled out before returning */
17240Sstevel@tonic-gate 		*t1394_single_hdl = NULL;
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
17270Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
17280Sstevel@tonic-gate 		return (DDI_FAILURE);
17290Sstevel@tonic-gate 	}
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	/*
17320Sstevel@tonic-gate 	 * Setup the isoch resources, etc.
17330Sstevel@tonic-gate 	 */
17340Sstevel@tonic-gate 	ret = t1394_setup_isoch_cec(t1394_hdl,
17350Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t)cec_new, 0, &err);
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
17380Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
17390Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17400Sstevel@tonic-gate 		    "Unexpected error from t1394_setup_isoch_cec()");
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 		*result = err;
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 		/* Leave the Isoch CEC */
17450Sstevel@tonic-gate 		ret = t1394_leave_isoch_cec(t1394_hdl,
17460Sstevel@tonic-gate 		    (t1394_isoch_cec_handle_t)cec_new, 0);
17470Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
17480Sstevel@tonic-gate 			/* Unable to leave the Isoch CEC */
17490Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_single_error,
17500Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17510Sstevel@tonic-gate 			    "Unexpected error from t1394_leave_isoch_cec()");
17520Sstevel@tonic-gate 			ASSERT(0);
17530Sstevel@tonic-gate 		}
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 		/* Free up the Isoch CEC */
17560Sstevel@tonic-gate 		ret = t1394_free_isoch_cec(t1394_hdl, flags,
17570Sstevel@tonic-gate 		    (t1394_isoch_cec_handle_t *)&cec_new);
17580Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
17590Sstevel@tonic-gate 			/* Unable to free the Isoch CEC */
17600Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_single_error,
17610Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17620Sstevel@tonic-gate 			    "Unexpected error from t1394_free_isoch_cec()");
17630Sstevel@tonic-gate 			ASSERT(0);
17640Sstevel@tonic-gate 		}
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 		/* Handle is nulled out before returning */
17670Sstevel@tonic-gate 		*t1394_single_hdl = NULL;
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
17700Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
17710Sstevel@tonic-gate 		return (DDI_FAILURE);
17720Sstevel@tonic-gate 	}
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 	/* Return the setup_args - channel num and speed */
17750Sstevel@tonic-gate 	mutex_enter(&cec_new->isoch_cec_mutex);
17760Sstevel@tonic-gate 	output_args->channel_num  = cec_new->realloc_chnl_num;
17770Sstevel@tonic-gate 	mutex_exit(&cec_new->isoch_cec_mutex);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	/* Update the handle */
17800Sstevel@tonic-gate 	*t1394_single_hdl = (t1394_isoch_single_handle_t)cec_new;
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
17830Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
17840Sstevel@tonic-gate 	return (DDI_SUCCESS);
17850Sstevel@tonic-gate }
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate /*
17880Sstevel@tonic-gate  * Function:    t1394_free_isoch_single()
17890Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
17900Sstevel@tonic-gate  *					    t1394_attach()
17910Sstevel@tonic-gate  *		t1394_single_hdl	The isoch "handle" return by
17920Sstevel@tonic-gate  *					    t1394_alloc_isoch_single()
17930Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
17940Sstevel@tonic-gate  *
17950Sstevel@tonic-gate  * Output(s):	None
17960Sstevel@tonic-gate  *
17970Sstevel@tonic-gate  * Description:	t1394_free_isoch_single() frees the isochronous resources
17980Sstevel@tonic-gate  *		and the handle that were allocated during the call to
17990Sstevel@tonic-gate  *		t1394_alloc_isoch_single().
18000Sstevel@tonic-gate  */
18010Sstevel@tonic-gate /* ARGSUSED */
18020Sstevel@tonic-gate void
t1394_free_isoch_single(t1394_handle_t t1394_hdl,t1394_isoch_single_handle_t * t1394_single_hdl,uint_t flags)18030Sstevel@tonic-gate t1394_free_isoch_single(t1394_handle_t t1394_hdl,
18040Sstevel@tonic-gate     t1394_isoch_single_handle_t *t1394_single_hdl, uint_t flags)
18050Sstevel@tonic-gate {
18060Sstevel@tonic-gate 	s1394_isoch_cec_t *cec_curr;
18070Sstevel@tonic-gate 	int		  ret;
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_single_enter,
18100Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
18130Sstevel@tonic-gate 	ASSERT(t1394_single_hdl != NULL);
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
18160Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)(*t1394_single_hdl);
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 	/*
18190Sstevel@tonic-gate 	 * Teardown the isoch resources, etc.
18200Sstevel@tonic-gate 	 */
18210Sstevel@tonic-gate 	ret = t1394_teardown_isoch_cec(t1394_hdl,
18220Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t)cec_curr, 0);
18230Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
18240Sstevel@tonic-gate 		/* Unable to teardown the Isoch CEC */
18250Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_single_error,
18260Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
18270Sstevel@tonic-gate 		    "Unexpected error from t1394_teardown_isoch_cec()");
18280Sstevel@tonic-gate 		ASSERT(0);
18290Sstevel@tonic-gate 	}
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate 	/*
18320Sstevel@tonic-gate 	 * Leave the Isoch CEC
18330Sstevel@tonic-gate 	 */
18340Sstevel@tonic-gate 	ret = t1394_leave_isoch_cec(t1394_hdl,
18350Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t)cec_curr, 0);
18360Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
18370Sstevel@tonic-gate 		/* Unable to leave the Isoch CEC */
18380Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_single_error,
18390Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
18400Sstevel@tonic-gate 		    "Unexpected error from t1394_leave_isoch_cec()");
18410Sstevel@tonic-gate 		ASSERT(0);
18420Sstevel@tonic-gate 	}
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 	/*
18450Sstevel@tonic-gate 	 * Free the Isoch CEC
18460Sstevel@tonic-gate 	 */
18470Sstevel@tonic-gate 	ret = t1394_free_isoch_cec(t1394_hdl, flags,
18480Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t *)&cec_curr);
18490Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
18500Sstevel@tonic-gate 		/* Unable to free the Isoch CEC */
18510Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_single_error,
18520Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
18530Sstevel@tonic-gate 		    "Unexpected error from t1394_free_isoch_cec()");
18540Sstevel@tonic-gate 		ASSERT(0);
18550Sstevel@tonic-gate 	}
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	/* Handle is nulled out before returning */
18580Sstevel@tonic-gate 	*t1394_single_hdl = NULL;
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_single_exit,
18610Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
18620Sstevel@tonic-gate }
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate /*
18650Sstevel@tonic-gate  * Function:    t1394_alloc_isoch_cec()
18660Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
18670Sstevel@tonic-gate  *					    t1394_attach()
18680Sstevel@tonic-gate  *		props			The structure used to set up the
18690Sstevel@tonic-gate  *					    overall characteristics of for
18700Sstevel@tonic-gate  *					    the Isoch CEC.
18710Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
18720Sstevel@tonic-gate  *
18730Sstevel@tonic-gate  * Output(s):	t1394_isoch_cec_hdl	The Isoch CEC "handle" used in all
18740Sstevel@tonic-gate  *					    subsequent isoch_cec() calls
18750Sstevel@tonic-gate  *
18760Sstevel@tonic-gate  * Description:	t1394_alloc_isoch_cec() allocates and initializes an
18770Sstevel@tonic-gate  *		isochronous channel event coordinator (Isoch CEC) for use
18780Sstevel@tonic-gate  *		in managing and coordinating activity for an isoch channel
18790Sstevel@tonic-gate  */
18800Sstevel@tonic-gate /* ARGSUSED */
18810Sstevel@tonic-gate int
t1394_alloc_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_props_t * props,uint_t flags,t1394_isoch_cec_handle_t * t1394_isoch_cec_hdl)18820Sstevel@tonic-gate t1394_alloc_isoch_cec(t1394_handle_t t1394_hdl, t1394_isoch_cec_props_t *props,
18830Sstevel@tonic-gate     uint_t flags, t1394_isoch_cec_handle_t *t1394_isoch_cec_hdl)
18840Sstevel@tonic-gate {
18850Sstevel@tonic-gate 	s1394_hal_t	  *hal;
18860Sstevel@tonic-gate 	s1394_isoch_cec_t *cec_new;
18870Sstevel@tonic-gate 	uint64_t	  temp;
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_enter,
18900Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
18930Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
18940Sstevel@tonic-gate 	ASSERT(props != NULL);
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 	/* Check for invalid channel_mask */
18990Sstevel@tonic-gate 	if (props->cec_channel_mask == 0) {
19000Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_cec_error,
19010Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
19020Sstevel@tonic-gate 		    "Invalid channel mask");
19030Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19040Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
19050Sstevel@tonic-gate 		return (DDI_FAILURE);
19060Sstevel@tonic-gate 	}
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	/* Test conditions specific to T1394_NO_IRM_ALLOC */
19090Sstevel@tonic-gate 	temp = props->cec_channel_mask;
19100Sstevel@tonic-gate 	if (props->cec_options & T1394_NO_IRM_ALLOC) {
19110Sstevel@tonic-gate 		/* If T1394_NO_IRM_ALLOC, then only one bit should be set */
19120Sstevel@tonic-gate 		if ((temp & (temp - 1)) != 0) {
19130Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_cec_error,
19140Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
19150Sstevel@tonic-gate 			    "Invalid channel mask");
19160Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19170Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_STACK, "");
19180Sstevel@tonic-gate 			return (DDI_FAILURE);
19190Sstevel@tonic-gate 		}
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 		/* If T1394_NO_IRM_ALLOC, then speeds should be equal */
19220Sstevel@tonic-gate 		if (props->cec_min_speed != props->cec_max_speed) {
19230Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_cec_error,
19240Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
19250Sstevel@tonic-gate 			    "Invalid speeds (min != max)");
19260Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19270Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_STACK, "");
19280Sstevel@tonic-gate 			return (DDI_FAILURE);
19290Sstevel@tonic-gate 		}
19300Sstevel@tonic-gate 	}
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate 	/* Check for invalid bandwidth */
19330Sstevel@tonic-gate 	if ((props->cec_bandwidth <= IEEE1394_BANDWIDTH_MIN) ||
19340Sstevel@tonic-gate 	    (props->cec_bandwidth > IEEE1394_BANDWIDTH_MAX)) {
19350Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_cec_error,
19360Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
19370Sstevel@tonic-gate 		    "Invalid bandwidth requirements");
19380Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19390Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
19400Sstevel@tonic-gate 		return (DDI_FAILURE);
19410Sstevel@tonic-gate 	}
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	/* Allocate the Isoch CEC structure */
19440Sstevel@tonic-gate 	cec_new = kmem_zalloc(sizeof (s1394_isoch_cec_t), KM_SLEEP);
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	/* Initialize the structure type */
19470Sstevel@tonic-gate 	cec_new->cec_type = S1394_PEER_TO_PEER;
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 	/* Create the mutex and "in_callbacks" cv */
19500Sstevel@tonic-gate 	mutex_init(&cec_new->isoch_cec_mutex, NULL, MUTEX_DRIVER,
19510Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
19520Sstevel@tonic-gate 	cv_init(&cec_new->in_callbacks_cv, NULL, CV_DRIVER,
19530Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 	/* Initialize the Isoch CEC's member list */
19560Sstevel@tonic-gate 	cec_new->cec_member_list_head	= NULL;
19570Sstevel@tonic-gate 	cec_new->cec_member_list_tail	= NULL;
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 	/* Initialize the filters */
19600Sstevel@tonic-gate 	cec_new->filter_min_speed	= props->cec_min_speed;
19610Sstevel@tonic-gate 	cec_new->filter_max_speed	= props->cec_max_speed;
19620Sstevel@tonic-gate 	cec_new->filter_current_speed	= cec_new->filter_max_speed;
19630Sstevel@tonic-gate 	cec_new->filter_channel_mask	= props->cec_channel_mask;
19640Sstevel@tonic-gate 	cec_new->bandwidth		= props->cec_bandwidth;
19650Sstevel@tonic-gate 	cec_new->cec_options		= props->cec_options;
19660Sstevel@tonic-gate 	cec_new->state_transitions	= ISOCH_CEC_FREE | ISOCH_CEC_JOIN |
19670Sstevel@tonic-gate 					    ISOCH_CEC_SETUP;
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate 	mutex_enter(&hal->isoch_cec_list_mutex);
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	/* Insert Isoch CEC into the HAL's list */
19720Sstevel@tonic-gate 	s1394_isoch_cec_list_insert(hal, cec_new);
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	mutex_exit(&hal->isoch_cec_list_mutex);
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate 	/* Update the handle and return */
19770Sstevel@tonic-gate 	*t1394_isoch_cec_hdl = (t1394_isoch_cec_handle_t)cec_new;
19780Sstevel@tonic-gate 
19790Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19800Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
19810Sstevel@tonic-gate 	return (DDI_SUCCESS);
19820Sstevel@tonic-gate }
19830Sstevel@tonic-gate 
19840Sstevel@tonic-gate /*
19850Sstevel@tonic-gate  * Function:    t1394_free_isoch_cec()
19860Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
19870Sstevel@tonic-gate  *					    t1394_attach()
19880Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
19890Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
19900Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
19910Sstevel@tonic-gate  *
19920Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully freed the Isoch CEC
19930Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to free the Isoch CEC
19940Sstevel@tonic-gate  *
19950Sstevel@tonic-gate  * Description:	t1394_free_isoch_cec() attempts to free the Isoch CEC
19960Sstevel@tonic-gate  *		structure.  It will fail (DDI_FAILURE) if there are any
19970Sstevel@tonic-gate  *		remaining members who have not yet left.
19980Sstevel@tonic-gate  */
19990Sstevel@tonic-gate /* ARGSUSED */
20000Sstevel@tonic-gate int
t1394_free_isoch_cec(t1394_handle_t t1394_hdl,uint_t flags,t1394_isoch_cec_handle_t * t1394_isoch_cec_hdl)20010Sstevel@tonic-gate t1394_free_isoch_cec(t1394_handle_t t1394_hdl, uint_t flags,
20020Sstevel@tonic-gate     t1394_isoch_cec_handle_t *t1394_isoch_cec_hdl)
20030Sstevel@tonic-gate {
20040Sstevel@tonic-gate 	s1394_hal_t	  *hal;
20050Sstevel@tonic-gate 	s1394_isoch_cec_t *cec_curr;
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_enter,
20080Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
20090Sstevel@tonic-gate 
20100Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
20110Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
20120Sstevel@tonic-gate 
20130Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
20160Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)(*t1394_isoch_cec_hdl);
20170Sstevel@tonic-gate 
20180Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
20190Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 	/* Are we in any callbacks? */
20220Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
20230Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
20240Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
20250Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_cec_error,
20260Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
20270Sstevel@tonic-gate 		    "Not allowed to free Isoch CEC (in callbacks)");
20280Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit,
20290Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
20300Sstevel@tonic-gate 		return (DDI_FAILURE);
20310Sstevel@tonic-gate 	}
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate 	/* Is "free" a legal state transition? */
20340Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_FREE) == 0) {
20350Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
20360Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
20370Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_cec_error,
20380Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
20390Sstevel@tonic-gate 		    "Not allowed to free Isoch CEC");
20400Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit,
20410Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
20420Sstevel@tonic-gate 		return (DDI_FAILURE);
20430Sstevel@tonic-gate 	}
20440Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 	mutex_enter(&hal->isoch_cec_list_mutex);
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 	/* Remove Isoch CEC from HAL's list */
20490Sstevel@tonic-gate 	s1394_isoch_cec_list_remove(hal, cec_curr);
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 	mutex_exit(&hal->isoch_cec_list_mutex);
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate 	/* Destroy the Isoch CEC's mutex and cv */
20540Sstevel@tonic-gate 	cv_destroy(&cec_curr->in_callbacks_cv);
20550Sstevel@tonic-gate 	mutex_destroy(&cec_curr->isoch_cec_mutex);
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	/* Free up the memory for the Isoch CEC struct */
20580Sstevel@tonic-gate 	kmem_free(cec_curr, sizeof (s1394_isoch_cec_t));
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 	/* Update the handle and return */
20610Sstevel@tonic-gate 	*t1394_isoch_cec_hdl = NULL;
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit,
20640Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
20650Sstevel@tonic-gate 	return (DDI_SUCCESS);
20660Sstevel@tonic-gate }
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate /*
20690Sstevel@tonic-gate  * Function:    t1394_join_isoch_cec()
20700Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
20710Sstevel@tonic-gate  *					    t1394_attach()
20720Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
20730Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
20740Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
20750Sstevel@tonic-gate  *		join_isoch_info		This structure provides infomation
20760Sstevel@tonic-gate  *					    about a target that wishes to join
20770Sstevel@tonic-gate  *					    the given Isoch CEC.  It gives
20780Sstevel@tonic-gate  *					    max_speed, channel_mask, etc.
20790Sstevel@tonic-gate  *
20800Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully joined the
20810Sstevel@tonic-gate  *					    Isoch CEC
20820Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to join the Isoch CEC
20830Sstevel@tonic-gate  *
20840Sstevel@tonic-gate  * Description:	t1394_join_isoch_cec() determines, based on the information
20850Sstevel@tonic-gate  *		given in the join_isoch_info structure, if the target may
20860Sstevel@tonic-gate  *		join the Isoch CEC.  If it is determined that the target may
20870Sstevel@tonic-gate  *		join, the specified callback routines are stored away for
20880Sstevel@tonic-gate  *		later use in the coordination tasks.
20890Sstevel@tonic-gate  */
20900Sstevel@tonic-gate /* ARGSUSED */
20910Sstevel@tonic-gate int
t1394_join_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags,t1394_join_isochinfo_t * join_isoch_info)20920Sstevel@tonic-gate t1394_join_isoch_cec(t1394_handle_t t1394_hdl,
20930Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags,
20940Sstevel@tonic-gate     t1394_join_isochinfo_t *join_isoch_info)
20950Sstevel@tonic-gate {
20960Sstevel@tonic-gate 	s1394_hal_t		 *hal;
20970Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
20980Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_new;
20990Sstevel@tonic-gate 	uint64_t		 check_mask;
21000Sstevel@tonic-gate 	uint_t			 curr_max_speed;
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_enter,
21030Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
21060Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
21110Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate 	/* Allocate a new Isoch CEC member structure */
21140Sstevel@tonic-gate 	member_new = kmem_zalloc(sizeof (s1394_isoch_cec_member_t), KM_SLEEP);
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
21170Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 	/* Are we in any callbacks? (Wait for them to finish) */
21200Sstevel@tonic-gate 	while (CEC_IN_ANY_CALLBACKS(cec_curr)) {
21210Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_TRUE;
21220Sstevel@tonic-gate 		cv_wait(&cec_curr->in_callbacks_cv,
21230Sstevel@tonic-gate 		    &cec_curr->isoch_cec_mutex);
21240Sstevel@tonic-gate 	}
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 	/* Is "join" a legal state transition? */
21270Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) == 0) {
21280Sstevel@tonic-gate 		kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
21290Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21300Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21310Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21320Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21330Sstevel@tonic-gate 		    "Not allowed to join Isoch CEC");
21340Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21350Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
21360Sstevel@tonic-gate 		return (DDI_FAILURE);
21370Sstevel@tonic-gate 	}
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	/* Check the channel mask for consistency */
21400Sstevel@tonic-gate 	check_mask = join_isoch_info->req_channel_mask &
21410Sstevel@tonic-gate 	    cec_curr->filter_channel_mask;
21420Sstevel@tonic-gate 	if (check_mask == 0) {
21430Sstevel@tonic-gate 		kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
21440Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21450Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21460Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21470Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21480Sstevel@tonic-gate 		    "Inconsistent channel mask specified");
21490Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21500Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
21510Sstevel@tonic-gate 		return (DDI_FAILURE);
21520Sstevel@tonic-gate 	}
21530Sstevel@tonic-gate 
21540Sstevel@tonic-gate 	/* Check for consistent speeds */
21550Sstevel@tonic-gate 	if (join_isoch_info->req_max_speed < cec_curr->filter_min_speed) {
21560Sstevel@tonic-gate 		kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
21570Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21580Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21590Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21600Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21610Sstevel@tonic-gate 		    "Inconsistent speed specified");
21620Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21630Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
21640Sstevel@tonic-gate 		return (DDI_FAILURE);
21650Sstevel@tonic-gate 	} else if (join_isoch_info->req_max_speed <
21660Sstevel@tonic-gate 	    cec_curr->filter_current_speed) {
21670Sstevel@tonic-gate 		curr_max_speed = join_isoch_info->req_max_speed;
21680Sstevel@tonic-gate 	} else {
21690Sstevel@tonic-gate 		curr_max_speed = cec_curr->filter_current_speed;
21700Sstevel@tonic-gate 	}
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate 	/* Check for no more than one talker */
21730Sstevel@tonic-gate 	if ((join_isoch_info->jii_options & T1394_TALKER) &&
21740Sstevel@tonic-gate 	    (cec_curr->cec_member_talker != NULL)) {
21750Sstevel@tonic-gate 		kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
21760Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21770Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21780Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21790Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21800Sstevel@tonic-gate 		    "Multiple talkers specified");
21810Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21820Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
21830Sstevel@tonic-gate 		return (DDI_FAILURE);
21840Sstevel@tonic-gate 	}
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 	/* Verify that all callbacks are non-NULL (for PEER_TO_PEER) */
21870Sstevel@tonic-gate 	if ((cec_curr->cec_type == S1394_PEER_TO_PEER) &&
21880Sstevel@tonic-gate 	    ((join_isoch_info->isoch_cec_evts.setup_target	== NULL) ||
21890Sstevel@tonic-gate 	    (join_isoch_info->isoch_cec_evts.start_target	== NULL) ||
21900Sstevel@tonic-gate 	    (join_isoch_info->isoch_cec_evts.stop_target	== NULL) ||
21910Sstevel@tonic-gate 	    (join_isoch_info->isoch_cec_evts.rsrc_fail_target	== NULL) ||
21920Sstevel@tonic-gate 	    (join_isoch_info->isoch_cec_evts.teardown_target	== NULL))) {
21930Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21940Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21950Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21960Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21970Sstevel@tonic-gate 		    "Invalid callbacks specified");
21980Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21990Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
22000Sstevel@tonic-gate 		return (DDI_FAILURE);
22010Sstevel@tonic-gate 	}
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 	/* Copy the events information into the struct */
22040Sstevel@tonic-gate 	member_new->isoch_cec_evts	= join_isoch_info->isoch_cec_evts;
22050Sstevel@tonic-gate 	member_new->isoch_cec_evts_arg	= join_isoch_info->isoch_cec_evts_arg;
22060Sstevel@tonic-gate 	member_new->cec_mem_options	= join_isoch_info->jii_options;
22070Sstevel@tonic-gate 	member_new->cec_mem_target	= (s1394_target_t *)t1394_hdl;
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 	/* Insert new member into Isoch CEC's member list */
22100Sstevel@tonic-gate 	s1394_isoch_cec_member_list_insert(hal, cec_curr, member_new);
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 	/* Update the channel mask filter */
22130Sstevel@tonic-gate 	cec_curr->filter_channel_mask	= check_mask;
22140Sstevel@tonic-gate 
22150Sstevel@tonic-gate 	/* Update the speed filter */
22160Sstevel@tonic-gate 	cec_curr->filter_current_speed	= curr_max_speed;
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate 	/* Update the talker pointer (if necessary) */
22190Sstevel@tonic-gate 	if (join_isoch_info->jii_options & T1394_TALKER)
22200Sstevel@tonic-gate 		cec_curr->cec_member_talker = cec_curr->cec_member_list_head;
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	/*
22230Sstevel@tonic-gate 	 * Now "leave" is a legal state transition
22240Sstevel@tonic-gate 	 * and "free" is an illegal state transition
22250Sstevel@tonic-gate 	 */
22260Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, ISOCH_CEC_LEAVE);
22270Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_FREE);
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
22300Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
22330Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
22340Sstevel@tonic-gate 	return (DDI_SUCCESS);
22350Sstevel@tonic-gate }
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate /*
22380Sstevel@tonic-gate  * Function:    t1394_leave_isoch_cec()
22390Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
22400Sstevel@tonic-gate  *					    t1394_attach()
22410Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
22420Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
22430Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
22440Sstevel@tonic-gate  *
22450Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully left the
22460Sstevel@tonic-gate  *					    Isoch CEC
22470Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to leave the Isoch CEC
22480Sstevel@tonic-gate  *
22490Sstevel@tonic-gate  * Description:	t1394_leave_isoch_cec() is used by a target driver to remove
22500Sstevel@tonic-gate  *		itself from the Isoch CEC's member list.  It is possible
22510Sstevel@tonic-gate  *		for this call to fail because the target is not found in
22520Sstevel@tonic-gate  *		the current member list, or because it is not an appropriate
22530Sstevel@tonic-gate  *		time for a target to leave.
22540Sstevel@tonic-gate  */
22550Sstevel@tonic-gate /* ARGSUSED */
22560Sstevel@tonic-gate int
t1394_leave_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags)22570Sstevel@tonic-gate t1394_leave_isoch_cec(t1394_handle_t t1394_hdl,
22580Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
22590Sstevel@tonic-gate {
22600Sstevel@tonic-gate 	s1394_hal_t		 *hal;
22610Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
22620Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_curr;
22630Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_temp;
22640Sstevel@tonic-gate 	boolean_t		 found;
22650Sstevel@tonic-gate 	uint64_t		 temp_channel_mask;
22660Sstevel@tonic-gate 	uint_t			 temp_max_speed;
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_enter,
22690Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
22700Sstevel@tonic-gate 
22710Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
22720Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
22730Sstevel@tonic-gate 
22740Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
22770Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
22800Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 	/* Are we in any callbacks? (Wait for them to finish) */
22830Sstevel@tonic-gate 	while (CEC_IN_ANY_CALLBACKS(cec_curr)) {
22840Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_TRUE;
22850Sstevel@tonic-gate 		cv_wait(&cec_curr->in_callbacks_cv,
22860Sstevel@tonic-gate 		    &cec_curr->isoch_cec_mutex);
22870Sstevel@tonic-gate 	}
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	/* Is "leave" a legal state transition? */
22900Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_LEAVE) == 0) {
22910Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
22920Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
22930Sstevel@tonic-gate 		TNF_PROBE_1(t1394_leave_isoch_cec_error,
22940Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
22950Sstevel@tonic-gate 		    "Not allowed to leave Isoch CEC");
22960Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit,
22970Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
22980Sstevel@tonic-gate 		return (DDI_FAILURE);
22990Sstevel@tonic-gate 	}
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 	/* Find the Target on the CEC's member list */
23020Sstevel@tonic-gate 	found = B_FALSE;
23030Sstevel@tonic-gate 	temp_channel_mask = cec_curr->cec_alloc_props.cec_channel_mask;
23040Sstevel@tonic-gate 	temp_max_speed	  = cec_curr->cec_alloc_props.cec_max_speed;
23050Sstevel@tonic-gate 	member_curr	  = cec_curr->cec_member_list_head;
23060Sstevel@tonic-gate 	while (member_curr != NULL) {
23070Sstevel@tonic-gate 		if (member_curr->cec_mem_target ==
23080Sstevel@tonic-gate 		    (s1394_target_t *)t1394_hdl) {
23090Sstevel@tonic-gate 			member_temp = member_curr;
23100Sstevel@tonic-gate 			found	    = B_TRUE;
23110Sstevel@tonic-gate 		} else {
23120Sstevel@tonic-gate 			/* Keep track of channel mask and max speed info */
23130Sstevel@tonic-gate 			temp_channel_mask &= member_curr->req_channel_mask;
23140Sstevel@tonic-gate 			if (member_curr->req_max_speed < temp_max_speed)
23150Sstevel@tonic-gate 				temp_max_speed = member_curr->req_max_speed;
23160Sstevel@tonic-gate 		}
23170Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_next;
23180Sstevel@tonic-gate 	}
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	/* Target not found on this Isoch CEC */
23210Sstevel@tonic-gate 	if (found == B_FALSE) {
23220Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
23230Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
23240Sstevel@tonic-gate 		TNF_PROBE_1(t1394_leave_isoch_cec_error,
23250Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
23260Sstevel@tonic-gate 		    "Target not found in Isoch CEC member list");
23270Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit,
23280Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
23290Sstevel@tonic-gate 		return (DDI_FAILURE);
23300Sstevel@tonic-gate 	} else {
23310Sstevel@tonic-gate 		/* This member's departure may change filter constraints */
23320Sstevel@tonic-gate 		cec_curr->filter_current_speed  = temp_max_speed;
23330Sstevel@tonic-gate 		cec_curr->filter_channel_mask   = temp_channel_mask;
23340Sstevel@tonic-gate 	}
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate 	/* Remove member from Isoch CEC's member list */
23370Sstevel@tonic-gate 	s1394_isoch_cec_member_list_remove(hal, cec_curr, member_temp);
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	/* If we are removing the talker, then update the pointer */
23400Sstevel@tonic-gate 	if (cec_curr->cec_member_talker == member_temp)
23410Sstevel@tonic-gate 		cec_curr->cec_member_talker = NULL;
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 	/* Is the Isoch CEC's member list empty? */
23440Sstevel@tonic-gate 	if ((cec_curr->cec_member_list_head == NULL) &&
23450Sstevel@tonic-gate 	    (cec_curr->cec_member_list_tail == NULL)) {
23460Sstevel@tonic-gate 		/*
23470Sstevel@tonic-gate 		 * Now "free" _might_ be a legal state transition
23480Sstevel@tonic-gate 		 * if we aren't in setup or start phases and "leave"
23490Sstevel@tonic-gate 		 * is definitely an illegal state transition
23500Sstevel@tonic-gate 		 */
23510Sstevel@tonic-gate 		if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) != 0)
23520Sstevel@tonic-gate 			CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
23530Sstevel@tonic-gate 		CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_LEAVE);
23540Sstevel@tonic-gate 	}
23550Sstevel@tonic-gate 
23560Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
23570Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
23580Sstevel@tonic-gate 
23590Sstevel@tonic-gate 	/* Free the Isoch CEC member structure */
23600Sstevel@tonic-gate 	kmem_free(member_temp, sizeof (s1394_isoch_cec_member_t));
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit,
23630Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
23640Sstevel@tonic-gate 	return (DDI_SUCCESS);
23650Sstevel@tonic-gate }
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate /*
23680Sstevel@tonic-gate  * Function:    t1394_setup_isoch_cec()
23690Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
23700Sstevel@tonic-gate  *					    t1394_attach()
23710Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
23720Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
23730Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
23740Sstevel@tonic-gate  *
23750Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
23760Sstevel@tonic-gate  *					    to target
23770Sstevel@tonic-gate  *
23780Sstevel@tonic-gate  * Description:	t1394_setup_isoch_cec() directs the 1394 Software Framework
23790Sstevel@tonic-gate  *		to allocate isochronous resources and invoke the setup_target()
23800Sstevel@tonic-gate  *		callback for each member of the Isoch CEC.  This call may
23810Sstevel@tonic-gate  *		fail because bandwidth was unavailable (T1394_ENO_BANDWIDTH),
23820Sstevel@tonic-gate  *		channels were unavailable (T1394_ENO_CHANNEL), or one of the
23830Sstevel@tonic-gate  *		member targets returned failure from its setup_target()
23840Sstevel@tonic-gate  *		callback.
23850Sstevel@tonic-gate  */
23860Sstevel@tonic-gate /* ARGSUSED */
23870Sstevel@tonic-gate int
t1394_setup_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags,int * result)23880Sstevel@tonic-gate t1394_setup_isoch_cec(t1394_handle_t t1394_hdl,
23890Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags, int *result)
23900Sstevel@tonic-gate {
23910Sstevel@tonic-gate 	s1394_hal_t			*hal;
23920Sstevel@tonic-gate 	s1394_isoch_cec_t		*cec_curr;
23930Sstevel@tonic-gate 	s1394_isoch_cec_member_t	*member_curr;
23940Sstevel@tonic-gate 	t1394_setup_target_args_t	target_args;
23950Sstevel@tonic-gate 	uint64_t			temp_chnl_mask;
23960Sstevel@tonic-gate 	uint32_t			old_chnl;
23970Sstevel@tonic-gate 	uint32_t			try_chnl;
23980Sstevel@tonic-gate 	uint_t				bw_alloc_units;
23990Sstevel@tonic-gate 	uint_t				generation;
24000Sstevel@tonic-gate 	int				chnl_num;
24010Sstevel@tonic-gate 	int				err;
24020Sstevel@tonic-gate 	int				ret;
24030Sstevel@tonic-gate 	int				j;
24040Sstevel@tonic-gate 	int	(*setup_callback)(t1394_isoch_cec_handle_t, opaque_t,
24050Sstevel@tonic-gate 			    t1394_setup_target_args_t *);
24060Sstevel@tonic-gate 
24070Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_enter,
24080Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
24090Sstevel@tonic-gate 
24100Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
24110Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
24120Sstevel@tonic-gate 
24130Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
24140Sstevel@tonic-gate 
24150Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
24160Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
24190Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate 	/* Are we in any callbacks? */
24220Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
24230Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
24240Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
24250Sstevel@tonic-gate 		TNF_PROBE_1(t1394_setup_isoch_cec_error,
24260Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
24270Sstevel@tonic-gate 		    "Not allowed to setup Isoch CEC (in callbacks)");
24280Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
24290Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
24300Sstevel@tonic-gate 		return (DDI_FAILURE);
24310Sstevel@tonic-gate 	}
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 	/* Is "setup" a legal state transition? */
24340Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_SETUP) == 0) {
24350Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
24360Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
24370Sstevel@tonic-gate 		TNF_PROBE_1(t1394_setup_isoch_cec_error,
24380Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
24390Sstevel@tonic-gate 		    "Not allowed to setup Isoch CEC");
24400Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
24410Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
24420Sstevel@tonic-gate 		return (DDI_FAILURE);
24430Sstevel@tonic-gate 	}
24440Sstevel@tonic-gate 
24450Sstevel@tonic-gate 	/* If T1394_NO_IRM_ALLOC is set then don't allocate... do callbacks */
24460Sstevel@tonic-gate 	if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
24470Sstevel@tonic-gate 		goto setup_do_callbacks;
24480Sstevel@tonic-gate 	}
24490Sstevel@tonic-gate 
24500Sstevel@tonic-gate 	/* Allocate bandwidth and channels */
24510Sstevel@tonic-gate 	for (j = 0; j < S1394_ISOCH_ALLOC_RETRIES; j++) {
24520Sstevel@tonic-gate 		/*
24530Sstevel@tonic-gate 		 * Get the current generation number - don't
24540Sstevel@tonic-gate 		 * need the lock because we are read only here
24550Sstevel@tonic-gate 		 */
24560Sstevel@tonic-gate 		generation = hal->generation_count;
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 		/* Compute how much bandwidth is needed */
24590Sstevel@tonic-gate 		bw_alloc_units = s1394_compute_bw_alloc_units(hal,
24600Sstevel@tonic-gate 		    cec_curr->bandwidth, cec_curr->filter_current_speed);
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 		/* Check that the generation has not changed - */
24630Sstevel@tonic-gate 		/* don't need the lock (read only) */
24640Sstevel@tonic-gate 		if (generation != hal->generation_count)
24650Sstevel@tonic-gate 			continue;
24660Sstevel@tonic-gate 
24670Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
24680Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
24690Sstevel@tonic-gate 
24700Sstevel@tonic-gate 		/* Try to allocate the bandwidth */
24710Sstevel@tonic-gate 		ret = s1394_bandwidth_alloc(hal, bw_alloc_units, generation,
24720Sstevel@tonic-gate 		    &err);
24730Sstevel@tonic-gate 
24740Sstevel@tonic-gate 		/* Lock the Isoch CEC member list */
24750Sstevel@tonic-gate 		mutex_enter(&cec_curr->isoch_cec_mutex);
24760Sstevel@tonic-gate 
24770Sstevel@tonic-gate 		/* If there was a bus reset, start over */
24780Sstevel@tonic-gate 		if (ret == DDI_FAILURE) {
24790Sstevel@tonic-gate 			if (err == CMD1394_EBUSRESET) {
24800Sstevel@tonic-gate 				continue; /* start over and try again */
24810Sstevel@tonic-gate 			} else {
24820Sstevel@tonic-gate 				*result = T1394_ENO_BANDWIDTH;
24830Sstevel@tonic-gate 				/* Unlock the Isoch CEC member list */
24840Sstevel@tonic-gate 				mutex_exit(&cec_curr->isoch_cec_mutex);
24850Sstevel@tonic-gate 				TNF_PROBE_1(t1394_setup_isoch_cec_error,
24860Sstevel@tonic-gate 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
24870Sstevel@tonic-gate 				    msg, "Unable to allocate isoch bandwidth");
24880Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
24890Sstevel@tonic-gate 				    S1394_TNF_SL_ISOCH_STACK, "");
24900Sstevel@tonic-gate 				return (DDI_FAILURE);
24910Sstevel@tonic-gate 			}
24920Sstevel@tonic-gate 		}
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 		/* Check that the generation has not changed - */
24950Sstevel@tonic-gate 		/* don't need the lock (read only) */
24960Sstevel@tonic-gate 		if (generation != hal->generation_count)
24970Sstevel@tonic-gate 			continue;
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 		/*
25000Sstevel@tonic-gate 		 * Allocate a channel
25010Sstevel@tonic-gate 		 *    From IEEE 1394-1995, Section 8.3.2.3.8: "Bits
25020Sstevel@tonic-gate 		 *    allocated in the CHANNELS_AVAILABLE_HI field of
25030Sstevel@tonic-gate 		 *    this register shall start at bit zero (channel
25040Sstevel@tonic-gate 		 *    number zero), and additional channel numbers shall
25050Sstevel@tonic-gate 		 *    be represented in a monotonically increasing sequence
25060Sstevel@tonic-gate 		 *    of bit numbers up to a maximum of bit 31 (channel
25070Sstevel@tonic-gate 		 *    number 31).  Bits allocated in the CHANNELS_AVAILABLE_LO
25080Sstevel@tonic-gate 		 *    field of this register shall start at bit zero
25090Sstevel@tonic-gate 		 *    (channel number 32), and additional channel numbers
25100Sstevel@tonic-gate 		 *    shall be represented in a monotonically increasing
25110Sstevel@tonic-gate 		 *    sequence of bit numbers up to a maximum of bit 31
25120Sstevel@tonic-gate 		 *    (channel number 63).
25130Sstevel@tonic-gate 		 */
25140Sstevel@tonic-gate 		temp_chnl_mask = cec_curr->filter_channel_mask;
25150Sstevel@tonic-gate 		for (chnl_num = 63; chnl_num >= 0; chnl_num--) {
25160Sstevel@tonic-gate 			if ((temp_chnl_mask & 1) == 1) {
25170Sstevel@tonic-gate 				try_chnl = (1 << ((63 - chnl_num) % 32));
25180Sstevel@tonic-gate 
25190Sstevel@tonic-gate 				/* Unlock the Isoch CEC member list */
25200Sstevel@tonic-gate 				mutex_exit(&cec_curr->isoch_cec_mutex);
25210Sstevel@tonic-gate 				if (chnl_num < 32) {
25220Sstevel@tonic-gate 					ret = s1394_channel_alloc(hal,
25230Sstevel@tonic-gate 					    try_chnl, generation,
25240Sstevel@tonic-gate 					    S1394_CHANNEL_ALLOC_HI, &old_chnl,
25250Sstevel@tonic-gate 					    &err);
25260Sstevel@tonic-gate 				} else {
25270Sstevel@tonic-gate 					ret = s1394_channel_alloc(hal,
25280Sstevel@tonic-gate 					    try_chnl, generation,
25290Sstevel@tonic-gate 					    S1394_CHANNEL_ALLOC_LO, &old_chnl,
25300Sstevel@tonic-gate 					    &err);
25310Sstevel@tonic-gate 				}
25320Sstevel@tonic-gate 				/* Lock the Isoch CEC member list */
25330Sstevel@tonic-gate 				mutex_enter(&cec_curr->isoch_cec_mutex);
25340Sstevel@tonic-gate 
25350Sstevel@tonic-gate 				/* Did we get a channel? (or a bus reset) */
25360Sstevel@tonic-gate 				if ((ret == DDI_SUCCESS) ||
25370Sstevel@tonic-gate 				    (err == CMD1394_EBUSRESET))
25380Sstevel@tonic-gate 					break;
25390Sstevel@tonic-gate 			}
25400Sstevel@tonic-gate 			temp_chnl_mask = temp_chnl_mask >> 1;
25410Sstevel@tonic-gate 		}
25420Sstevel@tonic-gate 
25430Sstevel@tonic-gate 		/* If we've tried all the possible channels, then fail */
25440Sstevel@tonic-gate 		if (chnl_num == 0) {
25450Sstevel@tonic-gate 			*result = T1394_ENO_CHANNEL;
25460Sstevel@tonic-gate 			/*
25470Sstevel@tonic-gate 			 * If we successfully allocate bandwidth, and
25480Sstevel@tonic-gate 			 * then fail getting a channel, we need to
25490Sstevel@tonic-gate 			 * free up the bandwidth
25500Sstevel@tonic-gate 			 */
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate 			/* Check that the generation has not changed */
25530Sstevel@tonic-gate 			/* lock not needed here (read only) */
25540Sstevel@tonic-gate 			if (generation != hal->generation_count)
25550Sstevel@tonic-gate 				continue;
25560Sstevel@tonic-gate 
25570Sstevel@tonic-gate 			/* Unlock the Isoch CEC member list */
25580Sstevel@tonic-gate 			mutex_exit(&cec_curr->isoch_cec_mutex);
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 			/* Try to free up the bandwidth */
25610Sstevel@tonic-gate 			ret = s1394_bandwidth_free(hal, bw_alloc_units,
25620Sstevel@tonic-gate 			    generation, &err);
25630Sstevel@tonic-gate 
25640Sstevel@tonic-gate 			/* Lock the Isoch CEC member list */
25650Sstevel@tonic-gate 			mutex_enter(&cec_curr->isoch_cec_mutex);
25660Sstevel@tonic-gate 
25670Sstevel@tonic-gate 			if (ret == DDI_FAILURE) {
25680Sstevel@tonic-gate 				if (err == CMD1394_EBUSRESET) {
25690Sstevel@tonic-gate 					continue;
25700Sstevel@tonic-gate 				} else {
25710Sstevel@tonic-gate 					TNF_PROBE_1(t1394_setup_isoch_cec_error,
25720Sstevel@tonic-gate 					    S1394_TNF_SL_ISOCH_ERROR, "",
25730Sstevel@tonic-gate 					    tnf_string, msg,
25740Sstevel@tonic-gate 					    "Unable to free isoch bandwidth");
25750Sstevel@tonic-gate 				}
25760Sstevel@tonic-gate 			}
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 			/* Unlock the Isoch CEC member list */
25790Sstevel@tonic-gate 			mutex_exit(&cec_curr->isoch_cec_mutex);
25800Sstevel@tonic-gate 			TNF_PROBE_1(t1394_setup_isoch_cec_error,
25810Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
25820Sstevel@tonic-gate 			    "Unable to allocate isoch channel");
25830Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
25840Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_STACK, "");
25850Sstevel@tonic-gate 			return (DDI_FAILURE);
25860Sstevel@tonic-gate 		}
25870Sstevel@tonic-gate 
25880Sstevel@tonic-gate 		/* If we got a channel, we're done (else start over) */
25890Sstevel@tonic-gate 		if (ret == DDI_SUCCESS)
25900Sstevel@tonic-gate 			break;
25910Sstevel@tonic-gate 		else if (err == CMD1394_EBUSRESET)
25920Sstevel@tonic-gate 			continue;
25930Sstevel@tonic-gate 	}
25940Sstevel@tonic-gate 
25950Sstevel@tonic-gate 	/* Have we gotten too many bus resets? */
25960Sstevel@tonic-gate 	if (j == S1394_ISOCH_ALLOC_RETRIES) {
25970Sstevel@tonic-gate 		*result = T1394_ENO_BANDWIDTH;
25980Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
25990Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
26000Sstevel@tonic-gate 		TNF_PROBE_1(t1394_setup_isoch_cec_error,
26010Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
26020Sstevel@tonic-gate 		    "Unable to allocate isoch channel");
26030Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
26040Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
26050Sstevel@tonic-gate 		return (DDI_FAILURE);
26060Sstevel@tonic-gate 	}
26070Sstevel@tonic-gate 
26080Sstevel@tonic-gate 	cec_curr->realloc_valid	    = B_TRUE;
26090Sstevel@tonic-gate 	cec_curr->realloc_chnl_num  = chnl_num;
26100Sstevel@tonic-gate 	cec_curr->realloc_bandwidth = cec_curr->bandwidth;
26110Sstevel@tonic-gate 	cec_curr->realloc_speed	    = cec_curr->filter_current_speed;
26120Sstevel@tonic-gate 
26130Sstevel@tonic-gate setup_do_callbacks:
26140Sstevel@tonic-gate 	/* Call all of the setup_target() callbacks */
26150Sstevel@tonic-gate 	target_args.channel_num	    = chnl_num;
26160Sstevel@tonic-gate 	target_args.channel_speed   = cec_curr->filter_current_speed;
26170Sstevel@tonic-gate 
26180Sstevel@tonic-gate 	/* Now we are going into the callbacks */
26190Sstevel@tonic-gate 	cec_curr->in_callbacks	    = B_TRUE;
26200Sstevel@tonic-gate 
26210Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
26220Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
26230Sstevel@tonic-gate 
26240Sstevel@tonic-gate 	member_curr = cec_curr->cec_member_list_head;
26250Sstevel@tonic-gate 	*result = 0;
26260Sstevel@tonic-gate 	while (member_curr != NULL) {
26270Sstevel@tonic-gate 		if (member_curr->isoch_cec_evts.setup_target != NULL) {
26280Sstevel@tonic-gate 			setup_callback =
26290Sstevel@tonic-gate 			    member_curr->isoch_cec_evts.setup_target;
26300Sstevel@tonic-gate 			ret = setup_callback(t1394_isoch_cec_hdl,
26310Sstevel@tonic-gate 			    member_curr->isoch_cec_evts_arg, &target_args);
26320Sstevel@tonic-gate 			if (ret != DDI_SUCCESS)
26330Sstevel@tonic-gate 				*result = T1394_ETARGET;
26340Sstevel@tonic-gate 		}
26350Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_next;
26360Sstevel@tonic-gate 	}
26370Sstevel@tonic-gate 
26380Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
26390Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	/* We are finished with the callbacks */
26420Sstevel@tonic-gate 	cec_curr->in_callbacks = B_FALSE;
26430Sstevel@tonic-gate 	if (cec_curr->cec_want_wakeup == B_TRUE) {
26440Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_FALSE;
26450Sstevel@tonic-gate 		cv_broadcast(&cec_curr->in_callbacks_cv);
26460Sstevel@tonic-gate 	}
26470Sstevel@tonic-gate 
26480Sstevel@tonic-gate 	/*
26490Sstevel@tonic-gate 	 * Now "start" and "teardown" are legal state transitions
26500Sstevel@tonic-gate 	 * and "join", "free", and "setup" are illegal state transitions
26510Sstevel@tonic-gate 	 */
26520Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
26530Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_FREE |
26540Sstevel@tonic-gate 	    ISOCH_CEC_SETUP));
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
26570Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
26580Sstevel@tonic-gate 
26590Sstevel@tonic-gate 	/* Return DDI_FAILURE if any targets failed setup */
26600Sstevel@tonic-gate 	if (*result != 0) {
26610Sstevel@tonic-gate 		TNF_PROBE_1(t1394_setup_isoch_cec_error,
26620Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
26630Sstevel@tonic-gate 		    "Target returned error in setup_target()");
26640Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
26650Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
26660Sstevel@tonic-gate 		return (DDI_FAILURE);
26670Sstevel@tonic-gate 	}
26680Sstevel@tonic-gate 
26690Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
26700Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
26710Sstevel@tonic-gate 	return (DDI_SUCCESS);
26720Sstevel@tonic-gate }
26730Sstevel@tonic-gate 
26740Sstevel@tonic-gate /*
26750Sstevel@tonic-gate  * Function:    t1394_start_isoch_cec()
26760Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
26770Sstevel@tonic-gate  *					    t1394_attach()
26780Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
26790Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
26800Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
26810Sstevel@tonic-gate  *
26820Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		All start_target() callbacks returned
26830Sstevel@tonic-gate  *					    successfully
26840Sstevel@tonic-gate  *		DDI_FAILURE		One or more start_target() callbacks
26850Sstevel@tonic-gate  *					    returned failure
26860Sstevel@tonic-gate  *
26870Sstevel@tonic-gate  * Description:	t1394_start_isoch_cec() directs the 1394 Software Framework
26880Sstevel@tonic-gate  *		to invoke each of the start_target() callbacks, first for
26890Sstevel@tonic-gate  *		each listener, then for the talker.
26900Sstevel@tonic-gate  */
26910Sstevel@tonic-gate /* ARGSUSED */
26920Sstevel@tonic-gate int
t1394_start_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags)26930Sstevel@tonic-gate t1394_start_isoch_cec(t1394_handle_t t1394_hdl,
26940Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
26950Sstevel@tonic-gate {
26960Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
26970Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_curr;
26980Sstevel@tonic-gate 	int			 ret;
26990Sstevel@tonic-gate 	boolean_t		 err;
27000Sstevel@tonic-gate 	int	(*start_callback)(t1394_isoch_cec_handle_t, opaque_t);
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_enter,
27030Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
27040Sstevel@tonic-gate 
27050Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
27060Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
27070Sstevel@tonic-gate 
27080Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
27090Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
27100Sstevel@tonic-gate 
27110Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
27120Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
27130Sstevel@tonic-gate 
27140Sstevel@tonic-gate 	/* Are we in any callbacks? */
27150Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
27160Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
27170Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
27180Sstevel@tonic-gate 		TNF_PROBE_1(t1394_start_isoch_cec_error,
27190Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
27200Sstevel@tonic-gate 		    "Not allowed to start Isoch CEC (in callbacks)");
27210Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
27220Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
27230Sstevel@tonic-gate 		return (DDI_FAILURE);
27240Sstevel@tonic-gate 	}
27250Sstevel@tonic-gate 
27260Sstevel@tonic-gate 	/* Is "start" a legal state transition? */
27270Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_START) == 0) {
27280Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
27290Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
27300Sstevel@tonic-gate 		TNF_PROBE_1(t1394_start_isoch_cec_error,
27310Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
27320Sstevel@tonic-gate 		    "Not allowed to start Isoch CEC");
27330Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
27340Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
27350Sstevel@tonic-gate 		return (DDI_FAILURE);
27360Sstevel@tonic-gate 	}
27370Sstevel@tonic-gate 
27380Sstevel@tonic-gate 	/* Now we are going into the callbacks */
27390Sstevel@tonic-gate 	cec_curr->in_callbacks = B_TRUE;
27400Sstevel@tonic-gate 
27410Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
27420Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 	/*
27450Sstevel@tonic-gate 	 * Call all of the start_target() callbacks
27460Sstevel@tonic-gate 	 * Start at the tail (listeners first) and
27470Sstevel@tonic-gate 	 * go toward the head (talker last)
27480Sstevel@tonic-gate 	 */
27490Sstevel@tonic-gate 	member_curr = cec_curr->cec_member_list_tail;
27500Sstevel@tonic-gate 	err = B_FALSE;
27510Sstevel@tonic-gate 	while (member_curr != NULL) {
27520Sstevel@tonic-gate 		if (member_curr->isoch_cec_evts.start_target != NULL) {
27530Sstevel@tonic-gate 			start_callback =
27540Sstevel@tonic-gate 			    member_curr->isoch_cec_evts.start_target;
27550Sstevel@tonic-gate 			ret = start_callback(t1394_isoch_cec_hdl,
27560Sstevel@tonic-gate 			    member_curr->isoch_cec_evts_arg);
27570Sstevel@tonic-gate 		if (ret != DDI_SUCCESS)
27580Sstevel@tonic-gate 			err = B_TRUE;
27590Sstevel@tonic-gate 		}
27600Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_prev;
27610Sstevel@tonic-gate 	}
27620Sstevel@tonic-gate 
27630Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
27640Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
27650Sstevel@tonic-gate 
27660Sstevel@tonic-gate 	/* We are finished with the callbacks */
27670Sstevel@tonic-gate 	cec_curr->in_callbacks = B_FALSE;
27680Sstevel@tonic-gate 	if (cec_curr->cec_want_wakeup == B_TRUE) {
27690Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_FALSE;
27700Sstevel@tonic-gate 		cv_broadcast(&cec_curr->in_callbacks_cv);
27710Sstevel@tonic-gate 	}
27720Sstevel@tonic-gate 
27730Sstevel@tonic-gate 	/*
27740Sstevel@tonic-gate 	 * Now "stop" is a legal state transitions
27750Sstevel@tonic-gate 	 * and "start" and "teardown" are illegal state transitions
27760Sstevel@tonic-gate 	 */
27770Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, ISOCH_CEC_STOP);
27780Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
27790Sstevel@tonic-gate 
27800Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
27810Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
27820Sstevel@tonic-gate 
27830Sstevel@tonic-gate 	/* Return DDI_FAILURE if any targets failed start */
27840Sstevel@tonic-gate 	if (err == B_TRUE) {
27850Sstevel@tonic-gate 		TNF_PROBE_1(t1394_start_isoch_cec_error,
27860Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
27870Sstevel@tonic-gate 		    "Target returned error in start_target()");
27880Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
27890Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
27900Sstevel@tonic-gate 		return (DDI_FAILURE);
27910Sstevel@tonic-gate 	}
27920Sstevel@tonic-gate 
27930Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
27940Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
27950Sstevel@tonic-gate 	return (DDI_SUCCESS);
27960Sstevel@tonic-gate }
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate /*
27990Sstevel@tonic-gate  * Function:    t1394_stop_isoch_cec()
28000Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
28010Sstevel@tonic-gate  *					    t1394_attach()
28020Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
28030Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
28040Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
28050Sstevel@tonic-gate  *
28060Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully stopped the
28070Sstevel@tonic-gate  *					    Isoch CEC
28080Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to stop the Isoch CEC
28090Sstevel@tonic-gate  *
28100Sstevel@tonic-gate  * Description:	t1394_stop_isoch_cec() directs the 1394 Software Framework
28110Sstevel@tonic-gate  *		to invoke each of the stop_target() callbacks, first for
28120Sstevel@tonic-gate  *		the talker, then for each listener.
28130Sstevel@tonic-gate  *		(This call will fail if it is called at an
28140Sstevel@tonic-gate  *		inappropriate time, i.e. before the t1394_start_isoch_cec()
28150Sstevel@tonic-gate  *		call, etc.)
28160Sstevel@tonic-gate  */
28170Sstevel@tonic-gate /* ARGSUSED */
28180Sstevel@tonic-gate int
t1394_stop_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags)28190Sstevel@tonic-gate t1394_stop_isoch_cec(t1394_handle_t t1394_hdl,
28200Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
28210Sstevel@tonic-gate {
28220Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
28230Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_curr;
28240Sstevel@tonic-gate 	void	(*stop_callback)(t1394_isoch_cec_handle_t, opaque_t);
28250Sstevel@tonic-gate 
28260Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_enter,
28270Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
28280Sstevel@tonic-gate 
28290Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
28300Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
28310Sstevel@tonic-gate 
28320Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
28330Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
28340Sstevel@tonic-gate 
28350Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
28360Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
28370Sstevel@tonic-gate 
28380Sstevel@tonic-gate 	/* Are we in any callbacks? */
28390Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
28400Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
28410Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
28420Sstevel@tonic-gate 		TNF_PROBE_1(t1394_stop_isoch_cec_error,
28430Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
28440Sstevel@tonic-gate 		    "Not allowed to stop Isoch CEC (in callbacks)");
28450Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit,
28460Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
28470Sstevel@tonic-gate 		return (DDI_FAILURE);
28480Sstevel@tonic-gate 	}
28490Sstevel@tonic-gate 
28500Sstevel@tonic-gate 	/* Is "stop" a legal state transition? */
28510Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_STOP) == 0) {
28520Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
28530Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
28540Sstevel@tonic-gate 		TNF_PROBE_1(t1394_stop_isoch_cec_error,
28550Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
28560Sstevel@tonic-gate 		    "Not allowed to stop Isoch CEC");
28570Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit,
28580Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
28590Sstevel@tonic-gate 		return (DDI_FAILURE);
28600Sstevel@tonic-gate 	}
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 	/* Now we are going into the callbacks */
28630Sstevel@tonic-gate 	cec_curr->in_callbacks = B_TRUE;
28640Sstevel@tonic-gate 
28650Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
28660Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
28670Sstevel@tonic-gate 
28680Sstevel@tonic-gate 	/*
28690Sstevel@tonic-gate 	 * Call all of the stop_target() callbacks
28700Sstevel@tonic-gate 	 * Start at the head (talker first) and
28710Sstevel@tonic-gate 	 * go toward the tail (listeners last)
28720Sstevel@tonic-gate 	 */
28730Sstevel@tonic-gate 	member_curr = cec_curr->cec_member_list_head;
28740Sstevel@tonic-gate 	while (member_curr != NULL) {
28750Sstevel@tonic-gate 		if (member_curr->isoch_cec_evts.stop_target != NULL) {
28760Sstevel@tonic-gate 			stop_callback =
28770Sstevel@tonic-gate 			    member_curr->isoch_cec_evts.stop_target;
28780Sstevel@tonic-gate 			stop_callback(t1394_isoch_cec_hdl,
28790Sstevel@tonic-gate 			    member_curr->isoch_cec_evts_arg);
28800Sstevel@tonic-gate 		}
28810Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_next;
28820Sstevel@tonic-gate 	}
28830Sstevel@tonic-gate 
28840Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
28850Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
28860Sstevel@tonic-gate 
28870Sstevel@tonic-gate 	/* We are finished with the callbacks */
28880Sstevel@tonic-gate 	cec_curr->in_callbacks = B_FALSE;
28890Sstevel@tonic-gate 	if (cec_curr->cec_want_wakeup == B_TRUE) {
28900Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_FALSE;
28910Sstevel@tonic-gate 		cv_broadcast(&cec_curr->in_callbacks_cv);
28920Sstevel@tonic-gate 	}
28930Sstevel@tonic-gate 
28940Sstevel@tonic-gate 	/*
28950Sstevel@tonic-gate 	 * Now "start" and "teardown" are legal state transitions
28960Sstevel@tonic-gate 	 * and "stop" is an illegal state transitions
28970Sstevel@tonic-gate 	 */
28980Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
28990Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_STOP);
29000Sstevel@tonic-gate 
29010Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
29020Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
29030Sstevel@tonic-gate 
29040Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit,
29050Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
29060Sstevel@tonic-gate 	return (DDI_SUCCESS);
29070Sstevel@tonic-gate }
29080Sstevel@tonic-gate 
29090Sstevel@tonic-gate /*
29100Sstevel@tonic-gate  * Function:    t1394_teardown_isoch_cec()
29110Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
29120Sstevel@tonic-gate  *					    t1394_attach()
29130Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
29140Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
29150Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
29160Sstevel@tonic-gate  *
29170Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully tore down the
29180Sstevel@tonic-gate  *					    Isoch CEC
29190Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to tear down the
29200Sstevel@tonic-gate  *					    Isoch CEC
29210Sstevel@tonic-gate  *
29220Sstevel@tonic-gate  * Description:	t1394_teardown_isoch_cec() directs the 1394 Software Framework
29230Sstevel@tonic-gate  *		to free up any isochronous resources we might be holding and
29240Sstevel@tonic-gate  *		call all of the teardown_target() callbacks.
29250Sstevel@tonic-gate  *		(This call will fail if it is called at an
29260Sstevel@tonic-gate  *		inappropriate time, i.e. before the t1394_start_isoch_cec()
29270Sstevel@tonic-gate  *		call, before the t1394_stop_isoch_cec, etc.
29280Sstevel@tonic-gate  */
29290Sstevel@tonic-gate /* ARGSUSED */
29300Sstevel@tonic-gate int
t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags)29310Sstevel@tonic-gate t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl,
29320Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
29330Sstevel@tonic-gate {
29340Sstevel@tonic-gate 	s1394_hal_t		 *hal;
29350Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
29360Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_curr;
29370Sstevel@tonic-gate 	uint32_t		 chnl_mask;
29380Sstevel@tonic-gate 	uint32_t		 old_chnl_mask;
29390Sstevel@tonic-gate 	uint_t			 bw_alloc_units;
29400Sstevel@tonic-gate 	uint_t			 generation;
29410Sstevel@tonic-gate 	int			 ret;
29420Sstevel@tonic-gate 	int			 err;
29430Sstevel@tonic-gate 	void	(*teardown_callback)(t1394_isoch_cec_handle_t, opaque_t);
29440Sstevel@tonic-gate 
29450Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_enter,
29460Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
29470Sstevel@tonic-gate 
29480Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
29490Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
29500Sstevel@tonic-gate 
29510Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
29520Sstevel@tonic-gate 
29530Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
29540Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
29550Sstevel@tonic-gate 
29560Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
29570Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
29580Sstevel@tonic-gate 
29590Sstevel@tonic-gate 	/* Are we in any callbacks? */
29600Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
29610Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
29620Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
29630Sstevel@tonic-gate 		TNF_PROBE_1(t1394_teardown_isoch_cec_error,
29640Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
29650Sstevel@tonic-gate 		    "Not allowed to teardown Isoch CEC (in callbacks)");
29660Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit,
29670Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
29680Sstevel@tonic-gate 		return (DDI_FAILURE);
29690Sstevel@tonic-gate 	}
29700Sstevel@tonic-gate 
29710Sstevel@tonic-gate 	/* Is "teardown" a legal state transition? */
29720Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_TEARDOWN) == 0) {
29730Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
29740Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
29750Sstevel@tonic-gate 		TNF_PROBE_1(t1394_teardown_isoch_cec_error,
29760Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
29770Sstevel@tonic-gate 		    "Not allowed to teardown Isoch CEC");
29780Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit,
29790Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
29800Sstevel@tonic-gate 		return (DDI_FAILURE);
29810Sstevel@tonic-gate 	}
29820Sstevel@tonic-gate 
29830Sstevel@tonic-gate 	/* If T1394_NO_IRM_ALLOC is set then don't free... do callbacks */
29840Sstevel@tonic-gate 	if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
29850Sstevel@tonic-gate 		goto teardown_do_callbacks;
29860Sstevel@tonic-gate 	}
29870Sstevel@tonic-gate 
29880Sstevel@tonic-gate 	/* If nothing has been allocated or we failed to */
29890Sstevel@tonic-gate 	/* reallocate, then we are done... call the callbacks */
29900Sstevel@tonic-gate 	if ((cec_curr->realloc_valid == B_FALSE) ||
29910Sstevel@tonic-gate 	    (cec_curr->realloc_failed == B_TRUE)) {
29920Sstevel@tonic-gate 		goto teardown_do_callbacks;
29930Sstevel@tonic-gate 	}
29940Sstevel@tonic-gate 
29950Sstevel@tonic-gate 	/*
29960Sstevel@tonic-gate 	 * Get the current generation number - don't need the
29970Sstevel@tonic-gate 	 * topology tree mutex here because it is read-only, and
29980Sstevel@tonic-gate 	 * there is a race condition with or without it.
29990Sstevel@tonic-gate 	 */
30000Sstevel@tonic-gate 	generation = hal->generation_count;
30010Sstevel@tonic-gate 
30020Sstevel@tonic-gate 	/* Compute the amount bandwidth to free */
30030Sstevel@tonic-gate 	bw_alloc_units = s1394_compute_bw_alloc_units(hal,
30040Sstevel@tonic-gate 	    cec_curr->bandwidth, cec_curr->realloc_speed);
30050Sstevel@tonic-gate 
30060Sstevel@tonic-gate 	/* Check that the generation has not changed - */
30070Sstevel@tonic-gate 	/* don't need the lock (read only) */
30080Sstevel@tonic-gate 	if (generation != hal->generation_count)
30090Sstevel@tonic-gate 		goto teardown_do_callbacks;
30100Sstevel@tonic-gate 
30110Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
30120Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
30130Sstevel@tonic-gate 
30140Sstevel@tonic-gate 	/* Try to free up the bandwidth */
30150Sstevel@tonic-gate 	ret = s1394_bandwidth_free(hal, bw_alloc_units, generation, &err);
30160Sstevel@tonic-gate 
30170Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
30180Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
30190Sstevel@tonic-gate 
30200Sstevel@tonic-gate 	if (ret == DDI_FAILURE) {
30210Sstevel@tonic-gate 		if (err == CMD1394_EBUSRESET) {
30220Sstevel@tonic-gate 			goto teardown_do_callbacks;
30230Sstevel@tonic-gate 		} else {
30240Sstevel@tonic-gate 			TNF_PROBE_1(t1394_teardown_isoch_cec_error,
30250Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
30260Sstevel@tonic-gate 			    "Unable to free allocated bandwidth");
30270Sstevel@tonic-gate 		}
30280Sstevel@tonic-gate 	}
30290Sstevel@tonic-gate 
30300Sstevel@tonic-gate 	/* Free the allocated channel */
30310Sstevel@tonic-gate 	chnl_mask = (1 << ((63 - cec_curr->realloc_chnl_num) % 32));
30320Sstevel@tonic-gate 
30330Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
30340Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
30350Sstevel@tonic-gate 	if (cec_curr->realloc_chnl_num < 32) {
30360Sstevel@tonic-gate 		ret = s1394_channel_free(hal, chnl_mask, generation,
30370Sstevel@tonic-gate 		    S1394_CHANNEL_ALLOC_HI, &old_chnl_mask, &err);
30380Sstevel@tonic-gate 	} else {
30390Sstevel@tonic-gate 		ret = s1394_channel_free(hal, chnl_mask, generation,
30400Sstevel@tonic-gate 		    S1394_CHANNEL_ALLOC_LO, &old_chnl_mask, &err);
30410Sstevel@tonic-gate 	}
30420Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
30430Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
30440Sstevel@tonic-gate 
30450Sstevel@tonic-gate 	if (ret == DDI_FAILURE) {
30460Sstevel@tonic-gate 		if (err == CMD1394_EBUSRESET) {
30470Sstevel@tonic-gate 			goto teardown_do_callbacks;
30480Sstevel@tonic-gate 		} else {
30490Sstevel@tonic-gate 			TNF_PROBE_1(t1394_teardown_isoch_cec_error,
30500Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
30510Sstevel@tonic-gate 			    "Unable to free allocated bandwidth");
30520Sstevel@tonic-gate 		}
30530Sstevel@tonic-gate 	}
30540Sstevel@tonic-gate 
30550Sstevel@tonic-gate teardown_do_callbacks:
30560Sstevel@tonic-gate 	/* From here on reallocation is unnecessary */
30570Sstevel@tonic-gate 	cec_curr->realloc_valid	    = B_FALSE;
30580Sstevel@tonic-gate 	cec_curr->realloc_chnl_num  = 0;
30590Sstevel@tonic-gate 	cec_curr->realloc_bandwidth = 0;
30600Sstevel@tonic-gate 
30610Sstevel@tonic-gate 	/* Now we are going into the callbacks */
30620Sstevel@tonic-gate 	cec_curr->in_callbacks	    = B_TRUE;
30630Sstevel@tonic-gate 
30640Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
30650Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
30660Sstevel@tonic-gate 
30670Sstevel@tonic-gate 	/* Call all of the teardown_target() callbacks */
30680Sstevel@tonic-gate 	member_curr = cec_curr->cec_member_list_head;
30690Sstevel@tonic-gate 	while (member_curr != NULL) {
30700Sstevel@tonic-gate 		if (member_curr->isoch_cec_evts.teardown_target != NULL) {
30710Sstevel@tonic-gate 			teardown_callback =
30720Sstevel@tonic-gate 			    member_curr->isoch_cec_evts.teardown_target;
30730Sstevel@tonic-gate 			teardown_callback(t1394_isoch_cec_hdl,
30740Sstevel@tonic-gate 			    member_curr->isoch_cec_evts_arg);
30750Sstevel@tonic-gate 		}
30760Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_next;
30770Sstevel@tonic-gate 	}
30780Sstevel@tonic-gate 
30790Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
30800Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
30810Sstevel@tonic-gate 
30820Sstevel@tonic-gate 	/* We are finished with the callbacks */
30830Sstevel@tonic-gate 	cec_curr->in_callbacks = B_FALSE;
30840Sstevel@tonic-gate 	if (cec_curr->cec_want_wakeup == B_TRUE) {
30850Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_FALSE;
30860Sstevel@tonic-gate 		cv_broadcast(&cec_curr->in_callbacks_cv);
30870Sstevel@tonic-gate 	}
30880Sstevel@tonic-gate 
30890Sstevel@tonic-gate 	/*
30900Sstevel@tonic-gate 	 * Now "join" and "setup" are legal state transitions
30910Sstevel@tonic-gate 	 * and "start" and "teardown" are illegal state transitions
30920Sstevel@tonic-gate 	 */
30930Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_SETUP));
30940Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
30950Sstevel@tonic-gate 
30960Sstevel@tonic-gate 	/* And if the member list is empty, then "free" is legal too */
30970Sstevel@tonic-gate 	if ((cec_curr->cec_member_list_head == NULL) &&
30980Sstevel@tonic-gate 	    (cec_curr->cec_member_list_tail == NULL)) {
30990Sstevel@tonic-gate 		CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
31000Sstevel@tonic-gate 	}
31010Sstevel@tonic-gate 
31020Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
31030Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
31040Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit,
31050Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
31060Sstevel@tonic-gate 	return (DDI_SUCCESS);
31070Sstevel@tonic-gate }
31080Sstevel@tonic-gate 
31090Sstevel@tonic-gate /*
31100Sstevel@tonic-gate  * Function:    t1394_alloc_isoch_dma()
31110Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
31120Sstevel@tonic-gate  *					    t1394_attach()
31130Sstevel@tonic-gate  *		idi			This structure contains information
31140Sstevel@tonic-gate  *					    for configuring the data flow for
31150Sstevel@tonic-gate  *					    isochronous DMA
31160Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
31170Sstevel@tonic-gate  *
31180Sstevel@tonic-gate  * Output(s):	t1394_idma_hdl		The IDMA "handle" used in all
31190Sstevel@tonic-gate  *					    subsequent isoch_dma() calls
31200Sstevel@tonic-gate  *		result			Used to pass more specific info back
31210Sstevel@tonic-gate  *					    to target
31220Sstevel@tonic-gate  *
31230Sstevel@tonic-gate  * Description:	t1394_alloc_isoch_dma() allocates and initializes an
31240Sstevel@tonic-gate  *		isochronous DMA resource for transmitting or receiving
31250Sstevel@tonic-gate  *		isochronous data.  If it fails, result may hold
31260Sstevel@tonic-gate  *		T1394_EIDMA_NO_RESRCS, indicating that no isoch DMA resource
31270Sstevel@tonic-gate  *		are available.
31280Sstevel@tonic-gate  */
31290Sstevel@tonic-gate /* ARGSUSED */
31300Sstevel@tonic-gate int
t1394_alloc_isoch_dma(t1394_handle_t t1394_hdl,id1394_isoch_dmainfo_t * idi,uint_t flags,t1394_isoch_dma_handle_t * t1394_idma_hdl,int * result)31310Sstevel@tonic-gate t1394_alloc_isoch_dma(t1394_handle_t t1394_hdl,
31320Sstevel@tonic-gate     id1394_isoch_dmainfo_t *idi, uint_t flags,
31330Sstevel@tonic-gate     t1394_isoch_dma_handle_t *t1394_idma_hdl, int *result)
31340Sstevel@tonic-gate {
31350Sstevel@tonic-gate 	s1394_hal_t	*hal;
31360Sstevel@tonic-gate 	int		ret;
31370Sstevel@tonic-gate 
31380Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_enter,
31390Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
31400Sstevel@tonic-gate 
31410Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
31420Sstevel@tonic-gate 	ASSERT(idi != NULL);
31430Sstevel@tonic-gate 	ASSERT(t1394_idma_hdl != NULL);
31440Sstevel@tonic-gate 
31450Sstevel@tonic-gate 	/* Find the HAL this target resides on */
31460Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
31470Sstevel@tonic-gate 
31480Sstevel@tonic-gate 	/* Sanity check dma options.  If talk enabled, listen should be off */
31490Sstevel@tonic-gate 	if ((idi->idma_options & ID1394_TALK) &&
31500Sstevel@tonic-gate 	    (idi->idma_options != ID1394_TALK)) {
31510Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_dma_talk_conflict_error,
31520Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
31530Sstevel@tonic-gate 		    "conflicting idma options; talker and listener");
31540Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit,
31550Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
31560Sstevel@tonic-gate 
31570Sstevel@tonic-gate 		*result = T1394_EIDMA_CONFLICT;
31580Sstevel@tonic-gate 		return (DDI_FAILURE);
31590Sstevel@tonic-gate 	}
31600Sstevel@tonic-gate 
31610Sstevel@tonic-gate 	/* Only one listen mode allowed */
31620Sstevel@tonic-gate 	if ((idi->idma_options & ID1394_LISTEN_PKT_MODE) &&
31630Sstevel@tonic-gate 	    (idi->idma_options & ID1394_LISTEN_BUF_MODE)) {
31640Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_dma_listen_conflict_error,
31650Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
31660Sstevel@tonic-gate 		    "conflicting idma options; both listener modes set");
31670Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit,
31680Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
31690Sstevel@tonic-gate 
31700Sstevel@tonic-gate 		*result = T1394_EIDMA_CONFLICT;
31710Sstevel@tonic-gate 		return (DDI_FAILURE);
31720Sstevel@tonic-gate 	}
31730Sstevel@tonic-gate 
31740Sstevel@tonic-gate 	/* Have HAL alloc a resource and compile ixl */
31750Sstevel@tonic-gate 	ret = HAL_CALL(hal).alloc_isoch_dma(hal->halinfo.hal_private, idi,
31760Sstevel@tonic-gate 	    (void **)t1394_idma_hdl, result);
31770Sstevel@tonic-gate 
31780Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
31790Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_dma_hal_error,
31800Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
31810Sstevel@tonic-gate 		    "HAL alloc_isoch_dma error, maybe IXL compilation");
31820Sstevel@tonic-gate 		if (*result == IXL1394_ENO_DMA_RESRCS) {
31830Sstevel@tonic-gate 			*result = T1394_EIDMA_NO_RESRCS;
31840Sstevel@tonic-gate 		}
31850Sstevel@tonic-gate 	}
31860Sstevel@tonic-gate 
31870Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit,
31880Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
31890Sstevel@tonic-gate 	return (ret);
31900Sstevel@tonic-gate }
31910Sstevel@tonic-gate 
31920Sstevel@tonic-gate /*
31930Sstevel@tonic-gate  * Function:    t1394_free_isoch_dma()
31940Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
31950Sstevel@tonic-gate  *					    t1394_attach()
31960Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
31970Sstevel@tonic-gate  *		t1394_idma_hdl		The IDMA "handle" returned by
31980Sstevel@tonic-gate  *					    t1394_alloc_isoch_dma()
31990Sstevel@tonic-gate  *
32000Sstevel@tonic-gate  * Output(s):	None
32010Sstevel@tonic-gate  *
32020Sstevel@tonic-gate  * Description:	t1394_free_isoch_dma() is used to free all DMA resources
32030Sstevel@tonic-gate  *		allocated for the isoch stream associated with t1394_idma_hdl.
32040Sstevel@tonic-gate  */
32050Sstevel@tonic-gate /* ARGSUSED */
32060Sstevel@tonic-gate void
t1394_free_isoch_dma(t1394_handle_t t1394_hdl,uint_t flags,t1394_isoch_dma_handle_t * t1394_idma_hdl)32070Sstevel@tonic-gate t1394_free_isoch_dma(t1394_handle_t t1394_hdl, uint_t flags,
32080Sstevel@tonic-gate     t1394_isoch_dma_handle_t *t1394_idma_hdl)
32090Sstevel@tonic-gate {
32100Sstevel@tonic-gate 	s1394_hal_t	*hal;
32110Sstevel@tonic-gate 
32120Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_dma_enter,
32130Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32140Sstevel@tonic-gate 
32150Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
32160Sstevel@tonic-gate 	ASSERT(*t1394_idma_hdl != NULL);
32170Sstevel@tonic-gate 
32180Sstevel@tonic-gate 	/* Find the HAL this target resides on */
32190Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
32200Sstevel@tonic-gate 
32210Sstevel@tonic-gate 	/* Tell HAL to release local isoch dma resources */
32220Sstevel@tonic-gate 	HAL_CALL(hal).free_isoch_dma(hal->halinfo.hal_private, *t1394_idma_hdl);
32230Sstevel@tonic-gate 
32240Sstevel@tonic-gate 	/* Null out isoch handle */
32250Sstevel@tonic-gate 	*t1394_idma_hdl = NULL;
32260Sstevel@tonic-gate 
32270Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_dma_exit,
32280Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32290Sstevel@tonic-gate }
32300Sstevel@tonic-gate 
32310Sstevel@tonic-gate /*
32320Sstevel@tonic-gate  * Function:    t1394_start_isoch_dma()
32330Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
32340Sstevel@tonic-gate  *					    t1394_attach()
32350Sstevel@tonic-gate  *		t1394_idma_hdl		The IDMA "handle" returned by
32360Sstevel@tonic-gate  *					    t1394_alloc_isoch_dma()
32370Sstevel@tonic-gate  *		idma_ctrlinfo		This structure contains control args
32380Sstevel@tonic-gate  *					    used when starting isoch DMA for
32390Sstevel@tonic-gate  *					    the allocated resource
32400Sstevel@tonic-gate  *		flags			One flag defined - ID1394_START_ON_CYCLE
32410Sstevel@tonic-gate  *
32420Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
32430Sstevel@tonic-gate  *					    to target
32440Sstevel@tonic-gate  *
32450Sstevel@tonic-gate  * Description:	t1394_start_isoch_dma() is used to start DMA for the isoch
32460Sstevel@tonic-gate  *		stream associated with t1394_idma_hdl.
32470Sstevel@tonic-gate  */
32480Sstevel@tonic-gate /* ARGSUSED */
32490Sstevel@tonic-gate int
t1394_start_isoch_dma(t1394_handle_t t1394_hdl,t1394_isoch_dma_handle_t t1394_idma_hdl,id1394_isoch_dma_ctrlinfo_t * idma_ctrlinfo,uint_t flags,int * result)32500Sstevel@tonic-gate t1394_start_isoch_dma(t1394_handle_t t1394_hdl,
32510Sstevel@tonic-gate     t1394_isoch_dma_handle_t t1394_idma_hdl,
32520Sstevel@tonic-gate     id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfo, uint_t flags,
32530Sstevel@tonic-gate     int *result)
32540Sstevel@tonic-gate {
32550Sstevel@tonic-gate 	s1394_hal_t	*hal;
32560Sstevel@tonic-gate 	int		ret;
32570Sstevel@tonic-gate 
32580Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_start_isoch_dma_enter,
32590Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32600Sstevel@tonic-gate 
32610Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
32620Sstevel@tonic-gate 	ASSERT(t1394_idma_hdl != NULL);
32630Sstevel@tonic-gate 	ASSERT(idma_ctrlinfo != NULL);
32640Sstevel@tonic-gate 
32650Sstevel@tonic-gate 	/* Find the HAL this target resides on */
32660Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
32670Sstevel@tonic-gate 
32680Sstevel@tonic-gate 	ret = HAL_CALL(hal).start_isoch_dma(hal->halinfo.hal_private,
32690Sstevel@tonic-gate 	    (void *)t1394_idma_hdl, idma_ctrlinfo, flags, result);
32700Sstevel@tonic-gate 
32710Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_start_isoch_dma_exit,
32720Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32730Sstevel@tonic-gate 	return (ret);
32740Sstevel@tonic-gate }
32750Sstevel@tonic-gate 
32760Sstevel@tonic-gate /*
32770Sstevel@tonic-gate  * Function:    t1394_stop_isoch_dma()
32780Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
32790Sstevel@tonic-gate  *					    t1394_attach()
32800Sstevel@tonic-gate  *		t1394_idma_hdl		The IDMA "handle" returned by
32810Sstevel@tonic-gate  *					    t1394_alloc_isoch_dma()
32820Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
32830Sstevel@tonic-gate  *
32840Sstevel@tonic-gate  * Output(s):	None
32850Sstevel@tonic-gate  *
32860Sstevel@tonic-gate  * Description:	t1394_stop_isoch_dma() is used to stop DMA for the isoch
32870Sstevel@tonic-gate  *		stream associated with t1394_idma_hdl.
32880Sstevel@tonic-gate  */
32890Sstevel@tonic-gate /* ARGSUSED */
32900Sstevel@tonic-gate void
t1394_stop_isoch_dma(t1394_handle_t t1394_hdl,t1394_isoch_dma_handle_t t1394_idma_hdl,uint_t flags)32910Sstevel@tonic-gate t1394_stop_isoch_dma(t1394_handle_t t1394_hdl,
32920Sstevel@tonic-gate     t1394_isoch_dma_handle_t t1394_idma_hdl, uint_t flags)
32930Sstevel@tonic-gate {
32940Sstevel@tonic-gate 	s1394_hal_t	*hal;
32950Sstevel@tonic-gate 	int		result;
32960Sstevel@tonic-gate 
32970Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_stop_isoch_dma_enter,
32980Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32990Sstevel@tonic-gate 
33000Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
33010Sstevel@tonic-gate 	ASSERT(t1394_idma_hdl != NULL);
33020Sstevel@tonic-gate 
33030Sstevel@tonic-gate 	/* Find the HAL this target resides on */
33040Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
33050Sstevel@tonic-gate 
33060Sstevel@tonic-gate 	HAL_CALL(hal).stop_isoch_dma(hal->halinfo.hal_private,
33070Sstevel@tonic-gate 	    (void *)t1394_idma_hdl, &result);
33080Sstevel@tonic-gate 
33090Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_stop_isoch_dma_exit,
33100Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
33110Sstevel@tonic-gate }
33120Sstevel@tonic-gate 
33130Sstevel@tonic-gate /*
33140Sstevel@tonic-gate  * Function:    t1394_update_isoch_dma()
33150Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
33160Sstevel@tonic-gate  *					    t1394_attach()
33170Sstevel@tonic-gate  *		t1394_idma_hdl		The IDMA "handle" returned by
33180Sstevel@tonic-gate  *					    t1394_alloc_isoch_dma()
33190Sstevel@tonic-gate  *		idma_updateinfo		This structure contains ixl command args
33200Sstevel@tonic-gate  *					    used when updating args in an
33210Sstevel@tonic-gate  *					    existing list of ixl commands with
33220Sstevel@tonic-gate  *					    args in a new list of ixl commands.
33230Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
33240Sstevel@tonic-gate  *
33250Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
33260Sstevel@tonic-gate  *					    to target
33270Sstevel@tonic-gate  *
33280Sstevel@tonic-gate  * Description:	t1394_update_isoch_dma() is used to alter an IXL program that
33290Sstevel@tonic-gate  *		has already been built (compiled) by t1394_alloc_isoch_dma().
33300Sstevel@tonic-gate  */
33310Sstevel@tonic-gate /* ARGSUSED */
33320Sstevel@tonic-gate int
t1394_update_isoch_dma(t1394_handle_t t1394_hdl,t1394_isoch_dma_handle_t t1394_idma_hdl,id1394_isoch_dma_updateinfo_t * idma_updateinfo,uint_t flags,int * result)33330Sstevel@tonic-gate t1394_update_isoch_dma(t1394_handle_t t1394_hdl,
33340Sstevel@tonic-gate     t1394_isoch_dma_handle_t t1394_idma_hdl,
33350Sstevel@tonic-gate     id1394_isoch_dma_updateinfo_t *idma_updateinfo, uint_t flags,
33360Sstevel@tonic-gate     int *result)
33370Sstevel@tonic-gate {
33380Sstevel@tonic-gate 	s1394_hal_t	*hal;
33390Sstevel@tonic-gate 	int		ret;
33400Sstevel@tonic-gate 
33410Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_update_isoch_dma_enter,
33420Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
33430Sstevel@tonic-gate 
33440Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
33450Sstevel@tonic-gate 	ASSERT(t1394_idma_hdl != NULL);
33460Sstevel@tonic-gate 	ASSERT(idma_updateinfo != NULL);
33470Sstevel@tonic-gate 
33480Sstevel@tonic-gate 	/* Find the HAL this target resides on */
33490Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
33500Sstevel@tonic-gate 
33510Sstevel@tonic-gate 	ret = HAL_CALL(hal).update_isoch_dma(hal->halinfo.hal_private,
33520Sstevel@tonic-gate 	    (void *)t1394_idma_hdl, idma_updateinfo, flags, result);
33530Sstevel@tonic-gate 
33540Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_update_isoch_dma_exit,
33550Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
33560Sstevel@tonic-gate 	return (ret);
33570Sstevel@tonic-gate }
33580Sstevel@tonic-gate 
33590Sstevel@tonic-gate /*
33600Sstevel@tonic-gate  * Function:    t1394_initiate_bus_reset()
33610Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
33620Sstevel@tonic-gate  *					    t1394_attach()
33630Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
33640Sstevel@tonic-gate  *
33650Sstevel@tonic-gate  * Output(s):	None
33660Sstevel@tonic-gate  *
33670Sstevel@tonic-gate  * Description:	t1394_initiate_bus_reset() determines whether the local
33680Sstevel@tonic-gate  *		device has a P1394A PHY and will support the arbitrated
33690Sstevel@tonic-gate  *		short bus reset. If not, it will initiate a normal bus reset.
33700Sstevel@tonic-gate  */
33710Sstevel@tonic-gate /* ARGSUSED */
33720Sstevel@tonic-gate void
t1394_initiate_bus_reset(t1394_handle_t t1394_hdl,uint_t flags)33730Sstevel@tonic-gate t1394_initiate_bus_reset(t1394_handle_t t1394_hdl, uint_t flags)
33740Sstevel@tonic-gate {
33750Sstevel@tonic-gate 	s1394_hal_t	*hal;
33760Sstevel@tonic-gate 	int		ret;
33770Sstevel@tonic-gate 
33780Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_initiate_bus_reset_enter,
33790Sstevel@tonic-gate 	    S1394_TNF_SL_BR_STACK, "");
33800Sstevel@tonic-gate 
33810Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
33820Sstevel@tonic-gate 
33830Sstevel@tonic-gate 	/* Find the HAL this target resides on */
33840Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
33850Sstevel@tonic-gate 
33860Sstevel@tonic-gate 	/* Reset the bus */
33870Sstevel@tonic-gate 	if (hal->halinfo.phy == H1394_PHY_1394A) {
33880Sstevel@tonic-gate 		ret = HAL_CALL(hal).short_bus_reset(hal->halinfo.hal_private);
33890Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
33900Sstevel@tonic-gate 			TNF_PROBE_1(t1394_initiate_bus_reset_error,
33910Sstevel@tonic-gate 			    S1394_TNF_SL_ERROR, "", tnf_string, msg,
33920Sstevel@tonic-gate 			    "Error initiating short bus reset");
33930Sstevel@tonic-gate 		}
33940Sstevel@tonic-gate 	} else {
33950Sstevel@tonic-gate 		ret = HAL_CALL(hal).bus_reset(hal->halinfo.hal_private);
33960Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
33970Sstevel@tonic-gate 			TNF_PROBE_1(t1394_initiate_bus_reset_error,
33980Sstevel@tonic-gate 			    S1394_TNF_SL_ERROR, "", tnf_string, msg,
33990Sstevel@tonic-gate 			    "Error initiating bus reset");
34000Sstevel@tonic-gate 		}
34010Sstevel@tonic-gate 	}
34020Sstevel@tonic-gate 
34030Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_initiate_bus_reset_exit,
34040Sstevel@tonic-gate 	    S1394_TNF_SL_BR_STACK, "");
34050Sstevel@tonic-gate }
34060Sstevel@tonic-gate 
34070Sstevel@tonic-gate /*
34080Sstevel@tonic-gate  * Function:    t1394_get_topology_map()
34090Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
34100Sstevel@tonic-gate  *					    t1394_attach()
34110Sstevel@tonic-gate  *		bus_generation		The current generation
34120Sstevel@tonic-gate  *		tm_length		The size of the tm_buffer given
34130Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
34140Sstevel@tonic-gate  *
34150Sstevel@tonic-gate  * Output(s):	tm_buffer		Filled in by the 1394 Software Framework
34160Sstevel@tonic-gate  *					    with the contents of the local
34170Sstevel@tonic-gate  *					    TOPOLOGY_MAP
34180Sstevel@tonic-gate  *
34190Sstevel@tonic-gate  * Description:	t1394_get_topology_map() returns the 1394 TOPLOGY_MAP.  See
34200Sstevel@tonic-gate  *		IEEE 1394-1995 Section 8.2.3.4.1 for format information.  This
34210Sstevel@tonic-gate  *		call can fail if there is a generation mismatch or the
34220Sstevel@tonic-gate  *		tm_buffer is too small to hold the TOPOLOGY_MAP.
34230Sstevel@tonic-gate  */
34240Sstevel@tonic-gate /* ARGSUSED */
34250Sstevel@tonic-gate int
t1394_get_topology_map(t1394_handle_t t1394_hdl,uint_t bus_generation,size_t tm_length,uint_t flags,uint32_t * tm_buffer)34260Sstevel@tonic-gate t1394_get_topology_map(t1394_handle_t t1394_hdl, uint_t bus_generation,
34270Sstevel@tonic-gate     size_t tm_length, uint_t flags, uint32_t *tm_buffer)
34280Sstevel@tonic-gate {
34290Sstevel@tonic-gate 	s1394_hal_t	*hal;
34300Sstevel@tonic-gate 	uint32_t	*tm_ptr;
34310Sstevel@tonic-gate 	uint_t		length;
34320Sstevel@tonic-gate 
34330Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_get_topology_map_enter, S1394_TNF_SL_CSR_STACK,
34340Sstevel@tonic-gate 	    "");
34350Sstevel@tonic-gate 
34360Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
34370Sstevel@tonic-gate 
34380Sstevel@tonic-gate 	/* Find the HAL this target resides on */
34390Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
34400Sstevel@tonic-gate 
34410Sstevel@tonic-gate 	/* Lock the topology tree */
34420Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
34430Sstevel@tonic-gate 
34440Sstevel@tonic-gate 	/* Check the bus_generation for the Topology Map */
34450Sstevel@tonic-gate 	if (bus_generation != hal->generation_count) {
34460Sstevel@tonic-gate 		/* Unlock the topology tree */
34470Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
34480Sstevel@tonic-gate 		TNF_PROBE_1(t1394_get_topology_map_error,
34490Sstevel@tonic-gate 		    S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
34500Sstevel@tonic-gate 		    "Generation mismatch");
34510Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit,
34520Sstevel@tonic-gate 		    S1394_TNF_SL_CSR_STACK, "");
34530Sstevel@tonic-gate 		return (DDI_FAILURE);
34540Sstevel@tonic-gate 	}
34550Sstevel@tonic-gate 
34560Sstevel@tonic-gate 	tm_ptr	= (uint32_t *)hal->CSR_topology_map;
34570Sstevel@tonic-gate 	length	= tm_ptr[0] >> 16;
34580Sstevel@tonic-gate 	length  = length * 4;	/* Bytes instead of quadlets   */
34590Sstevel@tonic-gate 	length  = length + 4;   /* don't forget the first quad */
34600Sstevel@tonic-gate 
34610Sstevel@tonic-gate 	/* Check that the buffer is big enough */
34620Sstevel@tonic-gate 	if (length > (uint_t)tm_length) {
34630Sstevel@tonic-gate 		/* Unlock the topology tree */
34640Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
34650Sstevel@tonic-gate 		TNF_PROBE_1(t1394_get_topology_map_error,
34660Sstevel@tonic-gate 		    S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
34670Sstevel@tonic-gate 		    "Buffer size too small");
34680Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit,
34690Sstevel@tonic-gate 		    S1394_TNF_SL_CSR_STACK, "");
34700Sstevel@tonic-gate 		return (DDI_FAILURE);
34710Sstevel@tonic-gate 	}
34720Sstevel@tonic-gate 
34730Sstevel@tonic-gate 	/* Do the copy */
34740Sstevel@tonic-gate 	bcopy(tm_ptr, tm_buffer, length);
34750Sstevel@tonic-gate 
34760Sstevel@tonic-gate 	/* Unlock the topology tree */
34770Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
34780Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit, S1394_TNF_SL_CSR_STACK,
34790Sstevel@tonic-gate 	    "");
34800Sstevel@tonic-gate 	return (DDI_SUCCESS);
34810Sstevel@tonic-gate }
34820Sstevel@tonic-gate 
34830Sstevel@tonic-gate /*
34840Sstevel@tonic-gate  * Function:    t1394_CRC16()
34850Sstevel@tonic-gate  * Input(s):    d			The data to compute the CRC-16 for
34860Sstevel@tonic-gate  *		crc_length		The length into the data to compute for
34870Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
34880Sstevel@tonic-gate  *
34890Sstevel@tonic-gate  * Output(s):	CRC			The CRC-16 computed for the length
34900Sstevel@tonic-gate  *					    of data specified
34910Sstevel@tonic-gate  *
34920Sstevel@tonic-gate  * Description:	t1394_CRC16() implements ISO/IEC 13213:1994, ANSI/IEEE Std
34930Sstevel@tonic-gate  *		1212, 1994 - 8.1.5.
34940Sstevel@tonic-gate  */
34950Sstevel@tonic-gate /* ARGSUSED */
34960Sstevel@tonic-gate uint_t
t1394_CRC16(uint32_t * d,size_t crc_length,uint_t flags)34970Sstevel@tonic-gate t1394_CRC16(uint32_t *d, size_t crc_length, uint_t flags)
34980Sstevel@tonic-gate {
34990Sstevel@tonic-gate 	/* Implements ISO/IEC 13213:1994,	*/
35000Sstevel@tonic-gate 	/* ANSI/IEEE Std 1212, 1994 - 8.1.5	*/
35010Sstevel@tonic-gate 	uint_t	ret;
35020Sstevel@tonic-gate 
35030Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_CRC16_enter, S1394_TNF_SL_STACK, "");
35040Sstevel@tonic-gate 
35050Sstevel@tonic-gate 	ret = s1394_CRC16((uint_t *)d, (uint_t)crc_length);
35060Sstevel@tonic-gate 
35070Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_CRC16_exit, S1394_TNF_SL_STACK, "");
35080Sstevel@tonic-gate 	return (ret);
35090Sstevel@tonic-gate }
35100Sstevel@tonic-gate 
35110Sstevel@tonic-gate /*
35120Sstevel@tonic-gate  * Function:    t1394_add_cfgrom_entry()
35130Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
35140Sstevel@tonic-gate  *					    t1394_attach()
35150Sstevel@tonic-gate  *		cfgrom_entryinfo	This structure holds the cfgrom key,
35160Sstevel@tonic-gate  *					    buffer, and size
35170Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
35180Sstevel@tonic-gate  *
35190Sstevel@tonic-gate  * Output(s):	t1394_cfgrom_hdl	The ConfigROM "handle" used in
35200Sstevel@tonic-gate  *					    t1394_rem_cfgrom_entry()
35210Sstevel@tonic-gate  *		result			Used to pass more specific info back
35220Sstevel@tonic-gate  *					    to target
35230Sstevel@tonic-gate  *
35240Sstevel@tonic-gate  * Description:	t1394_add_cfgrom_entry() adds an entry to the local Config ROM,
35250Sstevel@tonic-gate  *		updating the directory entries as necessary.  This call could
35260Sstevel@tonic-gate  *		fail because there is no room for the new entry in Config ROM
35270Sstevel@tonic-gate  *		(T1394_ECFGROM_FULL), the key is invalid (T1394_EINVALID_PARAM),
35280Sstevel@tonic-gate  *		or it was called in interrupt context (T1394_EINVALID_CONTEXT).
35290Sstevel@tonic-gate  */
35300Sstevel@tonic-gate /* ARGSUSED */
35310Sstevel@tonic-gate int
t1394_add_cfgrom_entry(t1394_handle_t t1394_hdl,t1394_cfgrom_entryinfo_t * cfgrom_entryinfo,uint_t flags,t1394_cfgrom_handle_t * t1394_cfgrom_hdl,int * result)35320Sstevel@tonic-gate t1394_add_cfgrom_entry(t1394_handle_t t1394_hdl,
35330Sstevel@tonic-gate     t1394_cfgrom_entryinfo_t *cfgrom_entryinfo, uint_t flags,
35340Sstevel@tonic-gate     t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
35350Sstevel@tonic-gate {
35360Sstevel@tonic-gate 	s1394_hal_t	*hal;
35370Sstevel@tonic-gate 	s1394_target_t	*target;
35380Sstevel@tonic-gate 	int		ret;
35390Sstevel@tonic-gate 	uint_t		key;
35400Sstevel@tonic-gate 	uint_t		size;
35410Sstevel@tonic-gate 	uint32_t	*buffer;
35420Sstevel@tonic-gate 
35430Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_enter,
35440Sstevel@tonic-gate 	    S1394_TNF_SL_CFGROM_STACK, "");
35450Sstevel@tonic-gate 
35460Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
35470Sstevel@tonic-gate 
35480Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
35490Sstevel@tonic-gate 
35500Sstevel@tonic-gate 	key = cfgrom_entryinfo->ce_key;
35510Sstevel@tonic-gate 	buffer = cfgrom_entryinfo->ce_buffer;
35520Sstevel@tonic-gate 	size = (uint_t)cfgrom_entryinfo->ce_size;
35530Sstevel@tonic-gate 
35540Sstevel@tonic-gate 	/* Check for a valid size */
35550Sstevel@tonic-gate 	if (size == 0) {
35560Sstevel@tonic-gate 		*result = T1394_EINVALID_PARAM;
35570Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(t1394_add_cfgrom_entry_error,
35580Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
35590Sstevel@tonic-gate 		    "Invalid size of Config ROM buffer (== 0)");
35600Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
35610Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_STACK, "");
35620Sstevel@tonic-gate 		return (DDI_FAILURE);
35630Sstevel@tonic-gate 	}
35640Sstevel@tonic-gate 
35650Sstevel@tonic-gate 	/* Check for a valid key type */
35660Sstevel@tonic-gate 	if (((key << IEEE1212_KEY_VALUE_SHIFT) & IEEE1212_KEY_TYPE_MASK) == 0) {
35670Sstevel@tonic-gate 		*result = T1394_EINVALID_PARAM;
35680Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(t1394_add_cfgrom_entry_error,
35690Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
35700Sstevel@tonic-gate 		    "Invalid key_type in Config ROM key");
35710Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
35720Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_STACK, "");
35730Sstevel@tonic-gate 		return (DDI_FAILURE);
35740Sstevel@tonic-gate 	}
35750Sstevel@tonic-gate 
35760Sstevel@tonic-gate 	/* Find the HAL this target resides on */
35770Sstevel@tonic-gate 	hal = target->on_hal;
35780Sstevel@tonic-gate 
35790Sstevel@tonic-gate 	/* Is this on the interrupt stack? */
3580*2273Sap25164 	if (servicing_interrupt()) {
35810Sstevel@tonic-gate 		*result = T1394_EINVALID_CONTEXT;
35820Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
35830Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_STACK, "");
35840Sstevel@tonic-gate 		return (DDI_FAILURE);
35850Sstevel@tonic-gate 	}
35860Sstevel@tonic-gate 
35870Sstevel@tonic-gate 	/* Lock the Config ROM buffer */
35880Sstevel@tonic-gate 	mutex_enter(&hal->local_config_rom_mutex);
35890Sstevel@tonic-gate 
35900Sstevel@tonic-gate 	ret = s1394_add_config_rom_entry(hal, key, buffer, size,
35910Sstevel@tonic-gate 	    (void **)t1394_cfgrom_hdl, result);
35920Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
35930Sstevel@tonic-gate 		if (*result == CMD1394_ERSRC_CONFLICT)
35940Sstevel@tonic-gate 			*result = T1394_ECFGROM_FULL;
35950Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
35960Sstevel@tonic-gate 
35970Sstevel@tonic-gate 		TNF_PROBE_1(t1394_add_cfgrom_entry_error,
35980Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
35990Sstevel@tonic-gate 		    "Failed in s1394_add_cfgrom_entry()");
36000Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
36010Sstevel@tonic-gate 		    "stacktrace 1394 s1394", "");
36020Sstevel@tonic-gate 		return (ret);
36030Sstevel@tonic-gate 	}
36040Sstevel@tonic-gate 
36050Sstevel@tonic-gate 	/* Setup the timeout function */
36060Sstevel@tonic-gate 	if (hal->config_rom_timer_set == B_FALSE) {
36070Sstevel@tonic-gate 		hal->config_rom_timer_set = B_TRUE;
36080Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36090Sstevel@tonic-gate 		hal->config_rom_timer =
36100Sstevel@tonic-gate 		    timeout(s1394_update_config_rom_callback, hal,
36110Sstevel@tonic-gate 			drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
36120Sstevel@tonic-gate 	} else {
36130Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36140Sstevel@tonic-gate 	}
36150Sstevel@tonic-gate 
36160Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
36170Sstevel@tonic-gate 	    S1394_TNF_SL_CFGROM_STACK, "");
36180Sstevel@tonic-gate 	return (ret);
36190Sstevel@tonic-gate }
36200Sstevel@tonic-gate 
36210Sstevel@tonic-gate /*
36220Sstevel@tonic-gate  * Function:    t1394_rem_cfgrom_entry()
36230Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
36240Sstevel@tonic-gate  *					    t1394_attach()
36250Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
36260Sstevel@tonic-gate  *		t1394_cfgrom_hdl	The ConfigROM "handle" returned by
36270Sstevel@tonic-gate  *					    t1394_add_cfgrom_entry()
36280Sstevel@tonic-gate  *
36290Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
36300Sstevel@tonic-gate  *					    to target
36310Sstevel@tonic-gate  *
36320Sstevel@tonic-gate  * Description:	t1394_rem_cfgrom_entry() is used to remove a previously added
36330Sstevel@tonic-gate  *		Config ROM entry (indicated by t1394_cfgrom_hdl).
36340Sstevel@tonic-gate  */
36350Sstevel@tonic-gate /* ARGSUSED */
36360Sstevel@tonic-gate int
t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl,uint_t flags,t1394_cfgrom_handle_t * t1394_cfgrom_hdl,int * result)36370Sstevel@tonic-gate t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl, uint_t flags,
36380Sstevel@tonic-gate     t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
36390Sstevel@tonic-gate {
36400Sstevel@tonic-gate 	s1394_hal_t	*hal;
36410Sstevel@tonic-gate 	s1394_target_t	*target;
36420Sstevel@tonic-gate 	int		ret;
36430Sstevel@tonic-gate 
36440Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_enter,
36450Sstevel@tonic-gate 	    S1394_TNF_SL_CFGROM_STACK, "");
36460Sstevel@tonic-gate 
36470Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
36480Sstevel@tonic-gate 
36490Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
36500Sstevel@tonic-gate 
36510Sstevel@tonic-gate 	/* Find the HAL this target resides on */
36520Sstevel@tonic-gate 	hal = target->on_hal;
36530Sstevel@tonic-gate 
36540Sstevel@tonic-gate 	/* Is this on the interrupt stack? */
3655*2273Sap25164 	if (servicing_interrupt()) {
36560Sstevel@tonic-gate 		*result = T1394_EINVALID_CONTEXT;
36570Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
36580Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_STACK, "");
36590Sstevel@tonic-gate 		return (DDI_FAILURE);
36600Sstevel@tonic-gate 	}
36610Sstevel@tonic-gate 
36620Sstevel@tonic-gate 	/* Lock the Config ROM buffer */
36630Sstevel@tonic-gate 	mutex_enter(&hal->local_config_rom_mutex);
36640Sstevel@tonic-gate 
36650Sstevel@tonic-gate 	ret = s1394_remove_config_rom_entry(hal, (void **)t1394_cfgrom_hdl,
36660Sstevel@tonic-gate 	    result);
36670Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
36680Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36690Sstevel@tonic-gate 		TNF_PROBE_1(t1394_rem_cfgrom_entry_error,
36700Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
36710Sstevel@tonic-gate 		    "Failed in s1394_remove_cfgrom_entry()");
36720Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
36730Sstevel@tonic-gate 		    "stacktrace 1394 s1394", "");
36740Sstevel@tonic-gate 		return (ret);
36750Sstevel@tonic-gate 	}
36760Sstevel@tonic-gate 
36770Sstevel@tonic-gate 	/* Setup the timeout function */
36780Sstevel@tonic-gate 	if (hal->config_rom_timer_set == B_FALSE) {
36790Sstevel@tonic-gate 		hal->config_rom_timer_set = B_TRUE;
36800Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36810Sstevel@tonic-gate 		hal->config_rom_timer =
36820Sstevel@tonic-gate 		    timeout(s1394_update_config_rom_callback, hal,
36830Sstevel@tonic-gate 			drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
36840Sstevel@tonic-gate 	} else {
36850Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36860Sstevel@tonic-gate 	}
36870Sstevel@tonic-gate 
36880Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
36890Sstevel@tonic-gate 	    S1394_TNF_SL_CFGROM_STACK, "");
36900Sstevel@tonic-gate 	return (ret);
36910Sstevel@tonic-gate }
36920Sstevel@tonic-gate 
36930Sstevel@tonic-gate /*
36940Sstevel@tonic-gate  * Function:    t1394_get_targetinfo()
36950Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
36960Sstevel@tonic-gate  *					    t1394_attach()
36970Sstevel@tonic-gate  *		bus_generation		The current generation
36980Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
36990Sstevel@tonic-gate  *
37000Sstevel@tonic-gate  * Output(s):	targetinfo		Structure containing max_payload,
37010Sstevel@tonic-gate  *					    max_speed, and target node ID.
37020Sstevel@tonic-gate  *
37030Sstevel@tonic-gate  * Description:	t1394_get_targetinfo() is used to retrieve information specific
37040Sstevel@tonic-gate  *		to a target device.  It will fail if the generation given
37050Sstevel@tonic-gate  *		does not match the current generation.
37060Sstevel@tonic-gate  */
37070Sstevel@tonic-gate /* ARGSUSED */
37080Sstevel@tonic-gate int
t1394_get_targetinfo(t1394_handle_t t1394_hdl,uint_t bus_generation,uint_t flags,t1394_targetinfo_t * targetinfo)37090Sstevel@tonic-gate t1394_get_targetinfo(t1394_handle_t t1394_hdl, uint_t bus_generation,
37100Sstevel@tonic-gate     uint_t flags, t1394_targetinfo_t *targetinfo)
37110Sstevel@tonic-gate {
37120Sstevel@tonic-gate 	s1394_hal_t	*hal;
37130Sstevel@tonic-gate 	s1394_target_t	*target;
37140Sstevel@tonic-gate 	uint_t		dev;
37150Sstevel@tonic-gate 	uint_t		curr;
37160Sstevel@tonic-gate 	uint_t		from_node;
37170Sstevel@tonic-gate 	uint_t		to_node;
37180Sstevel@tonic-gate 
37190Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_get_targetinfo_enter, S1394_TNF_SL_STACK, "");
37200Sstevel@tonic-gate 
37210Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
37220Sstevel@tonic-gate 
37230Sstevel@tonic-gate 	/* Find the HAL this target resides on */
37240Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
37250Sstevel@tonic-gate 
37260Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
37270Sstevel@tonic-gate 
37280Sstevel@tonic-gate 	/* Lock the topology tree */
37290Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
37300Sstevel@tonic-gate 
37310Sstevel@tonic-gate 	/* Check the bus_generation */
37320Sstevel@tonic-gate 	if (bus_generation != hal->generation_count) {
37330Sstevel@tonic-gate 		/* Unlock the topology tree */
37340Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
37350Sstevel@tonic-gate 		TNF_PROBE_3(t1394_get_targetinfo_error, S1394_TNF_SL_STACK, "",
37360Sstevel@tonic-gate 		    tnf_string, msg, "Generation mismatch",
37370Sstevel@tonic-gate 		    tnf_uint, gen, bus_generation,
37380Sstevel@tonic-gate 		    tnf_uint, current_gen, hal->generation_count);
37390Sstevel@tonic-gate 		return (DDI_FAILURE);
37400Sstevel@tonic-gate 	}
37410Sstevel@tonic-gate 
37420Sstevel@tonic-gate 	rw_enter(&hal->target_list_rwlock, RW_READER);
37430Sstevel@tonic-gate 	/*
37440Sstevel@tonic-gate 	 * If there is no node, report T1394_INVALID_NODEID for target_nodeID;
37450Sstevel@tonic-gate 	 * current_max_speed and current_max_payload are undefined for this
37460Sstevel@tonic-gate 	 * case.
37470Sstevel@tonic-gate 	 */
37480Sstevel@tonic-gate 	if (((target->target_state & S1394_TARG_GONE) != 0) ||
37490Sstevel@tonic-gate 	    (target->on_node == NULL)) {
37500Sstevel@tonic-gate 		targetinfo->target_nodeID = T1394_INVALID_NODEID;
37510Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(t1394_get_targetinfo_exit,
37520Sstevel@tonic-gate 		    S1394_TNF_SL_STACK, "", tnf_string, msg, "No device");
37530Sstevel@tonic-gate 	} else {
37540Sstevel@tonic-gate 		targetinfo->target_nodeID =
37550Sstevel@tonic-gate 		    (target->on_hal->node_id & IEEE1394_BUS_NUM_MASK) |
37560Sstevel@tonic-gate 		    target->on_node->node_num;
37570Sstevel@tonic-gate 
37580Sstevel@tonic-gate 		from_node = (target->on_hal->node_id) & IEEE1394_NODE_NUM_MASK;
37590Sstevel@tonic-gate 		to_node = target->on_node->node_num;
37600Sstevel@tonic-gate 
37610Sstevel@tonic-gate 		targetinfo->current_max_speed = (uint_t)s1394_speed_map_get(
37620Sstevel@tonic-gate 		    hal, from_node, to_node);
37630Sstevel@tonic-gate 
37640Sstevel@tonic-gate 		/* Get current_max_payload */
37650Sstevel@tonic-gate 		s1394_get_maxpayload(target, &dev, &curr);
37660Sstevel@tonic-gate 		targetinfo->current_max_payload	= curr;
37670Sstevel@tonic-gate 
37680Sstevel@tonic-gate 		TNF_PROBE_3_DEBUG(t1394_get_targetinfo_exit,
37690Sstevel@tonic-gate 		    S1394_TNF_SL_STACK, "",
37700Sstevel@tonic-gate 		    tnf_uint, payload, targetinfo->current_max_payload,
37710Sstevel@tonic-gate 		    tnf_uint, speed, targetinfo->current_max_speed,
37720Sstevel@tonic-gate 		    tnf_uint, nodeid, targetinfo->target_nodeID);
37730Sstevel@tonic-gate 	}
37740Sstevel@tonic-gate 
37750Sstevel@tonic-gate 	rw_exit(&hal->target_list_rwlock);
37760Sstevel@tonic-gate 	/* Unlock the topology tree */
37770Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
37780Sstevel@tonic-gate 	return (DDI_SUCCESS);
37790Sstevel@tonic-gate }
3780