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