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