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