xref: /titanic_52/usr/src/uts/common/io/1394/t1394.c (revision de710d24d2fae4468e64da999e1d952a247f142c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
580a70ef3Sap25164  * Common Development and Distribution License (the "License").
680a70ef3Sap25164  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2280a70ef3Sap25164  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * t1394.c
287c478bd9Sstevel@tonic-gate  *    1394 Target Driver Interface
297c478bd9Sstevel@tonic-gate  *    This file contains all of the 1394 Software Framework routines called
307c478bd9Sstevel@tonic-gate  *    by target drivers
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
33*de710d24SJosef 'Jeff' Sipek #include <sys/sysmacros.h>
347c478bd9Sstevel@tonic-gate #include <sys/conf.h>
357c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
3980a70ef3Sap25164 #include <sys/disp.h>
407c478bd9Sstevel@tonic-gate #include <sys/tnf_probe.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <sys/1394/t1394.h>
437c478bd9Sstevel@tonic-gate #include <sys/1394/s1394.h>
447c478bd9Sstevel@tonic-gate #include <sys/1394/h1394.h>
457c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1394.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate static int s1394_allow_detach = 0;
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * Function:    t1394_attach()
517c478bd9Sstevel@tonic-gate  * Input(s):    dip			The dip given to the target driver
527c478bd9Sstevel@tonic-gate  *					    in it's attach() routine
537c478bd9Sstevel@tonic-gate  *		version			The version of the target driver -
547c478bd9Sstevel@tonic-gate  *					    T1394_VERSION_V1
557c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
567c478bd9Sstevel@tonic-gate  *
577c478bd9Sstevel@tonic-gate  * Output(s):	attachinfo		Used to pass info back to target,
587c478bd9Sstevel@tonic-gate  *					    including bus generation, local
597c478bd9Sstevel@tonic-gate  *					    node ID, dma attribute, etc.
607c478bd9Sstevel@tonic-gate  *		t1394_hdl		The target "handle" to be used for
617c478bd9Sstevel@tonic-gate  *					    all subsequent calls into the
627c478bd9Sstevel@tonic-gate  *					    1394 Software Framework
637c478bd9Sstevel@tonic-gate  *
647c478bd9Sstevel@tonic-gate  * Description:	t1394_attach() registers the target (based on its dip) with
657c478bd9Sstevel@tonic-gate  *		the 1394 Software Framework.  It returns the bus_generation,
667c478bd9Sstevel@tonic-gate  *		local_nodeID, iblock_cookie and other useful information to
677c478bd9Sstevel@tonic-gate  *		the target, as well as a handle (t1394_hdl) that will be used
687c478bd9Sstevel@tonic-gate  *		in all subsequent calls into this framework.
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate /* ARGSUSED */
717c478bd9Sstevel@tonic-gate int
727c478bd9Sstevel@tonic-gate t1394_attach(dev_info_t *dip, int version, uint_t flags,
737c478bd9Sstevel@tonic-gate     t1394_attachinfo_t *attachinfo, t1394_handle_t *t1394_hdl)
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
767c478bd9Sstevel@tonic-gate 	s1394_target_t	*target;
777c478bd9Sstevel@tonic-gate 	uint_t		dev;
787c478bd9Sstevel@tonic-gate 	uint_t		curr;
797c478bd9Sstevel@tonic-gate 	uint_t		unit_dir;
807c478bd9Sstevel@tonic-gate 	int		hp_node = 0;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
837c478bd9Sstevel@tonic-gate 	ASSERT(attachinfo != NULL);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_attach_enter, S1394_TNF_SL_HOTPLUG_STACK, "");
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	*t1394_hdl = NULL;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	if (version != T1394_VERSION_V1) {
907c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_attach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
917c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Invalid version");
927c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_attach_exit,
937c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
947c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
957c478bd9Sstevel@tonic-gate 	}
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	hal = s1394_dip_to_hal(ddi_get_parent(dip));
987c478bd9Sstevel@tonic-gate 	if (hal == NULL) {
997c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_attach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
1007c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "No parent dip found for target");
1017c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_attach_exit,
1027c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
1037c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1047c478bd9Sstevel@tonic-gate 	}
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	hp_node = ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1097c478bd9Sstevel@tonic-gate 	    "hp-node");
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	/* Allocate space for s1394_target_t */
1127c478bd9Sstevel@tonic-gate 	target = kmem_zalloc(sizeof (s1394_target_t), KM_SLEEP);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	target->target_version = version;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	/* Copy in the params */
1197c478bd9Sstevel@tonic-gate 	target->target_dip = dip;
1207c478bd9Sstevel@tonic-gate 	target->on_hal	   = hal;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	/* Place the target on the appropriate node */
1237c478bd9Sstevel@tonic-gate 	target->on_node	= NULL;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	rw_enter(&target->on_hal->target_list_rwlock, RW_WRITER);
1267c478bd9Sstevel@tonic-gate 	if (hp_node != 0) {
1277c478bd9Sstevel@tonic-gate 		s1394_add_target_to_node(target);
1287c478bd9Sstevel@tonic-gate 		/*
1297c478bd9Sstevel@tonic-gate 		 * on_node can be NULL if the node got unplugged
1307c478bd9Sstevel@tonic-gate 		 * while the target driver is in its attach routine.
1317c478bd9Sstevel@tonic-gate 		 */
1327c478bd9Sstevel@tonic-gate 		if (target->on_node == NULL) {
1337c478bd9Sstevel@tonic-gate 			s1394_remove_target_from_node(target);
1347c478bd9Sstevel@tonic-gate 			rw_exit(&target->on_hal->target_list_rwlock);
1357c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->topology_tree_mutex);
1367c478bd9Sstevel@tonic-gate 			kmem_free(target, sizeof (s1394_target_t));
1377c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_attach_error,
1387c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
1397c478bd9Sstevel@tonic-gate 			    "on_node == NULL");
1407c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_attach_exit,
1417c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_HOTPLUG_STACK, "");
1427c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
1437c478bd9Sstevel@tonic-gate 		}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 		target->target_state = S1394_TARG_HP_NODE;
1467c478bd9Sstevel@tonic-gate 		if (S1394_NODE_BUS_PWR_CONSUMER(target->on_node) == B_TRUE)
1477c478bd9Sstevel@tonic-gate 			target->target_state |= S1394_TARG_BUS_PWR_CONSUMER;
1487c478bd9Sstevel@tonic-gate 	}
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/* Return the current generation */
1517c478bd9Sstevel@tonic-gate 	attachinfo->localinfo.bus_generation = target->on_hal->generation_count;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/* Fill in hal node id */
1547c478bd9Sstevel@tonic-gate 	attachinfo->localinfo.local_nodeID = target->on_hal->node_id;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	/* Give the target driver the iblock_cookie */
1577c478bd9Sstevel@tonic-gate 	attachinfo->iblock_cookie = target->on_hal->halinfo.hw_interrupt;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/* Give the target driver the attributes */
1607c478bd9Sstevel@tonic-gate 	attachinfo->acc_attr	= target->on_hal->halinfo.acc_attr;
1617c478bd9Sstevel@tonic-gate 	attachinfo->dma_attr	= target->on_hal->halinfo.dma_attr;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	unit_dir = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
1647c478bd9Sstevel@tonic-gate 		DDI_PROP_DONTPASS, "unit-dir-offset", 0);
1657c478bd9Sstevel@tonic-gate 	target->unit_dir = unit_dir;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	/* By default, disable all physical AR requests */
1687c478bd9Sstevel@tonic-gate 	target->physical_arreq_enabled = 0;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	/* Get dev_max_payload & current_max_payload */
1727c478bd9Sstevel@tonic-gate 	s1394_get_maxpayload(target, &dev, &curr);
1737c478bd9Sstevel@tonic-gate 	target->dev_max_payload		= dev;
1747c478bd9Sstevel@tonic-gate 	target->current_max_payload	= curr;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/* Add into linked list */
1777c478bd9Sstevel@tonic-gate 	if ((target->on_hal->target_head == NULL) &&
1787c478bd9Sstevel@tonic-gate 	    (target->on_hal->target_tail == NULL)) {
1797c478bd9Sstevel@tonic-gate 		target->on_hal->target_head = target;
1807c478bd9Sstevel@tonic-gate 		target->on_hal->target_tail = target;
1817c478bd9Sstevel@tonic-gate 	} else {
1827c478bd9Sstevel@tonic-gate 		target->on_hal->target_tail->target_next = target;
1837c478bd9Sstevel@tonic-gate 		target->target_prev = target->on_hal->target_tail;
1847c478bd9Sstevel@tonic-gate 		target->on_hal->target_tail = target;
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 	rw_exit(&target->on_hal->target_list_rwlock);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	/* Fill in services layer private info */
1897c478bd9Sstevel@tonic-gate 	*t1394_hdl = (t1394_handle_t)target;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_attach_exit, S1394_TNF_SL_HOTPLUG_STACK, "");
1947c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * Function:    t1394_detach()
1997c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
2007c478bd9Sstevel@tonic-gate  *					    t1394_attach()
2017c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
2027c478bd9Sstevel@tonic-gate  *
2037c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully detached
2047c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to detach
2057c478bd9Sstevel@tonic-gate  *
2067c478bd9Sstevel@tonic-gate  * Description:	t1394_detach() unregisters the target from the 1394 Software
2077c478bd9Sstevel@tonic-gate  *		Framework.  t1394_detach() can fail if the target has any
2087c478bd9Sstevel@tonic-gate  *		allocated commands that haven't been freed.
2097c478bd9Sstevel@tonic-gate  */
2107c478bd9Sstevel@tonic-gate /* ARGSUSED */
2117c478bd9Sstevel@tonic-gate int
2127c478bd9Sstevel@tonic-gate t1394_detach(t1394_handle_t *t1394_hdl, uint_t flags)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	s1394_target_t	*target;
2157c478bd9Sstevel@tonic-gate 	uint_t		num_cmds;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_detach_enter, S1394_TNF_SL_HOTPLUG_STACK, "");
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)(*t1394_hdl);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	ASSERT(target->on_hal);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	mutex_enter(&target->on_hal->topology_tree_mutex);
2267c478bd9Sstevel@tonic-gate 	rw_enter(&target->on_hal->target_list_rwlock, RW_WRITER);
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	/* How many cmds has this target allocated? */
2297c478bd9Sstevel@tonic-gate 	num_cmds = target->target_num_cmds;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	if (num_cmds != 0) {
2327c478bd9Sstevel@tonic-gate 		rw_exit(&target->on_hal->target_list_rwlock);
2337c478bd9Sstevel@tonic-gate 		mutex_exit(&target->on_hal->topology_tree_mutex);
2347c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_detach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
2357c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Must free all commands before detach()");
2367c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_detach_exit,
2377c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
2387c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	/*
2427c478bd9Sstevel@tonic-gate 	 * Remove from linked lists. Topology tree is already locked
2437c478bd9Sstevel@tonic-gate 	 * so that the node won't go away while we are looking at it.
2447c478bd9Sstevel@tonic-gate 	 */
2457c478bd9Sstevel@tonic-gate 	if ((target->on_hal->target_head == target) &&
2467c478bd9Sstevel@tonic-gate 	    (target->on_hal->target_tail == target)) {
2477c478bd9Sstevel@tonic-gate 		target->on_hal->target_head = NULL;
2487c478bd9Sstevel@tonic-gate 		target->on_hal->target_tail = NULL;
2497c478bd9Sstevel@tonic-gate 	} else {
2507c478bd9Sstevel@tonic-gate 		if (target->target_prev)
2517c478bd9Sstevel@tonic-gate 			target->target_prev->target_next = target->target_next;
2527c478bd9Sstevel@tonic-gate 		if (target->target_next)
2537c478bd9Sstevel@tonic-gate 			target->target_next->target_prev = target->target_prev;
2547c478bd9Sstevel@tonic-gate 		if (target->on_hal->target_head == target)
2557c478bd9Sstevel@tonic-gate 			target->on_hal->target_head = target->target_next;
2567c478bd9Sstevel@tonic-gate 		if (target->on_hal->target_tail == target)
2577c478bd9Sstevel@tonic-gate 			target->on_hal->target_tail = target->target_prev;
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	s1394_remove_target_from_node(target);
2617c478bd9Sstevel@tonic-gate 	rw_exit(&target->on_hal->target_list_rwlock);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	mutex_exit(&target->on_hal->topology_tree_mutex);
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	/* Free memory */
2667c478bd9Sstevel@tonic-gate 	kmem_free(target, sizeof (s1394_target_t));
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	*t1394_hdl = NULL;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_detach_exit, S1394_TNF_SL_HOTPLUG_STACK, "");
2717c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  * Function:    t1394_alloc_cmd()
2767c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
2777c478bd9Sstevel@tonic-gate  *					    t1394_attach()
2787c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is described below
2797c478bd9Sstevel@tonic-gate  *
2807c478bd9Sstevel@tonic-gate  * Output(s):	cmdp			Pointer to the newly allocated command
2817c478bd9Sstevel@tonic-gate  *
2827c478bd9Sstevel@tonic-gate  * Description:	t1394_alloc_cmd() allocates a command for use with the
2837c478bd9Sstevel@tonic-gate  *		t1394_read(), t1394_write(), or t1394_lock() interfaces
2847c478bd9Sstevel@tonic-gate  *		of the 1394 Software Framework.  By default, t1394_alloc_cmd()
2857c478bd9Sstevel@tonic-gate  *		may sleep while allocating memory for the command structure.
2867c478bd9Sstevel@tonic-gate  *		If this is undesirable, the target may set the
2877c478bd9Sstevel@tonic-gate  *		T1394_ALLOC_CMD_NOSLEEP bit in the flags parameter.  Also,
2887c478bd9Sstevel@tonic-gate  *		this call may fail because a target driver has already
2897c478bd9Sstevel@tonic-gate  *		allocated MAX_NUMBER_ALLOC_CMDS commands.
2907c478bd9Sstevel@tonic-gate  */
2917c478bd9Sstevel@tonic-gate int
2927c478bd9Sstevel@tonic-gate t1394_alloc_cmd(t1394_handle_t t1394_hdl, uint_t flags, cmd1394_cmd_t **cmdp)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	s1394_hal_t	 *hal;
2957c478bd9Sstevel@tonic-gate 	s1394_target_t	 *target;
2967c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
2977c478bd9Sstevel@tonic-gate 	uint_t		 num_cmds;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_cmd_enter, S1394_TNF_SL_ATREQ_STACK, "");
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
3067c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	rw_enter(&hal->target_list_rwlock, RW_WRITER);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/* How many cmds has this target allocated? */
3117c478bd9Sstevel@tonic-gate 	num_cmds = target->target_num_cmds;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	if (num_cmds >= MAX_NUMBER_ALLOC_CMDS) {
3147c478bd9Sstevel@tonic-gate 		rw_exit(&hal->target_list_rwlock);
3157c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_cmd_error, S1394_TNF_SL_ATREQ_ERROR,
3167c478bd9Sstevel@tonic-gate 		    "", tnf_string, msg, "Attempted to alloc > "
3177c478bd9Sstevel@tonic-gate 		    "MAX_NUMBER_ALLOC_CMDS");
3187c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit,
3197c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
3207c478bd9Sstevel@tonic-gate 		/* kstats - cmd alloc failures */
3217c478bd9Sstevel@tonic-gate 		hal->hal_kstats->cmd_alloc_fail++;
3227c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/* Increment the number of cmds this target has allocated? */
3267c478bd9Sstevel@tonic-gate 	target->target_num_cmds = num_cmds + 1;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	if (s1394_alloc_cmd(hal, flags, cmdp) != DDI_SUCCESS) {
3297c478bd9Sstevel@tonic-gate 		target->target_num_cmds = num_cmds;	/* Undo increment */
3307c478bd9Sstevel@tonic-gate 		rw_exit(&hal->target_list_rwlock);
3317c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
3327c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Failed to allocate command structure");
3337c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit,
3347c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
3357c478bd9Sstevel@tonic-gate 		/* kstats - cmd alloc failures */
3367c478bd9Sstevel@tonic-gate 		hal->hal_kstats->cmd_alloc_fail++;
3377c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	rw_exit(&hal->target_list_rwlock);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
3437c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(*cmdp);
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	/* Initialize the command's blocking mutex */
3467c478bd9Sstevel@tonic-gate 	mutex_init(&s_priv->blocking_mutex, NULL, MUTEX_DRIVER,
3477c478bd9Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	/* Initialize the command's blocking condition variable */
3507c478bd9Sstevel@tonic-gate 	cv_init(&s_priv->blocking_cv, NULL, CV_DRIVER, NULL);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit, S1394_TNF_SL_ATREQ_STACK, "");
3537c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate  * Function:    t1394_free_cmd()
3587c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
3597c478bd9Sstevel@tonic-gate  *					    t1394_attach()
3607c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
3617c478bd9Sstevel@tonic-gate  *		cmdp			Pointer to the command to be freed
3627c478bd9Sstevel@tonic-gate  *
3637c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully freed command
3647c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to free command
3657c478bd9Sstevel@tonic-gate  *
3667c478bd9Sstevel@tonic-gate  * Description:	t1394_free_cmd() attempts to free a command that has previously
3677c478bd9Sstevel@tonic-gate  *		been allocated by the target driver.  It is possible for
3687c478bd9Sstevel@tonic-gate  *		t1394_free_cmd() to fail because the command is currently
3697c478bd9Sstevel@tonic-gate  *		in-use by the 1394 Software Framework.
3707c478bd9Sstevel@tonic-gate  */
3717c478bd9Sstevel@tonic-gate /* ARGSUSED */
3727c478bd9Sstevel@tonic-gate int
3737c478bd9Sstevel@tonic-gate t1394_free_cmd(t1394_handle_t t1394_hdl, uint_t flags, cmd1394_cmd_t **cmdp)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate 	s1394_hal_t	 *hal;
3767c478bd9Sstevel@tonic-gate 	s1394_target_t	 *target;
3777c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
3787c478bd9Sstevel@tonic-gate 	uint_t		 num_cmds;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_cmd_enter, S1394_TNF_SL_ATREQ_STACK, "");
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
3877c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	rw_enter(&hal->target_list_rwlock, RW_WRITER);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/* How many cmds has this target allocated? */
3927c478bd9Sstevel@tonic-gate 	num_cmds = target->target_num_cmds;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if (num_cmds == 0) {
3957c478bd9Sstevel@tonic-gate 		rw_exit(&hal->target_list_rwlock);
3967c478bd9Sstevel@tonic-gate 		TNF_PROBE_2(t1394_free_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
3977c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "No commands left to be freed "
3987c478bd9Sstevel@tonic-gate 		    "(num_cmds <= 0)", tnf_uint, num_cmds, num_cmds);
3997c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_cmd_exit,
4007c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
4017c478bd9Sstevel@tonic-gate 		ASSERT(num_cmds != 0);
4027c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
4067c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(*cmdp);
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	/* Check that command isn't in use */
4097c478bd9Sstevel@tonic-gate 	if (s_priv->cmd_in_use == B_TRUE) {
4107c478bd9Sstevel@tonic-gate 		rw_exit(&hal->target_list_rwlock);
4117c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
4127c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Attempted to free an in-use command");
4137c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_cmd_exit,
4147c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
4157c478bd9Sstevel@tonic-gate 		ASSERT(s_priv->cmd_in_use == B_FALSE);
4167c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	/* Decrement the number of cmds this target has allocated */
4207c478bd9Sstevel@tonic-gate 	target->target_num_cmds--;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	rw_exit(&hal->target_list_rwlock);
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	/* Destroy the command's blocking condition variable */
4257c478bd9Sstevel@tonic-gate 	cv_destroy(&s_priv->blocking_cv);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	/* Destroy the command's blocking mutex */
4287c478bd9Sstevel@tonic-gate 	mutex_destroy(&s_priv->blocking_mutex);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	kmem_cache_free(hal->hal_kmem_cachep, *cmdp);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	/* Command pointer is set to NULL before returning */
4337c478bd9Sstevel@tonic-gate 	*cmdp = NULL;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	/* kstats - number of cmd frees */
4367c478bd9Sstevel@tonic-gate 	hal->hal_kstats->cmd_free++;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_cmd_exit, S1394_TNF_SL_ATREQ_STACK, "");
4397c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate  * Function:    t1394_read()
4447c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
4457c478bd9Sstevel@tonic-gate  *					    t1394_attach()
4467c478bd9Sstevel@tonic-gate  *		cmd			Pointer to the command to send
4477c478bd9Sstevel@tonic-gate  *
4487c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successful sent the command
4497c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to send command
4507c478bd9Sstevel@tonic-gate  *
4517c478bd9Sstevel@tonic-gate  * Description:	t1394_read() attempts to send an asynchronous read request
4527c478bd9Sstevel@tonic-gate  *		onto the 1394 bus.
4537c478bd9Sstevel@tonic-gate  */
4547c478bd9Sstevel@tonic-gate int
4557c478bd9Sstevel@tonic-gate t1394_read(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate 	s1394_hal_t	  *to_hal;
4587c478bd9Sstevel@tonic-gate 	s1394_target_t	  *target;
4597c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t  *s_priv;
4607c478bd9Sstevel@tonic-gate 	s1394_hal_state_t state;
4617c478bd9Sstevel@tonic-gate 	int		  ret;
4627c478bd9Sstevel@tonic-gate 	int		  err;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_read_enter, S1394_TNF_SL_ATREQ_STACK, "");
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
4677c478bd9Sstevel@tonic-gate 	ASSERT(cmd != NULL);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
4707c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/* Is this command currently in use? */
4737c478bd9Sstevel@tonic-gate 	if (s_priv->cmd_in_use == B_TRUE) {
4747c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
4757c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Attempted to resend an in-use command");
4767c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_read_exit, S1394_TNF_SL_ATREQ_STACK,
4777c478bd9Sstevel@tonic-gate 		    "");
4787c478bd9Sstevel@tonic-gate 		ASSERT(s_priv->cmd_in_use == B_FALSE);
4797c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	/* Set-up the destination of the command */
4857c478bd9Sstevel@tonic-gate 	to_hal = target->on_hal;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/* No status (default) */
4887c478bd9Sstevel@tonic-gate 	cmd->cmd_result = CMD1394_NOSTATUS;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	/* Check for proper command type */
4917c478bd9Sstevel@tonic-gate 	if ((cmd->cmd_type != CMD1394_ASYNCH_RD_QUAD) &&
4927c478bd9Sstevel@tonic-gate 	    (cmd->cmd_type != CMD1394_ASYNCH_RD_BLOCK)) {
4937c478bd9Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_COMMAND;
4947c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
4957c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Invalid command type specified");
4967c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_read_exit,
4977c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
4987c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	/* Is this a blocking command on interrupt stack? */
5027c478bd9Sstevel@tonic-gate 	if ((cmd->cmd_options & CMD1394_BLOCKING) &&
50380a70ef3Sap25164 	    (servicing_interrupt())) {
5047c478bd9Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
5057c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
5067c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Tried to use CMD1394_BLOCKING in "
5077c478bd9Sstevel@tonic-gate 		    "intr context");
5087c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_read_exit,
5097c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
5107c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	mutex_enter(&to_hal->topology_tree_mutex);
5147c478bd9Sstevel@tonic-gate 	state = to_hal->hal_state;
5157c478bd9Sstevel@tonic-gate 	if (state != S1394_HAL_NORMAL) {
5167c478bd9Sstevel@tonic-gate 		ret = s1394_HAL_asynch_error(to_hal, cmd, state);
5177c478bd9Sstevel@tonic-gate 		if (ret != CMD1394_CMDSUCCESS) {
5187c478bd9Sstevel@tonic-gate 			cmd->cmd_result = ret;
5197c478bd9Sstevel@tonic-gate 			mutex_exit(&to_hal->topology_tree_mutex);
5207c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	ret = s1394_setup_asynch_command(to_hal, target, cmd,
5257c478bd9Sstevel@tonic-gate 	    S1394_CMD_READ, &err);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	/* Command has now been put onto the queue! */
5287c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
5297c478bd9Sstevel@tonic-gate 		/* Copy error code into result */
5307c478bd9Sstevel@tonic-gate 		cmd->cmd_result = err;
5317c478bd9Sstevel@tonic-gate 		mutex_exit(&to_hal->topology_tree_mutex);
5327c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
5337c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Failed in s1394_setup_asynch_command()");
5347c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_read_exit,
5357c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ATREQ_STACK, "");
5367c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	/*
5407c478bd9Sstevel@tonic-gate 	 * If this command was sent during a bus reset,
5417c478bd9Sstevel@tonic-gate 	 * then put it onto the pending Q.
5427c478bd9Sstevel@tonic-gate 	 */
5437c478bd9Sstevel@tonic-gate 	if (state == S1394_HAL_RESET) {
5447c478bd9Sstevel@tonic-gate 		/* Remove cmd from outstanding request Q */
5457c478bd9Sstevel@tonic-gate 		s1394_remove_q_asynch_cmd(to_hal, cmd);
5467c478bd9Sstevel@tonic-gate 		/* Are we on the bus reset event stack? */
5477c478bd9Sstevel@tonic-gate 		if (s1394_on_br_thread(to_hal) == B_TRUE) {
5487c478bd9Sstevel@tonic-gate 			/* Blocking commands are not allowed */
5497c478bd9Sstevel@tonic-gate 			if (cmd->cmd_options & CMD1394_BLOCKING) {
5507c478bd9Sstevel@tonic-gate 				mutex_exit(&to_hal->topology_tree_mutex);
5517c478bd9Sstevel@tonic-gate 				s_priv->cmd_in_use = B_FALSE;
5527c478bd9Sstevel@tonic-gate 				cmd->cmd_result	   = CMD1394_EINVALID_CONTEXT;
5537c478bd9Sstevel@tonic-gate 				TNF_PROBE_1(t1394_read_error,
5547c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ATREQ_ERROR, "", tnf_string,
5557c478bd9Sstevel@tonic-gate 				    msg, "CMD1394_BLOCKING in bus reset "
5567c478bd9Sstevel@tonic-gate 				    "context");
5577c478bd9Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_read_exit,
5587c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ATREQ_STACK, "");
5597c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
5607c478bd9Sstevel@tonic-gate 			}
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		s1394_pending_q_insert(to_hal, cmd, S1394_PENDING_Q_FRONT);
5647c478bd9Sstevel@tonic-gate 		mutex_exit(&to_hal->topology_tree_mutex);
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 		/* Block (if necessary) */
5677c478bd9Sstevel@tonic-gate 		goto block_on_asynch_cmd;
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 	mutex_exit(&to_hal->topology_tree_mutex);
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	/* Send the command out */
5727c478bd9Sstevel@tonic-gate 	ret = s1394_xfer_asynch_command(to_hal, cmd, &err);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
5757c478bd9Sstevel@tonic-gate 		if (err == CMD1394_ESTALE_GENERATION) {
5767c478bd9Sstevel@tonic-gate 			/* Remove cmd from outstanding request Q */
5777c478bd9Sstevel@tonic-gate 			s1394_remove_q_asynch_cmd(to_hal, cmd);
5787c478bd9Sstevel@tonic-gate 			s1394_pending_q_insert(to_hal, cmd,
5797c478bd9Sstevel@tonic-gate 			    S1394_PENDING_Q_FRONT);
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 			/* Block (if necessary) */
5827c478bd9Sstevel@tonic-gate 			goto block_on_asynch_cmd;
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 		} else {
5857c478bd9Sstevel@tonic-gate 			/* Remove cmd from outstanding request Q */
5867c478bd9Sstevel@tonic-gate 			s1394_remove_q_asynch_cmd(to_hal, cmd);
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 			s_priv->cmd_in_use = B_FALSE;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 			/* Copy error code into result */
5917c478bd9Sstevel@tonic-gate 			cmd->cmd_result    = err;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR,
5947c478bd9Sstevel@tonic-gate 			    "", tnf_string, msg, "Failed in "
5957c478bd9Sstevel@tonic-gate 			    "s1394_xfer_asynch_command()");
5967c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_read_exit,
5977c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_STACK, "");
5987c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5997c478bd9Sstevel@tonic-gate 		}
6007c478bd9Sstevel@tonic-gate 	} else {
6017c478bd9Sstevel@tonic-gate 		/* Block (if necessary) */
6027c478bd9Sstevel@tonic-gate 		goto block_on_asynch_cmd;
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate block_on_asynch_cmd:
6067c478bd9Sstevel@tonic-gate 	s1394_block_on_asynch_cmd(cmd);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_read_exit,
6097c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ATREQ_STACK, "");
6107c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate /*
6147c478bd9Sstevel@tonic-gate  * Function:    t1394_write()
6157c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
6167c478bd9Sstevel@tonic-gate  *					    t1394_attach()
6177c478bd9Sstevel@tonic-gate  *		cmd			Pointer to the command to send
6187c478bd9Sstevel@tonic-gate  *
6197c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successful sent the command
6207c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to send command
6217c478bd9Sstevel@tonic-gate  *
6227c478bd9Sstevel@tonic-gate  * Description:	t1394_write() attempts to send an asynchronous write request
6237c478bd9Sstevel@tonic-gate  *		onto the 1394 bus.
6247c478bd9Sstevel@tonic-gate  */
6257c478bd9Sstevel@tonic-gate int
6267c478bd9Sstevel@tonic-gate t1394_write(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
6277c478bd9Sstevel@tonic-gate {
6287c478bd9Sstevel@tonic-gate 	s1394_hal_t	  *to_hal;
6297c478bd9Sstevel@tonic-gate 	s1394_target_t	  *target;
6307c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t  *s_priv;
6317c478bd9Sstevel@tonic-gate 	s1394_hal_state_t state;
6327c478bd9Sstevel@tonic-gate 	int		  ret;
6337c478bd9Sstevel@tonic-gate 	int		  err;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_write_enter, S1394_TNF_SL_ATREQ_STACK, "");
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
6387c478bd9Sstevel@tonic-gate 	ASSERT(cmd != NULL);
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
6417c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	/* Is this command currently in use? */
6447c478bd9Sstevel@tonic-gate 	if (s_priv->cmd_in_use == B_TRUE) {
6457c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
6467c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Attempted to resend an in-use command");
6477c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
6487c478bd9Sstevel@tonic-gate 		    "");
6497c478bd9Sstevel@tonic-gate 		ASSERT(s_priv->cmd_in_use == B_FALSE);
6507c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/* Set-up the destination of the command */
6567c478bd9Sstevel@tonic-gate 	to_hal = target->on_hal;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	/* Is this an FA request? */
6597c478bd9Sstevel@tonic-gate 	if (s_priv->cmd_ext_type == S1394_CMD_EXT_FA) {
6607c478bd9Sstevel@tonic-gate 		if (S1394_IS_CMD_FCP(s_priv) &&
6617c478bd9Sstevel@tonic-gate 		    (s1394_fcp_write_check_cmd(cmd) != DDI_SUCCESS)) {
6627c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_write_exit,
6637c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_STACK, "");
6647c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6657c478bd9Sstevel@tonic-gate 		}
6667c478bd9Sstevel@tonic-gate 		s1394_fa_convert_cmd(to_hal, cmd);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	/* No status (default) */
6707c478bd9Sstevel@tonic-gate 	cmd->cmd_result = CMD1394_NOSTATUS;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	/* Check for proper command type */
6737c478bd9Sstevel@tonic-gate 	if ((cmd->cmd_type != CMD1394_ASYNCH_WR_QUAD) &&
6747c478bd9Sstevel@tonic-gate 	    (cmd->cmd_type != CMD1394_ASYNCH_WR_BLOCK)) {
6757c478bd9Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_COMMAND;
6767c478bd9Sstevel@tonic-gate 		s1394_fa_check_restore_cmd(to_hal, cmd);
6777c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
6787c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Invalid command type specified");
6797c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
6807c478bd9Sstevel@tonic-gate 		    "");
6817c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	/* Is this a blocking command on interrupt stack? */
6857c478bd9Sstevel@tonic-gate 	if ((cmd->cmd_options & CMD1394_BLOCKING) &&
68680a70ef3Sap25164 	    (servicing_interrupt())) {
6877c478bd9Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
6887c478bd9Sstevel@tonic-gate 		s1394_fa_check_restore_cmd(to_hal, cmd);
6897c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
6907c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Tried to use CMD1394_BLOCKING in intr "
6917c478bd9Sstevel@tonic-gate 		    "context");
6927c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
6937c478bd9Sstevel@tonic-gate 		    "");
6947c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6957c478bd9Sstevel@tonic-gate 	}
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	mutex_enter(&to_hal->topology_tree_mutex);
6987c478bd9Sstevel@tonic-gate 	state = to_hal->hal_state;
6997c478bd9Sstevel@tonic-gate 	if (state != S1394_HAL_NORMAL) {
7007c478bd9Sstevel@tonic-gate 		ret = s1394_HAL_asynch_error(to_hal, cmd, state);
7017c478bd9Sstevel@tonic-gate 		if (ret != CMD1394_CMDSUCCESS) {
7027c478bd9Sstevel@tonic-gate 			cmd->cmd_result = ret;
7037c478bd9Sstevel@tonic-gate 			mutex_exit(&to_hal->topology_tree_mutex);
7047c478bd9Sstevel@tonic-gate 			s1394_fa_check_restore_cmd(to_hal, cmd);
7057c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7067c478bd9Sstevel@tonic-gate 		}
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	ret = s1394_setup_asynch_command(to_hal, target, cmd,
7107c478bd9Sstevel@tonic-gate 	    S1394_CMD_WRITE, &err);
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	/* Command has now been put onto the queue! */
7137c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
7147c478bd9Sstevel@tonic-gate 		/* Copy error code into result */
7157c478bd9Sstevel@tonic-gate 		cmd->cmd_result = err;
7167c478bd9Sstevel@tonic-gate 		mutex_exit(&to_hal->topology_tree_mutex);
7177c478bd9Sstevel@tonic-gate 		s1394_fa_check_restore_cmd(to_hal, cmd);
7187c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
7197c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Failed in s1394_setup_asynch_command()");
7207c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
7217c478bd9Sstevel@tonic-gate 		    "");
7227c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7237c478bd9Sstevel@tonic-gate 	}
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/*
7267c478bd9Sstevel@tonic-gate 	 * If this command was sent during a bus reset,
7277c478bd9Sstevel@tonic-gate 	 * then put it onto the pending Q.
7287c478bd9Sstevel@tonic-gate 	 */
7297c478bd9Sstevel@tonic-gate 	if (state == S1394_HAL_RESET) {
7307c478bd9Sstevel@tonic-gate 		/* Remove cmd from outstanding request Q */
7317c478bd9Sstevel@tonic-gate 		s1394_remove_q_asynch_cmd(to_hal, cmd);
7327c478bd9Sstevel@tonic-gate 		/* Are we on the bus reset event stack? */
7337c478bd9Sstevel@tonic-gate 		if (s1394_on_br_thread(to_hal) == B_TRUE) {
7347c478bd9Sstevel@tonic-gate 			/* Blocking commands are not allowed */
7357c478bd9Sstevel@tonic-gate 			if (cmd->cmd_options & CMD1394_BLOCKING) {
7367c478bd9Sstevel@tonic-gate 				mutex_exit(&to_hal->topology_tree_mutex);
7377c478bd9Sstevel@tonic-gate 				s_priv->cmd_in_use = B_FALSE;
7387c478bd9Sstevel@tonic-gate 				cmd->cmd_result    = CMD1394_EINVALID_CONTEXT;
7397c478bd9Sstevel@tonic-gate 				s1394_fa_check_restore_cmd(to_hal, cmd);
7407c478bd9Sstevel@tonic-gate 				TNF_PROBE_1(t1394_write_error,
7417c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ATREQ_ERROR, "", tnf_string,
7427c478bd9Sstevel@tonic-gate 				    msg, "CMD1394_BLOCKING in bus reset cntxt");
7437c478bd9Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_write_exit,
7447c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ATREQ_STACK, "");
7457c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
7467c478bd9Sstevel@tonic-gate 			}
7477c478bd9Sstevel@tonic-gate 		}
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 		s1394_pending_q_insert(to_hal, cmd, S1394_PENDING_Q_FRONT);
7507c478bd9Sstevel@tonic-gate 		mutex_exit(&to_hal->topology_tree_mutex);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		/* Block (if necessary) */
7537c478bd9Sstevel@tonic-gate 		s1394_block_on_asynch_cmd(cmd);
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
7567c478bd9Sstevel@tonic-gate 		    "");
7577c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
7587c478bd9Sstevel@tonic-gate 	}
7597c478bd9Sstevel@tonic-gate 	mutex_exit(&to_hal->topology_tree_mutex);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	/* Send the command out */
7627c478bd9Sstevel@tonic-gate 	ret = s1394_xfer_asynch_command(to_hal, cmd, &err);
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
7657c478bd9Sstevel@tonic-gate 		if (err == CMD1394_ESTALE_GENERATION) {
7667c478bd9Sstevel@tonic-gate 			/* Remove cmd from outstanding request Q */
7677c478bd9Sstevel@tonic-gate 			s1394_remove_q_asynch_cmd(to_hal, cmd);
7687c478bd9Sstevel@tonic-gate 			s1394_pending_q_insert(to_hal, cmd,
7697c478bd9Sstevel@tonic-gate 			    S1394_PENDING_Q_FRONT);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 			/* Block (if necessary) */
7727c478bd9Sstevel@tonic-gate 			s1394_block_on_asynch_cmd(cmd);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_write_exit,
7757c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_STACK, "");
7767c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
7777c478bd9Sstevel@tonic-gate 		} else {
7787c478bd9Sstevel@tonic-gate 			/* Remove cmd from outstanding request Q */
7797c478bd9Sstevel@tonic-gate 			s1394_remove_q_asynch_cmd(to_hal, cmd);
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 			s_priv->cmd_in_use = B_FALSE;
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 			/* Copy error code into result */
7847c478bd9Sstevel@tonic-gate 			cmd->cmd_result = err;
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 			s1394_fa_check_restore_cmd(to_hal, cmd);
7877c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_write_error,
7887c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_ERROR, "", tnf_string, msg,
7897c478bd9Sstevel@tonic-gate 			    "Failed in s1394_xfer_asynch_command()");
7907c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_write_exit,
7917c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ATREQ_STACK, "");
7927c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7937c478bd9Sstevel@tonic-gate 		}
7947c478bd9Sstevel@tonic-gate 	} else {
7957c478bd9Sstevel@tonic-gate 		/* Block (if necessary) */
7967c478bd9Sstevel@tonic-gate 		s1394_block_on_asynch_cmd(cmd);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
7997c478bd9Sstevel@tonic-gate 		    "");
8007c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate /*
8057c478bd9Sstevel@tonic-gate  * Function:    t1394_lock()
8067c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
8077c478bd9Sstevel@tonic-gate  *					    t1394_attach()
8087c478bd9Sstevel@tonic-gate  *		cmd			Pointer to the command to send
8097c478bd9Sstevel@tonic-gate  *
8107c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successful sent the command
8117c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to send command
8127c478bd9Sstevel@tonic-gate  *
8137c478bd9Sstevel@tonic-gate  * Description:	t1394_lock() attempts to send an asynchronous lock request
8147c478bd9Sstevel@tonic-gate  *		onto the 1394 bus.
8157c478bd9Sstevel@tonic-gate  */
8167c478bd9Sstevel@tonic-gate int
8177c478bd9Sstevel@tonic-gate t1394_lock(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
8187c478bd9Sstevel@tonic-gate {
8197c478bd9Sstevel@tonic-gate 	s1394_hal_t	    *to_hal;
8207c478bd9Sstevel@tonic-gate 	s1394_target_t	    *target;
8217c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t    *s_priv;
8227c478bd9Sstevel@tonic-gate 	s1394_hal_state_t   state;
8237c478bd9Sstevel@tonic-gate 	cmd1394_lock_type_t lock_type;
8247c478bd9Sstevel@tonic-gate 	uint_t		    num_retries;
8257c478bd9Sstevel@tonic-gate 	int		    ret;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_lock_enter, S1394_TNF_SL_ATREQ_STACK, "");
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
8307c478bd9Sstevel@tonic-gate 	ASSERT(cmd != NULL);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
8337c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	/* Is this command currently in use? */
8367c478bd9Sstevel@tonic-gate 	if (s_priv->cmd_in_use == B_TRUE) {
8377c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
8387c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Attempted to resend an in-use command");
8397c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
8407c478bd9Sstevel@tonic-gate 		    "");
8417c478bd9Sstevel@tonic-gate 		ASSERT(s_priv->cmd_in_use == B_FALSE);
8427c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8437c478bd9Sstevel@tonic-gate 	}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	/* Set-up the destination of the command */
8487c478bd9Sstevel@tonic-gate 	to_hal = target->on_hal;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	mutex_enter(&to_hal->topology_tree_mutex);
8517c478bd9Sstevel@tonic-gate 	state = to_hal->hal_state;
8527c478bd9Sstevel@tonic-gate 	if (state != S1394_HAL_NORMAL) {
8537c478bd9Sstevel@tonic-gate 		ret = s1394_HAL_asynch_error(to_hal, cmd, state);
8547c478bd9Sstevel@tonic-gate 		if (ret != CMD1394_CMDSUCCESS) {
8557c478bd9Sstevel@tonic-gate 			cmd->cmd_result = ret;
8567c478bd9Sstevel@tonic-gate 			mutex_exit(&to_hal->topology_tree_mutex);
8577c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8587c478bd9Sstevel@tonic-gate 		}
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate 	mutex_exit(&to_hal->topology_tree_mutex);
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	/* Check for proper command type */
8637c478bd9Sstevel@tonic-gate 	if ((cmd->cmd_type != CMD1394_ASYNCH_LOCK_32) &&
8647c478bd9Sstevel@tonic-gate 	    (cmd->cmd_type != CMD1394_ASYNCH_LOCK_64)) {
8657c478bd9Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_COMMAND;
8667c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
8677c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Invalid command type sent to "
8687c478bd9Sstevel@tonic-gate 		    "t1394_lock()");
8697c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
8707c478bd9Sstevel@tonic-gate 		    "");
8717c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8727c478bd9Sstevel@tonic-gate 	}
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	/* No status (default) */
8757c478bd9Sstevel@tonic-gate 	cmd->cmd_result = CMD1394_NOSTATUS;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	/* Is this a blocking command on interrupt stack? */
8787c478bd9Sstevel@tonic-gate 	if ((cmd->cmd_options & CMD1394_BLOCKING) &&
87980a70ef3Sap25164 	    (servicing_interrupt())) {
8807c478bd9Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
8817c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
8827c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Tried to use CMD1394_BLOCKING in intr "
8837c478bd9Sstevel@tonic-gate 		    "context");
8847c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
8857c478bd9Sstevel@tonic-gate 		    "");
8867c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
8907c478bd9Sstevel@tonic-gate 		lock_type	= cmd->cmd_u.l32.lock_type;
8917c478bd9Sstevel@tonic-gate 		num_retries	= cmd->cmd_u.l32.num_retries;
8927c478bd9Sstevel@tonic-gate 	} else {	/* (cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) */
8937c478bd9Sstevel@tonic-gate 		lock_type	= cmd->cmd_u.l64.lock_type;
8947c478bd9Sstevel@tonic-gate 		num_retries	= cmd->cmd_u.l64.num_retries;
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	/* Make sure num_retries is reasonable */
8987c478bd9Sstevel@tonic-gate 	ASSERT(num_retries <= MAX_NUMBER_OF_LOCK_RETRIES);
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	switch (lock_type) {
9017c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_MASK_SWAP:
9027c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_FETCH_ADD:
9037c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_LITTLE_ADD:
9047c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_BOUNDED_ADD:
9057c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_WRAP_ADD:
9067c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_COMPARE_SWAP:
9077c478bd9Sstevel@tonic-gate 		ret = s1394_compare_swap(to_hal, target, cmd);
9087c478bd9Sstevel@tonic-gate 		break;
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_BIT_AND:
9117c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_BIT_OR:
9127c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_BIT_XOR:
9137c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_INCREMENT:
9147c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_DECREMENT:
9157c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_ADD:
9167c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_SUBTRACT:
9177c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_THRESH_ADD:
9187c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_THRESH_SUBTRACT:
9197c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_CLIP_ADD:
9207c478bd9Sstevel@tonic-gate 	case CMD1394_LOCK_CLIP_SUBTRACT:
9217c478bd9Sstevel@tonic-gate 		ret = s1394_split_lock_req(to_hal, target, cmd);
9227c478bd9Sstevel@tonic-gate 		break;
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	default:
9257c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
9267c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Invalid lock_type in command");
9277c478bd9Sstevel@tonic-gate 		cmd->cmd_result = CMD1394_EINVALID_COMMAND;
9287c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
9297c478bd9Sstevel@tonic-gate 		break;
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK, "");
9337c478bd9Sstevel@tonic-gate 	return (ret);
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate  * Function:    t1394_alloc_addr()
9387c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
9397c478bd9Sstevel@tonic-gate  *					    t1394_attach()
9407c478bd9Sstevel@tonic-gate  *		addr_allocp		The structure used to specify the type,
9417c478bd9Sstevel@tonic-gate  *					    size, permissions, and callbacks
9427c478bd9Sstevel@tonic-gate  *					    (if any) for the requested block
9437c478bd9Sstevel@tonic-gate  *					    of 1394 address space
9447c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
9457c478bd9Sstevel@tonic-gate  *
9467c478bd9Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
9477c478bd9Sstevel@tonic-gate  *					    to target
9487c478bd9Sstevel@tonic-gate  *
9497c478bd9Sstevel@tonic-gate  * Description:	t1394_alloc_addr() requests that part of the 1394 Address Space
9507c478bd9Sstevel@tonic-gate  *		on the local node be set aside for this target driver, and
9517c478bd9Sstevel@tonic-gate  *		associated with this address space should be some permissions
9527c478bd9Sstevel@tonic-gate  *		and callbacks.  If the request is unable to be fulfilled,
9537c478bd9Sstevel@tonic-gate  *		t1394_alloc_addr() will return DDI_FAILURE and result will
9547c478bd9Sstevel@tonic-gate  *		indicate the reason.  T1394_EINVALID_PARAM indicates that the
9557c478bd9Sstevel@tonic-gate  *		combination of flags given is invalid, and T1394_EALLOC_ADDR
9567c478bd9Sstevel@tonic-gate  *		indicates that the requested type of address space is
9577c478bd9Sstevel@tonic-gate  *		unavailable.
9587c478bd9Sstevel@tonic-gate  */
9597c478bd9Sstevel@tonic-gate /* ARGSUSED */
9607c478bd9Sstevel@tonic-gate int
9617c478bd9Sstevel@tonic-gate t1394_alloc_addr(t1394_handle_t t1394_hdl, t1394_alloc_addr_t *addr_allocp,
9627c478bd9Sstevel@tonic-gate     uint_t flags, int *result)
9637c478bd9Sstevel@tonic-gate {
9647c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
9657c478bd9Sstevel@tonic-gate 	s1394_target_t	*target;
9667c478bd9Sstevel@tonic-gate 	uint64_t	addr_lo;
9677c478bd9Sstevel@tonic-gate 	uint64_t	addr_hi;
9687c478bd9Sstevel@tonic-gate 	int		err;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_addr_enter, S1394_TNF_SL_ARREQ_STACK,
9717c478bd9Sstevel@tonic-gate 	    "");
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
9747c478bd9Sstevel@tonic-gate 	ASSERT(addr_allocp != NULL);
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
9797c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	/* Get the bounds of the request */
9827c478bd9Sstevel@tonic-gate 	addr_lo = addr_allocp->aa_address;
9837c478bd9Sstevel@tonic-gate 	addr_hi = addr_lo + addr_allocp->aa_length;
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	/* Check combination of flags */
9867c478bd9Sstevel@tonic-gate 	if ((addr_allocp->aa_enable & T1394_ADDR_RDENBL) &&
9877c478bd9Sstevel@tonic-gate 	    (addr_allocp->aa_evts.recv_read_request == NULL) &&
9887c478bd9Sstevel@tonic-gate 	    (addr_allocp->aa_kmem_bufp == NULL)) {
9897c478bd9Sstevel@tonic-gate 		if ((addr_allocp->aa_type != T1394_ADDR_FIXED)	||
9907c478bd9Sstevel@tonic-gate 		    (addr_lo < hal->physical_addr_lo)		||
9917c478bd9Sstevel@tonic-gate 		    (addr_hi > hal->physical_addr_hi)) {
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 			/*
9947c478bd9Sstevel@tonic-gate 			 * Reads are enabled, but target doesn't want to
9957c478bd9Sstevel@tonic-gate 			 * be notified and hasn't given backing store
9967c478bd9Sstevel@tonic-gate 			 */
9977c478bd9Sstevel@tonic-gate 			*result = T1394_EINVALID_PARAM;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_addr_error,
10007c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
10017c478bd9Sstevel@tonic-gate 			    "Invalid flags "
10027c478bd9Sstevel@tonic-gate 			    "(RDs on, notify off, no backing store)");
10037c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
10047c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_STACK, "");
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10077c478bd9Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10087c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10097c478bd9Sstevel@tonic-gate 		} else {
10107c478bd9Sstevel@tonic-gate 			addr_allocp->aa_enable &= ~T1394_ADDR_RDENBL;
10117c478bd9Sstevel@tonic-gate 		}
10127c478bd9Sstevel@tonic-gate 	}
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	if ((addr_allocp->aa_enable & T1394_ADDR_WRENBL) &&
10157c478bd9Sstevel@tonic-gate 	    (addr_allocp->aa_evts.recv_write_request == NULL) &&
10167c478bd9Sstevel@tonic-gate 	    (addr_allocp->aa_kmem_bufp == NULL)) {
10177c478bd9Sstevel@tonic-gate 		if ((addr_allocp->aa_type != T1394_ADDR_FIXED)	||
10187c478bd9Sstevel@tonic-gate 		    (addr_lo < hal->physical_addr_lo)		||
10197c478bd9Sstevel@tonic-gate 		    (addr_hi > hal->physical_addr_hi)) {
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 			/*
10227c478bd9Sstevel@tonic-gate 			 * Writes are enabled, but target doesn't want to
10237c478bd9Sstevel@tonic-gate 			 * be notified and hasn't given backing store
10247c478bd9Sstevel@tonic-gate 			 */
10257c478bd9Sstevel@tonic-gate 			*result = T1394_EINVALID_PARAM;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_addr_error,
10287c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
10297c478bd9Sstevel@tonic-gate 			    "Invalid flags "
10307c478bd9Sstevel@tonic-gate 			    "(WRs on, notify off, no backing store)");
10317c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
10327c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_STACK, "");
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10357c478bd9Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10367c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10377c478bd9Sstevel@tonic-gate 		} else {
10387c478bd9Sstevel@tonic-gate 			addr_allocp->aa_enable &= ~T1394_ADDR_WRENBL;
10397c478bd9Sstevel@tonic-gate 		}
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	if ((addr_allocp->aa_enable & T1394_ADDR_LKENBL) &&
10437c478bd9Sstevel@tonic-gate 	    (addr_allocp->aa_evts.recv_lock_request == NULL) &&
10447c478bd9Sstevel@tonic-gate 	    (addr_allocp->aa_kmem_bufp == NULL)) {
10457c478bd9Sstevel@tonic-gate 		if ((addr_allocp->aa_type != T1394_ADDR_FIXED)	||
10467c478bd9Sstevel@tonic-gate 		    (addr_lo < hal->physical_addr_lo)		||
10477c478bd9Sstevel@tonic-gate 		    (addr_hi > hal->physical_addr_hi)) {
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 			/*
10507c478bd9Sstevel@tonic-gate 			 * Locks are enabled, but target doesn't want to
10517c478bd9Sstevel@tonic-gate 			 * be notified and hasn't given backing store
10527c478bd9Sstevel@tonic-gate 			 */
10537c478bd9Sstevel@tonic-gate 			*result = T1394_EINVALID_PARAM;
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_addr_error,
10567c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
10577c478bd9Sstevel@tonic-gate 			    "Invalid flags "
10587c478bd9Sstevel@tonic-gate 			    "(LKs on, notify off, no backing store)");
10597c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
10607c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ARREQ_STACK, "");
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10637c478bd9Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10647c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10657c478bd9Sstevel@tonic-gate 		} else {
10667c478bd9Sstevel@tonic-gate 			addr_allocp->aa_enable &= ~T1394_ADDR_LKENBL;
10677c478bd9Sstevel@tonic-gate 		}
10687c478bd9Sstevel@tonic-gate 	}
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	/* If not T1394_ADDR_FIXED, then allocate a block */
10717c478bd9Sstevel@tonic-gate 	if (addr_allocp->aa_type != T1394_ADDR_FIXED) {
10727c478bd9Sstevel@tonic-gate 		err = s1394_request_addr_blk((s1394_hal_t *)target->on_hal,
10737c478bd9Sstevel@tonic-gate 					addr_allocp);
10747c478bd9Sstevel@tonic-gate 		if (err != DDI_SUCCESS) {
10757c478bd9Sstevel@tonic-gate 			*result = T1394_EALLOC_ADDR;
10767c478bd9Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10777c478bd9Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10787c478bd9Sstevel@tonic-gate 		} else {
10797c478bd9Sstevel@tonic-gate 			*result = T1394_NOERROR;
10807c478bd9Sstevel@tonic-gate 		}
10817c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
10827c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
10837c478bd9Sstevel@tonic-gate 		return (err);
10847c478bd9Sstevel@tonic-gate 	} else {
10857c478bd9Sstevel@tonic-gate 		err = s1394_claim_addr_blk((s1394_hal_t *)target->on_hal,
10867c478bd9Sstevel@tonic-gate 					addr_allocp);
10877c478bd9Sstevel@tonic-gate 		if (err != DDI_SUCCESS) {
10887c478bd9Sstevel@tonic-gate 			*result = T1394_EALLOC_ADDR;
10897c478bd9Sstevel@tonic-gate 			/* kstats - addr alloc failures */
10907c478bd9Sstevel@tonic-gate 			hal->hal_kstats->addr_alloc_fail++;
10917c478bd9Sstevel@tonic-gate 		} else {
10927c478bd9Sstevel@tonic-gate 			*result = T1394_NOERROR;
10937c478bd9Sstevel@tonic-gate 			/* If physical, update the AR request counter */
10947c478bd9Sstevel@tonic-gate 			if ((addr_lo >= hal->physical_addr_lo) &&
10957c478bd9Sstevel@tonic-gate 			    (addr_hi <= hal->physical_addr_hi)) {
10967c478bd9Sstevel@tonic-gate 				rw_enter(&hal->target_list_rwlock, RW_WRITER);
10977c478bd9Sstevel@tonic-gate 				target->physical_arreq_enabled++;
10987c478bd9Sstevel@tonic-gate 				rw_exit(&hal->target_list_rwlock);
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 				s1394_physical_arreq_set_one(target);
11017c478bd9Sstevel@tonic-gate 			}
11027c478bd9Sstevel@tonic-gate 		}
11037c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
11047c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
11057c478bd9Sstevel@tonic-gate 		return (err);
11067c478bd9Sstevel@tonic-gate 	}
11077c478bd9Sstevel@tonic-gate }
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate /*
11107c478bd9Sstevel@tonic-gate  * Function:    t1394_free_addr()
11117c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
11127c478bd9Sstevel@tonic-gate  *					    t1394_attach()
11137c478bd9Sstevel@tonic-gate  *		addr_hdl		The address "handle" returned by the
11147c478bd9Sstevel@tonic-gate  *					   the t1394_alloc_addr() routine
11157c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
11167c478bd9Sstevel@tonic-gate  *
11177c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully freed memory
11187c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to free the memory block
11197c478bd9Sstevel@tonic-gate  *
11207c478bd9Sstevel@tonic-gate  * Description:	t1394_free_addr() attempts to free up memory that has been
11217c478bd9Sstevel@tonic-gate  *		allocated by the target using t1394_alloc_addr().
11227c478bd9Sstevel@tonic-gate  */
11237c478bd9Sstevel@tonic-gate /* ARGSUSED */
11247c478bd9Sstevel@tonic-gate int
11257c478bd9Sstevel@tonic-gate t1394_free_addr(t1394_handle_t t1394_hdl, t1394_addr_handle_t *addr_hdl,
11267c478bd9Sstevel@tonic-gate     uint_t flags)
11277c478bd9Sstevel@tonic-gate {
11287c478bd9Sstevel@tonic-gate 	s1394_addr_space_blk_t	*curr_blk;
11297c478bd9Sstevel@tonic-gate 	s1394_hal_t		*hal;
11307c478bd9Sstevel@tonic-gate 	s1394_target_t		*target;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_addr_enter, S1394_TNF_SL_ARREQ_STACK, "");
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
11357c478bd9Sstevel@tonic-gate 	ASSERT(addr_hdl != NULL);
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
11407c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	curr_blk = (s1394_addr_space_blk_t *)(*addr_hdl);
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	if (s1394_free_addr_blk(hal, curr_blk) != DDI_SUCCESS) {
11457c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_addr_exit,
11467c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
11477c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	/* If physical, update the AR request counter */
11517c478bd9Sstevel@tonic-gate 	if (curr_blk->addr_type == T1394_ADDR_FIXED) {
11527c478bd9Sstevel@tonic-gate 		target->physical_arreq_enabled--;
11537c478bd9Sstevel@tonic-gate 		s1394_physical_arreq_clear_one(target);
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	*addr_hdl = NULL;
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	/* kstats - number of addr frees */
11597c478bd9Sstevel@tonic-gate 	hal->hal_kstats->addr_space_free++;
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_addr_exit, S1394_TNF_SL_ARREQ_STACK, "");
11627c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11637c478bd9Sstevel@tonic-gate }
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate /*
11667c478bd9Sstevel@tonic-gate  * Function:    t1394_recv_request_done()
11677c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
11687c478bd9Sstevel@tonic-gate  *					    t1394_attach()
11697c478bd9Sstevel@tonic-gate  *		resp			Pointer to the command which the
11707c478bd9Sstevel@tonic-gate  *					    target received in it's callback
11717c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
11727c478bd9Sstevel@tonic-gate  *
11737c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully returned command
11747c478bd9Sstevel@tonic-gate  *					    to the 1394 Software Framework,
11757c478bd9Sstevel@tonic-gate  *					    and, if necessary, sent response
11767c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to return the command to
11777c478bd9Sstevel@tonic-gate  *					    the 1394 Software Framework
11787c478bd9Sstevel@tonic-gate  *
11797c478bd9Sstevel@tonic-gate  * Description:	t1394_recv_request_done() takes the command that is given and
11807c478bd9Sstevel@tonic-gate  *		determines whether that command requires a response to be
11817c478bd9Sstevel@tonic-gate  *		sent on the 1394 bus.  If it is necessary and it's response
11827c478bd9Sstevel@tonic-gate  *		code (cmd_result) has been set appropriately, then a response
11837c478bd9Sstevel@tonic-gate  *		will be sent.  If no response is necessary (broadcast or
11847c478bd9Sstevel@tonic-gate  *		posted write), then the command resources are reclaimed.
11857c478bd9Sstevel@tonic-gate  */
11867c478bd9Sstevel@tonic-gate /* ARGSUSED */
11877c478bd9Sstevel@tonic-gate int
11887c478bd9Sstevel@tonic-gate t1394_recv_request_done(t1394_handle_t t1394_hdl, cmd1394_cmd_t *resp,
11897c478bd9Sstevel@tonic-gate     uint_t flags)
11907c478bd9Sstevel@tonic-gate {
11917c478bd9Sstevel@tonic-gate 	s1394_hal_t	 *hal;
11927c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
11937c478bd9Sstevel@tonic-gate 	h1394_cmd_priv_t *h_priv;
11947c478bd9Sstevel@tonic-gate 	mblk_t		 *curr_blk;
11957c478bd9Sstevel@tonic-gate 	size_t		 msgb_len;
11967c478bd9Sstevel@tonic-gate 	size_t		 size;
11977c478bd9Sstevel@tonic-gate 	int		 ret;
11987c478bd9Sstevel@tonic-gate 	boolean_t	 response = B_TRUE;
11997c478bd9Sstevel@tonic-gate 	boolean_t	 posted_write = B_FALSE;
12007c478bd9Sstevel@tonic-gate 	boolean_t	 write_cmd = B_FALSE;
12017c478bd9Sstevel@tonic-gate 	boolean_t	 mblk_too_small;
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_recv_request_done_enter,
12047c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ARREQ_STACK, "");
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
12077c478bd9Sstevel@tonic-gate 	ASSERT(resp != NULL);
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
12107c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
12137c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(resp);
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	/* Get a pointer to the HAL private struct */
12167c478bd9Sstevel@tonic-gate 	h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	/* Is this an FA request? */
12197c478bd9Sstevel@tonic-gate 	if (s_priv->cmd_ext_type == S1394_CMD_EXT_FA) {
12207c478bd9Sstevel@tonic-gate 		s1394_fa_convert_cmd(hal, resp);
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	/* Is this a write request? */
12247c478bd9Sstevel@tonic-gate 	if ((resp->cmd_type == CMD1394_ASYNCH_WR_QUAD) ||
12257c478bd9Sstevel@tonic-gate 	    (resp->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
12267c478bd9Sstevel@tonic-gate 		write_cmd = B_TRUE;
12277c478bd9Sstevel@tonic-gate 		/* Is this a posted write request? */
12287c478bd9Sstevel@tonic-gate 		posted_write = s_priv->posted_write;
12297c478bd9Sstevel@tonic-gate 	}
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	/* If broadcast or posted write cmd, don't send response */
12327c478bd9Sstevel@tonic-gate 	if ((resp->broadcast == 1) ||
12337c478bd9Sstevel@tonic-gate 	    ((write_cmd == B_TRUE) && (posted_write == B_TRUE)))
12347c478bd9Sstevel@tonic-gate 		response = B_FALSE;
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	if (response == B_FALSE) {
12377c478bd9Sstevel@tonic-gate 		if ((write_cmd == B_TRUE) && (posted_write == B_TRUE)) {
12387c478bd9Sstevel@tonic-gate 			/* kstats - Posted Write error */
12397c478bd9Sstevel@tonic-gate 			hal->hal_kstats->arreq_posted_write_error++;
12407c478bd9Sstevel@tonic-gate 		}
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 		/* Free the command - Pass it back to the HAL */
12437c478bd9Sstevel@tonic-gate 		HAL_CALL(hal).response_complete(hal->halinfo.hal_private, resp,
12447c478bd9Sstevel@tonic-gate 		    h_priv);
12457c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
12467c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
12477c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
12487c478bd9Sstevel@tonic-gate 	}
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	ASSERT(response == B_TRUE);
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	/* Verify valid response code */
12537c478bd9Sstevel@tonic-gate 	switch (resp->cmd_result) {
12547c478bd9Sstevel@tonic-gate 	case IEEE1394_RESP_COMPLETE:
12557c478bd9Sstevel@tonic-gate 		/* Is the mblk_t too small? */
12567c478bd9Sstevel@tonic-gate 		if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK) {
12577c478bd9Sstevel@tonic-gate 			curr_blk = resp->cmd_u.b.data_block;
12587c478bd9Sstevel@tonic-gate 			size	 = resp->cmd_u.b.blk_length;
12597c478bd9Sstevel@tonic-gate 			msgb_len = 0;
12607c478bd9Sstevel@tonic-gate 			mblk_too_small = B_TRUE;
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 			if (curr_blk == NULL) {
12637c478bd9Sstevel@tonic-gate 				TNF_PROBE_1(t1394_recv_request_done_error,
12647c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string,
12657c478bd9Sstevel@tonic-gate 				    msg, "mblk_t is NULL in response");
12667c478bd9Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
12677c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ARREQ_STACK, "");
12687c478bd9Sstevel@tonic-gate 				/*
12697c478bd9Sstevel@tonic-gate 				 * Free the command - Pass it back
12707c478bd9Sstevel@tonic-gate 				 * to the HAL
12717c478bd9Sstevel@tonic-gate 				 */
12727c478bd9Sstevel@tonic-gate 				HAL_CALL(hal).response_complete(
12737c478bd9Sstevel@tonic-gate 				    hal->halinfo.hal_private, resp, h_priv);
12747c478bd9Sstevel@tonic-gate 				ASSERT(curr_blk != NULL);
12757c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
12767c478bd9Sstevel@tonic-gate 			}
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 			while (curr_blk != NULL) {
12797c478bd9Sstevel@tonic-gate 				msgb_len +=
12807c478bd9Sstevel@tonic-gate 				    (curr_blk->b_wptr - curr_blk->b_rptr);
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 				if (msgb_len >= size) {
12837c478bd9Sstevel@tonic-gate 					mblk_too_small = B_FALSE;
12847c478bd9Sstevel@tonic-gate 					break;
12857c478bd9Sstevel@tonic-gate 				}
12867c478bd9Sstevel@tonic-gate 				curr_blk = curr_blk->b_cont;
12877c478bd9Sstevel@tonic-gate 			}
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 			if (mblk_too_small == B_TRUE) {
12907c478bd9Sstevel@tonic-gate 				TNF_PROBE_1(t1394_recv_request_done_error,
12917c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string,
12927c478bd9Sstevel@tonic-gate 				    msg, "mblk_t too small in response");
12937c478bd9Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
12947c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ARREQ_STACK, "");
12957c478bd9Sstevel@tonic-gate 				/*
12967c478bd9Sstevel@tonic-gate 				 * Free the command - Pass it back
12977c478bd9Sstevel@tonic-gate 				 * to the HAL
12987c478bd9Sstevel@tonic-gate 				 */
12997c478bd9Sstevel@tonic-gate 				HAL_CALL(hal).response_complete(
13007c478bd9Sstevel@tonic-gate 				    hal->halinfo.hal_private, resp, h_priv);
13017c478bd9Sstevel@tonic-gate 				ASSERT(mblk_too_small != B_TRUE);
13027c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
13037c478bd9Sstevel@tonic-gate 			}
13047c478bd9Sstevel@tonic-gate 		}
13057c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
13067c478bd9Sstevel@tonic-gate 	case IEEE1394_RESP_CONFLICT_ERROR:
13077c478bd9Sstevel@tonic-gate 	case IEEE1394_RESP_DATA_ERROR:
13087c478bd9Sstevel@tonic-gate 	case IEEE1394_RESP_TYPE_ERROR:
13097c478bd9Sstevel@tonic-gate 	case IEEE1394_RESP_ADDRESS_ERROR:
13107c478bd9Sstevel@tonic-gate 		ret = s1394_send_response(hal, resp);
13117c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
13127c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
13137c478bd9Sstevel@tonic-gate 		return (ret);
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	default:
13167c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_recv_request_done_error,
13177c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
13187c478bd9Sstevel@tonic-gate 		    "Invalid response code");
13197c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
13207c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ARREQ_STACK, "");
13217c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate }
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate /*
13277c478bd9Sstevel@tonic-gate  * Function:    t1394_fcp_register_controller()
13287c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
13297c478bd9Sstevel@tonic-gate  *					    t1394_attach()
13307c478bd9Sstevel@tonic-gate  *		evts			The structure in which the target
13317c478bd9Sstevel@tonic-gate  *					    specifies its callback routines
13327c478bd9Sstevel@tonic-gate  *
13337c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
13347c478bd9Sstevel@tonic-gate  *
13357c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
13367c478bd9Sstevel@tonic-gate  *
13377c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
13387c478bd9Sstevel@tonic-gate  *
13397c478bd9Sstevel@tonic-gate  * Description:	Used to register the target within the Framework as an FCP
13407c478bd9Sstevel@tonic-gate  *		controller.
13417c478bd9Sstevel@tonic-gate  */
13427c478bd9Sstevel@tonic-gate /* ARGSUSED */
13437c478bd9Sstevel@tonic-gate int
13447c478bd9Sstevel@tonic-gate t1394_fcp_register_controller(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
13457c478bd9Sstevel@tonic-gate     uint_t flags)
13467c478bd9Sstevel@tonic-gate {
13477c478bd9Sstevel@tonic-gate 	int		result;
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_register_controller_enter,
13507c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	result = s1394_fcp_register_ctl((s1394_target_t *)t1394_hdl, evts);
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_register_controller_exit,
13577c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
13587c478bd9Sstevel@tonic-gate 	return (result);
13597c478bd9Sstevel@tonic-gate }
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate /*
13627c478bd9Sstevel@tonic-gate  * Function:    t1394_fcp_unregister_controller()
13637c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
13647c478bd9Sstevel@tonic-gate  *					    t1394_attach()
13657c478bd9Sstevel@tonic-gate  *
13667c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully unregistered.
13677c478bd9Sstevel@tonic-gate  *
13687c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Not unregistered due to failure.
13697c478bd9Sstevel@tonic-gate  *
13707c478bd9Sstevel@tonic-gate  * Description:	Used to unregister the target within the Framework as an FCP
13717c478bd9Sstevel@tonic-gate  *		controller.
13727c478bd9Sstevel@tonic-gate  */
13737c478bd9Sstevel@tonic-gate int
13747c478bd9Sstevel@tonic-gate t1394_fcp_unregister_controller(t1394_handle_t t1394_hdl)
13757c478bd9Sstevel@tonic-gate {
13767c478bd9Sstevel@tonic-gate 	int		result;
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_unregister_controller_enter,
13797c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	result = s1394_fcp_unregister_ctl((s1394_target_t *)t1394_hdl);
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_unregister_controller_exit,
13867c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
13877c478bd9Sstevel@tonic-gate 	return (result);
13887c478bd9Sstevel@tonic-gate }
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate /*
13917c478bd9Sstevel@tonic-gate  * Function:    t1394_fcp_register_target()
13927c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
13937c478bd9Sstevel@tonic-gate  *					    t1394_attach()
13947c478bd9Sstevel@tonic-gate  *		evts			The structure in which the target
13957c478bd9Sstevel@tonic-gate  *					    specifies its callback routines
13967c478bd9Sstevel@tonic-gate  *
13977c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
13987c478bd9Sstevel@tonic-gate  *
13997c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
14007c478bd9Sstevel@tonic-gate  *
14017c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
14027c478bd9Sstevel@tonic-gate  *
14037c478bd9Sstevel@tonic-gate  * Description:	Used to register the target within the Framework as an FCP
14047c478bd9Sstevel@tonic-gate  *		target.
14057c478bd9Sstevel@tonic-gate  */
14067c478bd9Sstevel@tonic-gate /* ARGSUSED */
14077c478bd9Sstevel@tonic-gate int
14087c478bd9Sstevel@tonic-gate t1394_fcp_register_target(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
14097c478bd9Sstevel@tonic-gate     uint_t flags)
14107c478bd9Sstevel@tonic-gate {
14117c478bd9Sstevel@tonic-gate 	int		result;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_register_target_enter,
14147c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	result = s1394_fcp_register_tgt((s1394_target_t *)t1394_hdl, evts);
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_register_target_exit,
14217c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
14227c478bd9Sstevel@tonic-gate 	return (result);
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate /*
14267c478bd9Sstevel@tonic-gate  * Function:    t1394_fcp_unregister_target()
14277c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
14287c478bd9Sstevel@tonic-gate  *					    t1394_attach()
14297c478bd9Sstevel@tonic-gate  *
14307c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully unregistered.
14317c478bd9Sstevel@tonic-gate  *
14327c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Not unregistered due to failure.
14337c478bd9Sstevel@tonic-gate  *
14347c478bd9Sstevel@tonic-gate  * Description:	Used to unregister the target within the Framework as an FCP
14357c478bd9Sstevel@tonic-gate  *		target.
14367c478bd9Sstevel@tonic-gate  */
14377c478bd9Sstevel@tonic-gate int
14387c478bd9Sstevel@tonic-gate t1394_fcp_unregister_target(t1394_handle_t t1394_hdl)
14397c478bd9Sstevel@tonic-gate {
14407c478bd9Sstevel@tonic-gate 	int		result;
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_unregister_target_enter,
14437c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	result = s1394_fcp_unregister_tgt((s1394_target_t *)t1394_hdl);
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_fcp_unregister_target_exit,
14507c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_FCP_STACK, "");
14517c478bd9Sstevel@tonic-gate 	return (result);
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate /*
14557c478bd9Sstevel@tonic-gate  * Function:    t1394_cmp_register()
14567c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
14577c478bd9Sstevel@tonic-gate  *					    t1394_attach()
14587c478bd9Sstevel@tonic-gate  *		evts			The structure in which the target
14597c478bd9Sstevel@tonic-gate  *					    specifies its callback routines
14607c478bd9Sstevel@tonic-gate  *
14617c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
14627c478bd9Sstevel@tonic-gate  *
14637c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
14647c478bd9Sstevel@tonic-gate  *
14657c478bd9Sstevel@tonic-gate  * Description:	Used to register the target within the Framework as a CMP
14667c478bd9Sstevel@tonic-gate  *		device.
14677c478bd9Sstevel@tonic-gate  */
14687c478bd9Sstevel@tonic-gate /* ARGSUSED */
14697c478bd9Sstevel@tonic-gate int
14707c478bd9Sstevel@tonic-gate t1394_cmp_register(t1394_handle_t t1394_hdl, t1394_cmp_evts_t *evts,
14717c478bd9Sstevel@tonic-gate     uint_t flags)
14727c478bd9Sstevel@tonic-gate {
14737c478bd9Sstevel@tonic-gate 	int		result;
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_register_enter, S1394_TNF_SL_CMP_STACK, "");
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 	result = s1394_cmp_register((s1394_target_t *)t1394_hdl, evts);
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_register_exit, S1394_TNF_SL_CMP_STACK, "");
14827c478bd9Sstevel@tonic-gate 	return (result);
14837c478bd9Sstevel@tonic-gate }
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate /*
14867c478bd9Sstevel@tonic-gate  * Function:    t1394_cmp_unregister()
14877c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
14887c478bd9Sstevel@tonic-gate  *					    t1394_attach()
14897c478bd9Sstevel@tonic-gate  *		evts			The structure in which the target
14907c478bd9Sstevel@tonic-gate  *					    specifies its callback routines
14917c478bd9Sstevel@tonic-gate  *
14927c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
14937c478bd9Sstevel@tonic-gate  *
14947c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
14957c478bd9Sstevel@tonic-gate  *
14967c478bd9Sstevel@tonic-gate  * Description:	Used to unregister the target within the Framework as a CMP
14977c478bd9Sstevel@tonic-gate  *		device.
14987c478bd9Sstevel@tonic-gate  */
14997c478bd9Sstevel@tonic-gate int
15007c478bd9Sstevel@tonic-gate t1394_cmp_unregister(t1394_handle_t t1394_hdl)
15017c478bd9Sstevel@tonic-gate {
15027c478bd9Sstevel@tonic-gate 	int		result;
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_unregister_enter, S1394_TNF_SL_CMP_STACK,
15057c478bd9Sstevel@tonic-gate 	    "");
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	result = s1394_cmp_unregister((s1394_target_t *)t1394_hdl);
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_unregister_exit, S1394_TNF_SL_CMP_STACK,
15127c478bd9Sstevel@tonic-gate 	    "");
15137c478bd9Sstevel@tonic-gate 	return (result);
15147c478bd9Sstevel@tonic-gate }
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate /*
15177c478bd9Sstevel@tonic-gate  * Function:    t1394_cmp_read()
15187c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
15197c478bd9Sstevel@tonic-gate  *					    t1394_attach()
15207c478bd9Sstevel@tonic-gate  *		reg			Register type.
15217c478bd9Sstevel@tonic-gate  *		valp			Returned register value.
15227c478bd9Sstevel@tonic-gate  *
15237c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
15247c478bd9Sstevel@tonic-gate  *
15257c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
15267c478bd9Sstevel@tonic-gate  *
15277c478bd9Sstevel@tonic-gate  * Description:	Used to read a CMP register value.
15287c478bd9Sstevel@tonic-gate  */
15297c478bd9Sstevel@tonic-gate int
15307c478bd9Sstevel@tonic-gate t1394_cmp_read(t1394_handle_t t1394_hdl, t1394_cmp_reg_t reg, uint32_t *valp)
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate 	int		result;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_read_enter, S1394_TNF_SL_CMP_STACK, "");
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	result = s1394_cmp_read((s1394_target_t *)t1394_hdl, reg, valp);
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_read_exit, S1394_TNF_SL_CMP_STACK, "");
15417c478bd9Sstevel@tonic-gate 	return (result);
15427c478bd9Sstevel@tonic-gate }
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate /*
15457c478bd9Sstevel@tonic-gate  * Function:    t1394_cmp_cas()
15467c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
15477c478bd9Sstevel@tonic-gate  *					    t1394_attach()
15487c478bd9Sstevel@tonic-gate  *		reg			Register type.
15497c478bd9Sstevel@tonic-gate  *		arg_val			Compare argument.
15507c478bd9Sstevel@tonic-gate  *		new_val			New register value.
15517c478bd9Sstevel@tonic-gate  *		old_valp		Returned original register value.
15527c478bd9Sstevel@tonic-gate  *
15537c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Successfully registered.
15547c478bd9Sstevel@tonic-gate  *
15557c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Not registered due to failure.
15567c478bd9Sstevel@tonic-gate  *
15577c478bd9Sstevel@tonic-gate  * Description:	Used to compare-swap a CMP register value.
15587c478bd9Sstevel@tonic-gate  */
15597c478bd9Sstevel@tonic-gate int
15607c478bd9Sstevel@tonic-gate t1394_cmp_cas(t1394_handle_t t1394_hdl, t1394_cmp_reg_t reg, uint32_t arg_val,
15617c478bd9Sstevel@tonic-gate     uint32_t new_val, uint32_t *old_valp)
15627c478bd9Sstevel@tonic-gate {
15637c478bd9Sstevel@tonic-gate 	int		result;
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_read_enter, S1394_TNF_SL_CMP_STACK, "");
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	result = s1394_cmp_cas((s1394_target_t *)t1394_hdl, reg, arg_val,
15707c478bd9Sstevel@tonic-gate 				new_val, old_valp);
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_cmp_read_exit, S1394_TNF_SL_CMP_STACK, "");
15737c478bd9Sstevel@tonic-gate 	return (result);
15747c478bd9Sstevel@tonic-gate }
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate /*
15777c478bd9Sstevel@tonic-gate  * Function:    t1394_alloc_isoch_single()
15787c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
15797c478bd9Sstevel@tonic-gate  *					    t1394_attach()
15807c478bd9Sstevel@tonic-gate  *		sii			The structure used to set up the
15817c478bd9Sstevel@tonic-gate  *					    overall characteristics of the
15827c478bd9Sstevel@tonic-gate  *					    isochronous stream
15837c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
15847c478bd9Sstevel@tonic-gate  *
15857c478bd9Sstevel@tonic-gate  * Output(s):	setup_args		Contains the channel number that was
15867c478bd9Sstevel@tonic-gate  *					    allocated
15877c478bd9Sstevel@tonic-gate  *		t1394_single_hdl	This in the isoch "handle" used in
15887c478bd9Sstevel@tonic-gate  *					    t1394_free_isoch_single()
15897c478bd9Sstevel@tonic-gate  *		result			Used to pass more specific info back
15907c478bd9Sstevel@tonic-gate  *					    to target
15917c478bd9Sstevel@tonic-gate  *
15927c478bd9Sstevel@tonic-gate  * Description:	t1394_alloc_isoch_single() is used to direct the 1394 Software
15937c478bd9Sstevel@tonic-gate  *		Framework to allocate an isochronous channel and bandwidth
15947c478bd9Sstevel@tonic-gate  *		from the Isochronous Resource Manager (IRM).  If a bus reset
15957c478bd9Sstevel@tonic-gate  *		occurs, the 1394 Software Framework attempts to reallocate the
15967c478bd9Sstevel@tonic-gate  *		same resources, calling the rsrc_fail_target() callback if
15977c478bd9Sstevel@tonic-gate  *		it is unsuccessful.
15987c478bd9Sstevel@tonic-gate  */
15997c478bd9Sstevel@tonic-gate /* ARGSUSED */
16007c478bd9Sstevel@tonic-gate int
16017c478bd9Sstevel@tonic-gate t1394_alloc_isoch_single(t1394_handle_t t1394_hdl,
16027c478bd9Sstevel@tonic-gate     t1394_isoch_singleinfo_t *sii, uint_t flags,
16037c478bd9Sstevel@tonic-gate     t1394_isoch_single_out_t *output_args,
16047c478bd9Sstevel@tonic-gate     t1394_isoch_single_handle_t	*t1394_single_hdl, int *result)
16057c478bd9Sstevel@tonic-gate {
16067c478bd9Sstevel@tonic-gate 	s1394_hal_t		*hal;
16077c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t	*cec_new;
16087c478bd9Sstevel@tonic-gate 	t1394_join_isochinfo_t	jii;
16097c478bd9Sstevel@tonic-gate 	int			ret;
16107c478bd9Sstevel@tonic-gate 	int			err;
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_enter,
16137c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
16167c478bd9Sstevel@tonic-gate 	ASSERT(t1394_single_hdl != NULL);
16177c478bd9Sstevel@tonic-gate 	ASSERT(sii != NULL);
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 	/* Check for invalid channel_mask */
16227c478bd9Sstevel@tonic-gate 	if (sii->si_channel_mask == 0) {
16237c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
16247c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
16257c478bd9Sstevel@tonic-gate 		    "Invalid channel mask");
16267c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
16277c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
16287c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
16297c478bd9Sstevel@tonic-gate 	}
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	/* Check for invalid bandwidth */
16327c478bd9Sstevel@tonic-gate 	if ((sii->si_bandwidth <= IEEE1394_BANDWIDTH_MIN) ||
16337c478bd9Sstevel@tonic-gate 	    (sii->si_bandwidth > IEEE1394_BANDWIDTH_MAX)) {
16347c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
16357c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
16367c478bd9Sstevel@tonic-gate 		    "Invalid bandwidth requirements");
16377c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
16387c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
16397c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
16407c478bd9Sstevel@tonic-gate 	}
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	/* Verify that rsrc_fail_target() callback is non-NULL */
16437c478bd9Sstevel@tonic-gate 	if (sii->rsrc_fail_target == NULL) {
16447c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
16457c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
16467c478bd9Sstevel@tonic-gate 		    "Invalid callback specified");
16477c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
16487c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
16497c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
16507c478bd9Sstevel@tonic-gate 	}
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 	/*
16537c478bd9Sstevel@tonic-gate 	 * Allocate an Isoch CEC of type S1394_SINGLE
16547c478bd9Sstevel@tonic-gate 	 */
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	/* Allocate the Isoch CEC structure */
16577c478bd9Sstevel@tonic-gate 	cec_new = kmem_zalloc(sizeof (s1394_isoch_cec_t), KM_SLEEP);
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	/* Initialize the structure type */
16607c478bd9Sstevel@tonic-gate 	cec_new->cec_type = S1394_SINGLE;
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 	/* Create the mutex and "in_callbacks" cv */
16637c478bd9Sstevel@tonic-gate 	mutex_init(&cec_new->isoch_cec_mutex, NULL, MUTEX_DRIVER,
16647c478bd9Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
16657c478bd9Sstevel@tonic-gate 	cv_init(&cec_new->in_callbacks_cv, NULL, CV_DRIVER,
16667c478bd9Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	/* Initialize the Isoch CEC's member list */
16697c478bd9Sstevel@tonic-gate 	cec_new->cec_member_list_head = NULL;
16707c478bd9Sstevel@tonic-gate 	cec_new->cec_member_list_tail = NULL;
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 	/* Initialize the filters */
16737c478bd9Sstevel@tonic-gate 	cec_new->filter_min_speed	= sii->si_speed;
16747c478bd9Sstevel@tonic-gate 	cec_new->filter_max_speed	= sii->si_speed;
16757c478bd9Sstevel@tonic-gate 	cec_new->filter_current_speed	= cec_new->filter_max_speed;
16767c478bd9Sstevel@tonic-gate 	cec_new->filter_channel_mask	= sii->si_channel_mask;
16777c478bd9Sstevel@tonic-gate 	cec_new->bandwidth		= sii->si_bandwidth;
16787c478bd9Sstevel@tonic-gate 	cec_new->state_transitions	= ISOCH_CEC_FREE | ISOCH_CEC_JOIN |
16797c478bd9Sstevel@tonic-gate 					    ISOCH_CEC_SETUP;
16807c478bd9Sstevel@tonic-gate 
16817c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->isoch_cec_list_mutex);
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	/* Insert Isoch CEC into the HAL's list */
16847c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_list_insert(hal, cec_new);
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->isoch_cec_list_mutex);
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	/*
16897c478bd9Sstevel@tonic-gate 	 * Join the newly created Isoch CEC
16907c478bd9Sstevel@tonic-gate 	 */
16917c478bd9Sstevel@tonic-gate 	jii.req_channel_mask	= sii->si_channel_mask;
16927c478bd9Sstevel@tonic-gate 	jii.req_max_speed	= sii->si_speed;
16937c478bd9Sstevel@tonic-gate 	jii.jii_options		= T1394_TALKER;
16947c478bd9Sstevel@tonic-gate 	jii.isoch_cec_evts_arg	= sii->single_evt_arg;
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 	/* All events are NULL except rsrc_fail_target() */
16977c478bd9Sstevel@tonic-gate 	jii.isoch_cec_evts.setup_target	    = NULL;
16987c478bd9Sstevel@tonic-gate 	jii.isoch_cec_evts.start_target	    = NULL;
16997c478bd9Sstevel@tonic-gate 	jii.isoch_cec_evts.stop_target	    = NULL;
17007c478bd9Sstevel@tonic-gate 	jii.isoch_cec_evts.stop_target	    = NULL;
17017c478bd9Sstevel@tonic-gate 	jii.isoch_cec_evts.teardown_target  = NULL;
17027c478bd9Sstevel@tonic-gate 	jii.isoch_cec_evts.rsrc_fail_target = sii->rsrc_fail_target;
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	ret = t1394_join_isoch_cec(t1394_hdl,
17057c478bd9Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t)cec_new, 0, &jii);
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
17087c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
17097c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17107c478bd9Sstevel@tonic-gate 		    "Unexpected error from t1394_join_isoch_cec()");
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 		ret = t1394_free_isoch_cec(t1394_hdl, flags,
17137c478bd9Sstevel@tonic-gate 		    (t1394_isoch_cec_handle_t *)&cec_new);
17147c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
17157c478bd9Sstevel@tonic-gate 			/* Unable to free the Isoch CEC */
17167c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_single_error,
17177c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17187c478bd9Sstevel@tonic-gate 			    "Unexpected error from t1394_free_isoch_cec()");
17197c478bd9Sstevel@tonic-gate 			ASSERT(0);
17207c478bd9Sstevel@tonic-gate 		}
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 		/* Handle is nulled out before returning */
17237c478bd9Sstevel@tonic-gate 		*t1394_single_hdl = NULL;
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
17267c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
17277c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17287c478bd9Sstevel@tonic-gate 	}
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	/*
17317c478bd9Sstevel@tonic-gate 	 * Setup the isoch resources, etc.
17327c478bd9Sstevel@tonic-gate 	 */
17337c478bd9Sstevel@tonic-gate 	ret = t1394_setup_isoch_cec(t1394_hdl,
17347c478bd9Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t)cec_new, 0, &err);
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
17377c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_single_error,
17387c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17397c478bd9Sstevel@tonic-gate 		    "Unexpected error from t1394_setup_isoch_cec()");
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 		*result = err;
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 		/* Leave the Isoch CEC */
17447c478bd9Sstevel@tonic-gate 		ret = t1394_leave_isoch_cec(t1394_hdl,
17457c478bd9Sstevel@tonic-gate 		    (t1394_isoch_cec_handle_t)cec_new, 0);
17467c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
17477c478bd9Sstevel@tonic-gate 			/* Unable to leave the Isoch CEC */
17487c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_single_error,
17497c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17507c478bd9Sstevel@tonic-gate 			    "Unexpected error from t1394_leave_isoch_cec()");
17517c478bd9Sstevel@tonic-gate 			ASSERT(0);
17527c478bd9Sstevel@tonic-gate 		}
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 		/* Free up the Isoch CEC */
17557c478bd9Sstevel@tonic-gate 		ret = t1394_free_isoch_cec(t1394_hdl, flags,
17567c478bd9Sstevel@tonic-gate 		    (t1394_isoch_cec_handle_t *)&cec_new);
17577c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
17587c478bd9Sstevel@tonic-gate 			/* Unable to free the Isoch CEC */
17597c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_single_error,
17607c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
17617c478bd9Sstevel@tonic-gate 			    "Unexpected error from t1394_free_isoch_cec()");
17627c478bd9Sstevel@tonic-gate 			ASSERT(0);
17637c478bd9Sstevel@tonic-gate 		}
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 		/* Handle is nulled out before returning */
17667c478bd9Sstevel@tonic-gate 		*t1394_single_hdl = NULL;
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
17697c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
17707c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17717c478bd9Sstevel@tonic-gate 	}
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	/* Return the setup_args - channel num and speed */
17747c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_new->isoch_cec_mutex);
17757c478bd9Sstevel@tonic-gate 	output_args->channel_num  = cec_new->realloc_chnl_num;
17767c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_new->isoch_cec_mutex);
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate 	/* Update the handle */
17797c478bd9Sstevel@tonic-gate 	*t1394_single_hdl = (t1394_isoch_single_handle_t)cec_new;
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
17827c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
17837c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate /*
17877c478bd9Sstevel@tonic-gate  * Function:    t1394_free_isoch_single()
17887c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
17897c478bd9Sstevel@tonic-gate  *					    t1394_attach()
17907c478bd9Sstevel@tonic-gate  *		t1394_single_hdl	The isoch "handle" return by
17917c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_single()
17927c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
17937c478bd9Sstevel@tonic-gate  *
17947c478bd9Sstevel@tonic-gate  * Output(s):	None
17957c478bd9Sstevel@tonic-gate  *
17967c478bd9Sstevel@tonic-gate  * Description:	t1394_free_isoch_single() frees the isochronous resources
17977c478bd9Sstevel@tonic-gate  *		and the handle that were allocated during the call to
17987c478bd9Sstevel@tonic-gate  *		t1394_alloc_isoch_single().
17997c478bd9Sstevel@tonic-gate  */
18007c478bd9Sstevel@tonic-gate /* ARGSUSED */
18017c478bd9Sstevel@tonic-gate void
18027c478bd9Sstevel@tonic-gate t1394_free_isoch_single(t1394_handle_t t1394_hdl,
18037c478bd9Sstevel@tonic-gate     t1394_isoch_single_handle_t *t1394_single_hdl, uint_t flags)
18047c478bd9Sstevel@tonic-gate {
18057c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t *cec_curr;
18067c478bd9Sstevel@tonic-gate 	int		  ret;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_single_enter,
18097c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
18127c478bd9Sstevel@tonic-gate 	ASSERT(t1394_single_hdl != NULL);
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
18157c478bd9Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)(*t1394_single_hdl);
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	/*
18187c478bd9Sstevel@tonic-gate 	 * Teardown the isoch resources, etc.
18197c478bd9Sstevel@tonic-gate 	 */
18207c478bd9Sstevel@tonic-gate 	ret = t1394_teardown_isoch_cec(t1394_hdl,
18217c478bd9Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t)cec_curr, 0);
18227c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
18237c478bd9Sstevel@tonic-gate 		/* Unable to teardown the Isoch CEC */
18247c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_single_error,
18257c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
18267c478bd9Sstevel@tonic-gate 		    "Unexpected error from t1394_teardown_isoch_cec()");
18277c478bd9Sstevel@tonic-gate 		ASSERT(0);
18287c478bd9Sstevel@tonic-gate 	}
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	/*
18317c478bd9Sstevel@tonic-gate 	 * Leave the Isoch CEC
18327c478bd9Sstevel@tonic-gate 	 */
18337c478bd9Sstevel@tonic-gate 	ret = t1394_leave_isoch_cec(t1394_hdl,
18347c478bd9Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t)cec_curr, 0);
18357c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
18367c478bd9Sstevel@tonic-gate 		/* Unable to leave the Isoch CEC */
18377c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_single_error,
18387c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
18397c478bd9Sstevel@tonic-gate 		    "Unexpected error from t1394_leave_isoch_cec()");
18407c478bd9Sstevel@tonic-gate 		ASSERT(0);
18417c478bd9Sstevel@tonic-gate 	}
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 	/*
18447c478bd9Sstevel@tonic-gate 	 * Free the Isoch CEC
18457c478bd9Sstevel@tonic-gate 	 */
18467c478bd9Sstevel@tonic-gate 	ret = t1394_free_isoch_cec(t1394_hdl, flags,
18477c478bd9Sstevel@tonic-gate 	    (t1394_isoch_cec_handle_t *)&cec_curr);
18487c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
18497c478bd9Sstevel@tonic-gate 		/* Unable to free the Isoch CEC */
18507c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_single_error,
18517c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
18527c478bd9Sstevel@tonic-gate 		    "Unexpected error from t1394_free_isoch_cec()");
18537c478bd9Sstevel@tonic-gate 		ASSERT(0);
18547c478bd9Sstevel@tonic-gate 	}
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate 	/* Handle is nulled out before returning */
18577c478bd9Sstevel@tonic-gate 	*t1394_single_hdl = NULL;
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_single_exit,
18607c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate /*
18647c478bd9Sstevel@tonic-gate  * Function:    t1394_alloc_isoch_cec()
18657c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
18667c478bd9Sstevel@tonic-gate  *					    t1394_attach()
18677c478bd9Sstevel@tonic-gate  *		props			The structure used to set up the
18687c478bd9Sstevel@tonic-gate  *					    overall characteristics of for
18697c478bd9Sstevel@tonic-gate  *					    the Isoch CEC.
18707c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
18717c478bd9Sstevel@tonic-gate  *
18727c478bd9Sstevel@tonic-gate  * Output(s):	t1394_isoch_cec_hdl	The Isoch CEC "handle" used in all
18737c478bd9Sstevel@tonic-gate  *					    subsequent isoch_cec() calls
18747c478bd9Sstevel@tonic-gate  *
18757c478bd9Sstevel@tonic-gate  * Description:	t1394_alloc_isoch_cec() allocates and initializes an
18767c478bd9Sstevel@tonic-gate  *		isochronous channel event coordinator (Isoch CEC) for use
18777c478bd9Sstevel@tonic-gate  *		in managing and coordinating activity for an isoch channel
18787c478bd9Sstevel@tonic-gate  */
18797c478bd9Sstevel@tonic-gate /* ARGSUSED */
18807c478bd9Sstevel@tonic-gate int
18817c478bd9Sstevel@tonic-gate t1394_alloc_isoch_cec(t1394_handle_t t1394_hdl, t1394_isoch_cec_props_t *props,
18827c478bd9Sstevel@tonic-gate     uint_t flags, t1394_isoch_cec_handle_t *t1394_isoch_cec_hdl)
18837c478bd9Sstevel@tonic-gate {
18847c478bd9Sstevel@tonic-gate 	s1394_hal_t	  *hal;
18857c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t *cec_new;
18867c478bd9Sstevel@tonic-gate 	uint64_t	  temp;
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_enter,
18897c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
18927c478bd9Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
18937c478bd9Sstevel@tonic-gate 	ASSERT(props != NULL);
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 	/* Check for invalid channel_mask */
18987c478bd9Sstevel@tonic-gate 	if (props->cec_channel_mask == 0) {
18997c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_cec_error,
19007c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
19017c478bd9Sstevel@tonic-gate 		    "Invalid channel mask");
19027c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19037c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
19047c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
19057c478bd9Sstevel@tonic-gate 	}
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 	/* Test conditions specific to T1394_NO_IRM_ALLOC */
19087c478bd9Sstevel@tonic-gate 	temp = props->cec_channel_mask;
19097c478bd9Sstevel@tonic-gate 	if (props->cec_options & T1394_NO_IRM_ALLOC) {
19107c478bd9Sstevel@tonic-gate 		/* If T1394_NO_IRM_ALLOC, then only one bit should be set */
1911*de710d24SJosef 'Jeff' Sipek 		if (!ISP2(temp)) {
19127c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_cec_error,
19137c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
19147c478bd9Sstevel@tonic-gate 			    "Invalid channel mask");
19157c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19167c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_STACK, "");
19177c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
19187c478bd9Sstevel@tonic-gate 		}
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 		/* If T1394_NO_IRM_ALLOC, then speeds should be equal */
19217c478bd9Sstevel@tonic-gate 		if (props->cec_min_speed != props->cec_max_speed) {
19227c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_alloc_isoch_cec_error,
19237c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
19247c478bd9Sstevel@tonic-gate 			    "Invalid speeds (min != max)");
19257c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19267c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_STACK, "");
19277c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
19287c478bd9Sstevel@tonic-gate 		}
19297c478bd9Sstevel@tonic-gate 	}
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 	/* Check for invalid bandwidth */
19327c478bd9Sstevel@tonic-gate 	if ((props->cec_bandwidth <= IEEE1394_BANDWIDTH_MIN) ||
19337c478bd9Sstevel@tonic-gate 	    (props->cec_bandwidth > IEEE1394_BANDWIDTH_MAX)) {
19347c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_cec_error,
19357c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
19367c478bd9Sstevel@tonic-gate 		    "Invalid bandwidth requirements");
19377c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19387c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
19397c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
19407c478bd9Sstevel@tonic-gate 	}
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	/* Allocate the Isoch CEC structure */
19437c478bd9Sstevel@tonic-gate 	cec_new = kmem_zalloc(sizeof (s1394_isoch_cec_t), KM_SLEEP);
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 	/* Initialize the structure type */
19467c478bd9Sstevel@tonic-gate 	cec_new->cec_type = S1394_PEER_TO_PEER;
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate 	/* Create the mutex and "in_callbacks" cv */
19497c478bd9Sstevel@tonic-gate 	mutex_init(&cec_new->isoch_cec_mutex, NULL, MUTEX_DRIVER,
19507c478bd9Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
19517c478bd9Sstevel@tonic-gate 	cv_init(&cec_new->in_callbacks_cv, NULL, CV_DRIVER,
19527c478bd9Sstevel@tonic-gate 	    hal->halinfo.hw_interrupt);
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 	/* Initialize the Isoch CEC's member list */
19557c478bd9Sstevel@tonic-gate 	cec_new->cec_member_list_head	= NULL;
19567c478bd9Sstevel@tonic-gate 	cec_new->cec_member_list_tail	= NULL;
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 	/* Initialize the filters */
19597c478bd9Sstevel@tonic-gate 	cec_new->filter_min_speed	= props->cec_min_speed;
19607c478bd9Sstevel@tonic-gate 	cec_new->filter_max_speed	= props->cec_max_speed;
19617c478bd9Sstevel@tonic-gate 	cec_new->filter_current_speed	= cec_new->filter_max_speed;
19627c478bd9Sstevel@tonic-gate 	cec_new->filter_channel_mask	= props->cec_channel_mask;
19637c478bd9Sstevel@tonic-gate 	cec_new->bandwidth		= props->cec_bandwidth;
19647c478bd9Sstevel@tonic-gate 	cec_new->cec_options		= props->cec_options;
19657c478bd9Sstevel@tonic-gate 	cec_new->state_transitions	= ISOCH_CEC_FREE | ISOCH_CEC_JOIN |
19667c478bd9Sstevel@tonic-gate 					    ISOCH_CEC_SETUP;
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->isoch_cec_list_mutex);
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 	/* Insert Isoch CEC into the HAL's list */
19717c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_list_insert(hal, cec_new);
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->isoch_cec_list_mutex);
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate 	/* Update the handle and return */
19767c478bd9Sstevel@tonic-gate 	*t1394_isoch_cec_hdl = (t1394_isoch_cec_handle_t)cec_new;
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
19797c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
19807c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
19817c478bd9Sstevel@tonic-gate }
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate /*
19847c478bd9Sstevel@tonic-gate  * Function:    t1394_free_isoch_cec()
19857c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
19867c478bd9Sstevel@tonic-gate  *					    t1394_attach()
19877c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
19887c478bd9Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
19897c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
19907c478bd9Sstevel@tonic-gate  *
19917c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully freed the Isoch CEC
19927c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to free the Isoch CEC
19937c478bd9Sstevel@tonic-gate  *
19947c478bd9Sstevel@tonic-gate  * Description:	t1394_free_isoch_cec() attempts to free the Isoch CEC
19957c478bd9Sstevel@tonic-gate  *		structure.  It will fail (DDI_FAILURE) if there are any
19967c478bd9Sstevel@tonic-gate  *		remaining members who have not yet left.
19977c478bd9Sstevel@tonic-gate  */
19987c478bd9Sstevel@tonic-gate /* ARGSUSED */
19997c478bd9Sstevel@tonic-gate int
20007c478bd9Sstevel@tonic-gate t1394_free_isoch_cec(t1394_handle_t t1394_hdl, uint_t flags,
20017c478bd9Sstevel@tonic-gate     t1394_isoch_cec_handle_t *t1394_isoch_cec_hdl)
20027c478bd9Sstevel@tonic-gate {
20037c478bd9Sstevel@tonic-gate 	s1394_hal_t	  *hal;
20047c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t *cec_curr;
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_enter,
20077c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
20107c478bd9Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
20157c478bd9Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)(*t1394_isoch_cec_hdl);
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
20187c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	/* Are we in any callbacks? */
20217c478bd9Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
20227c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
20237c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
20247c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_cec_error,
20257c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
20267c478bd9Sstevel@tonic-gate 		    "Not allowed to free Isoch CEC (in callbacks)");
20277c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit,
20287c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
20297c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
20307c478bd9Sstevel@tonic-gate 	}
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	/* Is "free" a legal state transition? */
20337c478bd9Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_FREE) == 0) {
20347c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
20357c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
20367c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_free_isoch_cec_error,
20377c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
20387c478bd9Sstevel@tonic-gate 		    "Not allowed to free Isoch CEC");
20397c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit,
20407c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
20417c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
20427c478bd9Sstevel@tonic-gate 	}
20437c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->isoch_cec_list_mutex);
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	/* Remove Isoch CEC from HAL's list */
20487c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_list_remove(hal, cec_curr);
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->isoch_cec_list_mutex);
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	/* Destroy the Isoch CEC's mutex and cv */
20537c478bd9Sstevel@tonic-gate 	cv_destroy(&cec_curr->in_callbacks_cv);
20547c478bd9Sstevel@tonic-gate 	mutex_destroy(&cec_curr->isoch_cec_mutex);
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	/* Free up the memory for the Isoch CEC struct */
20577c478bd9Sstevel@tonic-gate 	kmem_free(cec_curr, sizeof (s1394_isoch_cec_t));
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	/* Update the handle and return */
20607c478bd9Sstevel@tonic-gate 	*t1394_isoch_cec_hdl = NULL;
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit,
20637c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
20647c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
20657c478bd9Sstevel@tonic-gate }
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate /*
20687c478bd9Sstevel@tonic-gate  * Function:    t1394_join_isoch_cec()
20697c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
20707c478bd9Sstevel@tonic-gate  *					    t1394_attach()
20717c478bd9Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
20727c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
20737c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
20747c478bd9Sstevel@tonic-gate  *		join_isoch_info		This structure provides infomation
20757c478bd9Sstevel@tonic-gate  *					    about a target that wishes to join
20767c478bd9Sstevel@tonic-gate  *					    the given Isoch CEC.  It gives
20777c478bd9Sstevel@tonic-gate  *					    max_speed, channel_mask, etc.
20787c478bd9Sstevel@tonic-gate  *
20797c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully joined the
20807c478bd9Sstevel@tonic-gate  *					    Isoch CEC
20817c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to join the Isoch CEC
20827c478bd9Sstevel@tonic-gate  *
20837c478bd9Sstevel@tonic-gate  * Description:	t1394_join_isoch_cec() determines, based on the information
20847c478bd9Sstevel@tonic-gate  *		given in the join_isoch_info structure, if the target may
20857c478bd9Sstevel@tonic-gate  *		join the Isoch CEC.  If it is determined that the target may
20867c478bd9Sstevel@tonic-gate  *		join, the specified callback routines are stored away for
20877c478bd9Sstevel@tonic-gate  *		later use in the coordination tasks.
20887c478bd9Sstevel@tonic-gate  */
20897c478bd9Sstevel@tonic-gate /* ARGSUSED */
20907c478bd9Sstevel@tonic-gate int
20917c478bd9Sstevel@tonic-gate t1394_join_isoch_cec(t1394_handle_t t1394_hdl,
20927c478bd9Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags,
20937c478bd9Sstevel@tonic-gate     t1394_join_isochinfo_t *join_isoch_info)
20947c478bd9Sstevel@tonic-gate {
20957c478bd9Sstevel@tonic-gate 	s1394_hal_t		 *hal;
20967c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
20977c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_new;
20987c478bd9Sstevel@tonic-gate 	uint64_t		 check_mask;
20997c478bd9Sstevel@tonic-gate 	uint_t			 curr_max_speed;
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_enter,
21027c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
21057c478bd9Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
21107c478bd9Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 	/* Allocate a new Isoch CEC member structure */
21137c478bd9Sstevel@tonic-gate 	member_new = kmem_zalloc(sizeof (s1394_isoch_cec_member_t), KM_SLEEP);
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
21167c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 	/* Are we in any callbacks? (Wait for them to finish) */
21197c478bd9Sstevel@tonic-gate 	while (CEC_IN_ANY_CALLBACKS(cec_curr)) {
21207c478bd9Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_TRUE;
21217c478bd9Sstevel@tonic-gate 		cv_wait(&cec_curr->in_callbacks_cv,
21227c478bd9Sstevel@tonic-gate 		    &cec_curr->isoch_cec_mutex);
21237c478bd9Sstevel@tonic-gate 	}
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	/* Is "join" a legal state transition? */
21267c478bd9Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) == 0) {
21277c478bd9Sstevel@tonic-gate 		kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
21287c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21297c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21307c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21317c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21327c478bd9Sstevel@tonic-gate 		    "Not allowed to join Isoch CEC");
21337c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21347c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
21357c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
21367c478bd9Sstevel@tonic-gate 	}
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 	/* Check the channel mask for consistency */
21397c478bd9Sstevel@tonic-gate 	check_mask = join_isoch_info->req_channel_mask &
21407c478bd9Sstevel@tonic-gate 	    cec_curr->filter_channel_mask;
21417c478bd9Sstevel@tonic-gate 	if (check_mask == 0) {
21427c478bd9Sstevel@tonic-gate 		kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
21437c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21447c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21457c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21467c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21477c478bd9Sstevel@tonic-gate 		    "Inconsistent channel mask specified");
21487c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21497c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
21507c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
21517c478bd9Sstevel@tonic-gate 	}
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 	/* Check for consistent speeds */
21547c478bd9Sstevel@tonic-gate 	if (join_isoch_info->req_max_speed < cec_curr->filter_min_speed) {
21557c478bd9Sstevel@tonic-gate 		kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
21567c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21577c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21587c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21597c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21607c478bd9Sstevel@tonic-gate 		    "Inconsistent speed specified");
21617c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21627c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
21637c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
21647c478bd9Sstevel@tonic-gate 	} else if (join_isoch_info->req_max_speed <
21657c478bd9Sstevel@tonic-gate 	    cec_curr->filter_current_speed) {
21667c478bd9Sstevel@tonic-gate 		curr_max_speed = join_isoch_info->req_max_speed;
21677c478bd9Sstevel@tonic-gate 	} else {
21687c478bd9Sstevel@tonic-gate 		curr_max_speed = cec_curr->filter_current_speed;
21697c478bd9Sstevel@tonic-gate 	}
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 	/* Check for no more than one talker */
21727c478bd9Sstevel@tonic-gate 	if ((join_isoch_info->jii_options & T1394_TALKER) &&
21737c478bd9Sstevel@tonic-gate 	    (cec_curr->cec_member_talker != NULL)) {
21747c478bd9Sstevel@tonic-gate 		kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
21757c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21767c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21777c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21787c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21797c478bd9Sstevel@tonic-gate 		    "Multiple talkers specified");
21807c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21817c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
21827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
21837c478bd9Sstevel@tonic-gate 	}
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 	/* Verify that all callbacks are non-NULL (for PEER_TO_PEER) */
21867c478bd9Sstevel@tonic-gate 	if ((cec_curr->cec_type == S1394_PEER_TO_PEER) &&
21877c478bd9Sstevel@tonic-gate 	    ((join_isoch_info->isoch_cec_evts.setup_target	== NULL) ||
21887c478bd9Sstevel@tonic-gate 	    (join_isoch_info->isoch_cec_evts.start_target	== NULL) ||
21897c478bd9Sstevel@tonic-gate 	    (join_isoch_info->isoch_cec_evts.stop_target	== NULL) ||
21907c478bd9Sstevel@tonic-gate 	    (join_isoch_info->isoch_cec_evts.rsrc_fail_target	== NULL) ||
21917c478bd9Sstevel@tonic-gate 	    (join_isoch_info->isoch_cec_evts.teardown_target	== NULL))) {
21927c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
21937c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
21947c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_join_isoch_cec_error,
21957c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
21967c478bd9Sstevel@tonic-gate 		    "Invalid callbacks specified");
21977c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
21987c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
21997c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
22007c478bd9Sstevel@tonic-gate 	}
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	/* Copy the events information into the struct */
22037c478bd9Sstevel@tonic-gate 	member_new->isoch_cec_evts	= join_isoch_info->isoch_cec_evts;
22047c478bd9Sstevel@tonic-gate 	member_new->isoch_cec_evts_arg	= join_isoch_info->isoch_cec_evts_arg;
22057c478bd9Sstevel@tonic-gate 	member_new->cec_mem_options	= join_isoch_info->jii_options;
22067c478bd9Sstevel@tonic-gate 	member_new->cec_mem_target	= (s1394_target_t *)t1394_hdl;
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 	/* Insert new member into Isoch CEC's member list */
22097c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_list_insert(hal, cec_curr, member_new);
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate 	/* Update the channel mask filter */
22127c478bd9Sstevel@tonic-gate 	cec_curr->filter_channel_mask	= check_mask;
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 	/* Update the speed filter */
22157c478bd9Sstevel@tonic-gate 	cec_curr->filter_current_speed	= curr_max_speed;
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	/* Update the talker pointer (if necessary) */
22187c478bd9Sstevel@tonic-gate 	if (join_isoch_info->jii_options & T1394_TALKER)
22197c478bd9Sstevel@tonic-gate 		cec_curr->cec_member_talker = cec_curr->cec_member_list_head;
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	/*
22227c478bd9Sstevel@tonic-gate 	 * Now "leave" is a legal state transition
22237c478bd9Sstevel@tonic-gate 	 * and "free" is an illegal state transition
22247c478bd9Sstevel@tonic-gate 	 */
22257c478bd9Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, ISOCH_CEC_LEAVE);
22267c478bd9Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_FREE);
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
22297c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
22327c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
22337c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
22347c478bd9Sstevel@tonic-gate }
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate /*
22377c478bd9Sstevel@tonic-gate  * Function:    t1394_leave_isoch_cec()
22387c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
22397c478bd9Sstevel@tonic-gate  *					    t1394_attach()
22407c478bd9Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
22417c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
22427c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
22437c478bd9Sstevel@tonic-gate  *
22447c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully left the
22457c478bd9Sstevel@tonic-gate  *					    Isoch CEC
22467c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to leave the Isoch CEC
22477c478bd9Sstevel@tonic-gate  *
22487c478bd9Sstevel@tonic-gate  * Description:	t1394_leave_isoch_cec() is used by a target driver to remove
22497c478bd9Sstevel@tonic-gate  *		itself from the Isoch CEC's member list.  It is possible
22507c478bd9Sstevel@tonic-gate  *		for this call to fail because the target is not found in
22517c478bd9Sstevel@tonic-gate  *		the current member list, or because it is not an appropriate
22527c478bd9Sstevel@tonic-gate  *		time for a target to leave.
22537c478bd9Sstevel@tonic-gate  */
22547c478bd9Sstevel@tonic-gate /* ARGSUSED */
22557c478bd9Sstevel@tonic-gate int
22567c478bd9Sstevel@tonic-gate t1394_leave_isoch_cec(t1394_handle_t t1394_hdl,
22577c478bd9Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
22587c478bd9Sstevel@tonic-gate {
22597c478bd9Sstevel@tonic-gate 	s1394_hal_t		 *hal;
22607c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
22617c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_curr;
22627c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_temp;
22637c478bd9Sstevel@tonic-gate 	boolean_t		 found;
22647c478bd9Sstevel@tonic-gate 	uint64_t		 temp_channel_mask;
22657c478bd9Sstevel@tonic-gate 	uint_t			 temp_max_speed;
22667c478bd9Sstevel@tonic-gate 
22677c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_enter,
22687c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
22717c478bd9Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
22767c478bd9Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
22797c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate 	/* Are we in any callbacks? (Wait for them to finish) */
22827c478bd9Sstevel@tonic-gate 	while (CEC_IN_ANY_CALLBACKS(cec_curr)) {
22837c478bd9Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_TRUE;
22847c478bd9Sstevel@tonic-gate 		cv_wait(&cec_curr->in_callbacks_cv,
22857c478bd9Sstevel@tonic-gate 		    &cec_curr->isoch_cec_mutex);
22867c478bd9Sstevel@tonic-gate 	}
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate 	/* Is "leave" a legal state transition? */
22897c478bd9Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_LEAVE) == 0) {
22907c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
22917c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
22927c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_leave_isoch_cec_error,
22937c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
22947c478bd9Sstevel@tonic-gate 		    "Not allowed to leave Isoch CEC");
22957c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit,
22967c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
22977c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
22987c478bd9Sstevel@tonic-gate 	}
22997c478bd9Sstevel@tonic-gate 
23007c478bd9Sstevel@tonic-gate 	/* Find the Target on the CEC's member list */
23017c478bd9Sstevel@tonic-gate 	found = B_FALSE;
23027c478bd9Sstevel@tonic-gate 	temp_channel_mask = cec_curr->cec_alloc_props.cec_channel_mask;
23037c478bd9Sstevel@tonic-gate 	temp_max_speed	  = cec_curr->cec_alloc_props.cec_max_speed;
23047c478bd9Sstevel@tonic-gate 	member_curr	  = cec_curr->cec_member_list_head;
23057c478bd9Sstevel@tonic-gate 	while (member_curr != NULL) {
23067c478bd9Sstevel@tonic-gate 		if (member_curr->cec_mem_target ==
23077c478bd9Sstevel@tonic-gate 		    (s1394_target_t *)t1394_hdl) {
23087c478bd9Sstevel@tonic-gate 			member_temp = member_curr;
23097c478bd9Sstevel@tonic-gate 			found	    = B_TRUE;
23107c478bd9Sstevel@tonic-gate 		} else {
23117c478bd9Sstevel@tonic-gate 			/* Keep track of channel mask and max speed info */
23127c478bd9Sstevel@tonic-gate 			temp_channel_mask &= member_curr->req_channel_mask;
23137c478bd9Sstevel@tonic-gate 			if (member_curr->req_max_speed < temp_max_speed)
23147c478bd9Sstevel@tonic-gate 				temp_max_speed = member_curr->req_max_speed;
23157c478bd9Sstevel@tonic-gate 		}
23167c478bd9Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_next;
23177c478bd9Sstevel@tonic-gate 	}
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 	/* Target not found on this Isoch CEC */
23207c478bd9Sstevel@tonic-gate 	if (found == B_FALSE) {
23217c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
23227c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
23237c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_leave_isoch_cec_error,
23247c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
23257c478bd9Sstevel@tonic-gate 		    "Target not found in Isoch CEC member list");
23267c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit,
23277c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
23287c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
23297c478bd9Sstevel@tonic-gate 	} else {
23307c478bd9Sstevel@tonic-gate 		/* This member's departure may change filter constraints */
23317c478bd9Sstevel@tonic-gate 		cec_curr->filter_current_speed  = temp_max_speed;
23327c478bd9Sstevel@tonic-gate 		cec_curr->filter_channel_mask   = temp_channel_mask;
23337c478bd9Sstevel@tonic-gate 	}
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 	/* Remove member from Isoch CEC's member list */
23367c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_list_remove(hal, cec_curr, member_temp);
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 	/* If we are removing the talker, then update the pointer */
23397c478bd9Sstevel@tonic-gate 	if (cec_curr->cec_member_talker == member_temp)
23407c478bd9Sstevel@tonic-gate 		cec_curr->cec_member_talker = NULL;
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate 	/* Is the Isoch CEC's member list empty? */
23437c478bd9Sstevel@tonic-gate 	if ((cec_curr->cec_member_list_head == NULL) &&
23447c478bd9Sstevel@tonic-gate 	    (cec_curr->cec_member_list_tail == NULL)) {
23457c478bd9Sstevel@tonic-gate 		/*
23467c478bd9Sstevel@tonic-gate 		 * Now "free" _might_ be a legal state transition
23477c478bd9Sstevel@tonic-gate 		 * if we aren't in setup or start phases and "leave"
23487c478bd9Sstevel@tonic-gate 		 * is definitely an illegal state transition
23497c478bd9Sstevel@tonic-gate 		 */
23507c478bd9Sstevel@tonic-gate 		if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) != 0)
23517c478bd9Sstevel@tonic-gate 			CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
23527c478bd9Sstevel@tonic-gate 		CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_LEAVE);
23537c478bd9Sstevel@tonic-gate 	}
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
23567c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 	/* Free the Isoch CEC member structure */
23597c478bd9Sstevel@tonic-gate 	kmem_free(member_temp, sizeof (s1394_isoch_cec_member_t));
23607c478bd9Sstevel@tonic-gate 
23617c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit,
23627c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
23637c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
23647c478bd9Sstevel@tonic-gate }
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate /*
23677c478bd9Sstevel@tonic-gate  * Function:    t1394_setup_isoch_cec()
23687c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
23697c478bd9Sstevel@tonic-gate  *					    t1394_attach()
23707c478bd9Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
23717c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
23727c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
23737c478bd9Sstevel@tonic-gate  *
23747c478bd9Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
23757c478bd9Sstevel@tonic-gate  *					    to target
23767c478bd9Sstevel@tonic-gate  *
23777c478bd9Sstevel@tonic-gate  * Description:	t1394_setup_isoch_cec() directs the 1394 Software Framework
23787c478bd9Sstevel@tonic-gate  *		to allocate isochronous resources and invoke the setup_target()
23797c478bd9Sstevel@tonic-gate  *		callback for each member of the Isoch CEC.  This call may
23807c478bd9Sstevel@tonic-gate  *		fail because bandwidth was unavailable (T1394_ENO_BANDWIDTH),
23817c478bd9Sstevel@tonic-gate  *		channels were unavailable (T1394_ENO_CHANNEL), or one of the
23827c478bd9Sstevel@tonic-gate  *		member targets returned failure from its setup_target()
23837c478bd9Sstevel@tonic-gate  *		callback.
23847c478bd9Sstevel@tonic-gate  */
23857c478bd9Sstevel@tonic-gate /* ARGSUSED */
23867c478bd9Sstevel@tonic-gate int
23877c478bd9Sstevel@tonic-gate t1394_setup_isoch_cec(t1394_handle_t t1394_hdl,
23887c478bd9Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags, int *result)
23897c478bd9Sstevel@tonic-gate {
23907c478bd9Sstevel@tonic-gate 	s1394_hal_t			*hal;
23917c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t		*cec_curr;
23927c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t	*member_curr;
23937c478bd9Sstevel@tonic-gate 	t1394_setup_target_args_t	target_args;
23947c478bd9Sstevel@tonic-gate 	uint64_t			temp_chnl_mask;
23957c478bd9Sstevel@tonic-gate 	uint32_t			old_chnl;
23967c478bd9Sstevel@tonic-gate 	uint32_t			try_chnl;
23977c478bd9Sstevel@tonic-gate 	uint_t				bw_alloc_units;
23987c478bd9Sstevel@tonic-gate 	uint_t				generation;
23997c478bd9Sstevel@tonic-gate 	int				chnl_num;
24007c478bd9Sstevel@tonic-gate 	int				err;
24017c478bd9Sstevel@tonic-gate 	int				ret;
24027c478bd9Sstevel@tonic-gate 	int				j;
24037c478bd9Sstevel@tonic-gate 	int	(*setup_callback)(t1394_isoch_cec_handle_t, opaque_t,
24047c478bd9Sstevel@tonic-gate 			    t1394_setup_target_args_t *);
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_enter,
24077c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
24107c478bd9Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
24157c478bd9Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
24187c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
24197c478bd9Sstevel@tonic-gate 
24207c478bd9Sstevel@tonic-gate 	/* Are we in any callbacks? */
24217c478bd9Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
24227c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
24237c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
24247c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_setup_isoch_cec_error,
24257c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
24267c478bd9Sstevel@tonic-gate 		    "Not allowed to setup Isoch CEC (in callbacks)");
24277c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
24287c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
24297c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
24307c478bd9Sstevel@tonic-gate 	}
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate 	/* Is "setup" a legal state transition? */
24337c478bd9Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_SETUP) == 0) {
24347c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
24357c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
24367c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_setup_isoch_cec_error,
24377c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
24387c478bd9Sstevel@tonic-gate 		    "Not allowed to setup Isoch CEC");
24397c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
24407c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
24417c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
24427c478bd9Sstevel@tonic-gate 	}
24437c478bd9Sstevel@tonic-gate 
24447c478bd9Sstevel@tonic-gate 	/* If T1394_NO_IRM_ALLOC is set then don't allocate... do callbacks */
24457c478bd9Sstevel@tonic-gate 	if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
24467c478bd9Sstevel@tonic-gate 		goto setup_do_callbacks;
24477c478bd9Sstevel@tonic-gate 	}
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 	/* Allocate bandwidth and channels */
24507c478bd9Sstevel@tonic-gate 	for (j = 0; j < S1394_ISOCH_ALLOC_RETRIES; j++) {
24517c478bd9Sstevel@tonic-gate 		/*
24527c478bd9Sstevel@tonic-gate 		 * Get the current generation number - don't
24537c478bd9Sstevel@tonic-gate 		 * need the lock because we are read only here
24547c478bd9Sstevel@tonic-gate 		 */
24557c478bd9Sstevel@tonic-gate 		generation = hal->generation_count;
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 		/* Compute how much bandwidth is needed */
24587c478bd9Sstevel@tonic-gate 		bw_alloc_units = s1394_compute_bw_alloc_units(hal,
24597c478bd9Sstevel@tonic-gate 		    cec_curr->bandwidth, cec_curr->filter_current_speed);
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 		/* Check that the generation has not changed - */
24627c478bd9Sstevel@tonic-gate 		/* don't need the lock (read only) */
24637c478bd9Sstevel@tonic-gate 		if (generation != hal->generation_count)
24647c478bd9Sstevel@tonic-gate 			continue;
24657c478bd9Sstevel@tonic-gate 
24667c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
24677c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
24687c478bd9Sstevel@tonic-gate 
24697c478bd9Sstevel@tonic-gate 		/* Try to allocate the bandwidth */
24707c478bd9Sstevel@tonic-gate 		ret = s1394_bandwidth_alloc(hal, bw_alloc_units, generation,
24717c478bd9Sstevel@tonic-gate 		    &err);
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 		/* Lock the Isoch CEC member list */
24747c478bd9Sstevel@tonic-gate 		mutex_enter(&cec_curr->isoch_cec_mutex);
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 		/* If there was a bus reset, start over */
24777c478bd9Sstevel@tonic-gate 		if (ret == DDI_FAILURE) {
24787c478bd9Sstevel@tonic-gate 			if (err == CMD1394_EBUSRESET) {
24797c478bd9Sstevel@tonic-gate 				continue; /* start over and try again */
24807c478bd9Sstevel@tonic-gate 			} else {
24817c478bd9Sstevel@tonic-gate 				*result = T1394_ENO_BANDWIDTH;
24827c478bd9Sstevel@tonic-gate 				/* Unlock the Isoch CEC member list */
24837c478bd9Sstevel@tonic-gate 				mutex_exit(&cec_curr->isoch_cec_mutex);
24847c478bd9Sstevel@tonic-gate 				TNF_PROBE_1(t1394_setup_isoch_cec_error,
24857c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
24867c478bd9Sstevel@tonic-gate 				    msg, "Unable to allocate isoch bandwidth");
24877c478bd9Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
24887c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_ISOCH_STACK, "");
24897c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
24907c478bd9Sstevel@tonic-gate 			}
24917c478bd9Sstevel@tonic-gate 		}
24927c478bd9Sstevel@tonic-gate 
24937c478bd9Sstevel@tonic-gate 		/* Check that the generation has not changed - */
24947c478bd9Sstevel@tonic-gate 		/* don't need the lock (read only) */
24957c478bd9Sstevel@tonic-gate 		if (generation != hal->generation_count)
24967c478bd9Sstevel@tonic-gate 			continue;
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 		/*
24997c478bd9Sstevel@tonic-gate 		 * Allocate a channel
25007c478bd9Sstevel@tonic-gate 		 *    From IEEE 1394-1995, Section 8.3.2.3.8: "Bits
25017c478bd9Sstevel@tonic-gate 		 *    allocated in the CHANNELS_AVAILABLE_HI field of
25027c478bd9Sstevel@tonic-gate 		 *    this register shall start at bit zero (channel
25037c478bd9Sstevel@tonic-gate 		 *    number zero), and additional channel numbers shall
25047c478bd9Sstevel@tonic-gate 		 *    be represented in a monotonically increasing sequence
25057c478bd9Sstevel@tonic-gate 		 *    of bit numbers up to a maximum of bit 31 (channel
25067c478bd9Sstevel@tonic-gate 		 *    number 31).  Bits allocated in the CHANNELS_AVAILABLE_LO
25077c478bd9Sstevel@tonic-gate 		 *    field of this register shall start at bit zero
25087c478bd9Sstevel@tonic-gate 		 *    (channel number 32), and additional channel numbers
25097c478bd9Sstevel@tonic-gate 		 *    shall be represented in a monotonically increasing
25107c478bd9Sstevel@tonic-gate 		 *    sequence of bit numbers up to a maximum of bit 31
25117c478bd9Sstevel@tonic-gate 		 *    (channel number 63).
25127c478bd9Sstevel@tonic-gate 		 */
25137c478bd9Sstevel@tonic-gate 		temp_chnl_mask = cec_curr->filter_channel_mask;
25147c478bd9Sstevel@tonic-gate 		for (chnl_num = 63; chnl_num >= 0; chnl_num--) {
25157c478bd9Sstevel@tonic-gate 			if ((temp_chnl_mask & 1) == 1) {
25167c478bd9Sstevel@tonic-gate 				try_chnl = (1 << ((63 - chnl_num) % 32));
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 				/* Unlock the Isoch CEC member list */
25197c478bd9Sstevel@tonic-gate 				mutex_exit(&cec_curr->isoch_cec_mutex);
25207c478bd9Sstevel@tonic-gate 				if (chnl_num < 32) {
25217c478bd9Sstevel@tonic-gate 					ret = s1394_channel_alloc(hal,
25227c478bd9Sstevel@tonic-gate 					    try_chnl, generation,
25237c478bd9Sstevel@tonic-gate 					    S1394_CHANNEL_ALLOC_HI, &old_chnl,
25247c478bd9Sstevel@tonic-gate 					    &err);
25257c478bd9Sstevel@tonic-gate 				} else {
25267c478bd9Sstevel@tonic-gate 					ret = s1394_channel_alloc(hal,
25277c478bd9Sstevel@tonic-gate 					    try_chnl, generation,
25287c478bd9Sstevel@tonic-gate 					    S1394_CHANNEL_ALLOC_LO, &old_chnl,
25297c478bd9Sstevel@tonic-gate 					    &err);
25307c478bd9Sstevel@tonic-gate 				}
25317c478bd9Sstevel@tonic-gate 				/* Lock the Isoch CEC member list */
25327c478bd9Sstevel@tonic-gate 				mutex_enter(&cec_curr->isoch_cec_mutex);
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate 				/* Did we get a channel? (or a bus reset) */
25357c478bd9Sstevel@tonic-gate 				if ((ret == DDI_SUCCESS) ||
25367c478bd9Sstevel@tonic-gate 				    (err == CMD1394_EBUSRESET))
25377c478bd9Sstevel@tonic-gate 					break;
25387c478bd9Sstevel@tonic-gate 			}
25397c478bd9Sstevel@tonic-gate 			temp_chnl_mask = temp_chnl_mask >> 1;
25407c478bd9Sstevel@tonic-gate 		}
25417c478bd9Sstevel@tonic-gate 
25427c478bd9Sstevel@tonic-gate 		/* If we've tried all the possible channels, then fail */
25437c478bd9Sstevel@tonic-gate 		if (chnl_num == 0) {
25447c478bd9Sstevel@tonic-gate 			*result = T1394_ENO_CHANNEL;
25457c478bd9Sstevel@tonic-gate 			/*
25467c478bd9Sstevel@tonic-gate 			 * If we successfully allocate bandwidth, and
25477c478bd9Sstevel@tonic-gate 			 * then fail getting a channel, we need to
25487c478bd9Sstevel@tonic-gate 			 * free up the bandwidth
25497c478bd9Sstevel@tonic-gate 			 */
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate 			/* Check that the generation has not changed */
25527c478bd9Sstevel@tonic-gate 			/* lock not needed here (read only) */
25537c478bd9Sstevel@tonic-gate 			if (generation != hal->generation_count)
25547c478bd9Sstevel@tonic-gate 				continue;
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate 			/* Unlock the Isoch CEC member list */
25577c478bd9Sstevel@tonic-gate 			mutex_exit(&cec_curr->isoch_cec_mutex);
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 			/* Try to free up the bandwidth */
25607c478bd9Sstevel@tonic-gate 			ret = s1394_bandwidth_free(hal, bw_alloc_units,
25617c478bd9Sstevel@tonic-gate 			    generation, &err);
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 			/* Lock the Isoch CEC member list */
25647c478bd9Sstevel@tonic-gate 			mutex_enter(&cec_curr->isoch_cec_mutex);
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate 			if (ret == DDI_FAILURE) {
25677c478bd9Sstevel@tonic-gate 				if (err == CMD1394_EBUSRESET) {
25687c478bd9Sstevel@tonic-gate 					continue;
25697c478bd9Sstevel@tonic-gate 				} else {
25707c478bd9Sstevel@tonic-gate 					TNF_PROBE_1(t1394_setup_isoch_cec_error,
25717c478bd9Sstevel@tonic-gate 					    S1394_TNF_SL_ISOCH_ERROR, "",
25727c478bd9Sstevel@tonic-gate 					    tnf_string, msg,
25737c478bd9Sstevel@tonic-gate 					    "Unable to free isoch bandwidth");
25747c478bd9Sstevel@tonic-gate 				}
25757c478bd9Sstevel@tonic-gate 			}
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate 			/* Unlock the Isoch CEC member list */
25787c478bd9Sstevel@tonic-gate 			mutex_exit(&cec_curr->isoch_cec_mutex);
25797c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_setup_isoch_cec_error,
25807c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
25817c478bd9Sstevel@tonic-gate 			    "Unable to allocate isoch channel");
25827c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
25837c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_STACK, "");
25847c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
25857c478bd9Sstevel@tonic-gate 		}
25867c478bd9Sstevel@tonic-gate 
25877c478bd9Sstevel@tonic-gate 		/* If we got a channel, we're done (else start over) */
25887c478bd9Sstevel@tonic-gate 		if (ret == DDI_SUCCESS)
25897c478bd9Sstevel@tonic-gate 			break;
25907c478bd9Sstevel@tonic-gate 		else if (err == CMD1394_EBUSRESET)
25917c478bd9Sstevel@tonic-gate 			continue;
25927c478bd9Sstevel@tonic-gate 	}
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 	/* Have we gotten too many bus resets? */
25957c478bd9Sstevel@tonic-gate 	if (j == S1394_ISOCH_ALLOC_RETRIES) {
25967c478bd9Sstevel@tonic-gate 		*result = T1394_ENO_BANDWIDTH;
25977c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
25987c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
25997c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_setup_isoch_cec_error,
26007c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
26017c478bd9Sstevel@tonic-gate 		    "Unable to allocate isoch channel");
26027c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
26037c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
26047c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
26057c478bd9Sstevel@tonic-gate 	}
26067c478bd9Sstevel@tonic-gate 
26077c478bd9Sstevel@tonic-gate 	cec_curr->realloc_valid	    = B_TRUE;
26087c478bd9Sstevel@tonic-gate 	cec_curr->realloc_chnl_num  = chnl_num;
26097c478bd9Sstevel@tonic-gate 	cec_curr->realloc_bandwidth = cec_curr->bandwidth;
26107c478bd9Sstevel@tonic-gate 	cec_curr->realloc_speed	    = cec_curr->filter_current_speed;
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate setup_do_callbacks:
26137c478bd9Sstevel@tonic-gate 	/* Call all of the setup_target() callbacks */
26147c478bd9Sstevel@tonic-gate 	target_args.channel_num	    = chnl_num;
26157c478bd9Sstevel@tonic-gate 	target_args.channel_speed   = cec_curr->filter_current_speed;
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 	/* Now we are going into the callbacks */
26187c478bd9Sstevel@tonic-gate 	cec_curr->in_callbacks	    = B_TRUE;
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
26217c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate 	member_curr = cec_curr->cec_member_list_head;
26247c478bd9Sstevel@tonic-gate 	*result = 0;
26257c478bd9Sstevel@tonic-gate 	while (member_curr != NULL) {
26267c478bd9Sstevel@tonic-gate 		if (member_curr->isoch_cec_evts.setup_target != NULL) {
26277c478bd9Sstevel@tonic-gate 			setup_callback =
26287c478bd9Sstevel@tonic-gate 			    member_curr->isoch_cec_evts.setup_target;
26297c478bd9Sstevel@tonic-gate 			ret = setup_callback(t1394_isoch_cec_hdl,
26307c478bd9Sstevel@tonic-gate 			    member_curr->isoch_cec_evts_arg, &target_args);
26317c478bd9Sstevel@tonic-gate 			if (ret != DDI_SUCCESS)
26327c478bd9Sstevel@tonic-gate 				*result = T1394_ETARGET;
26337c478bd9Sstevel@tonic-gate 		}
26347c478bd9Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_next;
26357c478bd9Sstevel@tonic-gate 	}
26367c478bd9Sstevel@tonic-gate 
26377c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
26387c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate 	/* We are finished with the callbacks */
26417c478bd9Sstevel@tonic-gate 	cec_curr->in_callbacks = B_FALSE;
26427c478bd9Sstevel@tonic-gate 	if (cec_curr->cec_want_wakeup == B_TRUE) {
26437c478bd9Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_FALSE;
26447c478bd9Sstevel@tonic-gate 		cv_broadcast(&cec_curr->in_callbacks_cv);
26457c478bd9Sstevel@tonic-gate 	}
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate 	/*
26487c478bd9Sstevel@tonic-gate 	 * Now "start" and "teardown" are legal state transitions
26497c478bd9Sstevel@tonic-gate 	 * and "join", "free", and "setup" are illegal state transitions
26507c478bd9Sstevel@tonic-gate 	 */
26517c478bd9Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
26527c478bd9Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_FREE |
26537c478bd9Sstevel@tonic-gate 	    ISOCH_CEC_SETUP));
26547c478bd9Sstevel@tonic-gate 
26557c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
26567c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
26577c478bd9Sstevel@tonic-gate 
26587c478bd9Sstevel@tonic-gate 	/* Return DDI_FAILURE if any targets failed setup */
26597c478bd9Sstevel@tonic-gate 	if (*result != 0) {
26607c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_setup_isoch_cec_error,
26617c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
26627c478bd9Sstevel@tonic-gate 		    "Target returned error in setup_target()");
26637c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
26647c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
26657c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
26667c478bd9Sstevel@tonic-gate 	}
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
26697c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
26707c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
26717c478bd9Sstevel@tonic-gate }
26727c478bd9Sstevel@tonic-gate 
26737c478bd9Sstevel@tonic-gate /*
26747c478bd9Sstevel@tonic-gate  * Function:    t1394_start_isoch_cec()
26757c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
26767c478bd9Sstevel@tonic-gate  *					    t1394_attach()
26777c478bd9Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
26787c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
26797c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
26807c478bd9Sstevel@tonic-gate  *
26817c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		All start_target() callbacks returned
26827c478bd9Sstevel@tonic-gate  *					    successfully
26837c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		One or more start_target() callbacks
26847c478bd9Sstevel@tonic-gate  *					    returned failure
26857c478bd9Sstevel@tonic-gate  *
26867c478bd9Sstevel@tonic-gate  * Description:	t1394_start_isoch_cec() directs the 1394 Software Framework
26877c478bd9Sstevel@tonic-gate  *		to invoke each of the start_target() callbacks, first for
26887c478bd9Sstevel@tonic-gate  *		each listener, then for the talker.
26897c478bd9Sstevel@tonic-gate  */
26907c478bd9Sstevel@tonic-gate /* ARGSUSED */
26917c478bd9Sstevel@tonic-gate int
26927c478bd9Sstevel@tonic-gate t1394_start_isoch_cec(t1394_handle_t t1394_hdl,
26937c478bd9Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
26947c478bd9Sstevel@tonic-gate {
26957c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
26967c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_curr;
26977c478bd9Sstevel@tonic-gate 	int			 ret;
26987c478bd9Sstevel@tonic-gate 	boolean_t		 err;
26997c478bd9Sstevel@tonic-gate 	int	(*start_callback)(t1394_isoch_cec_handle_t, opaque_t);
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_enter,
27027c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
27037c478bd9Sstevel@tonic-gate 
27047c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
27057c478bd9Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
27087c478bd9Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
27097c478bd9Sstevel@tonic-gate 
27107c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
27117c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
27127c478bd9Sstevel@tonic-gate 
27137c478bd9Sstevel@tonic-gate 	/* Are we in any callbacks? */
27147c478bd9Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
27157c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
27167c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
27177c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_start_isoch_cec_error,
27187c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
27197c478bd9Sstevel@tonic-gate 		    "Not allowed to start Isoch CEC (in callbacks)");
27207c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
27217c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
27227c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27237c478bd9Sstevel@tonic-gate 	}
27247c478bd9Sstevel@tonic-gate 
27257c478bd9Sstevel@tonic-gate 	/* Is "start" a legal state transition? */
27267c478bd9Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_START) == 0) {
27277c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
27287c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
27297c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_start_isoch_cec_error,
27307c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
27317c478bd9Sstevel@tonic-gate 		    "Not allowed to start Isoch CEC");
27327c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
27337c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
27347c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27357c478bd9Sstevel@tonic-gate 	}
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 	/* Now we are going into the callbacks */
27387c478bd9Sstevel@tonic-gate 	cec_curr->in_callbacks = B_TRUE;
27397c478bd9Sstevel@tonic-gate 
27407c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
27417c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate 	/*
27447c478bd9Sstevel@tonic-gate 	 * Call all of the start_target() callbacks
27457c478bd9Sstevel@tonic-gate 	 * Start at the tail (listeners first) and
27467c478bd9Sstevel@tonic-gate 	 * go toward the head (talker last)
27477c478bd9Sstevel@tonic-gate 	 */
27487c478bd9Sstevel@tonic-gate 	member_curr = cec_curr->cec_member_list_tail;
27497c478bd9Sstevel@tonic-gate 	err = B_FALSE;
27507c478bd9Sstevel@tonic-gate 	while (member_curr != NULL) {
27517c478bd9Sstevel@tonic-gate 		if (member_curr->isoch_cec_evts.start_target != NULL) {
27527c478bd9Sstevel@tonic-gate 			start_callback =
27537c478bd9Sstevel@tonic-gate 			    member_curr->isoch_cec_evts.start_target;
27547c478bd9Sstevel@tonic-gate 			ret = start_callback(t1394_isoch_cec_hdl,
27557c478bd9Sstevel@tonic-gate 			    member_curr->isoch_cec_evts_arg);
27567c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS)
27577c478bd9Sstevel@tonic-gate 			err = B_TRUE;
27587c478bd9Sstevel@tonic-gate 		}
27597c478bd9Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_prev;
27607c478bd9Sstevel@tonic-gate 	}
27617c478bd9Sstevel@tonic-gate 
27627c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
27637c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 	/* We are finished with the callbacks */
27667c478bd9Sstevel@tonic-gate 	cec_curr->in_callbacks = B_FALSE;
27677c478bd9Sstevel@tonic-gate 	if (cec_curr->cec_want_wakeup == B_TRUE) {
27687c478bd9Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_FALSE;
27697c478bd9Sstevel@tonic-gate 		cv_broadcast(&cec_curr->in_callbacks_cv);
27707c478bd9Sstevel@tonic-gate 	}
27717c478bd9Sstevel@tonic-gate 
27727c478bd9Sstevel@tonic-gate 	/*
27737c478bd9Sstevel@tonic-gate 	 * Now "stop" is a legal state transitions
27747c478bd9Sstevel@tonic-gate 	 * and "start" and "teardown" are illegal state transitions
27757c478bd9Sstevel@tonic-gate 	 */
27767c478bd9Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, ISOCH_CEC_STOP);
27777c478bd9Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
27787c478bd9Sstevel@tonic-gate 
27797c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
27807c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
27817c478bd9Sstevel@tonic-gate 
27827c478bd9Sstevel@tonic-gate 	/* Return DDI_FAILURE if any targets failed start */
27837c478bd9Sstevel@tonic-gate 	if (err == B_TRUE) {
27847c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_start_isoch_cec_error,
27857c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
27867c478bd9Sstevel@tonic-gate 		    "Target returned error in start_target()");
27877c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
27887c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
27897c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27907c478bd9Sstevel@tonic-gate 	}
27917c478bd9Sstevel@tonic-gate 
27927c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
27937c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
27947c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
27957c478bd9Sstevel@tonic-gate }
27967c478bd9Sstevel@tonic-gate 
27977c478bd9Sstevel@tonic-gate /*
27987c478bd9Sstevel@tonic-gate  * Function:    t1394_stop_isoch_cec()
27997c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
28007c478bd9Sstevel@tonic-gate  *					    t1394_attach()
28017c478bd9Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
28027c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
28037c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
28047c478bd9Sstevel@tonic-gate  *
28057c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully stopped the
28067c478bd9Sstevel@tonic-gate  *					    Isoch CEC
28077c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to stop the Isoch CEC
28087c478bd9Sstevel@tonic-gate  *
28097c478bd9Sstevel@tonic-gate  * Description:	t1394_stop_isoch_cec() directs the 1394 Software Framework
28107c478bd9Sstevel@tonic-gate  *		to invoke each of the stop_target() callbacks, first for
28117c478bd9Sstevel@tonic-gate  *		the talker, then for each listener.
28127c478bd9Sstevel@tonic-gate  *		(This call will fail if it is called at an
28137c478bd9Sstevel@tonic-gate  *		inappropriate time, i.e. before the t1394_start_isoch_cec()
28147c478bd9Sstevel@tonic-gate  *		call, etc.)
28157c478bd9Sstevel@tonic-gate  */
28167c478bd9Sstevel@tonic-gate /* ARGSUSED */
28177c478bd9Sstevel@tonic-gate int
28187c478bd9Sstevel@tonic-gate t1394_stop_isoch_cec(t1394_handle_t t1394_hdl,
28197c478bd9Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
28207c478bd9Sstevel@tonic-gate {
28217c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
28227c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_curr;
28237c478bd9Sstevel@tonic-gate 	void	(*stop_callback)(t1394_isoch_cec_handle_t, opaque_t);
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_enter,
28267c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
28297c478bd9Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
28327c478bd9Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
28357c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
28367c478bd9Sstevel@tonic-gate 
28377c478bd9Sstevel@tonic-gate 	/* Are we in any callbacks? */
28387c478bd9Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
28397c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
28407c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
28417c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_stop_isoch_cec_error,
28427c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
28437c478bd9Sstevel@tonic-gate 		    "Not allowed to stop Isoch CEC (in callbacks)");
28447c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit,
28457c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
28467c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
28477c478bd9Sstevel@tonic-gate 	}
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate 	/* Is "stop" a legal state transition? */
28507c478bd9Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_STOP) == 0) {
28517c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
28527c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
28537c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_stop_isoch_cec_error,
28547c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
28557c478bd9Sstevel@tonic-gate 		    "Not allowed to stop Isoch CEC");
28567c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit,
28577c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
28587c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
28597c478bd9Sstevel@tonic-gate 	}
28607c478bd9Sstevel@tonic-gate 
28617c478bd9Sstevel@tonic-gate 	/* Now we are going into the callbacks */
28627c478bd9Sstevel@tonic-gate 	cec_curr->in_callbacks = B_TRUE;
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
28657c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 	/*
28687c478bd9Sstevel@tonic-gate 	 * Call all of the stop_target() callbacks
28697c478bd9Sstevel@tonic-gate 	 * Start at the head (talker first) and
28707c478bd9Sstevel@tonic-gate 	 * go toward the tail (listeners last)
28717c478bd9Sstevel@tonic-gate 	 */
28727c478bd9Sstevel@tonic-gate 	member_curr = cec_curr->cec_member_list_head;
28737c478bd9Sstevel@tonic-gate 	while (member_curr != NULL) {
28747c478bd9Sstevel@tonic-gate 		if (member_curr->isoch_cec_evts.stop_target != NULL) {
28757c478bd9Sstevel@tonic-gate 			stop_callback =
28767c478bd9Sstevel@tonic-gate 			    member_curr->isoch_cec_evts.stop_target;
28777c478bd9Sstevel@tonic-gate 			stop_callback(t1394_isoch_cec_hdl,
28787c478bd9Sstevel@tonic-gate 			    member_curr->isoch_cec_evts_arg);
28797c478bd9Sstevel@tonic-gate 		}
28807c478bd9Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_next;
28817c478bd9Sstevel@tonic-gate 	}
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
28847c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
28857c478bd9Sstevel@tonic-gate 
28867c478bd9Sstevel@tonic-gate 	/* We are finished with the callbacks */
28877c478bd9Sstevel@tonic-gate 	cec_curr->in_callbacks = B_FALSE;
28887c478bd9Sstevel@tonic-gate 	if (cec_curr->cec_want_wakeup == B_TRUE) {
28897c478bd9Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_FALSE;
28907c478bd9Sstevel@tonic-gate 		cv_broadcast(&cec_curr->in_callbacks_cv);
28917c478bd9Sstevel@tonic-gate 	}
28927c478bd9Sstevel@tonic-gate 
28937c478bd9Sstevel@tonic-gate 	/*
28947c478bd9Sstevel@tonic-gate 	 * Now "start" and "teardown" are legal state transitions
28957c478bd9Sstevel@tonic-gate 	 * and "stop" is an illegal state transitions
28967c478bd9Sstevel@tonic-gate 	 */
28977c478bd9Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
28987c478bd9Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_STOP);
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
29017c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
29027c478bd9Sstevel@tonic-gate 
29037c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit,
29047c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
29057c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
29067c478bd9Sstevel@tonic-gate }
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate /*
29097c478bd9Sstevel@tonic-gate  * Function:    t1394_teardown_isoch_cec()
29107c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
29117c478bd9Sstevel@tonic-gate  *					    t1394_attach()
29127c478bd9Sstevel@tonic-gate  *		t1394_isoch_cec_hdl	The Isoch CEC "handle" returned by
29137c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_cec()
29147c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
29157c478bd9Sstevel@tonic-gate  *
29167c478bd9Sstevel@tonic-gate  * Output(s):	DDI_SUCCESS		Target successfully tore down the
29177c478bd9Sstevel@tonic-gate  *					    Isoch CEC
29187c478bd9Sstevel@tonic-gate  *		DDI_FAILURE		Target failed to tear down the
29197c478bd9Sstevel@tonic-gate  *					    Isoch CEC
29207c478bd9Sstevel@tonic-gate  *
29217c478bd9Sstevel@tonic-gate  * Description:	t1394_teardown_isoch_cec() directs the 1394 Software Framework
29227c478bd9Sstevel@tonic-gate  *		to free up any isochronous resources we might be holding and
29237c478bd9Sstevel@tonic-gate  *		call all of the teardown_target() callbacks.
29247c478bd9Sstevel@tonic-gate  *		(This call will fail if it is called at an
29257c478bd9Sstevel@tonic-gate  *		inappropriate time, i.e. before the t1394_start_isoch_cec()
29267c478bd9Sstevel@tonic-gate  *		call, before the t1394_stop_isoch_cec, etc.
29277c478bd9Sstevel@tonic-gate  */
29287c478bd9Sstevel@tonic-gate /* ARGSUSED */
29297c478bd9Sstevel@tonic-gate int
29307c478bd9Sstevel@tonic-gate t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl,
29317c478bd9Sstevel@tonic-gate     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
29327c478bd9Sstevel@tonic-gate {
29337c478bd9Sstevel@tonic-gate 	s1394_hal_t		 *hal;
29347c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_t	 *cec_curr;
29357c478bd9Sstevel@tonic-gate 	s1394_isoch_cec_member_t *member_curr;
29367c478bd9Sstevel@tonic-gate 	uint32_t		 chnl_mask;
29377c478bd9Sstevel@tonic-gate 	uint32_t		 old_chnl_mask;
29387c478bd9Sstevel@tonic-gate 	uint_t			 bw_alloc_units;
29397c478bd9Sstevel@tonic-gate 	uint_t			 generation;
29407c478bd9Sstevel@tonic-gate 	int			 ret;
29417c478bd9Sstevel@tonic-gate 	int			 err;
29427c478bd9Sstevel@tonic-gate 	void	(*teardown_callback)(t1394_isoch_cec_handle_t, opaque_t);
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_enter,
29457c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
29467c478bd9Sstevel@tonic-gate 
29477c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
29487c478bd9Sstevel@tonic-gate 	ASSERT(t1394_isoch_cec_hdl != NULL);
29497c478bd9Sstevel@tonic-gate 
29507c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate 	/* Convert the handle to an Isoch CEC pointer */
29537c478bd9Sstevel@tonic-gate 	cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
29547c478bd9Sstevel@tonic-gate 
29557c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
29567c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
29577c478bd9Sstevel@tonic-gate 
29587c478bd9Sstevel@tonic-gate 	/* Are we in any callbacks? */
29597c478bd9Sstevel@tonic-gate 	if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
29607c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
29617c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
29627c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_teardown_isoch_cec_error,
29637c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
29647c478bd9Sstevel@tonic-gate 		    "Not allowed to teardown Isoch CEC (in callbacks)");
29657c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit,
29667c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
29677c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
29687c478bd9Sstevel@tonic-gate 	}
29697c478bd9Sstevel@tonic-gate 
29707c478bd9Sstevel@tonic-gate 	/* Is "teardown" a legal state transition? */
29717c478bd9Sstevel@tonic-gate 	if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_TEARDOWN) == 0) {
29727c478bd9Sstevel@tonic-gate 		/* Unlock the Isoch CEC member list */
29737c478bd9Sstevel@tonic-gate 		mutex_exit(&cec_curr->isoch_cec_mutex);
29747c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_teardown_isoch_cec_error,
29757c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
29767c478bd9Sstevel@tonic-gate 		    "Not allowed to teardown Isoch CEC");
29777c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit,
29787c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
29797c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
29807c478bd9Sstevel@tonic-gate 	}
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	/* If T1394_NO_IRM_ALLOC is set then don't free... do callbacks */
29837c478bd9Sstevel@tonic-gate 	if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
29847c478bd9Sstevel@tonic-gate 		goto teardown_do_callbacks;
29857c478bd9Sstevel@tonic-gate 	}
29867c478bd9Sstevel@tonic-gate 
29877c478bd9Sstevel@tonic-gate 	/* If nothing has been allocated or we failed to */
29887c478bd9Sstevel@tonic-gate 	/* reallocate, then we are done... call the callbacks */
29897c478bd9Sstevel@tonic-gate 	if ((cec_curr->realloc_valid == B_FALSE) ||
29907c478bd9Sstevel@tonic-gate 	    (cec_curr->realloc_failed == B_TRUE)) {
29917c478bd9Sstevel@tonic-gate 		goto teardown_do_callbacks;
29927c478bd9Sstevel@tonic-gate 	}
29937c478bd9Sstevel@tonic-gate 
29947c478bd9Sstevel@tonic-gate 	/*
29957c478bd9Sstevel@tonic-gate 	 * Get the current generation number - don't need the
29967c478bd9Sstevel@tonic-gate 	 * topology tree mutex here because it is read-only, and
29977c478bd9Sstevel@tonic-gate 	 * there is a race condition with or without it.
29987c478bd9Sstevel@tonic-gate 	 */
29997c478bd9Sstevel@tonic-gate 	generation = hal->generation_count;
30007c478bd9Sstevel@tonic-gate 
30017c478bd9Sstevel@tonic-gate 	/* Compute the amount bandwidth to free */
30027c478bd9Sstevel@tonic-gate 	bw_alloc_units = s1394_compute_bw_alloc_units(hal,
30037c478bd9Sstevel@tonic-gate 	    cec_curr->bandwidth, cec_curr->realloc_speed);
30047c478bd9Sstevel@tonic-gate 
30057c478bd9Sstevel@tonic-gate 	/* Check that the generation has not changed - */
30067c478bd9Sstevel@tonic-gate 	/* don't need the lock (read only) */
30077c478bd9Sstevel@tonic-gate 	if (generation != hal->generation_count)
30087c478bd9Sstevel@tonic-gate 		goto teardown_do_callbacks;
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
30117c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
30127c478bd9Sstevel@tonic-gate 
30137c478bd9Sstevel@tonic-gate 	/* Try to free up the bandwidth */
30147c478bd9Sstevel@tonic-gate 	ret = s1394_bandwidth_free(hal, bw_alloc_units, generation, &err);
30157c478bd9Sstevel@tonic-gate 
30167c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
30177c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
30187c478bd9Sstevel@tonic-gate 
30197c478bd9Sstevel@tonic-gate 	if (ret == DDI_FAILURE) {
30207c478bd9Sstevel@tonic-gate 		if (err == CMD1394_EBUSRESET) {
30217c478bd9Sstevel@tonic-gate 			goto teardown_do_callbacks;
30227c478bd9Sstevel@tonic-gate 		} else {
30237c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_teardown_isoch_cec_error,
30247c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
30257c478bd9Sstevel@tonic-gate 			    "Unable to free allocated bandwidth");
30267c478bd9Sstevel@tonic-gate 		}
30277c478bd9Sstevel@tonic-gate 	}
30287c478bd9Sstevel@tonic-gate 
30297c478bd9Sstevel@tonic-gate 	/* Free the allocated channel */
30307c478bd9Sstevel@tonic-gate 	chnl_mask = (1 << ((63 - cec_curr->realloc_chnl_num) % 32));
30317c478bd9Sstevel@tonic-gate 
30327c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
30337c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
30347c478bd9Sstevel@tonic-gate 	if (cec_curr->realloc_chnl_num < 32) {
30357c478bd9Sstevel@tonic-gate 		ret = s1394_channel_free(hal, chnl_mask, generation,
30367c478bd9Sstevel@tonic-gate 		    S1394_CHANNEL_ALLOC_HI, &old_chnl_mask, &err);
30377c478bd9Sstevel@tonic-gate 	} else {
30387c478bd9Sstevel@tonic-gate 		ret = s1394_channel_free(hal, chnl_mask, generation,
30397c478bd9Sstevel@tonic-gate 		    S1394_CHANNEL_ALLOC_LO, &old_chnl_mask, &err);
30407c478bd9Sstevel@tonic-gate 	}
30417c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
30427c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
30437c478bd9Sstevel@tonic-gate 
30447c478bd9Sstevel@tonic-gate 	if (ret == DDI_FAILURE) {
30457c478bd9Sstevel@tonic-gate 		if (err == CMD1394_EBUSRESET) {
30467c478bd9Sstevel@tonic-gate 			goto teardown_do_callbacks;
30477c478bd9Sstevel@tonic-gate 		} else {
30487c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_teardown_isoch_cec_error,
30497c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
30507c478bd9Sstevel@tonic-gate 			    "Unable to free allocated bandwidth");
30517c478bd9Sstevel@tonic-gate 		}
30527c478bd9Sstevel@tonic-gate 	}
30537c478bd9Sstevel@tonic-gate 
30547c478bd9Sstevel@tonic-gate teardown_do_callbacks:
30557c478bd9Sstevel@tonic-gate 	/* From here on reallocation is unnecessary */
30567c478bd9Sstevel@tonic-gate 	cec_curr->realloc_valid	    = B_FALSE;
30577c478bd9Sstevel@tonic-gate 	cec_curr->realloc_chnl_num  = 0;
30587c478bd9Sstevel@tonic-gate 	cec_curr->realloc_bandwidth = 0;
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate 	/* Now we are going into the callbacks */
30617c478bd9Sstevel@tonic-gate 	cec_curr->in_callbacks	    = B_TRUE;
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
30647c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate 	/* Call all of the teardown_target() callbacks */
30677c478bd9Sstevel@tonic-gate 	member_curr = cec_curr->cec_member_list_head;
30687c478bd9Sstevel@tonic-gate 	while (member_curr != NULL) {
30697c478bd9Sstevel@tonic-gate 		if (member_curr->isoch_cec_evts.teardown_target != NULL) {
30707c478bd9Sstevel@tonic-gate 			teardown_callback =
30717c478bd9Sstevel@tonic-gate 			    member_curr->isoch_cec_evts.teardown_target;
30727c478bd9Sstevel@tonic-gate 			teardown_callback(t1394_isoch_cec_hdl,
30737c478bd9Sstevel@tonic-gate 			    member_curr->isoch_cec_evts_arg);
30747c478bd9Sstevel@tonic-gate 		}
30757c478bd9Sstevel@tonic-gate 		member_curr = member_curr->cec_mem_next;
30767c478bd9Sstevel@tonic-gate 	}
30777c478bd9Sstevel@tonic-gate 
30787c478bd9Sstevel@tonic-gate 	/* Lock the Isoch CEC member list */
30797c478bd9Sstevel@tonic-gate 	mutex_enter(&cec_curr->isoch_cec_mutex);
30807c478bd9Sstevel@tonic-gate 
30817c478bd9Sstevel@tonic-gate 	/* We are finished with the callbacks */
30827c478bd9Sstevel@tonic-gate 	cec_curr->in_callbacks = B_FALSE;
30837c478bd9Sstevel@tonic-gate 	if (cec_curr->cec_want_wakeup == B_TRUE) {
30847c478bd9Sstevel@tonic-gate 		cec_curr->cec_want_wakeup = B_FALSE;
30857c478bd9Sstevel@tonic-gate 		cv_broadcast(&cec_curr->in_callbacks_cv);
30867c478bd9Sstevel@tonic-gate 	}
30877c478bd9Sstevel@tonic-gate 
30887c478bd9Sstevel@tonic-gate 	/*
30897c478bd9Sstevel@tonic-gate 	 * Now "join" and "setup" are legal state transitions
30907c478bd9Sstevel@tonic-gate 	 * and "start" and "teardown" are illegal state transitions
30917c478bd9Sstevel@tonic-gate 	 */
30927c478bd9Sstevel@tonic-gate 	CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_SETUP));
30937c478bd9Sstevel@tonic-gate 	CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
30947c478bd9Sstevel@tonic-gate 
30957c478bd9Sstevel@tonic-gate 	/* And if the member list is empty, then "free" is legal too */
30967c478bd9Sstevel@tonic-gate 	if ((cec_curr->cec_member_list_head == NULL) &&
30977c478bd9Sstevel@tonic-gate 	    (cec_curr->cec_member_list_tail == NULL)) {
30987c478bd9Sstevel@tonic-gate 		CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
30997c478bd9Sstevel@tonic-gate 	}
31007c478bd9Sstevel@tonic-gate 
31017c478bd9Sstevel@tonic-gate 	/* Unlock the Isoch CEC member list */
31027c478bd9Sstevel@tonic-gate 	mutex_exit(&cec_curr->isoch_cec_mutex);
31037c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit,
31047c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
31057c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
31067c478bd9Sstevel@tonic-gate }
31077c478bd9Sstevel@tonic-gate 
31087c478bd9Sstevel@tonic-gate /*
31097c478bd9Sstevel@tonic-gate  * Function:    t1394_alloc_isoch_dma()
31107c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
31117c478bd9Sstevel@tonic-gate  *					    t1394_attach()
31127c478bd9Sstevel@tonic-gate  *		idi			This structure contains information
31137c478bd9Sstevel@tonic-gate  *					    for configuring the data flow for
31147c478bd9Sstevel@tonic-gate  *					    isochronous DMA
31157c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
31167c478bd9Sstevel@tonic-gate  *
31177c478bd9Sstevel@tonic-gate  * Output(s):	t1394_idma_hdl		The IDMA "handle" used in all
31187c478bd9Sstevel@tonic-gate  *					    subsequent isoch_dma() calls
31197c478bd9Sstevel@tonic-gate  *		result			Used to pass more specific info back
31207c478bd9Sstevel@tonic-gate  *					    to target
31217c478bd9Sstevel@tonic-gate  *
31227c478bd9Sstevel@tonic-gate  * Description:	t1394_alloc_isoch_dma() allocates and initializes an
31237c478bd9Sstevel@tonic-gate  *		isochronous DMA resource for transmitting or receiving
31247c478bd9Sstevel@tonic-gate  *		isochronous data.  If it fails, result may hold
31257c478bd9Sstevel@tonic-gate  *		T1394_EIDMA_NO_RESRCS, indicating that no isoch DMA resource
31267c478bd9Sstevel@tonic-gate  *		are available.
31277c478bd9Sstevel@tonic-gate  */
31287c478bd9Sstevel@tonic-gate /* ARGSUSED */
31297c478bd9Sstevel@tonic-gate int
31307c478bd9Sstevel@tonic-gate t1394_alloc_isoch_dma(t1394_handle_t t1394_hdl,
31317c478bd9Sstevel@tonic-gate     id1394_isoch_dmainfo_t *idi, uint_t flags,
31327c478bd9Sstevel@tonic-gate     t1394_isoch_dma_handle_t *t1394_idma_hdl, int *result)
31337c478bd9Sstevel@tonic-gate {
31347c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
31357c478bd9Sstevel@tonic-gate 	int		ret;
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_enter,
31387c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
31397c478bd9Sstevel@tonic-gate 
31407c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
31417c478bd9Sstevel@tonic-gate 	ASSERT(idi != NULL);
31427c478bd9Sstevel@tonic-gate 	ASSERT(t1394_idma_hdl != NULL);
31437c478bd9Sstevel@tonic-gate 
31447c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
31457c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
31467c478bd9Sstevel@tonic-gate 
31477c478bd9Sstevel@tonic-gate 	/* Sanity check dma options.  If talk enabled, listen should be off */
31487c478bd9Sstevel@tonic-gate 	if ((idi->idma_options & ID1394_TALK) &&
31497c478bd9Sstevel@tonic-gate 	    (idi->idma_options != ID1394_TALK)) {
31507c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_dma_talk_conflict_error,
31517c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
31527c478bd9Sstevel@tonic-gate 		    "conflicting idma options; talker and listener");
31537c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit,
31547c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate 		*result = T1394_EIDMA_CONFLICT;
31577c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
31587c478bd9Sstevel@tonic-gate 	}
31597c478bd9Sstevel@tonic-gate 
31607c478bd9Sstevel@tonic-gate 	/* Only one listen mode allowed */
31617c478bd9Sstevel@tonic-gate 	if ((idi->idma_options & ID1394_LISTEN_PKT_MODE) &&
31627c478bd9Sstevel@tonic-gate 	    (idi->idma_options & ID1394_LISTEN_BUF_MODE)) {
31637c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_dma_listen_conflict_error,
31647c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
31657c478bd9Sstevel@tonic-gate 		    "conflicting idma options; both listener modes set");
31667c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit,
31677c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_STACK, "");
31687c478bd9Sstevel@tonic-gate 
31697c478bd9Sstevel@tonic-gate 		*result = T1394_EIDMA_CONFLICT;
31707c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
31717c478bd9Sstevel@tonic-gate 	}
31727c478bd9Sstevel@tonic-gate 
31737c478bd9Sstevel@tonic-gate 	/* Have HAL alloc a resource and compile ixl */
31747c478bd9Sstevel@tonic-gate 	ret = HAL_CALL(hal).alloc_isoch_dma(hal->halinfo.hal_private, idi,
31757c478bd9Sstevel@tonic-gate 	    (void **)t1394_idma_hdl, result);
31767c478bd9Sstevel@tonic-gate 
31777c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
31787c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_alloc_isoch_dma_hal_error,
31797c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
31807c478bd9Sstevel@tonic-gate 		    "HAL alloc_isoch_dma error, maybe IXL compilation");
31817c478bd9Sstevel@tonic-gate 		if (*result == IXL1394_ENO_DMA_RESRCS) {
31827c478bd9Sstevel@tonic-gate 			*result = T1394_EIDMA_NO_RESRCS;
31837c478bd9Sstevel@tonic-gate 		}
31847c478bd9Sstevel@tonic-gate 	}
31857c478bd9Sstevel@tonic-gate 
31867c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit,
31877c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
31887c478bd9Sstevel@tonic-gate 	return (ret);
31897c478bd9Sstevel@tonic-gate }
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate /*
31927c478bd9Sstevel@tonic-gate  * Function:    t1394_free_isoch_dma()
31937c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
31947c478bd9Sstevel@tonic-gate  *					    t1394_attach()
31957c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
31967c478bd9Sstevel@tonic-gate  *		t1394_idma_hdl		The IDMA "handle" returned by
31977c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_dma()
31987c478bd9Sstevel@tonic-gate  *
31997c478bd9Sstevel@tonic-gate  * Output(s):	None
32007c478bd9Sstevel@tonic-gate  *
32017c478bd9Sstevel@tonic-gate  * Description:	t1394_free_isoch_dma() is used to free all DMA resources
32027c478bd9Sstevel@tonic-gate  *		allocated for the isoch stream associated with t1394_idma_hdl.
32037c478bd9Sstevel@tonic-gate  */
32047c478bd9Sstevel@tonic-gate /* ARGSUSED */
32057c478bd9Sstevel@tonic-gate void
32067c478bd9Sstevel@tonic-gate t1394_free_isoch_dma(t1394_handle_t t1394_hdl, uint_t flags,
32077c478bd9Sstevel@tonic-gate     t1394_isoch_dma_handle_t *t1394_idma_hdl)
32087c478bd9Sstevel@tonic-gate {
32097c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
32107c478bd9Sstevel@tonic-gate 
32117c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_dma_enter,
32127c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
32157c478bd9Sstevel@tonic-gate 	ASSERT(*t1394_idma_hdl != NULL);
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
32187c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate 	/* Tell HAL to release local isoch dma resources */
32217c478bd9Sstevel@tonic-gate 	HAL_CALL(hal).free_isoch_dma(hal->halinfo.hal_private, *t1394_idma_hdl);
32227c478bd9Sstevel@tonic-gate 
32237c478bd9Sstevel@tonic-gate 	/* Null out isoch handle */
32247c478bd9Sstevel@tonic-gate 	*t1394_idma_hdl = NULL;
32257c478bd9Sstevel@tonic-gate 
32267c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_free_isoch_dma_exit,
32277c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32287c478bd9Sstevel@tonic-gate }
32297c478bd9Sstevel@tonic-gate 
32307c478bd9Sstevel@tonic-gate /*
32317c478bd9Sstevel@tonic-gate  * Function:    t1394_start_isoch_dma()
32327c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
32337c478bd9Sstevel@tonic-gate  *					    t1394_attach()
32347c478bd9Sstevel@tonic-gate  *		t1394_idma_hdl		The IDMA "handle" returned by
32357c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_dma()
32367c478bd9Sstevel@tonic-gate  *		idma_ctrlinfo		This structure contains control args
32377c478bd9Sstevel@tonic-gate  *					    used when starting isoch DMA for
32387c478bd9Sstevel@tonic-gate  *					    the allocated resource
32397c478bd9Sstevel@tonic-gate  *		flags			One flag defined - ID1394_START_ON_CYCLE
32407c478bd9Sstevel@tonic-gate  *
32417c478bd9Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
32427c478bd9Sstevel@tonic-gate  *					    to target
32437c478bd9Sstevel@tonic-gate  *
32447c478bd9Sstevel@tonic-gate  * Description:	t1394_start_isoch_dma() is used to start DMA for the isoch
32457c478bd9Sstevel@tonic-gate  *		stream associated with t1394_idma_hdl.
32467c478bd9Sstevel@tonic-gate  */
32477c478bd9Sstevel@tonic-gate /* ARGSUSED */
32487c478bd9Sstevel@tonic-gate int
32497c478bd9Sstevel@tonic-gate t1394_start_isoch_dma(t1394_handle_t t1394_hdl,
32507c478bd9Sstevel@tonic-gate     t1394_isoch_dma_handle_t t1394_idma_hdl,
32517c478bd9Sstevel@tonic-gate     id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfo, uint_t flags,
32527c478bd9Sstevel@tonic-gate     int *result)
32537c478bd9Sstevel@tonic-gate {
32547c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
32557c478bd9Sstevel@tonic-gate 	int		ret;
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_start_isoch_dma_enter,
32587c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32597c478bd9Sstevel@tonic-gate 
32607c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
32617c478bd9Sstevel@tonic-gate 	ASSERT(t1394_idma_hdl != NULL);
32627c478bd9Sstevel@tonic-gate 	ASSERT(idma_ctrlinfo != NULL);
32637c478bd9Sstevel@tonic-gate 
32647c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
32657c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
32667c478bd9Sstevel@tonic-gate 
32677c478bd9Sstevel@tonic-gate 	ret = HAL_CALL(hal).start_isoch_dma(hal->halinfo.hal_private,
32687c478bd9Sstevel@tonic-gate 	    (void *)t1394_idma_hdl, idma_ctrlinfo, flags, result);
32697c478bd9Sstevel@tonic-gate 
32707c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_start_isoch_dma_exit,
32717c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32727c478bd9Sstevel@tonic-gate 	return (ret);
32737c478bd9Sstevel@tonic-gate }
32747c478bd9Sstevel@tonic-gate 
32757c478bd9Sstevel@tonic-gate /*
32767c478bd9Sstevel@tonic-gate  * Function:    t1394_stop_isoch_dma()
32777c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
32787c478bd9Sstevel@tonic-gate  *					    t1394_attach()
32797c478bd9Sstevel@tonic-gate  *		t1394_idma_hdl		The IDMA "handle" returned by
32807c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_dma()
32817c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
32827c478bd9Sstevel@tonic-gate  *
32837c478bd9Sstevel@tonic-gate  * Output(s):	None
32847c478bd9Sstevel@tonic-gate  *
32857c478bd9Sstevel@tonic-gate  * Description:	t1394_stop_isoch_dma() is used to stop DMA for the isoch
32867c478bd9Sstevel@tonic-gate  *		stream associated with t1394_idma_hdl.
32877c478bd9Sstevel@tonic-gate  */
32887c478bd9Sstevel@tonic-gate /* ARGSUSED */
32897c478bd9Sstevel@tonic-gate void
32907c478bd9Sstevel@tonic-gate t1394_stop_isoch_dma(t1394_handle_t t1394_hdl,
32917c478bd9Sstevel@tonic-gate     t1394_isoch_dma_handle_t t1394_idma_hdl, uint_t flags)
32927c478bd9Sstevel@tonic-gate {
32937c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
32947c478bd9Sstevel@tonic-gate 	int		result;
32957c478bd9Sstevel@tonic-gate 
32967c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_stop_isoch_dma_enter,
32977c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
33007c478bd9Sstevel@tonic-gate 	ASSERT(t1394_idma_hdl != NULL);
33017c478bd9Sstevel@tonic-gate 
33027c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
33037c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
33047c478bd9Sstevel@tonic-gate 
33057c478bd9Sstevel@tonic-gate 	HAL_CALL(hal).stop_isoch_dma(hal->halinfo.hal_private,
33067c478bd9Sstevel@tonic-gate 	    (void *)t1394_idma_hdl, &result);
33077c478bd9Sstevel@tonic-gate 
33087c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_stop_isoch_dma_exit,
33097c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
33107c478bd9Sstevel@tonic-gate }
33117c478bd9Sstevel@tonic-gate 
33127c478bd9Sstevel@tonic-gate /*
33137c478bd9Sstevel@tonic-gate  * Function:    t1394_update_isoch_dma()
33147c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
33157c478bd9Sstevel@tonic-gate  *					    t1394_attach()
33167c478bd9Sstevel@tonic-gate  *		t1394_idma_hdl		The IDMA "handle" returned by
33177c478bd9Sstevel@tonic-gate  *					    t1394_alloc_isoch_dma()
33187c478bd9Sstevel@tonic-gate  *		idma_updateinfo		This structure contains ixl command args
33197c478bd9Sstevel@tonic-gate  *					    used when updating args in an
33207c478bd9Sstevel@tonic-gate  *					    existing list of ixl commands with
33217c478bd9Sstevel@tonic-gate  *					    args in a new list of ixl commands.
33227c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
33237c478bd9Sstevel@tonic-gate  *
33247c478bd9Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
33257c478bd9Sstevel@tonic-gate  *					    to target
33267c478bd9Sstevel@tonic-gate  *
33277c478bd9Sstevel@tonic-gate  * Description:	t1394_update_isoch_dma() is used to alter an IXL program that
33287c478bd9Sstevel@tonic-gate  *		has already been built (compiled) by t1394_alloc_isoch_dma().
33297c478bd9Sstevel@tonic-gate  */
33307c478bd9Sstevel@tonic-gate /* ARGSUSED */
33317c478bd9Sstevel@tonic-gate int
33327c478bd9Sstevel@tonic-gate t1394_update_isoch_dma(t1394_handle_t t1394_hdl,
33337c478bd9Sstevel@tonic-gate     t1394_isoch_dma_handle_t t1394_idma_hdl,
33347c478bd9Sstevel@tonic-gate     id1394_isoch_dma_updateinfo_t *idma_updateinfo, uint_t flags,
33357c478bd9Sstevel@tonic-gate     int *result)
33367c478bd9Sstevel@tonic-gate {
33377c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
33387c478bd9Sstevel@tonic-gate 	int		ret;
33397c478bd9Sstevel@tonic-gate 
33407c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_update_isoch_dma_enter,
33417c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
33427c478bd9Sstevel@tonic-gate 
33437c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
33447c478bd9Sstevel@tonic-gate 	ASSERT(t1394_idma_hdl != NULL);
33457c478bd9Sstevel@tonic-gate 	ASSERT(idma_updateinfo != NULL);
33467c478bd9Sstevel@tonic-gate 
33477c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
33487c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
33497c478bd9Sstevel@tonic-gate 
33507c478bd9Sstevel@tonic-gate 	ret = HAL_CALL(hal).update_isoch_dma(hal->halinfo.hal_private,
33517c478bd9Sstevel@tonic-gate 	    (void *)t1394_idma_hdl, idma_updateinfo, flags, result);
33527c478bd9Sstevel@tonic-gate 
33537c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_update_isoch_dma_exit,
33547c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_ISOCH_STACK, "");
33557c478bd9Sstevel@tonic-gate 	return (ret);
33567c478bd9Sstevel@tonic-gate }
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate /*
33597c478bd9Sstevel@tonic-gate  * Function:    t1394_initiate_bus_reset()
33607c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
33617c478bd9Sstevel@tonic-gate  *					    t1394_attach()
33627c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
33637c478bd9Sstevel@tonic-gate  *
33647c478bd9Sstevel@tonic-gate  * Output(s):	None
33657c478bd9Sstevel@tonic-gate  *
33667c478bd9Sstevel@tonic-gate  * Description:	t1394_initiate_bus_reset() determines whether the local
33677c478bd9Sstevel@tonic-gate  *		device has a P1394A PHY and will support the arbitrated
33687c478bd9Sstevel@tonic-gate  *		short bus reset. If not, it will initiate a normal bus reset.
33697c478bd9Sstevel@tonic-gate  */
33707c478bd9Sstevel@tonic-gate /* ARGSUSED */
33717c478bd9Sstevel@tonic-gate void
33727c478bd9Sstevel@tonic-gate t1394_initiate_bus_reset(t1394_handle_t t1394_hdl, uint_t flags)
33737c478bd9Sstevel@tonic-gate {
33747c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
33757c478bd9Sstevel@tonic-gate 	int		ret;
33767c478bd9Sstevel@tonic-gate 
33777c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_initiate_bus_reset_enter,
33787c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_BR_STACK, "");
33797c478bd9Sstevel@tonic-gate 
33807c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
33817c478bd9Sstevel@tonic-gate 
33827c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
33837c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
33847c478bd9Sstevel@tonic-gate 
33857c478bd9Sstevel@tonic-gate 	/* Reset the bus */
33867c478bd9Sstevel@tonic-gate 	if (hal->halinfo.phy == H1394_PHY_1394A) {
33877c478bd9Sstevel@tonic-gate 		ret = HAL_CALL(hal).short_bus_reset(hal->halinfo.hal_private);
33887c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
33897c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_initiate_bus_reset_error,
33907c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ERROR, "", tnf_string, msg,
33917c478bd9Sstevel@tonic-gate 			    "Error initiating short bus reset");
33927c478bd9Sstevel@tonic-gate 		}
33937c478bd9Sstevel@tonic-gate 	} else {
33947c478bd9Sstevel@tonic-gate 		ret = HAL_CALL(hal).bus_reset(hal->halinfo.hal_private);
33957c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
33967c478bd9Sstevel@tonic-gate 			TNF_PROBE_1(t1394_initiate_bus_reset_error,
33977c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_ERROR, "", tnf_string, msg,
33987c478bd9Sstevel@tonic-gate 			    "Error initiating bus reset");
33997c478bd9Sstevel@tonic-gate 		}
34007c478bd9Sstevel@tonic-gate 	}
34017c478bd9Sstevel@tonic-gate 
34027c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_initiate_bus_reset_exit,
34037c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_BR_STACK, "");
34047c478bd9Sstevel@tonic-gate }
34057c478bd9Sstevel@tonic-gate 
34067c478bd9Sstevel@tonic-gate /*
34077c478bd9Sstevel@tonic-gate  * Function:    t1394_get_topology_map()
34087c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
34097c478bd9Sstevel@tonic-gate  *					    t1394_attach()
34107c478bd9Sstevel@tonic-gate  *		bus_generation		The current generation
34117c478bd9Sstevel@tonic-gate  *		tm_length		The size of the tm_buffer given
34127c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
34137c478bd9Sstevel@tonic-gate  *
34147c478bd9Sstevel@tonic-gate  * Output(s):	tm_buffer		Filled in by the 1394 Software Framework
34157c478bd9Sstevel@tonic-gate  *					    with the contents of the local
34167c478bd9Sstevel@tonic-gate  *					    TOPOLOGY_MAP
34177c478bd9Sstevel@tonic-gate  *
34187c478bd9Sstevel@tonic-gate  * Description:	t1394_get_topology_map() returns the 1394 TOPLOGY_MAP.  See
34197c478bd9Sstevel@tonic-gate  *		IEEE 1394-1995 Section 8.2.3.4.1 for format information.  This
34207c478bd9Sstevel@tonic-gate  *		call can fail if there is a generation mismatch or the
34217c478bd9Sstevel@tonic-gate  *		tm_buffer is too small to hold the TOPOLOGY_MAP.
34227c478bd9Sstevel@tonic-gate  */
34237c478bd9Sstevel@tonic-gate /* ARGSUSED */
34247c478bd9Sstevel@tonic-gate int
34257c478bd9Sstevel@tonic-gate t1394_get_topology_map(t1394_handle_t t1394_hdl, uint_t bus_generation,
34267c478bd9Sstevel@tonic-gate     size_t tm_length, uint_t flags, uint32_t *tm_buffer)
34277c478bd9Sstevel@tonic-gate {
34287c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
34297c478bd9Sstevel@tonic-gate 	uint32_t	*tm_ptr;
34307c478bd9Sstevel@tonic-gate 	uint_t		length;
34317c478bd9Sstevel@tonic-gate 
34327c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_get_topology_map_enter, S1394_TNF_SL_CSR_STACK,
34337c478bd9Sstevel@tonic-gate 	    "");
34347c478bd9Sstevel@tonic-gate 
34357c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
34367c478bd9Sstevel@tonic-gate 
34377c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
34387c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
34397c478bd9Sstevel@tonic-gate 
34407c478bd9Sstevel@tonic-gate 	/* Lock the topology tree */
34417c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
34427c478bd9Sstevel@tonic-gate 
34437c478bd9Sstevel@tonic-gate 	/* Check the bus_generation for the Topology Map */
34447c478bd9Sstevel@tonic-gate 	if (bus_generation != hal->generation_count) {
34457c478bd9Sstevel@tonic-gate 		/* Unlock the topology tree */
34467c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
34477c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_get_topology_map_error,
34487c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
34497c478bd9Sstevel@tonic-gate 		    "Generation mismatch");
34507c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit,
34517c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CSR_STACK, "");
34527c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
34537c478bd9Sstevel@tonic-gate 	}
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate 	tm_ptr	= (uint32_t *)hal->CSR_topology_map;
34567c478bd9Sstevel@tonic-gate 	length	= tm_ptr[0] >> 16;
34577c478bd9Sstevel@tonic-gate 	length  = length * 4;	/* Bytes instead of quadlets   */
34587c478bd9Sstevel@tonic-gate 	length  = length + 4;   /* don't forget the first quad */
34597c478bd9Sstevel@tonic-gate 
34607c478bd9Sstevel@tonic-gate 	/* Check that the buffer is big enough */
34617c478bd9Sstevel@tonic-gate 	if (length > (uint_t)tm_length) {
34627c478bd9Sstevel@tonic-gate 		/* Unlock the topology tree */
34637c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
34647c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_get_topology_map_error,
34657c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
34667c478bd9Sstevel@tonic-gate 		    "Buffer size too small");
34677c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit,
34687c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CSR_STACK, "");
34697c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
34707c478bd9Sstevel@tonic-gate 	}
34717c478bd9Sstevel@tonic-gate 
34727c478bd9Sstevel@tonic-gate 	/* Do the copy */
34737c478bd9Sstevel@tonic-gate 	bcopy(tm_ptr, tm_buffer, length);
34747c478bd9Sstevel@tonic-gate 
34757c478bd9Sstevel@tonic-gate 	/* Unlock the topology tree */
34767c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
34777c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit, S1394_TNF_SL_CSR_STACK,
34787c478bd9Sstevel@tonic-gate 	    "");
34797c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
34807c478bd9Sstevel@tonic-gate }
34817c478bd9Sstevel@tonic-gate 
34827c478bd9Sstevel@tonic-gate /*
34837c478bd9Sstevel@tonic-gate  * Function:    t1394_CRC16()
34847c478bd9Sstevel@tonic-gate  * Input(s):    d			The data to compute the CRC-16 for
34857c478bd9Sstevel@tonic-gate  *		crc_length		The length into the data to compute for
34867c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
34877c478bd9Sstevel@tonic-gate  *
34887c478bd9Sstevel@tonic-gate  * Output(s):	CRC			The CRC-16 computed for the length
34897c478bd9Sstevel@tonic-gate  *					    of data specified
34907c478bd9Sstevel@tonic-gate  *
34917c478bd9Sstevel@tonic-gate  * Description:	t1394_CRC16() implements ISO/IEC 13213:1994, ANSI/IEEE Std
34927c478bd9Sstevel@tonic-gate  *		1212, 1994 - 8.1.5.
34937c478bd9Sstevel@tonic-gate  */
34947c478bd9Sstevel@tonic-gate /* ARGSUSED */
34957c478bd9Sstevel@tonic-gate uint_t
34967c478bd9Sstevel@tonic-gate t1394_CRC16(uint32_t *d, size_t crc_length, uint_t flags)
34977c478bd9Sstevel@tonic-gate {
34987c478bd9Sstevel@tonic-gate 	/* Implements ISO/IEC 13213:1994,	*/
34997c478bd9Sstevel@tonic-gate 	/* ANSI/IEEE Std 1212, 1994 - 8.1.5	*/
35007c478bd9Sstevel@tonic-gate 	uint_t	ret;
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_CRC16_enter, S1394_TNF_SL_STACK, "");
35037c478bd9Sstevel@tonic-gate 
35047c478bd9Sstevel@tonic-gate 	ret = s1394_CRC16((uint_t *)d, (uint_t)crc_length);
35057c478bd9Sstevel@tonic-gate 
35067c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_CRC16_exit, S1394_TNF_SL_STACK, "");
35077c478bd9Sstevel@tonic-gate 	return (ret);
35087c478bd9Sstevel@tonic-gate }
35097c478bd9Sstevel@tonic-gate 
35107c478bd9Sstevel@tonic-gate /*
35117c478bd9Sstevel@tonic-gate  * Function:    t1394_add_cfgrom_entry()
35127c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
35137c478bd9Sstevel@tonic-gate  *					    t1394_attach()
35147c478bd9Sstevel@tonic-gate  *		cfgrom_entryinfo	This structure holds the cfgrom key,
35157c478bd9Sstevel@tonic-gate  *					    buffer, and size
35167c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
35177c478bd9Sstevel@tonic-gate  *
35187c478bd9Sstevel@tonic-gate  * Output(s):	t1394_cfgrom_hdl	The ConfigROM "handle" used in
35197c478bd9Sstevel@tonic-gate  *					    t1394_rem_cfgrom_entry()
35207c478bd9Sstevel@tonic-gate  *		result			Used to pass more specific info back
35217c478bd9Sstevel@tonic-gate  *					    to target
35227c478bd9Sstevel@tonic-gate  *
35237c478bd9Sstevel@tonic-gate  * Description:	t1394_add_cfgrom_entry() adds an entry to the local Config ROM,
35247c478bd9Sstevel@tonic-gate  *		updating the directory entries as necessary.  This call could
35257c478bd9Sstevel@tonic-gate  *		fail because there is no room for the new entry in Config ROM
35267c478bd9Sstevel@tonic-gate  *		(T1394_ECFGROM_FULL), the key is invalid (T1394_EINVALID_PARAM),
35277c478bd9Sstevel@tonic-gate  *		or it was called in interrupt context (T1394_EINVALID_CONTEXT).
35287c478bd9Sstevel@tonic-gate  */
35297c478bd9Sstevel@tonic-gate /* ARGSUSED */
35307c478bd9Sstevel@tonic-gate int
35317c478bd9Sstevel@tonic-gate t1394_add_cfgrom_entry(t1394_handle_t t1394_hdl,
35327c478bd9Sstevel@tonic-gate     t1394_cfgrom_entryinfo_t *cfgrom_entryinfo, uint_t flags,
35337c478bd9Sstevel@tonic-gate     t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
35347c478bd9Sstevel@tonic-gate {
35357c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
35367c478bd9Sstevel@tonic-gate 	s1394_target_t	*target;
35377c478bd9Sstevel@tonic-gate 	int		ret;
35387c478bd9Sstevel@tonic-gate 	uint_t		key;
35397c478bd9Sstevel@tonic-gate 	uint_t		size;
35407c478bd9Sstevel@tonic-gate 	uint32_t	*buffer;
35417c478bd9Sstevel@tonic-gate 
35427c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_enter,
35437c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_CFGROM_STACK, "");
35447c478bd9Sstevel@tonic-gate 
35457c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
35467c478bd9Sstevel@tonic-gate 
35477c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
35487c478bd9Sstevel@tonic-gate 
35497c478bd9Sstevel@tonic-gate 	key = cfgrom_entryinfo->ce_key;
35507c478bd9Sstevel@tonic-gate 	buffer = cfgrom_entryinfo->ce_buffer;
35517c478bd9Sstevel@tonic-gate 	size = (uint_t)cfgrom_entryinfo->ce_size;
35527c478bd9Sstevel@tonic-gate 
35537c478bd9Sstevel@tonic-gate 	/* Check for a valid size */
35547c478bd9Sstevel@tonic-gate 	if (size == 0) {
35557c478bd9Sstevel@tonic-gate 		*result = T1394_EINVALID_PARAM;
35567c478bd9Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(t1394_add_cfgrom_entry_error,
35577c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
35587c478bd9Sstevel@tonic-gate 		    "Invalid size of Config ROM buffer (== 0)");
35597c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
35607c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_STACK, "");
35617c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
35627c478bd9Sstevel@tonic-gate 	}
35637c478bd9Sstevel@tonic-gate 
35647c478bd9Sstevel@tonic-gate 	/* Check for a valid key type */
35657c478bd9Sstevel@tonic-gate 	if (((key << IEEE1212_KEY_VALUE_SHIFT) & IEEE1212_KEY_TYPE_MASK) == 0) {
35667c478bd9Sstevel@tonic-gate 		*result = T1394_EINVALID_PARAM;
35677c478bd9Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(t1394_add_cfgrom_entry_error,
35687c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
35697c478bd9Sstevel@tonic-gate 		    "Invalid key_type in Config ROM key");
35707c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
35717c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_STACK, "");
35727c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
35737c478bd9Sstevel@tonic-gate 	}
35747c478bd9Sstevel@tonic-gate 
35757c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
35767c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
35777c478bd9Sstevel@tonic-gate 
35787c478bd9Sstevel@tonic-gate 	/* Is this on the interrupt stack? */
357980a70ef3Sap25164 	if (servicing_interrupt()) {
35807c478bd9Sstevel@tonic-gate 		*result = T1394_EINVALID_CONTEXT;
35817c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
35827c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_STACK, "");
35837c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
35847c478bd9Sstevel@tonic-gate 	}
35857c478bd9Sstevel@tonic-gate 
35867c478bd9Sstevel@tonic-gate 	/* Lock the Config ROM buffer */
35877c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->local_config_rom_mutex);
35887c478bd9Sstevel@tonic-gate 
35897c478bd9Sstevel@tonic-gate 	ret = s1394_add_config_rom_entry(hal, key, buffer, size,
35907c478bd9Sstevel@tonic-gate 	    (void **)t1394_cfgrom_hdl, result);
35917c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
35927c478bd9Sstevel@tonic-gate 		if (*result == CMD1394_ERSRC_CONFLICT)
35937c478bd9Sstevel@tonic-gate 			*result = T1394_ECFGROM_FULL;
35947c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
35957c478bd9Sstevel@tonic-gate 
35967c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_add_cfgrom_entry_error,
35977c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
35987c478bd9Sstevel@tonic-gate 		    "Failed in s1394_add_cfgrom_entry()");
35997c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
36007c478bd9Sstevel@tonic-gate 		    "stacktrace 1394 s1394", "");
36017c478bd9Sstevel@tonic-gate 		return (ret);
36027c478bd9Sstevel@tonic-gate 	}
36037c478bd9Sstevel@tonic-gate 
36047c478bd9Sstevel@tonic-gate 	/* Setup the timeout function */
36057c478bd9Sstevel@tonic-gate 	if (hal->config_rom_timer_set == B_FALSE) {
36067c478bd9Sstevel@tonic-gate 		hal->config_rom_timer_set = B_TRUE;
36077c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36087c478bd9Sstevel@tonic-gate 		hal->config_rom_timer =
36097c478bd9Sstevel@tonic-gate 		    timeout(s1394_update_config_rom_callback, hal,
36107c478bd9Sstevel@tonic-gate 			drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
36117c478bd9Sstevel@tonic-gate 	} else {
36127c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36137c478bd9Sstevel@tonic-gate 	}
36147c478bd9Sstevel@tonic-gate 
36157c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
36167c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_CFGROM_STACK, "");
36177c478bd9Sstevel@tonic-gate 	return (ret);
36187c478bd9Sstevel@tonic-gate }
36197c478bd9Sstevel@tonic-gate 
36207c478bd9Sstevel@tonic-gate /*
36217c478bd9Sstevel@tonic-gate  * Function:    t1394_rem_cfgrom_entry()
36227c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
36237c478bd9Sstevel@tonic-gate  *					    t1394_attach()
36247c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
36257c478bd9Sstevel@tonic-gate  *		t1394_cfgrom_hdl	The ConfigROM "handle" returned by
36267c478bd9Sstevel@tonic-gate  *					    t1394_add_cfgrom_entry()
36277c478bd9Sstevel@tonic-gate  *
36287c478bd9Sstevel@tonic-gate  * Output(s):	result			Used to pass more specific info back
36297c478bd9Sstevel@tonic-gate  *					    to target
36307c478bd9Sstevel@tonic-gate  *
36317c478bd9Sstevel@tonic-gate  * Description:	t1394_rem_cfgrom_entry() is used to remove a previously added
36327c478bd9Sstevel@tonic-gate  *		Config ROM entry (indicated by t1394_cfgrom_hdl).
36337c478bd9Sstevel@tonic-gate  */
36347c478bd9Sstevel@tonic-gate /* ARGSUSED */
36357c478bd9Sstevel@tonic-gate int
36367c478bd9Sstevel@tonic-gate t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl, uint_t flags,
36377c478bd9Sstevel@tonic-gate     t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
36387c478bd9Sstevel@tonic-gate {
36397c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
36407c478bd9Sstevel@tonic-gate 	s1394_target_t	*target;
36417c478bd9Sstevel@tonic-gate 	int		ret;
36427c478bd9Sstevel@tonic-gate 
36437c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_enter,
36447c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_CFGROM_STACK, "");
36457c478bd9Sstevel@tonic-gate 
36467c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
36477c478bd9Sstevel@tonic-gate 
36487c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
36497c478bd9Sstevel@tonic-gate 
36507c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
36517c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
36527c478bd9Sstevel@tonic-gate 
36537c478bd9Sstevel@tonic-gate 	/* Is this on the interrupt stack? */
365480a70ef3Sap25164 	if (servicing_interrupt()) {
36557c478bd9Sstevel@tonic-gate 		*result = T1394_EINVALID_CONTEXT;
36567c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
36577c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_STACK, "");
36587c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
36597c478bd9Sstevel@tonic-gate 	}
36607c478bd9Sstevel@tonic-gate 
36617c478bd9Sstevel@tonic-gate 	/* Lock the Config ROM buffer */
36627c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->local_config_rom_mutex);
36637c478bd9Sstevel@tonic-gate 
36647c478bd9Sstevel@tonic-gate 	ret = s1394_remove_config_rom_entry(hal, (void **)t1394_cfgrom_hdl,
36657c478bd9Sstevel@tonic-gate 	    result);
36667c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
36677c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36687c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(t1394_rem_cfgrom_entry_error,
36697c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
36707c478bd9Sstevel@tonic-gate 		    "Failed in s1394_remove_cfgrom_entry()");
36717c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
36727c478bd9Sstevel@tonic-gate 		    "stacktrace 1394 s1394", "");
36737c478bd9Sstevel@tonic-gate 		return (ret);
36747c478bd9Sstevel@tonic-gate 	}
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate 	/* Setup the timeout function */
36777c478bd9Sstevel@tonic-gate 	if (hal->config_rom_timer_set == B_FALSE) {
36787c478bd9Sstevel@tonic-gate 		hal->config_rom_timer_set = B_TRUE;
36797c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36807c478bd9Sstevel@tonic-gate 		hal->config_rom_timer =
36817c478bd9Sstevel@tonic-gate 		    timeout(s1394_update_config_rom_callback, hal,
36827c478bd9Sstevel@tonic-gate 			drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
36837c478bd9Sstevel@tonic-gate 	} else {
36847c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->local_config_rom_mutex);
36857c478bd9Sstevel@tonic-gate 	}
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
36887c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_CFGROM_STACK, "");
36897c478bd9Sstevel@tonic-gate 	return (ret);
36907c478bd9Sstevel@tonic-gate }
36917c478bd9Sstevel@tonic-gate 
36927c478bd9Sstevel@tonic-gate /*
36937c478bd9Sstevel@tonic-gate  * Function:    t1394_get_targetinfo()
36947c478bd9Sstevel@tonic-gate  * Input(s):    t1394_hdl		The target "handle" returned by
36957c478bd9Sstevel@tonic-gate  *					    t1394_attach()
36967c478bd9Sstevel@tonic-gate  *		bus_generation		The current generation
36977c478bd9Sstevel@tonic-gate  *		flags			The flags parameter is unused (for now)
36987c478bd9Sstevel@tonic-gate  *
36997c478bd9Sstevel@tonic-gate  * Output(s):	targetinfo		Structure containing max_payload,
37007c478bd9Sstevel@tonic-gate  *					    max_speed, and target node ID.
37017c478bd9Sstevel@tonic-gate  *
37027c478bd9Sstevel@tonic-gate  * Description:	t1394_get_targetinfo() is used to retrieve information specific
37037c478bd9Sstevel@tonic-gate  *		to a target device.  It will fail if the generation given
37047c478bd9Sstevel@tonic-gate  *		does not match the current generation.
37057c478bd9Sstevel@tonic-gate  */
37067c478bd9Sstevel@tonic-gate /* ARGSUSED */
37077c478bd9Sstevel@tonic-gate int
37087c478bd9Sstevel@tonic-gate t1394_get_targetinfo(t1394_handle_t t1394_hdl, uint_t bus_generation,
37097c478bd9Sstevel@tonic-gate     uint_t flags, t1394_targetinfo_t *targetinfo)
37107c478bd9Sstevel@tonic-gate {
37117c478bd9Sstevel@tonic-gate 	s1394_hal_t	*hal;
37127c478bd9Sstevel@tonic-gate 	s1394_target_t	*target;
37137c478bd9Sstevel@tonic-gate 	uint_t		dev;
37147c478bd9Sstevel@tonic-gate 	uint_t		curr;
37157c478bd9Sstevel@tonic-gate 	uint_t		from_node;
37167c478bd9Sstevel@tonic-gate 	uint_t		to_node;
37177c478bd9Sstevel@tonic-gate 
37187c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(t1394_get_targetinfo_enter, S1394_TNF_SL_STACK, "");
37197c478bd9Sstevel@tonic-gate 
37207c478bd9Sstevel@tonic-gate 	ASSERT(t1394_hdl != NULL);
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
37237c478bd9Sstevel@tonic-gate 	hal = ((s1394_target_t *)t1394_hdl)->on_hal;
37247c478bd9Sstevel@tonic-gate 
37257c478bd9Sstevel@tonic-gate 	target = (s1394_target_t *)t1394_hdl;
37267c478bd9Sstevel@tonic-gate 
37277c478bd9Sstevel@tonic-gate 	/* Lock the topology tree */
37287c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
37297c478bd9Sstevel@tonic-gate 
37307c478bd9Sstevel@tonic-gate 	/* Check the bus_generation */
37317c478bd9Sstevel@tonic-gate 	if (bus_generation != hal->generation_count) {
37327c478bd9Sstevel@tonic-gate 		/* Unlock the topology tree */
37337c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
37347c478bd9Sstevel@tonic-gate 		TNF_PROBE_3(t1394_get_targetinfo_error, S1394_TNF_SL_STACK, "",
37357c478bd9Sstevel@tonic-gate 		    tnf_string, msg, "Generation mismatch",
37367c478bd9Sstevel@tonic-gate 		    tnf_uint, gen, bus_generation,
37377c478bd9Sstevel@tonic-gate 		    tnf_uint, current_gen, hal->generation_count);
37387c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
37397c478bd9Sstevel@tonic-gate 	}
37407c478bd9Sstevel@tonic-gate 
37417c478bd9Sstevel@tonic-gate 	rw_enter(&hal->target_list_rwlock, RW_READER);
37427c478bd9Sstevel@tonic-gate 	/*
37437c478bd9Sstevel@tonic-gate 	 * If there is no node, report T1394_INVALID_NODEID for target_nodeID;
37447c478bd9Sstevel@tonic-gate 	 * current_max_speed and current_max_payload are undefined for this
37457c478bd9Sstevel@tonic-gate 	 * case.
37467c478bd9Sstevel@tonic-gate 	 */
37477c478bd9Sstevel@tonic-gate 	if (((target->target_state & S1394_TARG_GONE) != 0) ||
37487c478bd9Sstevel@tonic-gate 	    (target->on_node == NULL)) {
37497c478bd9Sstevel@tonic-gate 		targetinfo->target_nodeID = T1394_INVALID_NODEID;
37507c478bd9Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(t1394_get_targetinfo_exit,
37517c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_STACK, "", tnf_string, msg, "No device");
37527c478bd9Sstevel@tonic-gate 	} else {
37537c478bd9Sstevel@tonic-gate 		targetinfo->target_nodeID =
37547c478bd9Sstevel@tonic-gate 		    (target->on_hal->node_id & IEEE1394_BUS_NUM_MASK) |
37557c478bd9Sstevel@tonic-gate 		    target->on_node->node_num;
37567c478bd9Sstevel@tonic-gate 
37577c478bd9Sstevel@tonic-gate 		from_node = (target->on_hal->node_id) & IEEE1394_NODE_NUM_MASK;
37587c478bd9Sstevel@tonic-gate 		to_node = target->on_node->node_num;
37597c478bd9Sstevel@tonic-gate 
37607c478bd9Sstevel@tonic-gate 		targetinfo->current_max_speed = (uint_t)s1394_speed_map_get(
37617c478bd9Sstevel@tonic-gate 		    hal, from_node, to_node);
37627c478bd9Sstevel@tonic-gate 
37637c478bd9Sstevel@tonic-gate 		/* Get current_max_payload */
37647c478bd9Sstevel@tonic-gate 		s1394_get_maxpayload(target, &dev, &curr);
37657c478bd9Sstevel@tonic-gate 		targetinfo->current_max_payload	= curr;
37667c478bd9Sstevel@tonic-gate 
37677c478bd9Sstevel@tonic-gate 		TNF_PROBE_3_DEBUG(t1394_get_targetinfo_exit,
37687c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_STACK, "",
37697c478bd9Sstevel@tonic-gate 		    tnf_uint, payload, targetinfo->current_max_payload,
37707c478bd9Sstevel@tonic-gate 		    tnf_uint, speed, targetinfo->current_max_speed,
37717c478bd9Sstevel@tonic-gate 		    tnf_uint, nodeid, targetinfo->target_nodeID);
37727c478bd9Sstevel@tonic-gate 	}
37737c478bd9Sstevel@tonic-gate 
37747c478bd9Sstevel@tonic-gate 	rw_exit(&hal->target_list_rwlock);
37757c478bd9Sstevel@tonic-gate 	/* Unlock the topology tree */
37767c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
37777c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
37787c478bd9Sstevel@tonic-gate }
3779